Busybox: Upgrade to 1.21.1 (stable). lsof active.
[tomato.git] / release / src / router / php / Zend / zend_language_scanner.l
blob97c938ebf6cf1ade3218670802b42c56dea26624
1 /*
2    +----------------------------------------------------------------------+
3    | Zend Engine                                                          |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1998-2013 Zend Technologies Ltd. (http://www.zend.com) |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 2.00 of the Zend license,     |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.zend.com/license/2_00.txt.                                |
11    | If you did not receive a copy of the Zend license and are unable to  |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@zend.com so we can mail you a copy immediately.              |
14    +----------------------------------------------------------------------+
15    | Authors: Marcus Boerger <helly@php.net>                              |
16    |          Nuno Lopes <nlopess@php.net>                                |
17    |          Scott MacVicar <scottmac@php.net>                           |
18    | Flex version authors:                                                |
19    |          Andi Gutmans <andi@zend.com>                                |
20    |          Zeev Suraski <zeev@zend.com>                                |
21    +----------------------------------------------------------------------+
24 /* $Id$ */
26 #if 0
27 # define YYDEBUG(s, c) printf("state: %d char: %c\n", s, c)
28 #else
29 # define YYDEBUG(s, c)
30 #endif
32 #include "zend_language_scanner_defs.h"
34 #include <errno.h>
35 #include "zend.h"
36 #ifdef PHP_WIN32
37 # include <Winuser.h>
38 #endif
39 #include "zend_alloc.h"
40 #include <zend_language_parser.h>
41 #include "zend_compile.h"
42 #include "zend_language_scanner.h"
43 #include "zend_highlight.h"
44 #include "zend_constants.h"
45 #include "zend_variables.h"
46 #include "zend_operators.h"
47 #include "zend_API.h"
48 #include "zend_strtod.h"
49 #include "zend_exceptions.h"
50 #include "tsrm_virtual_cwd.h"
51 #include "tsrm_config_common.h"
53 #define YYCTYPE   unsigned char
54 #define YYFILL(n) { if ((YYCURSOR + n) >= (YYLIMIT + ZEND_MMAP_AHEAD)) { return 0; } }
55 #define YYCURSOR  SCNG(yy_cursor)
56 #define YYLIMIT   SCNG(yy_limit)
57 #define YYMARKER  SCNG(yy_marker)
59 #define YYGETCONDITION()  SCNG(yy_state)
60 #define YYSETCONDITION(s) SCNG(yy_state) = s
62 #define STATE(name)  yyc##name
64 /* emulate flex constructs */
65 #define BEGIN(state) YYSETCONDITION(STATE(state))
66 #define YYSTATE      YYGETCONDITION()
67 #define yytext       ((char*)SCNG(yy_text))
68 #define yyleng       SCNG(yy_leng)
69 #define yyless(x)    do { YYCURSOR = (unsigned char*)yytext + x; \
70                           yyleng   = (unsigned int)x; } while(0)
71 #define yymore()     goto yymore_restart
73 /* perform sanity check. If this message is triggered you should
74    increase the ZEND_MMAP_AHEAD value in the zend_streams.h file */
75 /*!max:re2c */
76 #if ZEND_MMAP_AHEAD < YYMAXFILL
77 # error ZEND_MMAP_AHEAD should be greater than or equal to YYMAXFILL
78 #endif
80 #ifdef HAVE_STDARG_H
81 # include <stdarg.h>
82 #endif
84 #ifdef HAVE_UNISTD_H
85 # include <unistd.h>
86 #endif
88 /* Globals Macros */
89 #define SCNG    LANG_SCNG
90 #ifdef ZTS
91 ZEND_API ts_rsrc_id language_scanner_globals_id;
92 #else
93 ZEND_API zend_php_scanner_globals language_scanner_globals;
94 #endif
96 #define HANDLE_NEWLINES(s, l)                                                                                                   \
97 do {                                                                                                                                                    \
98         char *p = (s), *boundary = p+(l);                                                                                       \
99                                                                                                                                                                 \
100         while (p<boundary) {                                                                                                            \
101                 if (*p == '\n' || (*p == '\r' && (*(p+1) != '\n'))) {                                   \
102                         CG(zend_lineno)++;                                                                                                      \
103                 }                                                                                                                                               \
104                 p++;                                                                                                                                    \
105         }                                                                                                                                                       \
106 } while (0)
108 #define HANDLE_NEWLINE(c) \
109 { \
110         if (c == '\n' || c == '\r') { \
111                 CG(zend_lineno)++; \
112         } \
115 /* To save initial string length after scanning to first variable, CG(doc_comment_len) can be reused */
116 #define SET_DOUBLE_QUOTES_SCANNED_LENGTH(len) CG(doc_comment_len) = (len)
117 #define GET_DOUBLE_QUOTES_SCANNED_LENGTH()    CG(doc_comment_len)
119 #define IS_LABEL_START(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z') || (c) == '_' || (c) >= 0x7F)
121 #define ZEND_IS_OCT(c)  ((c)>='0' && (c)<='7')
122 #define ZEND_IS_HEX(c)  (((c)>='0' && (c)<='9') || ((c)>='a' && (c)<='f') || ((c)>='A' && (c)<='F'))
124 BEGIN_EXTERN_C()
126 static size_t encoding_filter_script_to_internal(unsigned char **to, size_t *to_length, const unsigned char *from, size_t from_length TSRMLS_DC)
128         const zend_encoding *internal_encoding = zend_multibyte_get_internal_encoding(TSRMLS_C);
129         assert(internal_encoding && zend_multibyte_check_lexer_compatibility(internal_encoding));
130         return zend_multibyte_encoding_converter(to, to_length, from, from_length, internal_encoding, LANG_SCNG(script_encoding) TSRMLS_CC);
133 static size_t encoding_filter_script_to_intermediate(unsigned char **to, size_t *to_length, const unsigned char *from, size_t from_length TSRMLS_DC)
135         return zend_multibyte_encoding_converter(to, to_length, from, from_length, zend_multibyte_encoding_utf8, LANG_SCNG(script_encoding) TSRMLS_CC);
138 static size_t encoding_filter_intermediate_to_script(unsigned char **to, size_t *to_length, const unsigned char *from, size_t from_length TSRMLS_DC)
140         return zend_multibyte_encoding_converter(to, to_length, from, from_length,
141 LANG_SCNG(script_encoding), zend_multibyte_encoding_utf8 TSRMLS_CC);
144 static size_t encoding_filter_intermediate_to_internal(unsigned char **to, size_t *to_length, const unsigned char *from, size_t from_length TSRMLS_DC)
146         const zend_encoding *internal_encoding = zend_multibyte_get_internal_encoding(TSRMLS_C);
147         assert(internal_encoding && zend_multibyte_check_lexer_compatibility(internal_encoding));
148         return zend_multibyte_encoding_converter(to, to_length, from, from_length,
149 internal_encoding, zend_multibyte_encoding_utf8 TSRMLS_CC);
153 static void _yy_push_state(int new_state TSRMLS_DC)
155         zend_stack_push(&SCNG(state_stack), (void *) &YYGETCONDITION(), sizeof(int));
156         YYSETCONDITION(new_state);
159 #define yy_push_state(state_and_tsrm) _yy_push_state(yyc##state_and_tsrm)
161 static void yy_pop_state(TSRMLS_D)
163         int *stack_state;
164         zend_stack_top(&SCNG(state_stack), (void **) &stack_state);
165         YYSETCONDITION(*stack_state);
166         zend_stack_del_top(&SCNG(state_stack));
169 static void yy_scan_buffer(char *str, unsigned int len TSRMLS_DC)
171         YYCURSOR       = (YYCTYPE*)str;
172         YYLIMIT        = YYCURSOR + len;
173         if (!SCNG(yy_start)) {
174                 SCNG(yy_start) = YYCURSOR;
175         }
178 void startup_scanner(TSRMLS_D)
180         CG(parse_error) = 0;
181         CG(heredoc) = NULL;
182         CG(heredoc_len) = 0;
183         CG(doc_comment) = NULL;
184         CG(doc_comment_len) = 0;
185         zend_stack_init(&SCNG(state_stack));
188 void shutdown_scanner(TSRMLS_D)
190         if (CG(heredoc)) {
191                 efree(CG(heredoc));
192                 CG(heredoc_len)=0;
193         }
194         CG(parse_error) = 0;
195         zend_stack_destroy(&SCNG(state_stack));
196         RESET_DOC_COMMENT();
199 ZEND_API void zend_save_lexical_state(zend_lex_state *lex_state TSRMLS_DC)
201         lex_state->yy_leng   = SCNG(yy_leng);
202         lex_state->yy_start  = SCNG(yy_start);
203         lex_state->yy_text   = SCNG(yy_text);
204         lex_state->yy_cursor = SCNG(yy_cursor);
205         lex_state->yy_marker = SCNG(yy_marker);
206         lex_state->yy_limit  = SCNG(yy_limit);
208         lex_state->state_stack = SCNG(state_stack);
209         zend_stack_init(&SCNG(state_stack));
211         lex_state->in = SCNG(yy_in);
212         lex_state->yy_state = YYSTATE;
213         lex_state->filename = zend_get_compiled_filename(TSRMLS_C);
214         lex_state->lineno = CG(zend_lineno);
216         lex_state->script_org = SCNG(script_org);
217         lex_state->script_org_size = SCNG(script_org_size);
218         lex_state->script_filtered = SCNG(script_filtered);
219         lex_state->script_filtered_size = SCNG(script_filtered_size);
220         lex_state->input_filter = SCNG(input_filter);
221         lex_state->output_filter = SCNG(output_filter);
222         lex_state->script_encoding = SCNG(script_encoding);
225 ZEND_API void zend_restore_lexical_state(zend_lex_state *lex_state TSRMLS_DC)
227         SCNG(yy_leng)   = lex_state->yy_leng;
228         SCNG(yy_start)  = lex_state->yy_start;
229         SCNG(yy_text)   = lex_state->yy_text;
230         SCNG(yy_cursor) = lex_state->yy_cursor;
231         SCNG(yy_marker) = lex_state->yy_marker;
232         SCNG(yy_limit)  = lex_state->yy_limit;
234         zend_stack_destroy(&SCNG(state_stack));
235         SCNG(state_stack) = lex_state->state_stack;
237         SCNG(yy_in) = lex_state->in;
238         YYSETCONDITION(lex_state->yy_state);
239         CG(zend_lineno) = lex_state->lineno;
240         zend_restore_compiled_filename(lex_state->filename TSRMLS_CC);
242         if (SCNG(script_filtered)) {
243                 efree(SCNG(script_filtered));
244                 SCNG(script_filtered) = NULL;
245         }
246         SCNG(script_org) = lex_state->script_org;
247         SCNG(script_org_size) = lex_state->script_org_size;
248         SCNG(script_filtered) = lex_state->script_filtered;
249         SCNG(script_filtered_size) = lex_state->script_filtered_size;
250         SCNG(input_filter) = lex_state->input_filter;
251         SCNG(output_filter) = lex_state->output_filter;
252         SCNG(script_encoding) = lex_state->script_encoding;
254         if (CG(heredoc)) {
255                 efree(CG(heredoc));
256                 CG(heredoc) = NULL;
257                 CG(heredoc_len) = 0;
258         }
261 ZEND_API void zend_destroy_file_handle(zend_file_handle *file_handle TSRMLS_DC)
263         zend_llist_del_element(&CG(open_files), file_handle, (int (*)(void *, void *)) zend_compare_file_handles);
264         /* zend_file_handle_dtor() operates on the copy, so we have to NULLify the original here */
265         file_handle->opened_path = NULL;
266         if (file_handle->free_filename) {
267                 file_handle->filename = NULL;
268         }
271 #define BOM_UTF32_BE    "\x00\x00\xfe\xff"
272 #define BOM_UTF32_LE    "\xff\xfe\x00\x00"
273 #define BOM_UTF16_BE    "\xfe\xff"
274 #define BOM_UTF16_LE    "\xff\xfe"
275 #define BOM_UTF8                "\xef\xbb\xbf"
277 static const zend_encoding *zend_multibyte_detect_utf_encoding(const unsigned char *script, size_t script_size TSRMLS_DC)
279         const unsigned char *p;
280         int wchar_size = 2;
281         int le = 0;
283         /* utf-16 or utf-32? */
284         p = script;
285         while ((p-script) < script_size) {
286                 p = memchr(p, 0, script_size-(p-script)-2);
287                 if (!p) {
288                         break;
289                 }
290                 if (*(p+1) == '\0' && *(p+2) == '\0') {
291                         wchar_size = 4;
292                         break;
293                 }
295                 /* searching for UTF-32 specific byte orders, so this will do */
296                 p += 4;
297         }
299         /* BE or LE? */
300         p = script;
301         while ((p-script) < script_size) {
302                 if (*p == '\0' && *(p+wchar_size-1) != '\0') {
303                         /* BE */
304                         le = 0;
305                         break;
306                 } else if (*p != '\0' && *(p+wchar_size-1) == '\0') {
307                         /* LE* */
308                         le = 1;
309                         break;
310                 }
311                 p += wchar_size;
312         }
314         if (wchar_size == 2) {
315                 return le ? zend_multibyte_encoding_utf16le : zend_multibyte_encoding_utf16be;
316         } else {
317                 return le ? zend_multibyte_encoding_utf32le : zend_multibyte_encoding_utf32be;
318         }
320         return NULL;
323 static const zend_encoding* zend_multibyte_detect_unicode(TSRMLS_D)
325         const zend_encoding *script_encoding = NULL;
326         int bom_size;
327         unsigned char *pos1, *pos2;
329         if (LANG_SCNG(script_org_size) < sizeof(BOM_UTF32_LE)-1) {
330                 return NULL;
331         }
333         /* check out BOM */
334         if (!memcmp(LANG_SCNG(script_org), BOM_UTF32_BE, sizeof(BOM_UTF32_BE)-1)) {
335                 script_encoding = zend_multibyte_encoding_utf32be;
336                 bom_size = sizeof(BOM_UTF32_BE)-1;
337         } else if (!memcmp(LANG_SCNG(script_org), BOM_UTF32_LE, sizeof(BOM_UTF32_LE)-1)) {
338                 script_encoding = zend_multibyte_encoding_utf32le;
339                 bom_size = sizeof(BOM_UTF32_LE)-1;
340         } else if (!memcmp(LANG_SCNG(script_org), BOM_UTF16_BE, sizeof(BOM_UTF16_BE)-1)) {
341                 script_encoding = zend_multibyte_encoding_utf16be;
342                 bom_size = sizeof(BOM_UTF16_BE)-1;
343         } else if (!memcmp(LANG_SCNG(script_org), BOM_UTF16_LE, sizeof(BOM_UTF16_LE)-1)) {
344                 script_encoding = zend_multibyte_encoding_utf16le;
345                 bom_size = sizeof(BOM_UTF16_LE)-1;
346         } else if (!memcmp(LANG_SCNG(script_org), BOM_UTF8, sizeof(BOM_UTF8)-1)) {
347                 script_encoding = zend_multibyte_encoding_utf8;
348                 bom_size = sizeof(BOM_UTF8)-1;
349         }
351         if (script_encoding) {
352                 /* remove BOM */
353                 LANG_SCNG(script_org) += bom_size;
354                 LANG_SCNG(script_org_size) -= bom_size;
356                 return script_encoding;
357         }
359         /* script contains NULL bytes -> auto-detection */
360         if ((pos1 = memchr(LANG_SCNG(script_org), 0, LANG_SCNG(script_org_size)))) {
361                 /* check if the NULL byte is after the __HALT_COMPILER(); */
362                 pos2 = LANG_SCNG(script_org);
364                 while (pos1 - pos2 >= sizeof("__HALT_COMPILER();")-1) {
365                         pos2 = memchr(pos2, '_', pos1 - pos2);
366                         if (!pos2) break;
367                         pos2++;
368                         if (strncasecmp((char*)pos2, "_HALT_COMPILER", sizeof("_HALT_COMPILER")-1) == 0) {
369                                 pos2 += sizeof("_HALT_COMPILER")-1;
370                                 while (*pos2 == ' '  ||
371                                            *pos2 == '\t' ||
372                                            *pos2 == '\r' ||
373                                            *pos2 == '\n') {
374                                         pos2++;
375                                 }
376                                 if (*pos2 == '(') {
377                                         pos2++;
378                                         while (*pos2 == ' '  ||
379                                                    *pos2 == '\t' ||
380                                                    *pos2 == '\r' ||
381                                                    *pos2 == '\n') {
382                                                 pos2++;
383                                         }
384                                         if (*pos2 == ')') {
385                                                 pos2++;
386                                                 while (*pos2 == ' '  ||
387                                                            *pos2 == '\t' ||
388                                                            *pos2 == '\r' ||
389                                                            *pos2 == '\n') {
390                                                         pos2++;
391                                                 }
392                                                 if (*pos2 == ';') {
393                                                         return NULL;
394                                                 }
395                                         }
396                                 }
397                         }
398                 }
399                 /* make best effort if BOM is missing */
400                 return zend_multibyte_detect_utf_encoding(LANG_SCNG(script_org), LANG_SCNG(script_org_size) TSRMLS_CC);
401         }
403         return NULL;
406 static const zend_encoding* zend_multibyte_find_script_encoding(TSRMLS_D)
408         const zend_encoding *script_encoding;
410         if (CG(detect_unicode)) {
411                 /* check out bom(byte order mark) and see if containing wchars */
412                 script_encoding = zend_multibyte_detect_unicode(TSRMLS_C);
413                 if (script_encoding != NULL) {
414                         /* bom or wchar detection is prior to 'script_encoding' option */
415                         return script_encoding;
416                 }
417         }
419         /* if no script_encoding specified, just leave alone */
420         if (!CG(script_encoding_list) || !CG(script_encoding_list_size)) {
421                 return NULL;
422         }
424         /* if multiple encodings specified, detect automagically */
425         if (CG(script_encoding_list_size) > 1) {
426                 return zend_multibyte_encoding_detector(LANG_SCNG(script_org), LANG_SCNG(script_org_size), CG(script_encoding_list), CG(script_encoding_list_size) TSRMLS_CC);
427         }
429         return CG(script_encoding_list)[0];
432 ZEND_API int zend_multibyte_set_filter(const zend_encoding *onetime_encoding TSRMLS_DC)
434         const zend_encoding *internal_encoding = zend_multibyte_get_internal_encoding(TSRMLS_C);
435         const zend_encoding *script_encoding = onetime_encoding ? onetime_encoding: zend_multibyte_find_script_encoding(TSRMLS_C);
437         if (!script_encoding) {
438                 return FAILURE;
439         }
441         /* judge input/output filter */
442         LANG_SCNG(script_encoding) = script_encoding;
443         LANG_SCNG(input_filter) = NULL;
444         LANG_SCNG(output_filter) = NULL;
446         if (!internal_encoding || LANG_SCNG(script_encoding) == internal_encoding) {
447                 if (!zend_multibyte_check_lexer_compatibility(LANG_SCNG(script_encoding))) {
448                         /* and if not, work around w/ script_encoding -> utf-8 -> script_encoding conversion */
449                         LANG_SCNG(input_filter) = encoding_filter_script_to_intermediate;
450                         LANG_SCNG(output_filter) = encoding_filter_intermediate_to_script;
451                 } else {
452                         LANG_SCNG(input_filter) = NULL;
453                         LANG_SCNG(output_filter) = NULL;
454                 }
455                 return SUCCESS;
456         }
458         if (zend_multibyte_check_lexer_compatibility(internal_encoding)) {
459                 LANG_SCNG(input_filter) = encoding_filter_script_to_internal;
460                 LANG_SCNG(output_filter) = NULL;
461         } else if (zend_multibyte_check_lexer_compatibility(LANG_SCNG(script_encoding))) {
462                 LANG_SCNG(input_filter) = NULL;
463                 LANG_SCNG(output_filter) = encoding_filter_script_to_internal;
464         } else {
465                 /* both script and internal encodings are incompatible w/ flex */
466                 LANG_SCNG(input_filter) = encoding_filter_script_to_intermediate;
467                 LANG_SCNG(output_filter) = encoding_filter_intermediate_to_internal;
468         }
470         return 0;
473 ZEND_API int open_file_for_scanning(zend_file_handle *file_handle TSRMLS_DC)
475         const char *file_path = NULL;
476         char *buf;
477         size_t size, offset = 0;
479         /* The shebang line was read, get the current position to obtain the buffer start */
480         if (CG(start_lineno) == 2 && file_handle->type == ZEND_HANDLE_FP && file_handle->handle.fp) {
481                 if ((offset = ftell(file_handle->handle.fp)) == -1) {
482                         offset = 0;
483                 }
484         }
486         if (zend_stream_fixup(file_handle, &buf, &size TSRMLS_CC) == FAILURE) {
487                 return FAILURE;
488         }
490         zend_llist_add_element(&CG(open_files), file_handle);
491         if (file_handle->handle.stream.handle >= (void*)file_handle && file_handle->handle.stream.handle <= (void*)(file_handle+1)) {
492                 zend_file_handle *fh = (zend_file_handle*)zend_llist_get_last(&CG(open_files));
493                 size_t diff = (char*)file_handle->handle.stream.handle - (char*)file_handle;
494                 fh->handle.stream.handle = (void*)(((char*)fh) + diff);
495                 file_handle->handle.stream.handle = fh->handle.stream.handle;
496         }
498         /* Reset the scanner for scanning the new file */
499         SCNG(yy_in) = file_handle;
500         SCNG(yy_start) = NULL;
502         if (size != -1) {
503                 if (CG(multibyte)) {
504                         SCNG(script_org) = (unsigned char*)buf;
505                         SCNG(script_org_size) = size;
506                         SCNG(script_filtered) = NULL;
508                         zend_multibyte_set_filter(NULL TSRMLS_CC);
510                         if (SCNG(input_filter)) {
511                                 if ((size_t)-1 == SCNG(input_filter)(&SCNG(script_filtered), &SCNG(script_filtered_size), SCNG(script_org), SCNG(script_org_size) TSRMLS_CC)) {
512                                         zend_error_noreturn(E_COMPILE_ERROR, "Could not convert the script from the detected "
513                                                         "encoding \"%s\" to a compatible encoding", zend_multibyte_get_encoding_name(LANG_SCNG(script_encoding)));
514                                 }
515                                 buf = (char*)SCNG(script_filtered);
516                                 size = SCNG(script_filtered_size);
517                         }
518                 }
519                 SCNG(yy_start) = (unsigned char *)buf - offset;
520                 yy_scan_buffer(buf, size TSRMLS_CC);
521         } else {
522                 zend_error_noreturn(E_COMPILE_ERROR, "zend_stream_mmap() failed");
523         }
525         BEGIN(INITIAL);
527         if (file_handle->opened_path) {
528                 file_path = file_handle->opened_path;
529         } else {
530                 file_path = file_handle->filename;
531         }
533         zend_set_compiled_filename(file_path TSRMLS_CC);
535         if (CG(start_lineno)) {
536                 CG(zend_lineno) = CG(start_lineno);
537                 CG(start_lineno) = 0;
538         } else {
539                 CG(zend_lineno) = 1;
540         }
542         CG(increment_lineno) = 0;
543         return SUCCESS;
545 END_EXTERN_C()
548 ZEND_API zend_op_array *compile_file(zend_file_handle *file_handle, int type TSRMLS_DC)
550         zend_lex_state original_lex_state;
551         zend_op_array *op_array = (zend_op_array *) emalloc(sizeof(zend_op_array));
552         zend_op_array *original_active_op_array = CG(active_op_array);
553         zend_op_array *retval=NULL;
554         int compiler_result;
555         zend_bool compilation_successful=0;
556         znode retval_znode;
557         zend_bool original_in_compilation = CG(in_compilation);
559         retval_znode.op_type = IS_CONST;
560         retval_znode.u.constant.type = IS_LONG;
561         retval_znode.u.constant.value.lval = 1;
562         Z_UNSET_ISREF(retval_znode.u.constant);
563         Z_SET_REFCOUNT(retval_znode.u.constant, 1);
565         zend_save_lexical_state(&original_lex_state TSRMLS_CC);
567         retval = op_array; /* success oriented */
569         if (open_file_for_scanning(file_handle TSRMLS_CC)==FAILURE) {
570                 if (type==ZEND_REQUIRE) {
571                         zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename TSRMLS_CC);
572                         zend_bailout();
573                 } else {
574                         zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename TSRMLS_CC);
575                 }
576                 compilation_successful=0;
577         } else {
578                 init_op_array(op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC);
579                 CG(in_compilation) = 1;
580                 CG(active_op_array) = op_array;
581                 zend_stack_push(&CG(context_stack), (void *) &CG(context), sizeof(CG(context)));
582                 zend_init_compiler_context(TSRMLS_C);
583                 compiler_result = zendparse(TSRMLS_C);
584                 zend_do_return(&retval_znode, 0 TSRMLS_CC);
585                 CG(in_compilation) = original_in_compilation;
586                 if (compiler_result==1) { /* parser error */
587                         zend_bailout();
588                 }
589                 compilation_successful=1;
590         }
592         if (retval) {
593                 CG(active_op_array) = original_active_op_array;
594                 if (compilation_successful) {
595                         pass_two(op_array TSRMLS_CC);
596                         zend_release_labels(0 TSRMLS_CC);
597                 } else {
598                         efree(op_array);
599                         retval = NULL;
600                 }
601         }
602         zend_restore_lexical_state(&original_lex_state TSRMLS_CC);
603         return retval;
607 zend_op_array *compile_filename(int type, zval *filename TSRMLS_DC)
609         zend_file_handle file_handle;
610         zval tmp;
611         zend_op_array *retval;
612         char *opened_path = NULL;
614         if (filename->type != IS_STRING) {
615                 tmp = *filename;
616                 zval_copy_ctor(&tmp);
617                 convert_to_string(&tmp);
618                 filename = &tmp;
619         }
620         file_handle.filename = filename->value.str.val;
621         file_handle.free_filename = 0;
622         file_handle.type = ZEND_HANDLE_FILENAME;
623         file_handle.opened_path = NULL;
624         file_handle.handle.fp = NULL;
626         retval = zend_compile_file(&file_handle, type TSRMLS_CC);
627         if (retval && file_handle.handle.stream.handle) {
628                 int dummy = 1;
630                 if (!file_handle.opened_path) {
631                         file_handle.opened_path = opened_path = estrndup(filename->value.str.val, filename->value.str.len);
632                 }
634                 zend_hash_add(&EG(included_files), file_handle.opened_path, strlen(file_handle.opened_path)+1, (void *)&dummy, sizeof(int), NULL);
636                 if (opened_path) {
637                         efree(opened_path);
638                 }
639         }
640         zend_destroy_file_handle(&file_handle TSRMLS_CC);
642         if (filename==&tmp) {
643                 zval_dtor(&tmp);
644         }
645         return retval;
648 ZEND_API int zend_prepare_string_for_scanning(zval *str, char *filename TSRMLS_DC)
650         char *buf;
651         size_t size;
653         /* enforce two trailing NULLs for flex... */
654         if (IS_INTERNED(str->value.str.val)) {
655                 char *tmp = safe_emalloc(1, str->value.str.len, ZEND_MMAP_AHEAD);
656                 memcpy(tmp, str->value.str.val, str->value.str.len + ZEND_MMAP_AHEAD);
657                 str->value.str.val = tmp;
658         } else {
659                 str->value.str.val = safe_erealloc(str->value.str.val, 1, str->value.str.len, ZEND_MMAP_AHEAD);
660         }
662         memset(str->value.str.val + str->value.str.len, 0, ZEND_MMAP_AHEAD);
664         SCNG(yy_in) = NULL;
665         SCNG(yy_start) = NULL;
667         buf = str->value.str.val;
668         size = str->value.str.len;
670         if (CG(multibyte)) {
671                 SCNG(script_org) = (unsigned char*)buf;
672                 SCNG(script_org_size) = size;
673                 SCNG(script_filtered) = NULL;
675                 zend_multibyte_set_filter(zend_multibyte_get_internal_encoding(TSRMLS_C) TSRMLS_CC);
677                 if (SCNG(input_filter)) {
678                         if ((size_t)-1 == SCNG(input_filter)(&SCNG(script_filtered), &SCNG(script_filtered_size), SCNG(script_org), SCNG(script_org_size) TSRMLS_CC)) {
679                                 zend_error_noreturn(E_COMPILE_ERROR, "Could not convert the script from the detected "
680                                                 "encoding \"%s\" to a compatible encoding", zend_multibyte_get_encoding_name(LANG_SCNG(script_encoding)));
681                         }
682                         buf = (char*)SCNG(script_filtered);
683                         size = SCNG(script_filtered_size);
684                 }
685         }
687         yy_scan_buffer(buf, size TSRMLS_CC);
689         zend_set_compiled_filename(filename TSRMLS_CC);
690         CG(zend_lineno) = 1;
691         CG(increment_lineno) = 0;
692         return SUCCESS;
696 ZEND_API size_t zend_get_scanned_file_offset(TSRMLS_D)
698         size_t offset = SCNG(yy_cursor) - SCNG(yy_start);
699         if (SCNG(input_filter)) {
700                 size_t original_offset = offset, length = 0;
701                 do {
702                         unsigned char *p = NULL;
703                         if ((size_t)-1 == SCNG(input_filter)(&p, &length, SCNG(script_org), offset TSRMLS_CC)) {
704                                 return (size_t)-1;
705                         }
706                         efree(p);
707                         if (length > original_offset) {
708                                 offset--;
709                         } else if (length < original_offset) {
710                                 offset++;
711                         }
712                 } while (original_offset != length);
713         }
714         return offset;
718 zend_op_array *compile_string(zval *source_string, char *filename TSRMLS_DC)
720         zend_lex_state original_lex_state;
721         zend_op_array *op_array = (zend_op_array *) emalloc(sizeof(zend_op_array));
722         zend_op_array *original_active_op_array = CG(active_op_array);
723         zend_op_array *retval;
724         zval tmp;
725         int compiler_result;
726         zend_bool original_in_compilation = CG(in_compilation);
728         if (source_string->value.str.len==0) {
729                 efree(op_array);
730                 return NULL;
731         }
733         CG(in_compilation) = 1;
735         tmp = *source_string;
736         zval_copy_ctor(&tmp);
737         convert_to_string(&tmp);
738         source_string = &tmp;
740         zend_save_lexical_state(&original_lex_state TSRMLS_CC);
741         if (zend_prepare_string_for_scanning(source_string, filename TSRMLS_CC)==FAILURE) {
742                 efree(op_array);
743                 retval = NULL;
744         } else {
745                 zend_bool orig_interactive = CG(interactive);
747                 CG(interactive) = 0;
748                 init_op_array(op_array, ZEND_EVAL_CODE, INITIAL_OP_ARRAY_SIZE TSRMLS_CC);
749                 CG(interactive) = orig_interactive;
750                 CG(active_op_array) = op_array;
751                 zend_stack_push(&CG(context_stack), (void *) &CG(context), sizeof(CG(context)));
752                 zend_init_compiler_context(TSRMLS_C);
753                 BEGIN(ST_IN_SCRIPTING);
754                 compiler_result = zendparse(TSRMLS_C);
756                 if (SCNG(script_filtered)) {
757                         efree(SCNG(script_filtered));
758                         SCNG(script_filtered) = NULL;
759                 }
761                 if (compiler_result==1) {
762                         CG(active_op_array) = original_active_op_array;
763                         CG(unclean_shutdown)=1;
764                         destroy_op_array(op_array TSRMLS_CC);
765                         efree(op_array);
766                         retval = NULL;
767                 } else {
768                         zend_do_return(NULL, 0 TSRMLS_CC);
769                         CG(active_op_array) = original_active_op_array;
770                         pass_two(op_array TSRMLS_CC);
771                         zend_release_labels(0 TSRMLS_CC);
772                         retval = op_array;
773                 }
774         }
775         zend_restore_lexical_state(&original_lex_state TSRMLS_CC);
776         zval_dtor(&tmp);
777         CG(in_compilation) = original_in_compilation;
778         return retval;
782 BEGIN_EXTERN_C()
783 int highlight_file(char *filename, zend_syntax_highlighter_ini *syntax_highlighter_ini TSRMLS_DC)
785         zend_lex_state original_lex_state;
786         zend_file_handle file_handle;
788         file_handle.type = ZEND_HANDLE_FILENAME;
789         file_handle.filename = filename;
790         file_handle.free_filename = 0;
791         file_handle.opened_path = NULL;
792         zend_save_lexical_state(&original_lex_state TSRMLS_CC);
793         if (open_file_for_scanning(&file_handle TSRMLS_CC)==FAILURE) {
794                 zend_message_dispatcher(ZMSG_FAILED_HIGHLIGHT_FOPEN, filename TSRMLS_CC);
795                 zend_restore_lexical_state(&original_lex_state TSRMLS_CC);
796                 return FAILURE;
797         }
798         zend_highlight(syntax_highlighter_ini TSRMLS_CC);
799         if (SCNG(script_filtered)) {
800                 efree(SCNG(script_filtered));
801                 SCNG(script_filtered) = NULL;
802         }
803         zend_destroy_file_handle(&file_handle TSRMLS_CC);
804         zend_restore_lexical_state(&original_lex_state TSRMLS_CC);
805         return SUCCESS;
808 int highlight_string(zval *str, zend_syntax_highlighter_ini *syntax_highlighter_ini, char *str_name TSRMLS_DC)
810         zend_lex_state original_lex_state;
811         zval tmp = *str;
813         str = &tmp;
814         zval_copy_ctor(str);
815         zend_save_lexical_state(&original_lex_state TSRMLS_CC);
816         if (zend_prepare_string_for_scanning(str, str_name TSRMLS_CC)==FAILURE) {
817                 zend_restore_lexical_state(&original_lex_state TSRMLS_CC);
818                 return FAILURE;
819         }
820         BEGIN(INITIAL);
821         zend_highlight(syntax_highlighter_ini TSRMLS_CC);
822         if (SCNG(script_filtered)) {
823                 efree(SCNG(script_filtered));
824                 SCNG(script_filtered) = NULL;
825         }
826         zend_restore_lexical_state(&original_lex_state TSRMLS_CC);
827         zval_dtor(str);
828         return SUCCESS;
831 ZEND_API void zend_multibyte_yyinput_again(zend_encoding_filter old_input_filter, const zend_encoding *old_encoding TSRMLS_DC)
833         size_t length;
834         unsigned char *new_yy_start;
836         /* convert and set */
837         if (!SCNG(input_filter)) {
838                 if (SCNG(script_filtered)) {
839                         efree(SCNG(script_filtered));
840                         SCNG(script_filtered) = NULL;
841                 }
842                 SCNG(script_filtered_size) = 0;
843                 length = SCNG(script_org_size);
844                 new_yy_start = SCNG(script_org);
845         } else {
846                 if ((size_t)-1 == SCNG(input_filter)(&new_yy_start, &length, SCNG(script_org), SCNG(script_org_size) TSRMLS_CC)) {
847                         zend_error_noreturn(E_COMPILE_ERROR, "Could not convert the script from the detected "
848                                         "encoding \"%s\" to a compatible encoding", zend_multibyte_get_encoding_name(LANG_SCNG(script_encoding)));
849                 }
850                 SCNG(script_filtered) = new_yy_start;
851                 SCNG(script_filtered_size) = length;
852         }
854         SCNG(yy_cursor) = new_yy_start + (SCNG(yy_cursor) - SCNG(yy_start));
855         SCNG(yy_marker) = new_yy_start + (SCNG(yy_marker) - SCNG(yy_start));
856         SCNG(yy_text) = new_yy_start + (SCNG(yy_text) - SCNG(yy_start));
857         SCNG(yy_limit) = new_yy_start + (SCNG(yy_limit) - SCNG(yy_start));
859         SCNG(yy_start) = new_yy_start;
863 # define zend_copy_value(zendlval, yytext, yyleng) \
864         if (SCNG(output_filter)) { \
865                 size_t sz = 0; \
866                 SCNG(output_filter)((unsigned char **)&(zendlval->value.str.val), &sz, (unsigned char *)yytext, (size_t)yyleng TSRMLS_CC); \
867                 zendlval->value.str.len = sz; \
868         } else { \
869                 zendlval->value.str.val = (char *) estrndup(yytext, yyleng); \
870                 zendlval->value.str.len = yyleng; \
871         }
873 static void zend_scan_escape_string(zval *zendlval, char *str, int len, char quote_type TSRMLS_DC)
875         register char *s, *t;
876         char *end;
878         ZVAL_STRINGL(zendlval, str, len, 1);
880         /* convert escape sequences */
881         s = t = zendlval->value.str.val;
882         end = s+zendlval->value.str.len;
883         while (s<end) {
884                 if (*s=='\\') {
885                         s++;
886                         if (s >= end) {
887                                 *t++ = '\\';
888                                 break;
889                         }
891                         switch(*s) {
892                                 case 'n':
893                                         *t++ = '\n';
894                                         zendlval->value.str.len--;
895                                         break;
896                                 case 'r':
897                                         *t++ = '\r';
898                                         zendlval->value.str.len--;
899                                         break;
900                                 case 't':
901                                         *t++ = '\t';
902                                         zendlval->value.str.len--;
903                                         break;
904                                 case 'f':
905                                         *t++ = '\f';
906                                         zendlval->value.str.len--;
907                                         break;
908                                 case 'v':
909                                         *t++ = '\v';
910                                         zendlval->value.str.len--;
911                                         break;
912                                 case 'e':
913 #ifdef PHP_WIN32
914                                         *t++ = VK_ESCAPE;
915 #else
916                                         *t++ = '\e';
917 #endif
918                                         zendlval->value.str.len--;
919                                         break;
920                                 case '"':
921                                 case '`':
922                                         if (*s != quote_type) {
923                                                 *t++ = '\\';
924                                                 *t++ = *s;
925                                                 break;
926                                         }
927                                 case '\\':
928                                 case '$':
929                                         *t++ = *s;
930                                         zendlval->value.str.len--;
931                                         break;
932                                 case 'x':
933                                 case 'X':
934                                         if (ZEND_IS_HEX(*(s+1))) {
935                                                 char hex_buf[3] = { 0, 0, 0 };
937                                                 zendlval->value.str.len--; /* for the 'x' */
939                                                 hex_buf[0] = *(++s);
940                                                 zendlval->value.str.len--;
941                                                 if (ZEND_IS_HEX(*(s+1))) {
942                                                         hex_buf[1] = *(++s);
943                                                         zendlval->value.str.len--;
944                                                 }
945                                                 *t++ = (char) strtol(hex_buf, NULL, 16);
946                                         } else {
947                                                 *t++ = '\\';
948                                                 *t++ = *s;
949                                         }
950                                         break;
951                                 default:
952                                         /* check for an octal */
953                                         if (ZEND_IS_OCT(*s)) {
954                                                 char octal_buf[4] = { 0, 0, 0, 0 };
956                                                 octal_buf[0] = *s;
957                                                 zendlval->value.str.len--;
958                                                 if (ZEND_IS_OCT(*(s+1))) {
959                                                         octal_buf[1] = *(++s);
960                                                         zendlval->value.str.len--;
961                                                         if (ZEND_IS_OCT(*(s+1))) {
962                                                                 octal_buf[2] = *(++s);
963                                                                 zendlval->value.str.len--;
964                                                         }
965                                                 }
966                                                 *t++ = (char) strtol(octal_buf, NULL, 8);
967                                         } else {
968                                                 *t++ = '\\';
969                                                 *t++ = *s;
970                                         }
971                                         break;
972                         }
973                 } else {
974                         *t++ = *s;
975                 }
977                 if (*s == '\n' || (*s == '\r' && (*(s+1) != '\n'))) {
978                         CG(zend_lineno)++;
979                 }
980                 s++;
981         }
982         *t = 0;
983         if (SCNG(output_filter)) {
984                 size_t sz = 0;
985                 s = zendlval->value.str.val;
986                 SCNG(output_filter)((unsigned char **)&(zendlval->value.str.val), &sz, (unsigned char *)s, (size_t)zendlval->value.str.len TSRMLS_CC);
987                 zendlval->value.str.len = sz;
988                 efree(s);
989         }
993 int lex_scan(zval *zendlval TSRMLS_DC)
995 restart:
996         SCNG(yy_text) = YYCURSOR;
998 yymore_restart:
1000 /*!re2c
1001 re2c:yyfill:check = 0;
1002 LNUM    [0-9]+
1003 DNUM    ([0-9]*"."[0-9]+)|([0-9]+"."[0-9]*)
1004 EXPONENT_DNUM   (({LNUM}|{DNUM})[eE][+-]?{LNUM})
1005 HNUM    "0x"[0-9a-fA-F]+
1006 BNUM    "0b"[01]+
1007 LABEL   [a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*
1008 WHITESPACE [ \n\r\t]+
1009 TABS_AND_SPACES [ \t]*
1010 TOKENS [;:,.\[\]()|^&+-/*=%!~$<>?@]
1011 ANY_CHAR [^]
1012 NEWLINE ("\r"|"\n"|"\r\n")
1014 /* compute yyleng before each rule */
1015 <!*> := yyleng = YYCURSOR - SCNG(yy_text);
1018 <ST_IN_SCRIPTING>"exit" {
1019         return T_EXIT;
1022 <ST_IN_SCRIPTING>"die" {
1023         return T_EXIT;
1026 <ST_IN_SCRIPTING>"function" {
1027         return T_FUNCTION;
1030 <ST_IN_SCRIPTING>"const" {
1031         return T_CONST;
1034 <ST_IN_SCRIPTING>"return" {
1035         return T_RETURN;
1038 <ST_IN_SCRIPTING>"try" {
1039         return T_TRY;
1042 <ST_IN_SCRIPTING>"catch" {
1043         return T_CATCH;
1046 <ST_IN_SCRIPTING>"throw" {
1047         return T_THROW;
1050 <ST_IN_SCRIPTING>"if" {
1051         return T_IF;
1054 <ST_IN_SCRIPTING>"elseif" {
1055         return T_ELSEIF;
1058 <ST_IN_SCRIPTING>"endif" {
1059         return T_ENDIF;
1062 <ST_IN_SCRIPTING>"else" {
1063         return T_ELSE;
1066 <ST_IN_SCRIPTING>"while" {
1067         return T_WHILE;
1070 <ST_IN_SCRIPTING>"endwhile" {
1071         return T_ENDWHILE;
1074 <ST_IN_SCRIPTING>"do" {
1075         return T_DO;
1078 <ST_IN_SCRIPTING>"for" {
1079         return T_FOR;
1082 <ST_IN_SCRIPTING>"endfor" {
1083         return T_ENDFOR;
1086 <ST_IN_SCRIPTING>"foreach" {
1087         return T_FOREACH;
1090 <ST_IN_SCRIPTING>"endforeach" {
1091         return T_ENDFOREACH;
1094 <ST_IN_SCRIPTING>"declare" {
1095         return T_DECLARE;
1098 <ST_IN_SCRIPTING>"enddeclare" {
1099         return T_ENDDECLARE;
1102 <ST_IN_SCRIPTING>"instanceof" {
1103         return T_INSTANCEOF;
1106 <ST_IN_SCRIPTING>"as" {
1107         return T_AS;
1110 <ST_IN_SCRIPTING>"switch" {
1111         return T_SWITCH;
1114 <ST_IN_SCRIPTING>"endswitch" {
1115         return T_ENDSWITCH;
1118 <ST_IN_SCRIPTING>"case" {
1119         return T_CASE;
1122 <ST_IN_SCRIPTING>"default" {
1123         return T_DEFAULT;
1126 <ST_IN_SCRIPTING>"break" {
1127         return T_BREAK;
1130 <ST_IN_SCRIPTING>"continue" {
1131         return T_CONTINUE;
1134 <ST_IN_SCRIPTING>"goto" {
1135         return T_GOTO;
1138 <ST_IN_SCRIPTING>"echo" {
1139         return T_ECHO;
1142 <ST_IN_SCRIPTING>"print" {
1143         return T_PRINT;
1146 <ST_IN_SCRIPTING>"class" {
1147         return T_CLASS;
1150 <ST_IN_SCRIPTING>"interface" {
1151         return T_INTERFACE;
1154 <ST_IN_SCRIPTING>"trait" {
1155         return T_TRAIT;
1158 <ST_IN_SCRIPTING>"extends" {
1159         return T_EXTENDS;
1162 <ST_IN_SCRIPTING>"implements" {
1163         return T_IMPLEMENTS;
1166 <ST_IN_SCRIPTING>"->" {
1167         yy_push_state(ST_LOOKING_FOR_PROPERTY TSRMLS_CC);
1168         return T_OBJECT_OPERATOR;
1171 <ST_IN_SCRIPTING,ST_LOOKING_FOR_PROPERTY>{WHITESPACE}+ {
1172         zendlval->value.str.val = yytext; /* no copying - intentional */
1173         zendlval->value.str.len = yyleng;
1174         zendlval->type = IS_STRING;
1175         HANDLE_NEWLINES(yytext, yyleng);
1176         return T_WHITESPACE;
1179 <ST_LOOKING_FOR_PROPERTY>"->" {
1180         return T_OBJECT_OPERATOR;
1183 <ST_LOOKING_FOR_PROPERTY>{LABEL} {
1184         yy_pop_state(TSRMLS_C);
1185         zend_copy_value(zendlval, yytext, yyleng);
1186         zendlval->type = IS_STRING;
1187         return T_STRING;
1190 <ST_LOOKING_FOR_PROPERTY>{ANY_CHAR} {
1191         yyless(0);
1192         yy_pop_state(TSRMLS_C);
1193         goto restart;
1196 <ST_IN_SCRIPTING>"::" {
1197         return T_PAAMAYIM_NEKUDOTAYIM;
1200 <ST_IN_SCRIPTING>"\\" {
1201         return T_NS_SEPARATOR;
1204 <ST_IN_SCRIPTING>"new" {
1205         return T_NEW;
1208 <ST_IN_SCRIPTING>"clone" {
1209         return T_CLONE;
1212 <ST_IN_SCRIPTING>"var" {
1213         return T_VAR;
1216 <ST_IN_SCRIPTING>"("{TABS_AND_SPACES}("int"|"integer"){TABS_AND_SPACES}")" {
1217         return T_INT_CAST;
1220 <ST_IN_SCRIPTING>"("{TABS_AND_SPACES}("real"|"double"|"float"){TABS_AND_SPACES}")" {
1221         return T_DOUBLE_CAST;
1224 <ST_IN_SCRIPTING>"("{TABS_AND_SPACES}("string"|"binary"){TABS_AND_SPACES}")" {
1225         return T_STRING_CAST;
1228 <ST_IN_SCRIPTING>"("{TABS_AND_SPACES}"array"{TABS_AND_SPACES}")" {
1229         return T_ARRAY_CAST;
1232 <ST_IN_SCRIPTING>"("{TABS_AND_SPACES}"object"{TABS_AND_SPACES}")" {
1233         return T_OBJECT_CAST;
1236 <ST_IN_SCRIPTING>"("{TABS_AND_SPACES}("bool"|"boolean"){TABS_AND_SPACES}")" {
1237         return T_BOOL_CAST;
1240 <ST_IN_SCRIPTING>"("{TABS_AND_SPACES}("unset"){TABS_AND_SPACES}")" {
1241         return T_UNSET_CAST;
1244 <ST_IN_SCRIPTING>"eval" {
1245         return T_EVAL;
1248 <ST_IN_SCRIPTING>"include" {
1249         return T_INCLUDE;
1252 <ST_IN_SCRIPTING>"include_once" {
1253         return T_INCLUDE_ONCE;
1256 <ST_IN_SCRIPTING>"require" {
1257         return T_REQUIRE;
1260 <ST_IN_SCRIPTING>"require_once" {
1261         return T_REQUIRE_ONCE;
1264 <ST_IN_SCRIPTING>"namespace" {
1265         return T_NAMESPACE;
1268 <ST_IN_SCRIPTING>"use" {
1269         return T_USE;
1272 <ST_IN_SCRIPTING>"insteadof" {
1273         return T_INSTEADOF;
1276 <ST_IN_SCRIPTING>"global" {
1277         return T_GLOBAL;
1280 <ST_IN_SCRIPTING>"isset" {
1281         return T_ISSET;
1284 <ST_IN_SCRIPTING>"empty" {
1285         return T_EMPTY;
1288 <ST_IN_SCRIPTING>"__halt_compiler" {
1289         return T_HALT_COMPILER;
1292 <ST_IN_SCRIPTING>"static" {
1293         return T_STATIC;
1296 <ST_IN_SCRIPTING>"abstract" {
1297         return T_ABSTRACT;
1300 <ST_IN_SCRIPTING>"final" {
1301         return T_FINAL;
1304 <ST_IN_SCRIPTING>"private" {
1305         return T_PRIVATE;
1308 <ST_IN_SCRIPTING>"protected" {
1309         return T_PROTECTED;
1312 <ST_IN_SCRIPTING>"public" {
1313         return T_PUBLIC;
1316 <ST_IN_SCRIPTING>"unset" {
1317         return T_UNSET;
1320 <ST_IN_SCRIPTING>"=>" {
1321         return T_DOUBLE_ARROW;
1324 <ST_IN_SCRIPTING>"list" {
1325         return T_LIST;
1328 <ST_IN_SCRIPTING>"array" {
1329         return T_ARRAY;
1332 <ST_IN_SCRIPTING>"callable" {
1333  return T_CALLABLE;
1336 <ST_IN_SCRIPTING>"++" {
1337         return T_INC;
1340 <ST_IN_SCRIPTING>"--" {
1341         return T_DEC;
1344 <ST_IN_SCRIPTING>"===" {
1345         return T_IS_IDENTICAL;
1348 <ST_IN_SCRIPTING>"!==" {
1349         return T_IS_NOT_IDENTICAL;
1352 <ST_IN_SCRIPTING>"==" {
1353         return T_IS_EQUAL;
1356 <ST_IN_SCRIPTING>"!="|"<>" {
1357         return T_IS_NOT_EQUAL;
1360 <ST_IN_SCRIPTING>"<=" {
1361         return T_IS_SMALLER_OR_EQUAL;
1364 <ST_IN_SCRIPTING>">=" {
1365         return T_IS_GREATER_OR_EQUAL;
1368 <ST_IN_SCRIPTING>"+=" {
1369         return T_PLUS_EQUAL;
1372 <ST_IN_SCRIPTING>"-=" {
1373         return T_MINUS_EQUAL;
1376 <ST_IN_SCRIPTING>"*=" {
1377         return T_MUL_EQUAL;
1380 <ST_IN_SCRIPTING>"/=" {
1381         return T_DIV_EQUAL;
1384 <ST_IN_SCRIPTING>".=" {
1385         return T_CONCAT_EQUAL;
1388 <ST_IN_SCRIPTING>"%=" {
1389         return T_MOD_EQUAL;
1392 <ST_IN_SCRIPTING>"<<=" {
1393         return T_SL_EQUAL;
1396 <ST_IN_SCRIPTING>">>=" {
1397         return T_SR_EQUAL;
1400 <ST_IN_SCRIPTING>"&=" {
1401         return T_AND_EQUAL;
1404 <ST_IN_SCRIPTING>"|=" {
1405         return T_OR_EQUAL;
1408 <ST_IN_SCRIPTING>"^=" {
1409         return T_XOR_EQUAL;
1412 <ST_IN_SCRIPTING>"||" {
1413         return T_BOOLEAN_OR;
1416 <ST_IN_SCRIPTING>"&&" {
1417         return T_BOOLEAN_AND;
1420 <ST_IN_SCRIPTING>"OR" {
1421         return T_LOGICAL_OR;
1424 <ST_IN_SCRIPTING>"AND" {
1425         return T_LOGICAL_AND;
1428 <ST_IN_SCRIPTING>"XOR" {
1429         return T_LOGICAL_XOR;
1432 <ST_IN_SCRIPTING>"<<" {
1433         return T_SL;
1436 <ST_IN_SCRIPTING>">>" {
1437         return T_SR;
1440 <ST_IN_SCRIPTING>{TOKENS} {
1441         return yytext[0];
1445 <ST_IN_SCRIPTING>"{" {
1446         yy_push_state(ST_IN_SCRIPTING TSRMLS_CC);
1447         return '{';
1451 <ST_DOUBLE_QUOTES,ST_BACKQUOTE,ST_HEREDOC>"${" {
1452         yy_push_state(ST_LOOKING_FOR_VARNAME TSRMLS_CC);
1453         return T_DOLLAR_OPEN_CURLY_BRACES;
1457 <ST_IN_SCRIPTING>"}" {
1458         RESET_DOC_COMMENT();
1459         if (!zend_stack_is_empty(&SCNG(state_stack))) {
1460                 yy_pop_state(TSRMLS_C);
1461         }
1462         return '}';
1466 <ST_LOOKING_FOR_VARNAME>{LABEL} {
1467         zend_copy_value(zendlval, yytext, yyleng);
1468         zendlval->type = IS_STRING;
1469         yy_pop_state(TSRMLS_C);
1470         yy_push_state(ST_IN_SCRIPTING TSRMLS_CC);
1471         return T_STRING_VARNAME;
1475 <ST_LOOKING_FOR_VARNAME>{ANY_CHAR} {
1476         yyless(0);
1477         yy_pop_state(TSRMLS_C);
1478         yy_push_state(ST_IN_SCRIPTING TSRMLS_CC);
1479         goto restart;
1482 <ST_IN_SCRIPTING>{BNUM} {
1483         char *bin = yytext + 2; /* Skip "0b" */
1484         int len = yyleng - 2;
1486         /* Skip any leading 0s */
1487         while (*bin == '0') {
1488                 ++bin;
1489                 --len;
1490         }
1492         if (len < SIZEOF_LONG * 8) {
1493                 if (len == 0) {
1494                         zendlval->value.lval = 0;
1495                 } else {
1496                         zendlval->value.lval = strtol(bin, NULL, 2);
1497                 }
1498                 zendlval->type = IS_LONG;
1499                 return T_LNUMBER;
1500         } else {
1501                 zendlval->value.dval = zend_bin_strtod(bin, NULL);
1502                 zendlval->type = IS_DOUBLE;
1503                 return T_DNUMBER;
1504         }
1507 <ST_IN_SCRIPTING>{LNUM} {
1508         if (yyleng < MAX_LENGTH_OF_LONG - 1) { /* Won't overflow */
1509                 zendlval->value.lval = strtol(yytext, NULL, 0);
1510         } else {
1511                 errno = 0;
1512                 zendlval->value.lval = strtol(yytext, NULL, 0);
1513                 if (errno == ERANGE) { /* Overflow */
1514                         if (yytext[0] == '0') { /* octal overflow */
1515                                 zendlval->value.dval = zend_oct_strtod(yytext, NULL);
1516                         } else {
1517                                 zendlval->value.dval = zend_strtod(yytext, NULL);
1518                         }
1519                         zendlval->type = IS_DOUBLE;
1520                         return T_DNUMBER;
1521                 }
1522         }
1524         zendlval->type = IS_LONG;
1525         return T_LNUMBER;
1528 <ST_IN_SCRIPTING>{HNUM} {
1529         char *hex = yytext + 2; /* Skip "0x" */
1530         int len = yyleng - 2;
1532         /* Skip any leading 0s */
1533         while (*hex == '0') {
1534                 hex++;
1535                 len--;
1536         }
1538         if (len < SIZEOF_LONG * 2 || (len == SIZEOF_LONG * 2 && *hex <= '7')) {
1539                 if (len == 0) {
1540                         zendlval->value.lval = 0;
1541                 } else {
1542                         zendlval->value.lval = strtol(hex, NULL, 16);
1543                 }
1544                 zendlval->type = IS_LONG;
1545                 return T_LNUMBER;
1546         } else {
1547                 zendlval->value.dval = zend_hex_strtod(hex, NULL);
1548                 zendlval->type = IS_DOUBLE;
1549                 return T_DNUMBER;
1550         }
1553 <ST_VAR_OFFSET>[0]|([1-9][0-9]*) { /* Offset could be treated as a long */
1554         if (yyleng < MAX_LENGTH_OF_LONG - 1 || (yyleng == MAX_LENGTH_OF_LONG - 1 && strcmp(yytext, long_min_digits) < 0)) {
1555                 zendlval->value.lval = strtol(yytext, NULL, 10);
1556                 zendlval->type = IS_LONG;
1557         } else {
1558                 zendlval->value.str.val = (char *)estrndup(yytext, yyleng);
1559                 zendlval->value.str.len = yyleng;
1560                 zendlval->type = IS_STRING;
1561         }
1562         return T_NUM_STRING;
1565 <ST_VAR_OFFSET>{LNUM}|{HNUM}|{BNUM} { /* Offset must be treated as a string */
1566         zendlval->value.str.val = (char *)estrndup(yytext, yyleng);
1567         zendlval->value.str.len = yyleng;
1568         zendlval->type = IS_STRING;
1569         return T_NUM_STRING;
1572 <ST_IN_SCRIPTING>{DNUM}|{EXPONENT_DNUM} {
1573         zendlval->value.dval = zend_strtod(yytext, NULL);
1574         zendlval->type = IS_DOUBLE;
1575         return T_DNUMBER;
1578 <ST_IN_SCRIPTING>"__CLASS__" {
1579         const char *class_name = NULL;
1580         
1581         if (CG(active_class_entry)
1582                 && (ZEND_ACC_TRAIT ==
1583                         (CG(active_class_entry)->ce_flags & ZEND_ACC_TRAIT))) {
1584                 /* We create a special __CLASS__ constant that is going to be resolved
1585                    at run-time */
1586                 zendlval->value.str.len = sizeof("__CLASS__")-1;
1587                 zendlval->value.str.val = estrndup("__CLASS__", zendlval->value.str.len);
1588                 zendlval->type = IS_CONSTANT;
1589         } else {
1590                 if (CG(active_class_entry)) {
1591                         class_name = CG(active_class_entry)->name;
1592                 }
1593                 
1594                 if (!class_name) {
1595                         class_name = "";
1596                 }
1597                 
1598                 zendlval->value.str.len = strlen(class_name);
1599                 zendlval->value.str.val = estrndup(class_name, zendlval->value.str.len);
1600                 zendlval->type = IS_STRING;
1601         }
1602         return T_CLASS_C;
1605 <ST_IN_SCRIPTING>"__TRAIT__" {
1606         const char *trait_name = NULL;
1607         
1608         if (CG(active_class_entry)
1609                 && (ZEND_ACC_TRAIT == 
1610                         (CG(active_class_entry)->ce_flags & ZEND_ACC_TRAIT))) {
1611                 trait_name = CG(active_class_entry)->name;
1612         }
1613         
1614         if (!trait_name) {
1615                 trait_name = "";
1616         }
1617         
1618         zendlval->value.str.len = strlen(trait_name);
1619         zendlval->value.str.val = estrndup(trait_name, zendlval->value.str.len);
1620         zendlval->type = IS_STRING;
1621         
1622         return T_TRAIT_C;
1625 <ST_IN_SCRIPTING>"__FUNCTION__" {
1626         const char *func_name = NULL;
1628         if (CG(active_op_array)) {
1629                 func_name = CG(active_op_array)->function_name;
1630         }
1632         if (!func_name) {
1633                 func_name = "";
1634         }
1635         zendlval->value.str.len = strlen(func_name);
1636         zendlval->value.str.val = estrndup(func_name, zendlval->value.str.len);
1637         zendlval->type = IS_STRING;
1638         return T_FUNC_C;
1641 <ST_IN_SCRIPTING>"__METHOD__" {
1642         const char *class_name = CG(active_class_entry) ? CG(active_class_entry)->name : NULL;
1643         const char *func_name = CG(active_op_array)? CG(active_op_array)->function_name : NULL;
1644         size_t len = 0;
1646         if (class_name) {
1647                 len += strlen(class_name) + 2;
1648         }
1649         if (func_name) {
1650                 len += strlen(func_name);
1651         }
1653         zendlval->value.str.len = zend_spprintf(&zendlval->value.str.val, 0, "%s%s%s",
1654                 class_name ? class_name : "",
1655                 class_name && func_name ? "::" : "",
1656                 func_name ? func_name : ""
1657                 );
1658         zendlval->type = IS_STRING;
1659         return T_METHOD_C;
1662 <ST_IN_SCRIPTING>"__LINE__" {
1663         zendlval->value.lval = CG(zend_lineno);
1664         zendlval->type = IS_LONG;
1665         return T_LINE;
1668 <ST_IN_SCRIPTING>"__FILE__" {
1669         char *filename = zend_get_compiled_filename(TSRMLS_C);
1671         if (!filename) {
1672                 filename = "";
1673         }
1674         zendlval->value.str.len = strlen(filename);
1675         zendlval->value.str.val = estrndup(filename, zendlval->value.str.len);
1676         zendlval->type = IS_STRING;
1677         return T_FILE;
1680 <ST_IN_SCRIPTING>"__DIR__" {
1681         char *filename = zend_get_compiled_filename(TSRMLS_C);
1682         const size_t filename_len = strlen(filename);
1683         char *dirname;
1685         if (!filename) {
1686                 filename = "";
1687         }
1689         dirname = estrndup(filename, filename_len);
1690         zend_dirname(dirname, filename_len);
1692         if (strcmp(dirname, ".") == 0) {
1693                 dirname = erealloc(dirname, MAXPATHLEN);
1694 #if HAVE_GETCWD
1695                 VCWD_GETCWD(dirname, MAXPATHLEN);
1696 #elif HAVE_GETWD
1697                 VCWD_GETWD(dirname);
1698 #endif
1699         }
1701         zendlval->value.str.len = strlen(dirname);
1702         zendlval->value.str.val = dirname;
1703         zendlval->type = IS_STRING;
1704         return T_DIR;
1707 <ST_IN_SCRIPTING>"__NAMESPACE__" {
1708         if (CG(current_namespace)) {
1709                 *zendlval = *CG(current_namespace);
1710                 zval_copy_ctor(zendlval);
1711         } else {
1712                 ZVAL_EMPTY_STRING(zendlval);
1713         }
1714         return T_NS_C;
1717 <INITIAL>"<script"{WHITESPACE}+"language"{WHITESPACE}*"="{WHITESPACE}*("php"|"\"php\""|"'php'"){WHITESPACE}*">" {
1718         YYCTYPE *bracket = (YYCTYPE*)zend_memrchr(yytext, '<', yyleng - (sizeof("script language=php>") - 1));
1720         if (bracket != SCNG(yy_text)) {
1721                 /* Handle previously scanned HTML, as possible <script> tags found are assumed to not be PHP's */
1722                 YYCURSOR = bracket;
1723                 goto inline_html;
1724         }
1726         HANDLE_NEWLINES(yytext, yyleng);
1727         zendlval->value.str.val = yytext; /* no copying - intentional */
1728         zendlval->value.str.len = yyleng;
1729         zendlval->type = IS_STRING;
1730         BEGIN(ST_IN_SCRIPTING);
1731         return T_OPEN_TAG;
1735 <INITIAL>"<%=" {
1736         if (CG(asp_tags)) {
1737                 zendlval->value.str.val = yytext; /* no copying - intentional */
1738                 zendlval->value.str.len = yyleng;
1739                 zendlval->type = IS_STRING;
1740                 BEGIN(ST_IN_SCRIPTING);
1741                 return T_OPEN_TAG_WITH_ECHO;
1742         } else {
1743                 goto inline_char_handler;
1744         }
1748 <INITIAL>"<?=" {
1749         zendlval->value.str.val = yytext; /* no copying - intentional */
1750         zendlval->value.str.len = yyleng;
1751         zendlval->type = IS_STRING;
1752         BEGIN(ST_IN_SCRIPTING);
1753         return T_OPEN_TAG_WITH_ECHO;
1757 <INITIAL>"<%" {
1758         if (CG(asp_tags)) {
1759                 zendlval->value.str.val = yytext; /* no copying - intentional */
1760                 zendlval->value.str.len = yyleng;
1761                 zendlval->type = IS_STRING;
1762                 BEGIN(ST_IN_SCRIPTING);
1763                 return T_OPEN_TAG;
1764         } else {
1765                 goto inline_char_handler;
1766         }
1770 <INITIAL>"<?php"([ \t]|{NEWLINE}) {
1771         zendlval->value.str.val = yytext; /* no copying - intentional */
1772         zendlval->value.str.len = yyleng;
1773         zendlval->type = IS_STRING;
1774         HANDLE_NEWLINE(yytext[yyleng-1]);
1775         BEGIN(ST_IN_SCRIPTING);
1776         return T_OPEN_TAG;
1780 <INITIAL>"<?" {
1781         if (CG(short_tags)) {
1782                 zendlval->value.str.val = yytext; /* no copying - intentional */
1783                 zendlval->value.str.len = yyleng;
1784                 zendlval->type = IS_STRING;
1785                 BEGIN(ST_IN_SCRIPTING);
1786                 return T_OPEN_TAG;
1787         } else {
1788                 goto inline_char_handler;
1789         }
1792 <INITIAL>{ANY_CHAR} {
1793         if (YYCURSOR > YYLIMIT) {
1794                 return 0;
1795         }
1797 inline_char_handler:
1799         while (1) {
1800                 YYCTYPE *ptr = memchr(YYCURSOR, '<', YYLIMIT - YYCURSOR);
1802                 YYCURSOR = ptr ? ptr + 1 : YYLIMIT;
1804                 if (YYCURSOR < YYLIMIT) {
1805                         switch (*YYCURSOR) {
1806                                 case '?':
1807                                         if (CG(short_tags) || !strncasecmp((char*)YYCURSOR + 1, "php", 3) || (*(YYCURSOR + 1) == '=')) { /* Assume [ \t\n\r] follows "php" */
1808                                                 break;
1809                                         }
1810                                         continue;
1811                                 case '%':
1812                                         if (CG(asp_tags)) {
1813                                                 break;
1814                                         }
1815                                         continue;
1816                                 case 's':
1817                                 case 'S':
1818                                         /* Probably NOT an opening PHP <script> tag, so don't end the HTML chunk yet
1819                                          * If it is, the PHP <script> tag rule checks for any HTML scanned before it */
1820                                         YYCURSOR--;
1821                                         yymore();
1822                                 default:
1823                                         continue;
1824                         }
1826                         YYCURSOR--;
1827                 }
1829                 break;
1830         }
1832 inline_html:
1833         yyleng = YYCURSOR - SCNG(yy_text);
1835         if (SCNG(output_filter)) {
1836                 int readsize;
1837                 size_t sz = 0;
1838                 readsize = SCNG(output_filter)((unsigned char **)&(zendlval->value.str.val), &sz, (unsigned char *)yytext, (size_t)yyleng TSRMLS_CC);
1839                 zendlval->value.str.len = sz;
1840                 if (readsize < yyleng) {
1841                         yyless(readsize);
1842                 }
1843         } else {
1844           zendlval->value.str.val = (char *) estrndup(yytext, yyleng);
1845           zendlval->value.str.len = yyleng;
1846         }
1847         zendlval->type = IS_STRING;
1848         HANDLE_NEWLINES(yytext, yyleng);
1849         return T_INLINE_HTML;
1853 /* Make sure a label character follows "->", otherwise there is no property
1854  * and "->" will be taken literally
1855  */
1856 <ST_DOUBLE_QUOTES,ST_HEREDOC,ST_BACKQUOTE>"$"{LABEL}"->"[a-zA-Z_\x7f-\xff] {
1857         yyless(yyleng - 3);
1858         yy_push_state(ST_LOOKING_FOR_PROPERTY TSRMLS_CC);
1859         zend_copy_value(zendlval, (yytext+1), (yyleng-1));
1860         zendlval->type = IS_STRING;
1861         return T_VARIABLE;
1864 /* A [ always designates a variable offset, regardless of what follows
1865  */
1866 <ST_DOUBLE_QUOTES,ST_HEREDOC,ST_BACKQUOTE>"$"{LABEL}"[" {
1867         yyless(yyleng - 1);
1868         yy_push_state(ST_VAR_OFFSET TSRMLS_CC);
1869         zend_copy_value(zendlval, (yytext+1), (yyleng-1));
1870         zendlval->type = IS_STRING;
1871         return T_VARIABLE;
1874 <ST_IN_SCRIPTING,ST_DOUBLE_QUOTES,ST_HEREDOC,ST_BACKQUOTE,ST_VAR_OFFSET>"$"{LABEL} {
1875         zend_copy_value(zendlval, (yytext+1), (yyleng-1));
1876         zendlval->type = IS_STRING;
1877         return T_VARIABLE;
1880 <ST_VAR_OFFSET>"]" {
1881         yy_pop_state(TSRMLS_C);
1882         return ']';
1885 <ST_VAR_OFFSET>{TOKENS}|[{}"`] {
1886         /* Only '[' can be valid, but returning other tokens will allow a more explicit parse error */
1887         return yytext[0];
1890 <ST_VAR_OFFSET>[ \n\r\t\\'#] {
1891         /* Invalid rule to return a more explicit parse error with proper line number */
1892         yyless(0);
1893         yy_pop_state(TSRMLS_C);
1894         return T_ENCAPSED_AND_WHITESPACE;
1897 <ST_IN_SCRIPTING,ST_VAR_OFFSET>{LABEL} {
1898         zend_copy_value(zendlval, yytext, yyleng);
1899         zendlval->type = IS_STRING;
1900         return T_STRING;
1904 <ST_IN_SCRIPTING>"#"|"//" {
1905         while (YYCURSOR < YYLIMIT) {
1906                 switch (*YYCURSOR++) {
1907                         case '\r':
1908                                 if (*YYCURSOR == '\n') {
1909                                         YYCURSOR++;
1910                                 }
1911                                 /* fall through */
1912                         case '\n':
1913                                 CG(zend_lineno)++;
1914                                 break;
1915                         case '%':
1916                                 if (!CG(asp_tags)) {
1917                                         continue;
1918                                 }
1919                                 /* fall through */
1920                         case '?':
1921                                 if (*YYCURSOR == '>') {
1922                                         YYCURSOR--;
1923                                         break;
1924                                 }
1925                                 /* fall through */
1926                         default:
1927                                 continue;
1928                 }
1930                 break;
1931         }
1933         yyleng = YYCURSOR - SCNG(yy_text);
1935         return T_COMMENT;
1938 <ST_IN_SCRIPTING>"/*"|"/**"{WHITESPACE} {
1939         int doc_com;
1941         if (yyleng > 2) {
1942                 doc_com = 1;
1943                 RESET_DOC_COMMENT();
1944         } else {
1945                 doc_com = 0;
1946         }
1948         while (YYCURSOR < YYLIMIT) {
1949                 if (*YYCURSOR++ == '*' && *YYCURSOR == '/') {
1950                         break;
1951                 }
1952         }
1954         if (YYCURSOR < YYLIMIT) {
1955                 YYCURSOR++;
1956         } else {
1957                 zend_error(E_COMPILE_WARNING, "Unterminated comment starting line %d", CG(zend_lineno));
1958         }
1960         yyleng = YYCURSOR - SCNG(yy_text);
1961         HANDLE_NEWLINES(yytext, yyleng);
1963         if (doc_com) {
1964                 CG(doc_comment) = estrndup(yytext, yyleng);
1965                 CG(doc_comment_len) = yyleng;
1966                 return T_DOC_COMMENT;
1967         }
1969         return T_COMMENT;
1972 <ST_IN_SCRIPTING>("?>"|"</script"{WHITESPACE}*">"){NEWLINE}? {
1973         zendlval->value.str.val = yytext; /* no copying - intentional */
1974         zendlval->value.str.len = yyleng;
1975         zendlval->type = IS_STRING;
1976         BEGIN(INITIAL);
1977         return T_CLOSE_TAG;  /* implicit ';' at php-end tag */
1981 <ST_IN_SCRIPTING>"%>"{NEWLINE}? {
1982         if (CG(asp_tags)) {
1983                 BEGIN(INITIAL);
1984                 zendlval->value.str.len = yyleng;
1985                 zendlval->type = IS_STRING;
1986                 zendlval->value.str.val = yytext; /* no copying - intentional */
1987                 return T_CLOSE_TAG;  /* implicit ';' at php-end tag */
1988         } else {
1989                 yyless(1);
1990                 return yytext[0];
1991         }
1995 <ST_IN_SCRIPTING>b?['] {
1996         register char *s, *t;
1997         char *end;
1998         int bprefix = (yytext[0] != '\'') ? 1 : 0;
2000         while (1) {
2001                 if (YYCURSOR < YYLIMIT) {
2002                         if (*YYCURSOR == '\'') {
2003                                 YYCURSOR++;
2004                                 yyleng = YYCURSOR - SCNG(yy_text);
2006                                 break;
2007                         } else if (*YYCURSOR++ == '\\' && YYCURSOR < YYLIMIT) {
2008                                 YYCURSOR++;
2009                         }
2010                 } else {
2011                         yyleng = YYLIMIT - SCNG(yy_text);
2013                         /* Unclosed single quotes; treat similar to double quotes, but without a separate token
2014                          * for ' (unrecognized by parser), instead of old flex fallback to "Unexpected character..."
2015                          * rule, which continued in ST_IN_SCRIPTING state after the quote */
2016                         return T_ENCAPSED_AND_WHITESPACE;
2017                 }
2018         }
2020         zendlval->value.str.val = estrndup(yytext+bprefix+1, yyleng-bprefix-2);
2021         zendlval->value.str.len = yyleng-bprefix-2;
2022         zendlval->type = IS_STRING;
2024         /* convert escape sequences */
2025         s = t = zendlval->value.str.val;
2026         end = s+zendlval->value.str.len;
2027         while (s<end) {
2028                 if (*s=='\\') {
2029                         s++;
2031                         switch(*s) {
2032                                 case '\\':
2033                                 case '\'':
2034                                         *t++ = *s;
2035                                         zendlval->value.str.len--;
2036                                         break;
2037                                 default:
2038                                         *t++ = '\\';
2039                                         *t++ = *s;
2040                                         break;
2041                         }
2042                 } else {
2043                         *t++ = *s;
2044                 }
2046                 if (*s == '\n' || (*s == '\r' && (*(s+1) != '\n'))) {
2047                         CG(zend_lineno)++;
2048                 }
2049                 s++;
2050         }
2051         *t = 0;
2053         if (SCNG(output_filter)) {
2054                 size_t sz = 0;
2055                 s = zendlval->value.str.val;
2056                 SCNG(output_filter)((unsigned char **)&(zendlval->value.str.val), &sz, (unsigned char *)s, (size_t)zendlval->value.str.len TSRMLS_CC);
2057                 zendlval->value.str.len = sz;
2058                 efree(s);
2059         }
2060         return T_CONSTANT_ENCAPSED_STRING;
2064 <ST_IN_SCRIPTING>b?["] {
2065         int bprefix = (yytext[0] != '"') ? 1 : 0;
2067         while (YYCURSOR < YYLIMIT) {
2068                 switch (*YYCURSOR++) {
2069                         case '"':
2070                                 yyleng = YYCURSOR - SCNG(yy_text);
2071                                 zend_scan_escape_string(zendlval, yytext+bprefix+1, yyleng-bprefix-2, '"' TSRMLS_CC);
2072                                 return T_CONSTANT_ENCAPSED_STRING;
2073                         case '$':
2074                                 if (IS_LABEL_START(*YYCURSOR) || *YYCURSOR == '{') {
2075                                         break;
2076                                 }
2077                                 continue;
2078                         case '{':
2079                                 if (*YYCURSOR == '$') {
2080                                         break;
2081                                 }
2082                                 continue;
2083                         case '\\':
2084                                 if (YYCURSOR < YYLIMIT) {
2085                                         YYCURSOR++;
2086                                 }
2087                                 /* fall through */
2088                         default:
2089                                 continue;
2090                 }
2092                 YYCURSOR--;
2093                 break;
2094         }
2096         /* Remember how much was scanned to save rescanning */
2097         SET_DOUBLE_QUOTES_SCANNED_LENGTH(YYCURSOR - SCNG(yy_text) - yyleng);
2099         YYCURSOR = SCNG(yy_text) + yyleng;
2101         BEGIN(ST_DOUBLE_QUOTES);
2102         return '"';
2106 <ST_IN_SCRIPTING>b?"<<<"{TABS_AND_SPACES}({LABEL}|([']{LABEL}['])|(["]{LABEL}["])){NEWLINE} {
2107         char *s;
2108         int bprefix = (yytext[0] != '<') ? 1 : 0;
2110         /* save old heredoc label */
2111         Z_STRVAL_P(zendlval) = CG(heredoc);
2112         Z_STRLEN_P(zendlval) = CG(heredoc_len);
2114         CG(zend_lineno)++;
2115         CG(heredoc_len) = yyleng-bprefix-3-1-(yytext[yyleng-2]=='\r'?1:0);
2116         s = yytext+bprefix+3;
2117         while ((*s == ' ') || (*s == '\t')) {
2118                 s++;
2119                 CG(heredoc_len)--;
2120         }
2122         if (*s == '\'') {
2123                 s++;
2124                 CG(heredoc_len) -= 2;
2126                 BEGIN(ST_NOWDOC);
2127         } else {
2128                 if (*s == '"') {
2129                         s++;
2130                         CG(heredoc_len) -= 2;
2131                 }
2133                 BEGIN(ST_HEREDOC);
2134         }
2136         CG(heredoc) = estrndup(s, CG(heredoc_len));
2138         /* Check for ending label on the next line */
2139         if (CG(heredoc_len) < YYLIMIT - YYCURSOR && !memcmp(YYCURSOR, s, CG(heredoc_len))) {
2140                 YYCTYPE *end = YYCURSOR + CG(heredoc_len);
2142                 if (*end == ';') {
2143                         end++;
2144                 }
2146                 if (*end == '\n' || *end == '\r') {
2147                         BEGIN(ST_END_HEREDOC);
2148                 }
2149         }
2151         return T_START_HEREDOC;
2155 <ST_IN_SCRIPTING>[`] {
2156         BEGIN(ST_BACKQUOTE);
2157         return '`';
2161 <ST_END_HEREDOC>{ANY_CHAR} {
2162         YYCURSOR += CG(heredoc_len) - 1;
2163         yyleng = CG(heredoc_len);
2165         Z_STRVAL_P(zendlval) = CG(heredoc);
2166         Z_STRLEN_P(zendlval) = CG(heredoc_len);
2167         CG(heredoc) = NULL;
2168         CG(heredoc_len) = 0;
2169         BEGIN(ST_IN_SCRIPTING);
2170         return T_END_HEREDOC;
2174 <ST_DOUBLE_QUOTES,ST_BACKQUOTE,ST_HEREDOC>"{$" {
2175         zendlval->value.lval = (long) '{';
2176         yy_push_state(ST_IN_SCRIPTING TSRMLS_CC);
2177         yyless(1);
2178         return T_CURLY_OPEN;
2182 <ST_DOUBLE_QUOTES>["] {
2183         BEGIN(ST_IN_SCRIPTING);
2184         return '"';
2187 <ST_BACKQUOTE>[`] {
2188         BEGIN(ST_IN_SCRIPTING);
2189         return '`';
2193 <ST_DOUBLE_QUOTES>{ANY_CHAR} {
2194         if (GET_DOUBLE_QUOTES_SCANNED_LENGTH()) {
2195                 YYCURSOR += GET_DOUBLE_QUOTES_SCANNED_LENGTH() - 1;
2196                 SET_DOUBLE_QUOTES_SCANNED_LENGTH(0);
2198                 goto double_quotes_scan_done;
2199         }
2201         if (YYCURSOR > YYLIMIT) {
2202                 return 0;
2203         }
2204         if (yytext[0] == '\\' && YYCURSOR < YYLIMIT) {
2205                 YYCURSOR++;
2206         }
2208         while (YYCURSOR < YYLIMIT) {
2209                 switch (*YYCURSOR++) {
2210                         case '"':
2211                                 break;
2212                         case '$':
2213                                 if (IS_LABEL_START(*YYCURSOR) || *YYCURSOR == '{') {
2214                                         break;
2215                                 }
2216                                 continue;
2217                         case '{':
2218                                 if (*YYCURSOR == '$') {
2219                                         break;
2220                                 }
2221                                 continue;
2222                         case '\\':
2223                                 if (YYCURSOR < YYLIMIT) {
2224                                         YYCURSOR++;
2225                                 }
2226                                 /* fall through */
2227                         default:
2228                                 continue;
2229                 }
2231                 YYCURSOR--;
2232                 break;
2233         }
2235 double_quotes_scan_done:
2236         yyleng = YYCURSOR - SCNG(yy_text);
2238         zend_scan_escape_string(zendlval, yytext, yyleng, '"' TSRMLS_CC);
2239         return T_ENCAPSED_AND_WHITESPACE;
2243 <ST_BACKQUOTE>{ANY_CHAR} {
2244         if (YYCURSOR > YYLIMIT) {
2245                 return 0;
2246         }
2247         if (yytext[0] == '\\' && YYCURSOR < YYLIMIT) {
2248                 YYCURSOR++;
2249         }
2251         while (YYCURSOR < YYLIMIT) {
2252                 switch (*YYCURSOR++) {
2253                         case '`':
2254                                 break;
2255                         case '$':
2256                                 if (IS_LABEL_START(*YYCURSOR) || *YYCURSOR == '{') {
2257                                         break;
2258                                 }
2259                                 continue;
2260                         case '{':
2261                                 if (*YYCURSOR == '$') {
2262                                         break;
2263                                 }
2264                                 continue;
2265                         case '\\':
2266                                 if (YYCURSOR < YYLIMIT) {
2267                                         YYCURSOR++;
2268                                 }
2269                                 /* fall through */
2270                         default:
2271                                 continue;
2272                 }
2274                 YYCURSOR--;
2275                 break;
2276         }
2278         yyleng = YYCURSOR - SCNG(yy_text);
2280         zend_scan_escape_string(zendlval, yytext, yyleng, '`' TSRMLS_CC);
2281         return T_ENCAPSED_AND_WHITESPACE;
2285 <ST_HEREDOC>{ANY_CHAR} {
2286         int newline = 0;
2288         if (YYCURSOR > YYLIMIT) {
2289                 return 0;
2290         }
2292         YYCURSOR--;
2294         while (YYCURSOR < YYLIMIT) {
2295                 switch (*YYCURSOR++) {
2296                         case '\r':
2297                                 if (*YYCURSOR == '\n') {
2298                                         YYCURSOR++;
2299                                 }
2300                                 /* fall through */
2301                         case '\n':
2302                                 /* Check for ending label on the next line */
2303                                 if (IS_LABEL_START(*YYCURSOR) && CG(heredoc_len) < YYLIMIT - YYCURSOR && !memcmp(YYCURSOR, CG(heredoc), CG(heredoc_len))) {
2304                                         YYCTYPE *end = YYCURSOR + CG(heredoc_len);
2306                                         if (*end == ';') {
2307                                                 end++;
2308                                         }
2310                                         if (*end == '\n' || *end == '\r') {
2311                                                 /* newline before label will be subtracted from returned text, but
2312                                                  * yyleng/yytext will include it, for zend_highlight/strip, tokenizer, etc. */
2313                                                 if (YYCURSOR[-2] == '\r' && YYCURSOR[-1] == '\n') {
2314                                                         newline = 2; /* Windows newline */
2315                                                 } else {
2316                                                         newline = 1;
2317                                                 }
2319                                                 CG(increment_lineno) = 1; /* For newline before label */
2320                                                 BEGIN(ST_END_HEREDOC);
2322                                                 goto heredoc_scan_done;
2323                                         }
2324                                 }
2325                                 continue;
2326                         case '$':
2327                                 if (IS_LABEL_START(*YYCURSOR) || *YYCURSOR == '{') {
2328                                         break;
2329                                 }
2330                                 continue;
2331                         case '{':
2332                                 if (*YYCURSOR == '$') {
2333                                         break;
2334                                 }
2335                                 continue;
2336                         case '\\':
2337                                 if (YYCURSOR < YYLIMIT && *YYCURSOR != '\n' && *YYCURSOR != '\r') {
2338                                         YYCURSOR++;
2339                                 }
2340                                 /* fall through */
2341                         default:
2342                                 continue;
2343                 }
2345                 YYCURSOR--;
2346                 break;
2347         }
2349 heredoc_scan_done:
2350         yyleng = YYCURSOR - SCNG(yy_text);
2352         zend_scan_escape_string(zendlval, yytext, yyleng - newline, 0 TSRMLS_CC);
2353         return T_ENCAPSED_AND_WHITESPACE;
2357 <ST_NOWDOC>{ANY_CHAR} {
2358         int newline = 0;
2360         if (YYCURSOR > YYLIMIT) {
2361                 return 0;
2362         }
2364         YYCURSOR--;
2366         while (YYCURSOR < YYLIMIT) {
2367                 switch (*YYCURSOR++) {
2368                         case '\r':
2369                                 if (*YYCURSOR == '\n') {
2370                                         YYCURSOR++;
2371                                 }
2372                                 /* fall through */
2373                         case '\n':
2374                                 /* Check for ending label on the next line */
2375                                 if (IS_LABEL_START(*YYCURSOR) && CG(heredoc_len) < YYLIMIT - YYCURSOR && !memcmp(YYCURSOR, CG(heredoc), CG(heredoc_len))) {
2376                                         YYCTYPE *end = YYCURSOR + CG(heredoc_len);
2378                                         if (*end == ';') {
2379                                                 end++;
2380                                         }
2382                                         if (*end == '\n' || *end == '\r') {
2383                                                 /* newline before label will be subtracted from returned text, but
2384                                                  * yyleng/yytext will include it, for zend_highlight/strip, tokenizer, etc. */
2385                                                 if (YYCURSOR[-2] == '\r' && YYCURSOR[-1] == '\n') {
2386                                                         newline = 2; /* Windows newline */
2387                                                 } else {
2388                                                         newline = 1;
2389                                                 }
2391                                                 CG(increment_lineno) = 1; /* For newline before label */
2392                                                 BEGIN(ST_END_HEREDOC);
2394                                                 goto nowdoc_scan_done;
2395                                         }
2396                                 }
2397                                 /* fall through */
2398                         default:
2399                                 continue;
2400                 }
2401         }
2403 nowdoc_scan_done:
2404         yyleng = YYCURSOR - SCNG(yy_text);
2406         zend_copy_value(zendlval, yytext, yyleng - newline);
2407         zendlval->type = IS_STRING;
2408         HANDLE_NEWLINES(yytext, yyleng - newline);
2409         return T_ENCAPSED_AND_WHITESPACE;
2413 <ST_IN_SCRIPTING,ST_VAR_OFFSET>{ANY_CHAR} {
2414         if (YYCURSOR > YYLIMIT) {
2415                 return 0;
2416         }
2418         zend_error(E_COMPILE_WARNING,"Unexpected character in input:  '%c' (ASCII=%d) state=%d", yytext[0], yytext[0], YYSTATE);
2419         goto restart;