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   +----------------------------------------------------------------------+
22*/
23
24/* $Id$ */
25
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
31
32#include "zend_language_scanner_defs.h"
33
34#include <errno.h>
35#include "zend.h"
36#include "zend_alloc.h"
37#include <zend_language_parser.h>
38#include "zend_compile.h"
39#include "zend_language_scanner.h"
40#include "zend_highlight.h"
41#include "zend_constants.h"
42#include "zend_variables.h"
43#include "zend_operators.h"
44#include "zend_API.h"
45#include "zend_strtod.h"
46#include "zend_exceptions.h"
47#include "tsrm_virtual_cwd.h"
48#include "tsrm_config_common.h"
49
50#define YYCTYPE   unsigned char
51#define YYFILL(n) { if ((YYCURSOR + n) >= (YYLIMIT + ZEND_MMAP_AHEAD)) { return 0; } }
52#define YYCURSOR  SCNG(yy_cursor)
53#define YYLIMIT   SCNG(yy_limit)
54#define YYMARKER  SCNG(yy_marker)
55
56#define YYGETCONDITION()  SCNG(yy_state)
57#define YYSETCONDITION(s) SCNG(yy_state) = s
58
59#define STATE(name)  yyc##name
60
61/* emulate flex constructs */
62#define BEGIN(state) YYSETCONDITION(STATE(state))
63#define YYSTATE      YYGETCONDITION()
64#define yytext       ((char*)SCNG(yy_text))
65#define yyleng       SCNG(yy_leng)
66#define yyless(x)    do { YYCURSOR = (unsigned char*)yytext + x; \
67                          yyleng   = (unsigned int)x; } while(0)
68#define yymore()     goto yymore_restart
69
70/* perform sanity check. If this message is triggered you should
71   increase the ZEND_MMAP_AHEAD value in the zend_streams.h file */
72/*!max:re2c */
73#if ZEND_MMAP_AHEAD < YYMAXFILL
74# error ZEND_MMAP_AHEAD should be greater than or equal to YYMAXFILL
75#endif
76
77#ifdef HAVE_STDARG_H
78# include <stdarg.h>
79#endif
80
81#ifdef HAVE_UNISTD_H
82# include <unistd.h>
83#endif
84
85/* Globals Macros */
86#define SCNG    LANG_SCNG
87#ifdef ZTS
88ZEND_API ts_rsrc_id language_scanner_globals_id;
89#else
90ZEND_API zend_php_scanner_globals language_scanner_globals;
91#endif
92
93#define HANDLE_NEWLINES(s, l)                                                   \
94do {                                                                            \
95    char *p = (s), *boundary = p+(l);                                           \
96                                                                                \
97    while (p<boundary) {                                                        \
98        if (*p == '\n' || (*p == '\r' && (*(p+1) != '\n'))) {                   \
99            CG(zend_lineno)++;                                                  \
100        }                                                                       \
101        p++;                                                                    \
102    }                                                                           \
103} while (0)
104
105#define HANDLE_NEWLINE(c) \
106{ \
107    if (c == '\n' || c == '\r') { \
108        CG(zend_lineno)++; \
109    } \
110}
111
112/* To save initial string length after scanning to first variable, CG(doc_comment_len) can be reused */
113#define SET_DOUBLE_QUOTES_SCANNED_LENGTH(len) CG(doc_comment_len) = (len)
114#define GET_DOUBLE_QUOTES_SCANNED_LENGTH()    CG(doc_comment_len)
115
116#define IS_LABEL_START(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z') || (c) == '_' || (c) >= 0x7F)
117
118#define ZEND_IS_OCT(c)  ((c)>='0' && (c)<='7')
119#define ZEND_IS_HEX(c)  (((c)>='0' && (c)<='9') || ((c)>='a' && (c)<='f') || ((c)>='A' && (c)<='F'))
120
121BEGIN_EXTERN_C()
122
123static void _yy_push_state(int new_state TSRMLS_DC)
124{
125    zend_stack_push(&SCNG(state_stack), (void *) &YYGETCONDITION(), sizeof(int));
126    YYSETCONDITION(new_state);
127}
128
129#define yy_push_state(state_and_tsrm) _yy_push_state(yyc##state_and_tsrm)
130
131static void yy_pop_state(TSRMLS_D)
132{
133    int *stack_state;
134    zend_stack_top(&SCNG(state_stack), (void **) &stack_state);
135    YYSETCONDITION(*stack_state);
136    zend_stack_del_top(&SCNG(state_stack));
137}
138
139static void yy_scan_buffer(char *str, unsigned int len TSRMLS_DC)
140{
141    YYCURSOR       = (YYCTYPE*)str;
142    YYLIMIT        = YYCURSOR + len;
143    if (!SCNG(yy_start)) {
144        SCNG(yy_start) = YYCURSOR;
145    }
146}
147
148void startup_scanner(TSRMLS_D)
149{
150    CG(heredoc) = NULL;
151    CG(heredoc_len) = 0;
152    CG(doc_comment) = NULL;
153    CG(doc_comment_len) = 0;
154    zend_stack_init(&SCNG(state_stack));
155}
156
157void shutdown_scanner(TSRMLS_D)
158{
159    if (CG(heredoc)) {
160        efree(CG(heredoc));
161        CG(heredoc_len)=0;
162    }
163    zend_stack_destroy(&SCNG(state_stack));
164    RESET_DOC_COMMENT();
165}
166
167ZEND_API void zend_save_lexical_state(zend_lex_state *lex_state TSRMLS_DC)
168{
169    lex_state->yy_leng   = SCNG(yy_leng);
170    lex_state->yy_start  = SCNG(yy_start);
171    lex_state->yy_text   = SCNG(yy_text);
172    lex_state->yy_cursor = SCNG(yy_cursor);
173    lex_state->yy_marker = SCNG(yy_marker);
174    lex_state->yy_limit  = SCNG(yy_limit);
175
176    lex_state->state_stack = SCNG(state_stack);
177    zend_stack_init(&SCNG(state_stack));
178
179    lex_state->in = SCNG(yy_in);
180    lex_state->yy_state = YYSTATE;
181    lex_state->filename = zend_get_compiled_filename(TSRMLS_C);
182    lex_state->lineno = CG(zend_lineno);
183
184#ifdef ZEND_MULTIBYTE
185    lex_state->script_org = SCNG(script_org);
186    lex_state->script_org_size = SCNG(script_org_size);
187    lex_state->script_filtered = SCNG(script_filtered);
188    lex_state->script_filtered_size = SCNG(script_filtered_size);
189    lex_state->input_filter = SCNG(input_filter);
190    lex_state->output_filter = SCNG(output_filter);
191    lex_state->script_encoding = SCNG(script_encoding);
192    lex_state->internal_encoding = SCNG(internal_encoding);
193#endif /* ZEND_MULTIBYTE */
194}
195
196ZEND_API void zend_restore_lexical_state(zend_lex_state *lex_state TSRMLS_DC)
197{
198    SCNG(yy_leng)   = lex_state->yy_leng;
199    SCNG(yy_start)  = lex_state->yy_start;
200    SCNG(yy_text)   = lex_state->yy_text;
201    SCNG(yy_cursor) = lex_state->yy_cursor;
202    SCNG(yy_marker) = lex_state->yy_marker;
203    SCNG(yy_limit)  = lex_state->yy_limit;
204
205    zend_stack_destroy(&SCNG(state_stack));
206    SCNG(state_stack) = lex_state->state_stack;
207
208    SCNG(yy_in) = lex_state->in;
209    YYSETCONDITION(lex_state->yy_state);
210    CG(zend_lineno) = lex_state->lineno;
211    zend_restore_compiled_filename(lex_state->filename TSRMLS_CC);
212#ifdef ZEND_MULTIBYTE
213    if (SCNG(script_org)) {
214        efree(SCNG(script_org));
215        SCNG(script_org) = NULL;
216    }
217    if (SCNG(script_filtered)) {
218        efree(SCNG(script_filtered));
219        SCNG(script_filtered) = NULL;
220    }
221    SCNG(script_org) = lex_state->script_org;
222    SCNG(script_org_size) = lex_state->script_org_size;
223    SCNG(script_filtered) = lex_state->script_filtered;
224    SCNG(script_filtered_size) = lex_state->script_filtered_size;
225    SCNG(input_filter) = lex_state->input_filter;
226    SCNG(output_filter) = lex_state->output_filter;
227    SCNG(script_encoding) = lex_state->script_encoding;
228    SCNG(internal_encoding) = lex_state->internal_encoding;
229#endif /* ZEND_MULTIBYTE */
230
231    if (CG(heredoc)) {
232        efree(CG(heredoc));
233        CG(heredoc) = NULL;
234        CG(heredoc_len) = 0;
235    }
236}
237
238ZEND_API void zend_destroy_file_handle(zend_file_handle *file_handle TSRMLS_DC)
239{
240    zend_llist_del_element(&CG(open_files), file_handle, (int (*)(void *, void *)) zend_compare_file_handles);
241    /* zend_file_handle_dtor() operates on the copy, so we have to NULLify the original here */
242    file_handle->opened_path = NULL;
243    if (file_handle->free_filename) {
244        file_handle->filename = NULL;
245    }
246}
247
248
249ZEND_API int open_file_for_scanning(zend_file_handle *file_handle TSRMLS_DC)
250{
251    char *file_path = NULL, *buf;
252    size_t size, offset = 0;
253
254    /* The shebang line was read, get the current position to obtain the buffer start */
255    if (CG(start_lineno) == 2 && file_handle->type == ZEND_HANDLE_FP && file_handle->handle.fp) {
256        if ((offset = ftell(file_handle->handle.fp)) == -1) {
257            offset = 0;
258        }
259    }
260
261    if (zend_stream_fixup(file_handle, &buf, &size TSRMLS_CC) == FAILURE) {
262        return FAILURE;
263    }
264
265    zend_llist_add_element(&CG(open_files), file_handle);
266    if (file_handle->handle.stream.handle >= (void*)file_handle && file_handle->handle.stream.handle <= (void*)(file_handle+1)) {
267        zend_file_handle *fh = (zend_file_handle*)zend_llist_get_last(&CG(open_files));
268        size_t diff = (char*)file_handle->handle.stream.handle - (char*)file_handle;
269        fh->handle.stream.handle = (void*)(((char*)fh) + diff);
270        file_handle->handle.stream.handle = fh->handle.stream.handle;
271    }
272
273    /* Reset the scanner for scanning the new file */
274    SCNG(yy_in) = file_handle;
275    SCNG(yy_start) = NULL;
276
277    if (size != -1) {
278#ifdef ZEND_MULTIBYTE
279        if (zend_multibyte_read_script((unsigned char *)buf, size TSRMLS_CC) != 0) {
280            return FAILURE;
281        }
282
283        SCNG(yy_in) = NULL;
284
285        zend_multibyte_set_filter(NULL TSRMLS_CC);
286
287        if (!SCNG(input_filter)) {
288            SCNG(script_filtered) = (unsigned char*)emalloc(SCNG(script_org_size)+2);
289            memcpy(SCNG(script_filtered), SCNG(script_org), SCNG(script_org_size)+1);
290            SCNG(script_filtered_size) = SCNG(script_org_size);
291        } else {
292            SCNG(input_filter)(&SCNG(script_filtered), &SCNG(script_filtered_size), SCNG(script_org), SCNG(script_org_size) TSRMLS_CC);
293            if (SCNG(script_filtered) == NULL) {
294                zend_error_noreturn(E_COMPILE_ERROR, "Could not convert the script from the detected "
295                        "encoding \"%s\" to a compatible encoding", LANG_SCNG(script_encoding)->name);
296            }
297        }
298        SCNG(yy_start) = SCNG(script_filtered) - offset;
299        yy_scan_buffer((char *)SCNG(script_filtered), SCNG(script_filtered_size) TSRMLS_CC);
300#else /* !ZEND_MULTIBYTE */
301        SCNG(yy_start) = buf - offset;
302        yy_scan_buffer(buf, size TSRMLS_CC);
303#endif /* ZEND_MULTIBYTE */
304    } else {
305        zend_error_noreturn(E_COMPILE_ERROR, "zend_stream_mmap() failed");
306    }
307
308    BEGIN(INITIAL);
309
310    if (file_handle->opened_path) {
311        file_path = file_handle->opened_path;
312    } else {
313        file_path = file_handle->filename;
314    }
315
316    zend_set_compiled_filename(file_path TSRMLS_CC);
317
318    if (CG(start_lineno)) {
319        CG(zend_lineno) = CG(start_lineno);
320        CG(start_lineno) = 0;
321    } else {
322        CG(zend_lineno) = 1;
323    }
324
325    CG(increment_lineno) = 0;
326    return SUCCESS;
327}
328END_EXTERN_C()
329
330
331ZEND_API zend_op_array *compile_file(zend_file_handle *file_handle, int type TSRMLS_DC)
332{
333    zend_lex_state original_lex_state;
334    zend_op_array *op_array = (zend_op_array *) emalloc(sizeof(zend_op_array));
335    zend_op_array *original_active_op_array = CG(active_op_array);
336    zend_op_array *retval=NULL;
337    int compiler_result;
338    zend_bool compilation_successful=0;
339    znode retval_znode;
340    zend_bool original_in_compilation = CG(in_compilation);
341
342    retval_znode.op_type = IS_CONST;
343    retval_znode.u.constant.type = IS_LONG;
344    retval_znode.u.constant.value.lval = 1;
345    Z_UNSET_ISREF(retval_znode.u.constant);
346    Z_SET_REFCOUNT(retval_znode.u.constant, 1);
347
348    zend_save_lexical_state(&original_lex_state TSRMLS_CC);
349
350    retval = op_array; /* success oriented */
351
352    if (open_file_for_scanning(file_handle TSRMLS_CC)==FAILURE) {
353        if (type==ZEND_REQUIRE) {
354            zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename TSRMLS_CC);
355            zend_bailout();
356        } else {
357            zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename TSRMLS_CC);
358        }
359        compilation_successful=0;
360    } else {
361        init_op_array(op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC);
362        CG(in_compilation) = 1;
363        CG(active_op_array) = op_array;
364        compiler_result = zendparse(TSRMLS_C);
365        zend_do_return(&retval_znode, 0 TSRMLS_CC);
366        CG(in_compilation) = original_in_compilation;
367        if (compiler_result==1) { /* parser error */
368            zend_bailout();
369        }
370        compilation_successful=1;
371    }
372
373    if (retval) {
374        CG(active_op_array) = original_active_op_array;
375        if (compilation_successful) {
376            pass_two(op_array TSRMLS_CC);
377            zend_release_labels(TSRMLS_C);
378        } else {
379            efree(op_array);
380            retval = NULL;
381        }
382    }
383    zend_restore_lexical_state(&original_lex_state TSRMLS_CC);
384    return retval;
385}
386
387
388zend_op_array *compile_filename(int type, zval *filename TSRMLS_DC)
389{
390    zend_file_handle file_handle;
391    zval tmp;
392    zend_op_array *retval;
393    char *opened_path = NULL;
394
395    if (filename->type != IS_STRING) {
396        tmp = *filename;
397        zval_copy_ctor(&tmp);
398        convert_to_string(&tmp);
399        filename = &tmp;
400    }
401    file_handle.filename = filename->value.str.val;
402    file_handle.free_filename = 0;
403    file_handle.type = ZEND_HANDLE_FILENAME;
404    file_handle.opened_path = NULL;
405    file_handle.handle.fp = NULL;
406
407    retval = zend_compile_file(&file_handle, type TSRMLS_CC);
408    if (retval && file_handle.handle.stream.handle) {
409        int dummy = 1;
410
411        if (!file_handle.opened_path) {
412            file_handle.opened_path = opened_path = estrndup(filename->value.str.val, filename->value.str.len);
413        }
414
415        zend_hash_add(&EG(included_files), file_handle.opened_path, strlen(file_handle.opened_path)+1, (void *)&dummy, sizeof(int), NULL);
416
417        if (opened_path) {
418            efree(opened_path);
419        }
420    }
421    zend_destroy_file_handle(&file_handle TSRMLS_CC);
422
423    if (filename==&tmp) {
424        zval_dtor(&tmp);
425    }
426    return retval;
427}
428
429ZEND_API int zend_prepare_string_for_scanning(zval *str, char *filename TSRMLS_DC)
430{
431    /* enforce two trailing NULLs for flex... */
432    str->value.str.val = safe_erealloc(str->value.str.val, 1, str->value.str.len, ZEND_MMAP_AHEAD);
433
434    memset(str->value.str.val + str->value.str.len, 0, ZEND_MMAP_AHEAD);
435
436    SCNG(yy_in)=NULL;
437    SCNG(yy_start) = NULL;
438
439#ifdef ZEND_MULTIBYTE
440    SCNG(script_org) = (unsigned char *)estrdup(str->value.str.val);
441    SCNG(script_org_size) = str->value.str.len;
442
443    zend_multibyte_set_filter(CG(internal_encoding) TSRMLS_CC);
444
445    if (!SCNG(input_filter)) {
446        SCNG(script_filtered) = (unsigned char*)emalloc(SCNG(script_org_size)+2);
447        memcpy(SCNG(script_filtered), SCNG(script_org), SCNG(script_org_size)+1);
448        SCNG(script_filtered_size) = SCNG(script_org_size);
449    } else {
450        SCNG(input_filter)(&SCNG(script_filtered), &SCNG(script_filtered_size), SCNG(script_org), SCNG(script_org_size) TSRMLS_CC);
451    }
452
453    yy_scan_buffer((char *)SCNG(script_filtered), SCNG(script_filtered_size) TSRMLS_CC);
454#else /* !ZEND_MULTIBYTE */
455    yy_scan_buffer(str->value.str.val, str->value.str.len TSRMLS_CC);
456#endif /* ZEND_MULTIBYTE */
457
458    zend_set_compiled_filename(filename TSRMLS_CC);
459    CG(zend_lineno) = 1;
460    CG(increment_lineno) = 0;
461    return SUCCESS;
462}
463
464
465ZEND_API size_t zend_get_scanned_file_offset(TSRMLS_D)
466{
467    size_t offset = SCNG(yy_cursor) - SCNG(yy_start);
468#ifdef ZEND_MULTIBYTE
469    if (SCNG(input_filter)) {
470        size_t original_offset = offset, length = 0; do {
471            unsigned char *p = NULL;
472            SCNG(input_filter)(&p, &length, SCNG(script_org), offset TSRMLS_CC);
473            if (!p) {
474                break;
475            }
476            efree(p);
477            if (length > original_offset) {
478                offset--;
479            } else if (length < original_offset) {
480                offset++;
481            }
482        } while (original_offset != length);
483    }
484#endif
485    return offset;
486}
487
488
489zend_op_array *compile_string(zval *source_string, char *filename TSRMLS_DC)
490{
491    zend_lex_state original_lex_state;
492    zend_op_array *op_array = (zend_op_array *) emalloc(sizeof(zend_op_array));
493    zend_op_array *original_active_op_array = CG(active_op_array);
494    zend_op_array *retval;
495    zval tmp;
496    int compiler_result;
497    zend_bool original_in_compilation = CG(in_compilation);
498
499    if (source_string->value.str.len==0) {
500        efree(op_array);
501        return NULL;
502    }
503
504    CG(in_compilation) = 1;
505
506    tmp = *source_string;
507    zval_copy_ctor(&tmp);
508    convert_to_string(&tmp);
509    source_string = &tmp;
510
511    zend_save_lexical_state(&original_lex_state TSRMLS_CC);
512    if (zend_prepare_string_for_scanning(source_string, filename TSRMLS_CC)==FAILURE) {
513        efree(op_array);
514        retval = NULL;
515    } else {
516        zend_bool orig_interactive = CG(interactive);
517
518        CG(interactive) = 0;
519        init_op_array(op_array, ZEND_EVAL_CODE, INITIAL_OP_ARRAY_SIZE TSRMLS_CC);
520        CG(interactive) = orig_interactive;
521        CG(active_op_array) = op_array;
522        BEGIN(ST_IN_SCRIPTING);
523        compiler_result = zendparse(TSRMLS_C);
524
525#ifdef ZEND_MULTIBYTE
526        if (SCNG(script_org)) {
527            efree(SCNG(script_org));
528            SCNG(script_org) = NULL;
529        }
530        if (SCNG(script_filtered)) {
531            efree(SCNG(script_filtered));
532            SCNG(script_filtered) = NULL;
533        }
534#endif /* ZEND_MULTIBYTE */
535
536        if (compiler_result==1) {
537            CG(active_op_array) = original_active_op_array;
538            CG(unclean_shutdown)=1;
539            destroy_op_array(op_array TSRMLS_CC);
540            efree(op_array);
541            retval = NULL;
542        } else {
543            zend_do_return(NULL, 0 TSRMLS_CC);
544            CG(active_op_array) = original_active_op_array;
545            pass_two(op_array TSRMLS_CC);
546            zend_release_labels(TSRMLS_C);
547            retval = op_array;
548        }
549    }
550    zend_restore_lexical_state(&original_lex_state TSRMLS_CC);
551    zval_dtor(&tmp);
552    CG(in_compilation) = original_in_compilation;
553    return retval;
554}
555
556
557BEGIN_EXTERN_C()
558int highlight_file(char *filename, zend_syntax_highlighter_ini *syntax_highlighter_ini TSRMLS_DC)
559{
560    zend_lex_state original_lex_state;
561    zend_file_handle file_handle;
562
563    file_handle.type = ZEND_HANDLE_FILENAME;
564    file_handle.filename = filename;
565    file_handle.free_filename = 0;
566    file_handle.opened_path = NULL;
567    zend_save_lexical_state(&original_lex_state TSRMLS_CC);
568    if (open_file_for_scanning(&file_handle TSRMLS_CC)==FAILURE) {
569        zend_message_dispatcher(ZMSG_FAILED_HIGHLIGHT_FOPEN, filename TSRMLS_CC);
570        zend_restore_lexical_state(&original_lex_state TSRMLS_CC);
571        return FAILURE;
572    }
573    zend_highlight(syntax_highlighter_ini TSRMLS_CC);
574#ifdef ZEND_MULTIBYTE
575    if (SCNG(script_org)) {
576        efree(SCNG(script_org));
577        SCNG(script_org) = NULL;
578    }
579    if (SCNG(script_filtered)) {
580        efree(SCNG(script_filtered));
581        SCNG(script_filtered) = NULL;
582    }
583#endif /* ZEND_MULTIBYTE */
584    zend_destroy_file_handle(&file_handle TSRMLS_CC);
585    zend_restore_lexical_state(&original_lex_state TSRMLS_CC);
586    return SUCCESS;
587}
588
589int highlight_string(zval *str, zend_syntax_highlighter_ini *syntax_highlighter_ini, char *str_name TSRMLS_DC)
590{
591    zend_lex_state original_lex_state;
592    zval tmp = *str;
593
594    str = &tmp;
595    zval_copy_ctor(str);
596    zend_save_lexical_state(&original_lex_state TSRMLS_CC);
597    if (zend_prepare_string_for_scanning(str, str_name TSRMLS_CC)==FAILURE) {
598        zend_restore_lexical_state(&original_lex_state TSRMLS_CC);
599        return FAILURE;
600    }
601    BEGIN(INITIAL);
602    zend_highlight(syntax_highlighter_ini TSRMLS_CC);
603#ifdef ZEND_MULTIBYTE
604    if (SCNG(script_org)) {
605        efree(SCNG(script_org));
606        SCNG(script_org) = NULL;
607    }
608    if (SCNG(script_filtered)) {
609        efree(SCNG(script_filtered));
610        SCNG(script_filtered) = NULL;
611    }
612#endif /* ZEND_MULTIBYTE */
613    zend_restore_lexical_state(&original_lex_state TSRMLS_CC);
614    zval_dtor(str);
615    return SUCCESS;
616}
617END_EXTERN_C()
618
619#ifdef ZEND_MULTIBYTE
620
621BEGIN_EXTERN_C()
622ZEND_API void zend_multibyte_yyinput_again(zend_encoding_filter old_input_filter, zend_encoding *old_encoding TSRMLS_DC)
623{
624    size_t original_offset, offset, free_flag, new_len, length;
625    unsigned char *p;
626
627    /* calculate current position */
628    offset = original_offset = YYCURSOR - SCNG(yy_start);
629    if (old_input_filter && offset > 0) {
630        zend_encoding *new_encoding = SCNG(script_encoding);
631        zend_encoding_filter new_filter = SCNG(input_filter);
632        SCNG(script_encoding) = old_encoding;
633        SCNG(input_filter) = old_input_filter;
634        offset = zend_get_scanned_file_offset(TSRMLS_C);
635        SCNG(script_encoding) = new_encoding;
636        SCNG(input_filter) = new_filter;
637    }
638
639    /* convert and set */
640    if (!SCNG(input_filter)) {
641        length = SCNG(script_org_size) - offset;
642        p = SCNG(script_org) + offset;
643        free_flag = 0;
644    } else {
645        SCNG(input_filter)(&p, &length, SCNG(script_org) + offset, SCNG(script_org_size) - offset TSRMLS_CC);
646        free_flag = 1;
647    }
648
649    new_len = original_offset + length;
650
651    if (new_len > YYLIMIT - SCNG(yy_start)) {
652        unsigned char *new_yy_start = erealloc(SCNG(yy_start), new_len);
653        SCNG(yy_cursor) = new_yy_start + (SCNG(yy_cursor) - SCNG(yy_start));
654        SCNG(yy_marker) = new_yy_start + (SCNG(yy_marker) - SCNG(yy_start));
655        SCNG(yy_text) = new_yy_start + (SCNG(yy_text) - SCNG(yy_start));
656        SCNG(yy_start) = new_yy_start;
657        SCNG(script_filtered) = new_yy_start;
658        SCNG(script_filtered_size) = new_len;
659    }
660
661    SCNG(yy_limit) = SCNG(yy_start) + new_len;
662    memmove(SCNG(yy_start) + original_offset, p, length);
663
664    if (free_flag) {
665        efree(p);
666    }
667}
668
669
670ZEND_API int zend_multibyte_yyinput(zend_file_handle *file_handle, char *buf, size_t len TSRMLS_DC)
671{
672    size_t n;
673
674    if (CG(interactive) == 0) {
675        if (zend_stream_fixup(file_handle, &buf, &len TSRMLS_CC) == FAILURE) {
676            return FAILURE;
677        }
678        n = len;
679        return n;
680    }
681
682    /* interactive */
683    if (SCNG(script_org)) {
684        efree(SCNG(script_org));
685    }
686    if (SCNG(script_filtered)) {
687        efree(SCNG(script_filtered));
688    }
689    SCNG(script_org) = NULL;
690    SCNG(script_org_size) = 0;
691
692    /* TODO: support widechars */
693    if (zend_stream_fixup(file_handle, &buf, &len TSRMLS_CC) == FAILURE) {
694        return FAILURE;
695    }
696    n = len;
697
698    SCNG(script_org_size) = n;
699    SCNG(script_org) = (unsigned char*)emalloc(SCNG(script_org_size) + 1);
700    memcpy(SCNG(script_org), buf, n);
701
702    return n;
703}
704
705
706ZEND_API int zend_multibyte_read_script(unsigned char *buf, size_t n TSRMLS_DC)
707{
708    if (SCNG(script_org)) {
709        efree(SCNG(script_org));
710        SCNG(script_org) = NULL;
711    }
712    SCNG(script_org_size) = n;
713
714    SCNG(script_org) = (unsigned char*)emalloc(SCNG(script_org_size) + 1);
715    memcpy(SCNG(script_org), buf, n);
716    *(SCNG(script_org)+SCNG(script_org_size)) = '\0';
717
718    return 0;
719}
720
721
722# define zend_copy_value(zendlval, yytext, yyleng) \
723    if (SCNG(output_filter)) { \
724        size_t sz = 0; \
725        SCNG(output_filter)((unsigned char **)&(zendlval->value.str.val), &sz, (unsigned char *)yytext, (size_t)yyleng TSRMLS_CC); \
726        zendlval->value.str.len = sz; \
727    } else { \
728        zendlval->value.str.val = (char *) estrndup(yytext, yyleng); \
729        zendlval->value.str.len = yyleng; \
730    }
731#else /* ZEND_MULTIBYTE */
732# define zend_copy_value(zendlval, yytext, yyleng) \
733    zendlval->value.str.val = (char *)estrndup(yytext, yyleng); \
734    zendlval->value.str.len = yyleng;
735#endif /* ZEND_MULTIBYTE */
736
737static void zend_scan_escape_string(zval *zendlval, char *str, int len, char quote_type TSRMLS_DC)
738{
739    register char *s, *t;
740    char *end;
741
742    ZVAL_STRINGL(zendlval, str, len, 1);
743
744    /* convert escape sequences */
745    s = t = zendlval->value.str.val;
746    end = s+zendlval->value.str.len;
747    while (s<end) {
748        if (*s=='\\') {
749            s++;
750            if (s >= end) {
751                *t++ = '\\';
752                break;
753            }
754
755            switch(*s) {
756                case 'n':
757                    *t++ = '\n';
758                    zendlval->value.str.len--;
759                    break;
760                case 'r':
761                    *t++ = '\r';
762                    zendlval->value.str.len--;
763                    break;
764                case 't':
765                    *t++ = '\t';
766                    zendlval->value.str.len--;
767                    break;
768                case 'f':
769                    *t++ = '\f';
770                    zendlval->value.str.len--;
771                    break;
772                case 'v':
773                    *t++ = '\v';
774                    zendlval->value.str.len--;
775                    break;
776                case '"':
777                case '`':
778                    if (*s != quote_type) {
779                        *t++ = '\\';
780                        *t++ = *s;
781                        break;
782                    }
783                case '\\':
784                case '$':
785                    *t++ = *s;
786                    zendlval->value.str.len--;
787                    break;
788                case 'x':
789                case 'X':
790                    if (ZEND_IS_HEX(*(s+1))) {
791                        char hex_buf[3] = { 0, 0, 0 };
792
793                        zendlval->value.str.len--; /* for the 'x' */
794
795                        hex_buf[0] = *(++s);
796                        zendlval->value.str.len--;
797                        if (ZEND_IS_HEX(*(s+1))) {
798                            hex_buf[1] = *(++s);
799                            zendlval->value.str.len--;
800                        }
801                        *t++ = (char) strtol(hex_buf, NULL, 16);
802                    } else {
803                        *t++ = '\\';
804                        *t++ = *s;
805                    }
806                    break;
807                default:
808                    /* check for an octal */
809                    if (ZEND_IS_OCT(*s)) {
810                        char octal_buf[4] = { 0, 0, 0, 0 };
811
812                        octal_buf[0] = *s;
813                        zendlval->value.str.len--;
814                        if (ZEND_IS_OCT(*(s+1))) {
815                            octal_buf[1] = *(++s);
816                            zendlval->value.str.len--;
817                            if (ZEND_IS_OCT(*(s+1))) {
818                                octal_buf[2] = *(++s);
819                                zendlval->value.str.len--;
820                            }
821                        }
822                        *t++ = (char) strtol(octal_buf, NULL, 8);
823                    } else {
824                        *t++ = '\\';
825                        *t++ = *s;
826                    }
827                    break;
828            }
829        } else {
830            *t++ = *s;
831        }
832
833        if (*s == '\n' || (*s == '\r' && (*(s+1) != '\n'))) {
834            CG(zend_lineno)++;
835        }
836        s++;
837    }
838    *t = 0;
839#ifdef ZEND_MULTIBYTE
840    if (SCNG(output_filter)) {
841        size_t sz = 0;
842        s = zendlval->value.str.val;
843        SCNG(output_filter)((unsigned char **)&(zendlval->value.str.val), &sz, (unsigned char *)s, (size_t)zendlval->value.str.len TSRMLS_CC);
844        zendlval->value.str.len = sz;
845        efree(s);
846    }
847#endif /* ZEND_MULTIBYTE */
848}
849
850
851int lex_scan(zval *zendlval TSRMLS_DC)
852{
853restart:
854    SCNG(yy_text) = YYCURSOR;
855
856yymore_restart:
857
858/*!re2c
859re2c:yyfill:check = 0;
860LNUM    [0-9]+
861DNUM    ([0-9]*"."[0-9]+)|([0-9]+"."[0-9]*)
862EXPONENT_DNUM   (({LNUM}|{DNUM})[eE][+-]?{LNUM})
863HNUM    "0x"[0-9a-fA-F]+
864LABEL   [a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*
865WHITESPACE [ \n\r\t]+
866TABS_AND_SPACES [ \t]*
867TOKENS [;:,.\[\]()|^&+-/*=%!~$<>?@]
868ANY_CHAR [^]
869NEWLINE ("\r"|"\n"|"\r\n")
870
871/* compute yyleng before each rule */
872<!*> := yyleng = YYCURSOR - SCNG(yy_text);
873
874
875<ST_IN_SCRIPTING>"exit" {
876    return T_EXIT;
877}
878
879<ST_IN_SCRIPTING>"die" {
880    return T_EXIT;
881}
882
883<ST_IN_SCRIPTING>"function" {
884    return T_FUNCTION;
885}
886
887<ST_IN_SCRIPTING>"const" {
888    return T_CONST;
889}
890
891<ST_IN_SCRIPTING>"return" {
892    return T_RETURN;
893}
894
895<ST_IN_SCRIPTING>"try" {
896    return T_TRY;
897}
898
899<ST_IN_SCRIPTING>"catch" {
900    return T_CATCH;
901}
902
903<ST_IN_SCRIPTING>"throw" {
904    return T_THROW;
905}
906
907<ST_IN_SCRIPTING>"if" {
908    return T_IF;
909}
910
911<ST_IN_SCRIPTING>"elseif" {
912    return T_ELSEIF;
913}
914
915<ST_IN_SCRIPTING>"endif" {
916    return T_ENDIF;
917}
918
919<ST_IN_SCRIPTING>"else" {
920    return T_ELSE;
921}
922
923<ST_IN_SCRIPTING>"while" {
924    return T_WHILE;
925}
926
927<ST_IN_SCRIPTING>"endwhile" {
928    return T_ENDWHILE;
929}
930
931<ST_IN_SCRIPTING>"do" {
932    return T_DO;
933}
934
935<ST_IN_SCRIPTING>"for" {
936    return T_FOR;
937}
938
939<ST_IN_SCRIPTING>"endfor" {
940    return T_ENDFOR;
941}
942
943<ST_IN_SCRIPTING>"foreach" {
944    return T_FOREACH;
945}
946
947<ST_IN_SCRIPTING>"endforeach" {
948    return T_ENDFOREACH;
949}
950
951<ST_IN_SCRIPTING>"declare" {
952    return T_DECLARE;
953}
954
955<ST_IN_SCRIPTING>"enddeclare" {
956    return T_ENDDECLARE;
957}
958
959<ST_IN_SCRIPTING>"instanceof" {
960    return T_INSTANCEOF;
961}
962
963<ST_IN_SCRIPTING>"as" {
964    return T_AS;
965}
966
967<ST_IN_SCRIPTING>"switch" {
968    return T_SWITCH;
969}
970
971<ST_IN_SCRIPTING>"endswitch" {
972    return T_ENDSWITCH;
973}
974
975<ST_IN_SCRIPTING>"case" {
976    return T_CASE;
977}
978
979<ST_IN_SCRIPTING>"default" {
980    return T_DEFAULT;
981}
982
983<ST_IN_SCRIPTING>"break" {
984    return T_BREAK;
985}
986
987<ST_IN_SCRIPTING>"continue" {
988    return T_CONTINUE;
989}
990
991<ST_IN_SCRIPTING>"goto" {
992    return T_GOTO;
993}
994
995<ST_IN_SCRIPTING>"echo" {
996    return T_ECHO;
997}
998
999<ST_IN_SCRIPTING>"print" {
1000    return T_PRINT;
1001}
1002
1003<ST_IN_SCRIPTING>"class" {
1004    return T_CLASS;
1005}
1006
1007<ST_IN_SCRIPTING>"interface" {
1008    return T_INTERFACE;
1009}
1010
1011<ST_IN_SCRIPTING>"extends" {
1012    return T_EXTENDS;
1013}
1014
1015<ST_IN_SCRIPTING>"implements" {
1016    return T_IMPLEMENTS;
1017}
1018
1019<ST_IN_SCRIPTING>"->" {
1020    yy_push_state(ST_LOOKING_FOR_PROPERTY TSRMLS_CC);
1021    return T_OBJECT_OPERATOR;
1022}
1023
1024<ST_IN_SCRIPTING,ST_LOOKING_FOR_PROPERTY>{WHITESPACE}+ {
1025    zendlval->value.str.val = yytext; /* no copying - intentional */
1026    zendlval->value.str.len = yyleng;
1027    zendlval->type = IS_STRING;
1028    HANDLE_NEWLINES(yytext, yyleng);
1029    return T_WHITESPACE;
1030}
1031
1032<ST_LOOKING_FOR_PROPERTY>"->" {
1033    return T_OBJECT_OPERATOR;
1034}
1035
1036<ST_LOOKING_FOR_PROPERTY>{LABEL} {
1037    yy_pop_state(TSRMLS_C);
1038    zend_copy_value(zendlval, yytext, yyleng);
1039    zendlval->type = IS_STRING;
1040    return T_STRING;
1041}
1042
1043<ST_LOOKING_FOR_PROPERTY>{ANY_CHAR} {
1044    yyless(0);
1045    yy_pop_state(TSRMLS_C);
1046    goto restart;
1047}
1048
1049<ST_IN_SCRIPTING>"::" {
1050    return T_PAAMAYIM_NEKUDOTAYIM;
1051}
1052
1053<ST_IN_SCRIPTING>"\\" {
1054    return T_NS_SEPARATOR;
1055}
1056
1057<ST_IN_SCRIPTING>"new" {
1058    return T_NEW;
1059}
1060
1061<ST_IN_SCRIPTING>"clone" {
1062    return T_CLONE;
1063}
1064
1065<ST_IN_SCRIPTING>"var" {
1066    return T_VAR;
1067}
1068
1069<ST_IN_SCRIPTING>"("{TABS_AND_SPACES}("int"|"integer"){TABS_AND_SPACES}")" {
1070    return T_INT_CAST;
1071}
1072
1073<ST_IN_SCRIPTING>"("{TABS_AND_SPACES}("real"|"double"|"float"){TABS_AND_SPACES}")" {
1074    return T_DOUBLE_CAST;
1075}
1076
1077<ST_IN_SCRIPTING>"("{TABS_AND_SPACES}"string"{TABS_AND_SPACES}")" {
1078    return T_STRING_CAST;
1079}
1080
1081<ST_IN_SCRIPTING>"("{TABS_AND_SPACES}"binary"{TABS_AND_SPACES}")" {
1082    return T_STRING_CAST;
1083}
1084
1085<ST_IN_SCRIPTING>"("{TABS_AND_SPACES}"array"{TABS_AND_SPACES}")" {
1086    return T_ARRAY_CAST;
1087}
1088
1089<ST_IN_SCRIPTING>"("{TABS_AND_SPACES}"object"{TABS_AND_SPACES}")" {
1090    return T_OBJECT_CAST;
1091}
1092
1093<ST_IN_SCRIPTING>"("{TABS_AND_SPACES}("bool"|"boolean"){TABS_AND_SPACES}")" {
1094    return T_BOOL_CAST;
1095}
1096
1097<ST_IN_SCRIPTING>"("{TABS_AND_SPACES}("unset"){TABS_AND_SPACES}")" {
1098    return T_UNSET_CAST;
1099}
1100
1101<ST_IN_SCRIPTING>"eval" {
1102    return T_EVAL;
1103}
1104
1105<ST_IN_SCRIPTING>"include" {
1106    return T_INCLUDE;
1107}
1108
1109<ST_IN_SCRIPTING>"include_once" {
1110    return T_INCLUDE_ONCE;
1111}
1112
1113<ST_IN_SCRIPTING>"require" {
1114    return T_REQUIRE;
1115}
1116
1117<ST_IN_SCRIPTING>"require_once" {
1118    return T_REQUIRE_ONCE;
1119}
1120
1121<ST_IN_SCRIPTING>"namespace" {
1122    return T_NAMESPACE;
1123}
1124
1125<ST_IN_SCRIPTING>"use" {
1126    return T_USE;
1127}
1128
1129<ST_IN_SCRIPTING>"global" {
1130    return T_GLOBAL;
1131}
1132
1133<ST_IN_SCRIPTING>"isset" {
1134    return T_ISSET;
1135}
1136
1137<ST_IN_SCRIPTING>"empty" {
1138    return T_EMPTY;
1139}
1140
1141<ST_IN_SCRIPTING>"__halt_compiler" {
1142    return T_HALT_COMPILER;
1143}
1144
1145<ST_IN_SCRIPTING>"static" {
1146    return T_STATIC;
1147}
1148
1149<ST_IN_SCRIPTING>"abstract" {
1150    return T_ABSTRACT;
1151}
1152
1153<ST_IN_SCRIPTING>"final" {
1154    return T_FINAL;
1155}
1156
1157<ST_IN_SCRIPTING>"private" {
1158    return T_PRIVATE;
1159}
1160
1161<ST_IN_SCRIPTING>"protected" {
1162    return T_PROTECTED;
1163}
1164
1165<ST_IN_SCRIPTING>"public" {
1166    return T_PUBLIC;
1167}
1168
1169<ST_IN_SCRIPTING>"unset" {
1170    return T_UNSET;
1171}
1172
1173<ST_IN_SCRIPTING>"=>" {
1174    return T_DOUBLE_ARROW;
1175}
1176
1177<ST_IN_SCRIPTING>"list" {
1178    return T_LIST;
1179}
1180
1181<ST_IN_SCRIPTING>"array" {
1182    return T_ARRAY;
1183}
1184
1185<ST_IN_SCRIPTING>"++" {
1186    return T_INC;
1187}
1188
1189<ST_IN_SCRIPTING>"--" {
1190    return T_DEC;
1191}
1192
1193<ST_IN_SCRIPTING>"===" {
1194    return T_IS_IDENTICAL;
1195}
1196
1197<ST_IN_SCRIPTING>"!==" {
1198    return T_IS_NOT_IDENTICAL;
1199}
1200
1201<ST_IN_SCRIPTING>"==" {
1202    return T_IS_EQUAL;
1203}
1204
1205<ST_IN_SCRIPTING>"!="|"<>" {
1206    return T_IS_NOT_EQUAL;
1207}
1208
1209<ST_IN_SCRIPTING>"<=" {
1210    return T_IS_SMALLER_OR_EQUAL;
1211}
1212
1213<ST_IN_SCRIPTING>">=" {
1214    return T_IS_GREATER_OR_EQUAL;
1215}
1216
1217<ST_IN_SCRIPTING>"+=" {
1218    return T_PLUS_EQUAL;
1219}
1220
1221<ST_IN_SCRIPTING>"-=" {
1222    return T_MINUS_EQUAL;
1223}
1224
1225<ST_IN_SCRIPTING>"*=" {
1226    return T_MUL_EQUAL;
1227}
1228
1229<ST_IN_SCRIPTING>"/=" {
1230    return T_DIV_EQUAL;
1231}
1232
1233<ST_IN_SCRIPTING>".=" {
1234    return T_CONCAT_EQUAL;
1235}
1236
1237<ST_IN_SCRIPTING>"%=" {
1238    return T_MOD_EQUAL;
1239}
1240
1241<ST_IN_SCRIPTING>"<<=" {
1242    return T_SL_EQUAL;
1243}
1244
1245<ST_IN_SCRIPTING>">>=" {
1246    return T_SR_EQUAL;
1247}
1248
1249<ST_IN_SCRIPTING>"&=" {
1250    return T_AND_EQUAL;
1251}
1252
1253<ST_IN_SCRIPTING>"|=" {
1254    return T_OR_EQUAL;
1255}
1256
1257<ST_IN_SCRIPTING>"^=" {
1258    return T_XOR_EQUAL;
1259}
1260
1261<ST_IN_SCRIPTING>"||" {
1262    return T_BOOLEAN_OR;
1263}
1264
1265<ST_IN_SCRIPTING>"&&" {
1266    return T_BOOLEAN_AND;
1267}
1268
1269<ST_IN_SCRIPTING>"OR" {
1270    return T_LOGICAL_OR;
1271}
1272
1273<ST_IN_SCRIPTING>"AND" {
1274    return T_LOGICAL_AND;
1275}
1276
1277<ST_IN_SCRIPTING>"XOR" {
1278    return T_LOGICAL_XOR;
1279}
1280
1281<ST_IN_SCRIPTING>"<<" {
1282    return T_SL;
1283}
1284
1285<ST_IN_SCRIPTING>">>" {
1286    return T_SR;
1287}
1288
1289<ST_IN_SCRIPTING>{TOKENS} {
1290    return yytext[0];
1291}
1292
1293
1294<ST_IN_SCRIPTING>"{" {
1295    yy_push_state(ST_IN_SCRIPTING TSRMLS_CC);
1296    return '{';
1297}
1298
1299
1300<ST_DOUBLE_QUOTES,ST_BACKQUOTE,ST_HEREDOC>"${" {
1301    yy_push_state(ST_LOOKING_FOR_VARNAME TSRMLS_CC);
1302    return T_DOLLAR_OPEN_CURLY_BRACES;
1303}
1304
1305
1306<ST_IN_SCRIPTING>"}" {
1307    RESET_DOC_COMMENT();
1308    if (!zend_stack_is_empty(&SCNG(state_stack))) {
1309        yy_pop_state(TSRMLS_C);
1310    }
1311    return '}';
1312}
1313
1314
1315<ST_LOOKING_FOR_VARNAME>{LABEL} {
1316    zend_copy_value(zendlval, yytext, yyleng);
1317    zendlval->type = IS_STRING;
1318    yy_pop_state(TSRMLS_C);
1319    yy_push_state(ST_IN_SCRIPTING TSRMLS_CC);
1320    return T_STRING_VARNAME;
1321}
1322
1323
1324<ST_LOOKING_FOR_VARNAME>{ANY_CHAR} {
1325    yyless(0);
1326    yy_pop_state(TSRMLS_C);
1327    yy_push_state(ST_IN_SCRIPTING TSRMLS_CC);
1328    goto restart;
1329}
1330
1331
1332<ST_IN_SCRIPTING>{LNUM} {
1333    if (yyleng < MAX_LENGTH_OF_LONG - 1) { /* Won't overflow */
1334        zendlval->value.lval = strtol(yytext, NULL, 0);
1335    } else {
1336        errno = 0;
1337        zendlval->value.lval = strtol(yytext, NULL, 0);
1338        if (errno == ERANGE) { /* Overflow */
1339            if (yytext[0] == '0') { /* octal overflow */
1340                zendlval->value.dval = zend_oct_strtod(yytext, NULL);
1341            } else {
1342                zendlval->value.dval = zend_strtod(yytext, NULL);
1343            }
1344            zendlval->type = IS_DOUBLE;
1345            return T_DNUMBER;
1346        }
1347    }
1348
1349    zendlval->type = IS_LONG;
1350    return T_LNUMBER;
1351}
1352
1353<ST_IN_SCRIPTING>{HNUM} {
1354    char *hex = yytext + 2; /* Skip "0x" */
1355    int len = yyleng - 2;
1356
1357    /* Skip any leading 0s */
1358    while (*hex == '0') {
1359        hex++;
1360        len--;
1361    }
1362
1363    if (len < SIZEOF_LONG * 2 || (len == SIZEOF_LONG * 2 && *hex <= '7')) {
1364        if (len == 0) {
1365            zendlval->value.lval = 0;
1366        } else {
1367            zendlval->value.lval = strtol(hex, NULL, 16);
1368        }
1369        zendlval->type = IS_LONG;
1370        return T_LNUMBER;
1371    } else {
1372        zendlval->value.dval = zend_hex_strtod(hex, NULL);
1373        zendlval->type = IS_DOUBLE;
1374        return T_DNUMBER;
1375    }
1376}
1377
1378<ST_VAR_OFFSET>[0]|([1-9][0-9]*) { /* Offset could be treated as a long */
1379    if (yyleng < MAX_LENGTH_OF_LONG - 1 || (yyleng == MAX_LENGTH_OF_LONG - 1 && strcmp(yytext, long_min_digits) < 0)) {
1380        zendlval->value.lval = strtol(yytext, NULL, 10);
1381        zendlval->type = IS_LONG;
1382    } else {
1383        zendlval->value.str.val = (char *)estrndup(yytext, yyleng);
1384        zendlval->value.str.len = yyleng;
1385        zendlval->type = IS_STRING;
1386    }
1387    return T_NUM_STRING;
1388}
1389
1390<ST_VAR_OFFSET>{LNUM}|{HNUM} { /* Offset must be treated as a string */
1391    zendlval->value.str.val = (char *)estrndup(yytext, yyleng);
1392    zendlval->value.str.len = yyleng;
1393    zendlval->type = IS_STRING;
1394    return T_NUM_STRING;
1395}
1396
1397<ST_IN_SCRIPTING>{DNUM}|{EXPONENT_DNUM} {
1398    zendlval->value.dval = zend_strtod(yytext, NULL);
1399    zendlval->type = IS_DOUBLE;
1400    return T_DNUMBER;
1401}
1402
1403<ST_IN_SCRIPTING>"__CLASS__" {
1404    char *class_name = NULL;
1405
1406    if (CG(active_class_entry)) {
1407        class_name = CG(active_class_entry)->name;
1408    }
1409
1410    if (!class_name) {
1411        class_name = "";
1412    }
1413    zendlval->value.str.len = strlen(class_name);
1414    zendlval->value.str.val = estrndup(class_name, zendlval->value.str.len);
1415    zendlval->type = IS_STRING;
1416    return T_CLASS_C;
1417}
1418
1419<ST_IN_SCRIPTING>"__FUNCTION__" {
1420    char *func_name = NULL;
1421
1422    if (CG(active_op_array)) {
1423        func_name = CG(active_op_array)->function_name;
1424    }
1425
1426    if (!func_name) {
1427        func_name = "";
1428    }
1429    zendlval->value.str.len = strlen(func_name);
1430    zendlval->value.str.val = estrndup(func_name, zendlval->value.str.len);
1431    zendlval->type = IS_STRING;
1432    return T_FUNC_C;
1433}
1434
1435<ST_IN_SCRIPTING>"__METHOD__" {
1436    char *class_name = CG(active_class_entry) ? CG(active_class_entry)->name : NULL;
1437    char *func_name = CG(active_op_array)? CG(active_op_array)->function_name : NULL;
1438    size_t len = 0;
1439
1440    if (class_name) {
1441        len += strlen(class_name) + 2;
1442    }
1443    if (func_name) {
1444        len += strlen(func_name);
1445    }
1446
1447    zendlval->value.str.len = zend_spprintf(&zendlval->value.str.val, 0, "%s%s%s",
1448        class_name ? class_name : "",
1449        class_name && func_name ? "::" : "",
1450        func_name ? func_name : ""
1451        );
1452    zendlval->type = IS_STRING;
1453    return T_METHOD_C;
1454}
1455
1456<ST_IN_SCRIPTING>"__LINE__" {
1457    zendlval->value.lval = CG(zend_lineno);
1458    zendlval->type = IS_LONG;
1459    return T_LINE;
1460}
1461
1462<ST_IN_SCRIPTING>"__FILE__" {
1463    char *filename = zend_get_compiled_filename(TSRMLS_C);
1464
1465    if (!filename) {
1466        filename = "";
1467    }
1468    zendlval->value.str.len = strlen(filename);
1469    zendlval->value.str.val = estrndup(filename, zendlval->value.str.len);
1470    zendlval->type = IS_STRING;
1471    return T_FILE;
1472}
1473
1474<ST_IN_SCRIPTING>"__DIR__" {
1475    char *filename = zend_get_compiled_filename(TSRMLS_C);
1476    const size_t filename_len = strlen(filename);
1477    char *dirname;
1478
1479    if (!filename) {
1480        filename = "";
1481    }
1482
1483    dirname = estrndup(filename, filename_len);
1484    zend_dirname(dirname, filename_len);
1485
1486    if (strcmp(dirname, ".") == 0) {
1487        dirname = erealloc(dirname, MAXPATHLEN);
1488#if HAVE_GETCWD
1489        VCWD_GETCWD(dirname, MAXPATHLEN);
1490#elif HAVE_GETWD
1491        VCWD_GETWD(dirname);
1492#endif
1493    }
1494
1495    zendlval->value.str.len = strlen(dirname);
1496    zendlval->value.str.val = dirname;
1497    zendlval->type = IS_STRING;
1498    return T_DIR;
1499}
1500
1501<ST_IN_SCRIPTING>"__NAMESPACE__" {
1502    if (CG(current_namespace)) {
1503        *zendlval = *CG(current_namespace);
1504        zval_copy_ctor(zendlval);
1505    } else {
1506        ZVAL_EMPTY_STRING(zendlval);
1507    }
1508    return T_NS_C;
1509}
1510
1511<INITIAL>"<script"{WHITESPACE}+"language"{WHITESPACE}*"="{WHITESPACE}*("php"|"\"php\""|"'php'"){WHITESPACE}*">" {
1512    YYCTYPE *bracket = zend_memrchr(yytext, '<', yyleng - (sizeof("script language=php>") - 1));
1513
1514    if (bracket != SCNG(yy_text)) {
1515        /* Handle previously scanned HTML, as possible <script> tags found are assumed to not be PHP's */
1516        YYCURSOR = bracket;
1517        goto inline_html;
1518    }
1519
1520    HANDLE_NEWLINES(yytext, yyleng);
1521    zendlval->value.str.val = yytext; /* no copying - intentional */
1522    zendlval->value.str.len = yyleng;
1523    zendlval->type = IS_STRING;
1524    BEGIN(ST_IN_SCRIPTING);
1525    return T_OPEN_TAG;
1526}
1527
1528
1529<INITIAL>"<%=" {
1530    if (CG(asp_tags)) {
1531        zendlval->value.str.val = yytext; /* no copying - intentional */
1532        zendlval->value.str.len = yyleng;
1533        zendlval->type = IS_STRING;
1534        BEGIN(ST_IN_SCRIPTING);
1535        return T_OPEN_TAG_WITH_ECHO;
1536    } else {
1537        goto inline_char_handler;
1538    }
1539}
1540
1541
1542<INITIAL>"<?=" {
1543    if (CG(short_tags)) {
1544        zendlval->value.str.val = yytext; /* no copying - intentional */
1545        zendlval->value.str.len = yyleng;
1546        zendlval->type = IS_STRING;
1547        BEGIN(ST_IN_SCRIPTING);
1548        return T_OPEN_TAG_WITH_ECHO;
1549    } else {
1550        goto inline_char_handler;
1551    }
1552}
1553
1554
1555<INITIAL>"<%" {
1556    if (CG(asp_tags)) {
1557        zendlval->value.str.val = yytext; /* no copying - intentional */
1558        zendlval->value.str.len = yyleng;
1559        zendlval->type = IS_STRING;
1560        BEGIN(ST_IN_SCRIPTING);
1561        return T_OPEN_TAG;
1562    } else {
1563        goto inline_char_handler;
1564    }
1565}
1566
1567
1568<INITIAL>"<?php"([ \t]|{NEWLINE}) {
1569    zendlval->value.str.val = yytext; /* no copying - intentional */
1570    zendlval->value.str.len = yyleng;
1571    zendlval->type = IS_STRING;
1572    HANDLE_NEWLINE(yytext[yyleng-1]);
1573    BEGIN(ST_IN_SCRIPTING);
1574    return T_OPEN_TAG;
1575}
1576
1577
1578<INITIAL>"<?" {
1579    if (CG(short_tags)) {
1580        zendlval->value.str.val = yytext; /* no copying - intentional */
1581        zendlval->value.str.len = yyleng;
1582        zendlval->type = IS_STRING;
1583        BEGIN(ST_IN_SCRIPTING);
1584        return T_OPEN_TAG;
1585    } else {
1586        goto inline_char_handler;
1587    }
1588}
1589
1590<INITIAL>{ANY_CHAR} {
1591    if (YYCURSOR > YYLIMIT) {
1592        return 0;
1593    }
1594
1595inline_char_handler:
1596
1597    while (1) {
1598        YYCTYPE *ptr = memchr(YYCURSOR, '<', YYLIMIT - YYCURSOR);
1599
1600        YYCURSOR = ptr ? ptr + 1 : YYLIMIT;
1601
1602        if (YYCURSOR < YYLIMIT) {
1603            switch (*YYCURSOR) {
1604                case '?':
1605                    if (CG(short_tags) || !strncasecmp(YYCURSOR + 1, "php", 3)) { /* Assume [ \t\n\r] follows "php" */
1606                        break;
1607                    }
1608                    continue;
1609                case '%':
1610                    if (CG(asp_tags)) {
1611                        break;
1612                    }
1613                    continue;
1614                case 's':
1615                case 'S':
1616                    /* Probably NOT an opening PHP <script> tag, so don't end the HTML chunk yet
1617                     * If it is, the PHP <script> tag rule checks for any HTML scanned before it */
1618                    YYCURSOR--;
1619                    yymore();
1620                default:
1621                    continue;
1622            }
1623
1624            YYCURSOR--;
1625        }
1626
1627        break;
1628    }
1629
1630inline_html:
1631    yyleng = YYCURSOR - SCNG(yy_text);
1632
1633#ifdef ZEND_MULTIBYTE
1634    if (SCNG(output_filter)) {
1635        int readsize;
1636        size_t sz = 0;
1637        readsize = SCNG(output_filter)((unsigned char **)&(zendlval->value.str.val), &sz, (unsigned char *)yytext, (size_t)yyleng TSRMLS_CC);
1638        zendlval->value.str.len = sz;
1639        if (readsize < yyleng) {
1640            yyless(readsize);
1641        }
1642    } else {
1643      zendlval->value.str.val = (char *) estrndup(yytext, yyleng);
1644      zendlval->value.str.len = yyleng;
1645    }
1646#else /* !ZEND_MULTIBYTE */
1647    zendlval->value.str.val = (char *) estrndup(yytext, yyleng);
1648    zendlval->value.str.len = yyleng;
1649#endif
1650    zendlval->type = IS_STRING;
1651    HANDLE_NEWLINES(yytext, yyleng);
1652    return T_INLINE_HTML;
1653}
1654
1655
1656/* Make sure a label character follows "->", otherwise there is no property
1657 * and "->" will be taken literally
1658 */
1659<ST_DOUBLE_QUOTES,ST_HEREDOC,ST_BACKQUOTE>"$"{LABEL}"->"[a-zA-Z_\x7f-\xff] {
1660    yyless(yyleng - 3);
1661    yy_push_state(ST_LOOKING_FOR_PROPERTY TSRMLS_CC);
1662    zend_copy_value(zendlval, (yytext+1), (yyleng-1));
1663    zendlval->type = IS_STRING;
1664    return T_VARIABLE;
1665}
1666
1667/* A [ always designates a variable offset, regardless of what follows
1668 */
1669<ST_DOUBLE_QUOTES,ST_HEREDOC,ST_BACKQUOTE>"$"{LABEL}"[" {
1670    yyless(yyleng - 1);
1671    yy_push_state(ST_VAR_OFFSET TSRMLS_CC);
1672    zend_copy_value(zendlval, (yytext+1), (yyleng-1));
1673    zendlval->type = IS_STRING;
1674    return T_VARIABLE;
1675}
1676
1677<ST_IN_SCRIPTING,ST_DOUBLE_QUOTES,ST_HEREDOC,ST_BACKQUOTE,ST_VAR_OFFSET>"$"{LABEL} {
1678    zend_copy_value(zendlval, (yytext+1), (yyleng-1));
1679    zendlval->type = IS_STRING;
1680    return T_VARIABLE;
1681}
1682
1683<ST_VAR_OFFSET>"]" {
1684    yy_pop_state(TSRMLS_C);
1685    return ']';
1686}
1687
1688<ST_VAR_OFFSET>{TOKENS}|[{}"`] {
1689    /* Only '[' can be valid, but returning other tokens will allow a more explicit parse error */
1690    return yytext[0];
1691}
1692
1693<ST_VAR_OFFSET>[ \n\r\t\\'#] {
1694    /* Invalid rule to return a more explicit parse error with proper line number */
1695    yyless(0);
1696    yy_pop_state(TSRMLS_C);
1697    return T_ENCAPSED_AND_WHITESPACE;
1698}
1699
1700<ST_IN_SCRIPTING,ST_VAR_OFFSET>{LABEL} {
1701    zend_copy_value(zendlval, yytext, yyleng);
1702    zendlval->type = IS_STRING;
1703    return T_STRING;
1704}
1705
1706
1707<ST_IN_SCRIPTING>"#"|"//" {
1708    while (YYCURSOR < YYLIMIT) {
1709        switch (*YYCURSOR++) {
1710            case '\r':
1711                if (*YYCURSOR == '\n') {
1712                    YYCURSOR++;
1713                }
1714                /* fall through */
1715            case '\n':
1716                CG(zend_lineno)++;
1717                break;
1718            case '%':
1719                if (!CG(asp_tags)) {
1720                    continue;
1721                }
1722                /* fall through */
1723            case '?':
1724                if (*YYCURSOR == '>') {
1725                    YYCURSOR--;
1726                    break;
1727                }
1728                /* fall through */
1729            default:
1730                continue;
1731        }
1732
1733        break;
1734    }
1735
1736    yyleng = YYCURSOR - SCNG(yy_text);
1737
1738    return T_COMMENT;
1739}
1740
1741<ST_IN_SCRIPTING>"/*"|"/**"{WHITESPACE} {
1742    int doc_com;
1743
1744    if (yyleng > 2) {
1745        doc_com = 1;
1746        RESET_DOC_COMMENT();
1747    } else {
1748        doc_com = 0;
1749    }
1750
1751    while (YYCURSOR < YYLIMIT) {
1752        if (*YYCURSOR++ == '*' && *YYCURSOR == '/') {
1753            break;
1754        }
1755    }
1756
1757    if (YYCURSOR < YYLIMIT) {
1758        YYCURSOR++;
1759    } else {
1760        zend_error(E_COMPILE_WARNING, "Unterminated comment starting line %d", CG(zend_lineno));
1761    }
1762
1763    yyleng = YYCURSOR - SCNG(yy_text);
1764    HANDLE_NEWLINES(yytext, yyleng);
1765
1766    if (doc_com) {
1767        CG(doc_comment) = estrndup(yytext, yyleng);
1768        CG(doc_comment_len) = yyleng;
1769        return T_DOC_COMMENT;
1770    }
1771
1772    return T_COMMENT;
1773}
1774
1775<ST_IN_SCRIPTING>("?>"|"</script"{WHITESPACE}*">"){NEWLINE}? {
1776    zendlval->value.str.val = yytext; /* no copying - intentional */
1777    zendlval->value.str.len = yyleng;
1778    zendlval->type = IS_STRING;
1779    BEGIN(INITIAL);
1780    return T_CLOSE_TAG;  /* implicit ';' at php-end tag */
1781}
1782
1783
1784<ST_IN_SCRIPTING>"%>"{NEWLINE}? {
1785    if (CG(asp_tags)) {
1786        BEGIN(INITIAL);
1787        zendlval->value.str.len = yyleng;
1788        zendlval->type = IS_STRING;
1789        zendlval->value.str.val = yytext; /* no copying - intentional */
1790        return T_CLOSE_TAG;  /* implicit ';' at php-end tag */
1791    } else {
1792        yyless(1);
1793        return yytext[0];
1794    }
1795}
1796
1797
1798<ST_IN_SCRIPTING>b?['] {
1799    register char *s, *t;
1800    char *end;
1801    int bprefix = (yytext[0] != '\'') ? 1 : 0;
1802
1803    while (1) {
1804        if (YYCURSOR < YYLIMIT) {
1805            if (*YYCURSOR == '\'') {
1806                YYCURSOR++;
1807                yyleng = YYCURSOR - SCNG(yy_text);
1808
1809                break;
1810            } else if (*YYCURSOR++ == '\\' && YYCURSOR < YYLIMIT) {
1811                YYCURSOR++;
1812            }
1813        } else {
1814            yyleng = YYLIMIT - SCNG(yy_text);
1815
1816            /* Unclosed single quotes; treat similar to double quotes, but without a separate token
1817             * for ' (unrecognized by parser), instead of old flex fallback to "Unexpected character..."
1818             * rule, which continued in ST_IN_SCRIPTING state after the quote */
1819            return T_ENCAPSED_AND_WHITESPACE;
1820        }
1821    }
1822
1823    zendlval->value.str.val = estrndup(yytext+bprefix+1, yyleng-bprefix-2);
1824    zendlval->value.str.len = yyleng-bprefix-2;
1825    zendlval->type = IS_STRING;
1826
1827    /* convert escape sequences */
1828    s = t = zendlval->value.str.val;
1829    end = s+zendlval->value.str.len;
1830    while (s<end) {
1831        if (*s=='\\') {
1832            s++;
1833
1834            switch(*s) {
1835                case '\\':
1836                case '\'':
1837                    *t++ = *s;
1838                    zendlval->value.str.len--;
1839                    break;
1840                default:
1841                    *t++ = '\\';
1842                    *t++ = *s;
1843                    break;
1844            }
1845        } else {
1846            *t++ = *s;
1847        }
1848
1849        if (*s == '\n' || (*s == '\r' && (*(s+1) != '\n'))) {
1850            CG(zend_lineno)++;
1851        }
1852        s++;
1853    }
1854    *t = 0;
1855
1856#ifdef ZEND_MULTIBYTE
1857    if (SCNG(output_filter)) {
1858        size_t sz = 0;
1859        s = zendlval->value.str.val;
1860        SCNG(output_filter)((unsigned char **)&(zendlval->value.str.val), &sz, (unsigned char *)s, (size_t)zendlval->value.str.len TSRMLS_CC);
1861        zendlval->value.str.len = sz;
1862        efree(s);
1863    }
1864#endif /* ZEND_MULTIBYTE */
1865    return T_CONSTANT_ENCAPSED_STRING;
1866}
1867
1868
1869<ST_IN_SCRIPTING>b?["] {
1870    int bprefix = (yytext[0] != '"') ? 1 : 0;
1871
1872    while (YYCURSOR < YYLIMIT) {
1873        switch (*YYCURSOR++) {
1874            case '"':
1875                yyleng = YYCURSOR - SCNG(yy_text);
1876                zend_scan_escape_string(zendlval, yytext+bprefix+1, yyleng-bprefix-2, '"' TSRMLS_CC);
1877                return T_CONSTANT_ENCAPSED_STRING;
1878            case '$':
1879                if (IS_LABEL_START(*YYCURSOR) || *YYCURSOR == '{') {
1880                    break;
1881                }
1882                continue;
1883            case '{':
1884                if (*YYCURSOR == '$') {
1885                    break;
1886                }
1887                continue;
1888            case '\\':
1889                if (YYCURSOR < YYLIMIT) {
1890                    YYCURSOR++;
1891                }
1892                /* fall through */
1893            default:
1894                continue;
1895        }
1896
1897        YYCURSOR--;
1898        break;
1899    }
1900
1901    /* Remember how much was scanned to save rescanning */
1902    SET_DOUBLE_QUOTES_SCANNED_LENGTH(YYCURSOR - SCNG(yy_text) - yyleng);
1903
1904    YYCURSOR = SCNG(yy_text) + yyleng;
1905
1906    BEGIN(ST_DOUBLE_QUOTES);
1907    return '"';
1908}
1909
1910
1911<ST_IN_SCRIPTING>b?"<<<"{TABS_AND_SPACES}({LABEL}|([']{LABEL}['])|(["]{LABEL}["])){NEWLINE} {
1912    char *s;
1913    int bprefix = (yytext[0] != '<') ? 1 : 0;
1914
1915    /* save old heredoc label */
1916    Z_STRVAL_P(zendlval) = CG(heredoc);
1917    Z_STRLEN_P(zendlval) = CG(heredoc_len);
1918
1919    CG(zend_lineno)++;
1920    CG(heredoc_len) = yyleng-bprefix-3-1-(yytext[yyleng-2]=='\r'?1:0);
1921    s = yytext+bprefix+3;
1922    while ((*s == ' ') || (*s == '\t')) {
1923        s++;
1924        CG(heredoc_len)--;
1925    }
1926
1927    if (*s == '\'') {
1928        s++;
1929        CG(heredoc_len) -= 2;
1930
1931        BEGIN(ST_NOWDOC);
1932    } else {
1933        if (*s == '"') {
1934            s++;
1935            CG(heredoc_len) -= 2;
1936        }
1937
1938        BEGIN(ST_HEREDOC);
1939    }
1940
1941    CG(heredoc) = estrndup(s, CG(heredoc_len));
1942
1943    /* Check for ending label on the next line */
1944    if (CG(heredoc_len) < YYLIMIT - YYCURSOR && !memcmp(YYCURSOR, s, CG(heredoc_len))) {
1945        YYCTYPE *end = YYCURSOR + CG(heredoc_len);
1946
1947        if (*end == ';') {
1948            end++;
1949        }
1950
1951        if (*end == '\n' || *end == '\r') {
1952            BEGIN(ST_END_HEREDOC);
1953        }
1954    }
1955
1956    return T_START_HEREDOC;
1957}
1958
1959
1960<ST_IN_SCRIPTING>[`] {
1961    BEGIN(ST_BACKQUOTE);
1962    return '`';
1963}
1964
1965
1966<ST_END_HEREDOC>{ANY_CHAR} {
1967    YYCURSOR += CG(heredoc_len) - 1;
1968    yyleng = CG(heredoc_len);
1969
1970    Z_STRVAL_P(zendlval) = CG(heredoc);
1971    Z_STRLEN_P(zendlval) = CG(heredoc_len);
1972    CG(heredoc) = NULL;
1973    CG(heredoc_len) = 0;
1974    BEGIN(ST_IN_SCRIPTING);
1975    return T_END_HEREDOC;
1976}
1977
1978
1979<ST_DOUBLE_QUOTES,ST_BACKQUOTE,ST_HEREDOC>"{$" {
1980    zendlval->value.lval = (long) '{';
1981    yy_push_state(ST_IN_SCRIPTING TSRMLS_CC);
1982    yyless(1);
1983    return T_CURLY_OPEN;
1984}
1985
1986
1987<ST_DOUBLE_QUOTES>["] {
1988    BEGIN(ST_IN_SCRIPTING);
1989    return '"';
1990}
1991
1992<ST_BACKQUOTE>[`] {
1993    BEGIN(ST_IN_SCRIPTING);
1994    return '`';
1995}
1996
1997
1998<ST_DOUBLE_QUOTES>{ANY_CHAR} {
1999    if (GET_DOUBLE_QUOTES_SCANNED_LENGTH()) {
2000        YYCURSOR += GET_DOUBLE_QUOTES_SCANNED_LENGTH() - 1;
2001        SET_DOUBLE_QUOTES_SCANNED_LENGTH(0);
2002
2003        goto double_quotes_scan_done;
2004    }
2005
2006    if (YYCURSOR > YYLIMIT) {
2007        return 0;
2008    }
2009    if (yytext[0] == '\\' && YYCURSOR < YYLIMIT) {
2010        YYCURSOR++;
2011    }
2012
2013    while (YYCURSOR < YYLIMIT) {
2014        switch (*YYCURSOR++) {
2015            case '"':
2016                break;
2017            case '$':
2018                if (IS_LABEL_START(*YYCURSOR) || *YYCURSOR == '{') {
2019                    break;
2020                }
2021                continue;
2022            case '{':
2023                if (*YYCURSOR == '$') {
2024                    break;
2025                }
2026                continue;
2027            case '\\':
2028                if (YYCURSOR < YYLIMIT) {
2029                    YYCURSOR++;
2030                }
2031                /* fall through */
2032            default:
2033                continue;
2034        }
2035
2036        YYCURSOR--;
2037        break;
2038    }
2039
2040double_quotes_scan_done:
2041    yyleng = YYCURSOR - SCNG(yy_text);
2042
2043    zend_scan_escape_string(zendlval, yytext, yyleng, '"' TSRMLS_CC);
2044    return T_ENCAPSED_AND_WHITESPACE;
2045}
2046
2047
2048<ST_BACKQUOTE>{ANY_CHAR} {
2049    if (YYCURSOR > YYLIMIT) {
2050        return 0;
2051    }
2052    if (yytext[0] == '\\' && YYCURSOR < YYLIMIT) {
2053        YYCURSOR++;
2054    }
2055
2056    while (YYCURSOR < YYLIMIT) {
2057        switch (*YYCURSOR++) {
2058            case '`':
2059                break;
2060            case '$':
2061                if (IS_LABEL_START(*YYCURSOR) || *YYCURSOR == '{') {
2062                    break;
2063                }
2064                continue;
2065            case '{':
2066                if (*YYCURSOR == '$') {
2067                    break;
2068                }
2069                continue;
2070            case '\\':
2071                if (YYCURSOR < YYLIMIT) {
2072                    YYCURSOR++;
2073                }
2074                /* fall through */
2075            default:
2076                continue;
2077        }
2078
2079        YYCURSOR--;
2080        break;
2081    }
2082
2083    yyleng = YYCURSOR - SCNG(yy_text);
2084
2085    zend_scan_escape_string(zendlval, yytext, yyleng, '`' TSRMLS_CC);
2086    return T_ENCAPSED_AND_WHITESPACE;
2087}
2088
2089
2090<ST_HEREDOC>{ANY_CHAR} {
2091    int newline = 0;
2092
2093    if (YYCURSOR > YYLIMIT) {
2094        return 0;
2095    }
2096
2097    YYCURSOR--;
2098
2099    while (YYCURSOR < YYLIMIT) {
2100        switch (*YYCURSOR++) {
2101            case '\r':
2102                if (*YYCURSOR == '\n') {
2103                    YYCURSOR++;
2104                }
2105                /* fall through */
2106            case '\n':
2107                /* Check for ending label on the next line */
2108                if (IS_LABEL_START(*YYCURSOR) && CG(heredoc_len) < YYLIMIT - YYCURSOR && !memcmp(YYCURSOR, CG(heredoc), CG(heredoc_len))) {
2109                    YYCTYPE *end = YYCURSOR + CG(heredoc_len);
2110
2111                    if (*end == ';') {
2112                        end++;
2113                    }
2114
2115                    if (*end == '\n' || *end == '\r') {
2116                        /* newline before label will be subtracted from returned text, but
2117                         * yyleng/yytext will include it, for zend_highlight/strip, tokenizer, etc. */
2118                        if (YYCURSOR[-2] == '\r' && YYCURSOR[-1] == '\n') {
2119                            newline = 2; /* Windows newline */
2120                        } else {
2121                            newline = 1;
2122                        }
2123
2124                        CG(increment_lineno) = 1; /* For newline before label */
2125                        BEGIN(ST_END_HEREDOC);
2126
2127                        goto heredoc_scan_done;
2128                    }
2129                }
2130                continue;
2131            case '$':
2132                if (IS_LABEL_START(*YYCURSOR) || *YYCURSOR == '{') {
2133                    break;
2134                }
2135                continue;
2136            case '{':
2137                if (*YYCURSOR == '$') {
2138                    break;
2139                }
2140                continue;
2141            case '\\':
2142                if (YYCURSOR < YYLIMIT && *YYCURSOR != '\n' && *YYCURSOR != '\r') {
2143                    YYCURSOR++;
2144                }
2145                /* fall through */
2146            default:
2147                continue;
2148        }
2149
2150        YYCURSOR--;
2151        break;
2152    }
2153
2154heredoc_scan_done:
2155    yyleng = YYCURSOR - SCNG(yy_text);
2156
2157    zend_scan_escape_string(zendlval, yytext, yyleng - newline, 0 TSRMLS_CC);
2158    return T_ENCAPSED_AND_WHITESPACE;
2159}
2160
2161
2162<ST_NOWDOC>{ANY_CHAR} {
2163    int newline = 0;
2164
2165    if (YYCURSOR > YYLIMIT) {
2166        return 0;
2167    }
2168
2169    YYCURSOR--;
2170
2171    while (YYCURSOR < YYLIMIT) {
2172        switch (*YYCURSOR++) {
2173            case '\r':
2174                if (*YYCURSOR == '\n') {
2175                    YYCURSOR++;
2176                }
2177                /* fall through */
2178            case '\n':
2179                /* Check for ending label on the next line */
2180                if (IS_LABEL_START(*YYCURSOR) && CG(heredoc_len) < YYLIMIT - YYCURSOR && !memcmp(YYCURSOR, CG(heredoc), CG(heredoc_len))) {
2181                    YYCTYPE *end = YYCURSOR + CG(heredoc_len);
2182
2183                    if (*end == ';') {
2184                        end++;
2185                    }
2186
2187                    if (*end == '\n' || *end == '\r') {
2188                        /* newline before label will be subtracted from returned text, but
2189                         * yyleng/yytext will include it, for zend_highlight/strip, tokenizer, etc. */
2190                        if (YYCURSOR[-2] == '\r' && YYCURSOR[-1] == '\n') {
2191                            newline = 2; /* Windows newline */
2192                        } else {
2193                            newline = 1;
2194                        }
2195
2196                        CG(increment_lineno) = 1; /* For newline before label */
2197                        BEGIN(ST_END_HEREDOC);
2198
2199                        goto nowdoc_scan_done;
2200                    }
2201                }
2202                /* fall through */
2203            default:
2204                continue;
2205        }
2206    }
2207
2208nowdoc_scan_done:
2209    yyleng = YYCURSOR - SCNG(yy_text);
2210
2211    zend_copy_value(zendlval, yytext, yyleng - newline);
2212    zendlval->type = IS_STRING;
2213    HANDLE_NEWLINES(yytext, yyleng - newline);
2214    return T_ENCAPSED_AND_WHITESPACE;
2215}
2216
2217
2218<ST_IN_SCRIPTING,ST_VAR_OFFSET>{ANY_CHAR} {
2219    if (YYCURSOR > YYLIMIT) {
2220        return 0;
2221    }
2222
2223    zend_error(E_COMPILE_WARNING,"Unexpected character in input:  '%c' (ASCII=%d) state=%d", yytext[0], yytext[0], YYSTATE);
2224    goto restart;
2225}
2226
2227*/
2228}
2229