xref: /PHP-5.3/Zend/zend_language_scanner.l (revision 831fbcf3)
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
88 ZEND_API ts_rsrc_id language_scanner_globals_id;
89 #else
90 ZEND_API zend_php_scanner_globals language_scanner_globals;
91 #endif
92 
93 #define HANDLE_NEWLINES(s, l)													\
94 do {																			\
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 
BEGIN_EXTERN_C()121 BEGIN_EXTERN_C()
122 
123 static 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 
yy_pop_state(TSRMLS_D)131 static 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 
yy_scan_buffer(char * str,unsigned int len TSRMLS_DC)139 static 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 
startup_scanner(TSRMLS_D)148 void 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 
shutdown_scanner(TSRMLS_D)157 void 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 
zend_save_lexical_state(zend_lex_state * lex_state TSRMLS_DC)167 ZEND_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 
zend_restore_lexical_state(zend_lex_state * lex_state TSRMLS_DC)196 ZEND_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 
zend_destroy_file_handle(zend_file_handle * file_handle TSRMLS_DC)238 ZEND_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 
open_file_for_scanning(zend_file_handle * file_handle TSRMLS_DC)249 ZEND_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 }
END_EXTERN_C()328 END_EXTERN_C()
329 
330 
331 ZEND_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 
compile_filename(int type,zval * filename TSRMLS_DC)388 zend_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 
zend_prepare_string_for_scanning(zval * str,char * filename TSRMLS_DC)429 ZEND_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 
zend_get_scanned_file_offset(TSRMLS_D)465 ZEND_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 
compile_string(zval * source_string,char * filename TSRMLS_DC)489 zend_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 
BEGIN_EXTERN_C()557 BEGIN_EXTERN_C()
558 int 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 
highlight_string(zval * str,zend_syntax_highlighter_ini * syntax_highlighter_ini,char * str_name TSRMLS_DC)589 int 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 }
617 END_EXTERN_C()
618 
619 #ifdef ZEND_MULTIBYTE
620 
BEGIN_EXTERN_C()621 BEGIN_EXTERN_C()
622 ZEND_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 
zend_multibyte_yyinput(zend_file_handle * file_handle,char * buf,size_t len TSRMLS_DC)670 ZEND_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 
zend_multibyte_read_script(unsigned char * buf,size_t n TSRMLS_DC)706 ZEND_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 
zend_scan_escape_string(zval * zendlval,char * str,int len,char quote_type TSRMLS_DC)737 static 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 
lex_scan(zval * zendlval TSRMLS_DC)851 int lex_scan(zval *zendlval TSRMLS_DC)
852 {
853 restart:
854 	SCNG(yy_text) = YYCURSOR;
855 
856 yymore_restart:
857 
858 /*!re2c
859 re2c:yyfill:check = 0;
860 LNUM	[0-9]+
861 DNUM	([0-9]*"."[0-9]+)|([0-9]+"."[0-9]*)
862 EXPONENT_DNUM	(({LNUM}|{DNUM})[eE][+-]?{LNUM})
863 HNUM	"0x"[0-9a-fA-F]+
864 LABEL	[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*
865 WHITESPACE [ \n\r\t]+
866 TABS_AND_SPACES [ \t]*
867 TOKENS [;:,.\[\]()|^&+-/*=%!~$<>?@]
868 ANY_CHAR [^]
869 NEWLINE ("\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 
1595 inline_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 
1630 inline_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 
2040 double_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 
2154 heredoc_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 
2208 nowdoc_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