7892b14d544f15eed503fb45f735fcdbbc7ac716
[m6w6/ext-psi] / src / parser.re
1 /*******************************************************************************
2 Copyright (c) 2016, Michael Wallner <mike@php.net>.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
8 * Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
18 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *******************************************************************************/
25
26 #include "php_psi_stdinc.h"
27 #include <sys/mman.h>
28 #include <assert.h>
29 #include <errno.h>
30 #include <stdarg.h>
31
32 #include "parser.h"
33
34 /*!max:re2c*/
35 #ifndef YYMAXFILL
36 # define YYMAXFILL 256
37 #endif
38
39 struct psi_parser *psi_parser_init(struct psi_parser *P, psi_error_cb error, unsigned flags)
40 {
41 if (!P) {
42 P = malloc(sizeof(*P));
43 }
44 memset(P, 0, sizeof(*P));
45
46 psi_data_ctor_with_dtors(PSI_DATA(P), error, flags);
47
48 P->preproc = psi_cpp_init(P);
49
50 psi_cpp_load_defaults(P->preproc);
51
52 return P;
53 }
54
55 struct psi_parser_input *psi_parser_open_file(struct psi_parser *P, const char *filename, bool report_errors)
56 {
57 struct stat sb;
58 FILE *fp;
59 struct psi_parser_input *fb;
60
61 if (stat(filename, &sb)) {
62 if (report_errors) {
63 P->error(PSI_DATA(P), NULL, PSI_WARNING,
64 "Could not stat '%s': %s",
65 filename, strerror(errno));
66 }
67 return NULL;
68 }
69
70 if (!(fb = malloc(sizeof(*fb) + strlen(filename) + 1 + sb.st_size + YYMAXFILL))) {
71 if (report_errors) {
72 P->error(PSI_DATA(P), NULL, PSI_WARNING,
73 "Could not allocate %zu bytes for reading '%s': %s",
74 sb.st_size + YYMAXFILL, filename, strerror(errno));
75 }
76 return NULL;
77 }
78
79 if (!(fp = fopen(filename, "r"))) {
80 free(fb);
81 if (report_errors) {
82 P->error(PSI_DATA(P), NULL, PSI_WARNING,
83 "Could not open '%s' for reading: %s",
84 filename, strerror(errno));
85 }
86 return NULL;
87 }
88
89 if (sb.st_size != fread(fb->buffer, 1, sb.st_size, fp)) {
90 free(fb);
91 fclose(fp);
92 if (report_errors) {
93 P->error(PSI_DATA(P), NULL, PSI_WARNING,
94 "Could not read %zu bytes from '%s': %s",
95 sb.st_size + YYMAXFILL, filename, strerror(errno));
96 }
97 return NULL;
98 }
99
100 memset(fb->buffer + sb.st_size, 0, YYMAXFILL);
101 fb->length = sb.st_size;
102 fb->file = &fb->buffer[sb.st_size + YYMAXFILL];
103 memcpy(fb->file, filename, strlen(filename) + 1);
104
105 return fb;
106 }
107
108 struct psi_parser_input *psi_parser_open_string(struct psi_parser *P, const char *string, size_t length)
109 {
110 struct psi_parser_input *sb;
111
112 if (!(sb = malloc(sizeof(*sb) + sizeof("<stdin>") + length + YYMAXFILL))) {
113 P->error(PSI_DATA(P), NULL, PSI_WARNING,
114 "Could not allocate %zu bytes: %s",
115 length + YYMAXFILL, strerror(errno));
116 return NULL;
117 }
118
119 memcpy(sb->buffer, string, length);
120 memset(sb->buffer + length, 0, YYMAXFILL);
121
122 sb->length = length;
123 sb->file = &sb->buffer[length + YYMAXFILL];
124 memcpy(sb->file, "<stdin>", sizeof("<stdin>"));
125
126 return sb;
127 }
128
129 #if 0
130 static void psi_parser_register_constants(struct psi_parser *P)
131 {
132 zend_string *key;
133 zval *val;
134
135 ZEND_HASH_FOREACH_STR_KEY_VAL(&P->cpp.defs, key, val)
136 {
137 struct psi_impl_def_val *iv;
138 struct psi_const_type *ct;
139 struct psi_const *c;
140 const char *ctn;
141 token_t ctt;
142 impl_val tmp;
143 zend_string *str;
144
145 ZVAL_DEREF(val);
146 switch (Z_TYPE_P(val)) {
147 case IS_TRUE:
148 case IS_FALSE:
149 ctt = PSI_T_BOOL;
150 ctn = "bool";
151 tmp.zend.bval = Z_TYPE_P(val) == IS_TRUE;
152 break;
153 case IS_LONG:
154 ctt = PSI_T_INT;
155 ctn = "int";
156 tmp.zend.lval = Z_LVAL_P(val);
157 break;
158 case IS_DOUBLE:
159 ctt = PSI_T_FLOAT;
160 ctn = "float";
161 tmp.dval = Z_DVAL_P(val);
162 break;
163 default:
164 ctt = PSI_T_STRING;
165 ctn = "string";
166 str = zval_get_string(val);
167 tmp.zend.str = zend_string_dup(str, 1);
168 zend_string_release(str);
169 break;
170 }
171
172 iv = psi_impl_def_val_init(ctt, NULL);
173 iv->ival = tmp;
174 ct = psi_const_type_init(ctt, ctn);
175 c = psi_const_init(ct, key->val, iv);
176 if (!P->consts) {
177 P->consts = psi_plist_init((psi_plist_dtor) psi_const_free);
178 }
179 P->consts = psi_plist_add(P->consts, &c);
180 }
181 ZEND_HASH_FOREACH_END();
182 }
183 #endif
184
185 struct psi_plist *psi_parser_preprocess(struct psi_parser *P, struct psi_plist **tokens)
186 {
187 if (psi_cpp_process(P->preproc, tokens)) {
188 return *tokens;
189 }
190 return NULL;
191 }
192
193 bool psi_parser_process(struct psi_parser *P, struct psi_plist *tokens, size_t *processed)
194 {
195 if (psi_plist_count(tokens)) {
196 return 0 == psi_parser_proc_parse(P, tokens, processed);
197 }
198 return true;
199 }
200
201 void psi_parser_postprocess(struct psi_parser *P)
202 {
203 unsigned flags;
204 zend_string *name;
205 struct psi_validate_scope scope = {0};
206
207 psi_validate_scope_ctor(&scope);
208 scope.defs = &P->preproc->defs;
209
210 flags = P->flags;
211 P->flags |= PSI_SILENT;
212
213 /* register const macros */
214 ZEND_HASH_FOREACH_STR_KEY_PTR(&P->preproc->defs, name, scope.macro)
215 {
216 if (scope.macro->sig) {
217 } else if (scope.macro->exp) {
218 if (psi_num_exp_validate(PSI_DATA(P), scope.macro->exp, &scope)) {
219 struct psi_impl_type *type;
220 struct psi_impl_def_val *def;
221 struct psi_const *cnst;
222 struct psi_num_exp *num;
223 char *name_str = malloc(name->len + sizeof("psi\\"));
224
225 strcat(strcpy(name_str, "psi\\"), name->val);
226 num = psi_num_exp_copy(scope.macro->exp);
227 def = psi_impl_def_val_init(PSI_T_NUMBER, num);
228 type = psi_impl_type_init(PSI_T_NUMBER, "<eval number>");
229 cnst = psi_const_init(type, name_str, def);
230 P->consts = psi_plist_add(P->consts, &cnst);
231 free(name_str);
232 }
233 } else {
234 if (psi_plist_count(scope.macro->tokens) == 1) {
235 struct psi_token *t;
236
237 if (psi_plist_get(scope.macro->tokens, 0, &t)) {
238 if (t->type == PSI_T_QUOTED_STRING) {
239 struct psi_impl_type *type;
240 struct psi_impl_def_val *def;
241 struct psi_const *cnst;
242 char *name_str = malloc(name->len + sizeof("psi\\"));
243
244 strcat(strcpy(name_str, "psi\\"), name->val);
245 type = psi_impl_type_init(PSI_T_STRING, "string");
246 def = psi_impl_def_val_init(PSI_T_QUOTED_STRING, t->text);
247 cnst = psi_const_init(type, name_str, def);
248 P->consts = psi_plist_add(P->consts, &cnst);
249 free(name_str);
250 }
251 }
252 }
253 }
254 }
255 ZEND_HASH_FOREACH_END();
256
257 P->flags = flags;
258
259 psi_validate_scope_dtor(&scope);
260 }
261
262 bool psi_parser_parse(struct psi_parser *P, struct psi_parser_input *I)
263 {
264 struct psi_plist *scanned, *preproc;
265 size_t processed = 0;
266
267 if (!(scanned = psi_parser_scan(P, I))) {
268 return false;
269 }
270
271 if (!(preproc = psi_parser_preprocess(P, &scanned))) {
272 psi_plist_free(scanned);
273 return false;
274 }
275
276 if (!psi_parser_process(P, preproc, &processed)) {
277 psi_plist_free(preproc);
278 return false;
279 }
280
281 psi_parser_postprocess(P);
282
283 psi_plist_free(preproc);
284 return true;
285 }
286
287 void psi_parser_dtor(struct psi_parser *P)
288 {
289 psi_cpp_free(&P->preproc);
290 psi_data_dtor(PSI_DATA(P));
291
292 memset(P, 0, sizeof(*P));
293 }
294
295 void psi_parser_free(struct psi_parser **P)
296 {
297 if (*P) {
298 psi_parser_dtor(*P);
299 free(*P);
300 *P = NULL;
301 }
302 }
303
304 #define NEWLINE() \
305 eol = cur; \
306 ++I->lines
307
308 #define NEWTOKEN(t) \
309 token = psi_token_init(t, tok, cur - tok, tok - eol + 1, I->lines, I->file); \
310 tokens = psi_plist_add(tokens, &token); \
311 if (P->flags & PSI_DEBUG) { \
312 fprintf(stderr, "PSI< "); \
313 psi_token_dump(2, token); \
314 }
315
316 union int_suffix {
317 char s[4];
318 uint32_t i;
319 };
320
321 struct psi_plist *psi_parser_scan(struct psi_parser *P, struct psi_parser_input *I)
322 {
323 struct psi_plist *tokens;
324 struct psi_token *token;
325 const char *tok, *cur, *lim, *mrk, *eol, *ctxmrk;
326 unsigned parens;
327 bool escaped;
328 token_t char_width;
329
330 PSI_DEBUG_PRINT(P, "PSI: scanning %s\n", I->file);
331
332 tok = mrk = eol = cur = I->buffer;
333 lim = I->buffer + I->length;
334 I->lines = 1;
335 tokens = psi_plist_init((psi_plist_dtor) psi_token_free);
336
337 start: ;
338 char_width = 1;
339 ctxmrk = NULL;
340 tok = cur;
341
342 (void) ctxmrk;
343
344 /*!re2c
345
346 re2c:indent:top = 2;
347 re2c:define:YYCTYPE = "unsigned char";
348 re2c:define:YYCURSOR = cur;
349 re2c:define:YYLIMIT = lim;
350 re2c:define:YYMARKER = mrk;
351 re2c:define:YYCTXMARKER = ctxmrk;
352 re2c:define:YYFILL = "if (cur >= lim) goto done;";
353 re2c:yyfill:parameter = 0;
354
355 W = [a-zA-Z0-9_\x80-\xff];
356 SP = [ \t\f];
357 EOL = [\r\n];
358 NAME = [a-zA-Z_\x80-\xff] W*;
359 NSNAME = (NAME)? ("\\" NAME)+;
360 DOLLAR_NAME = '$' W+;
361 CPP_HEADER = "<" [-._/a-zA-Z0-9]+ ">";
362 CPP_ATTRIBUTE = "__attribute__" SP* "((";
363
364 DEC_CONST = [1-9] [0-9]*;
365 OCT_CONST = "0" [0-7]*;
366 HEX_CONST = '0x' [0-9a-fA-F]+;
367 INT_CONST = (DEC_CONST | OCT_CONST | HEX_CONST);
368
369 FLT_HEX_CONST = HEX_CONST ("." [0-9a-fA-F]*)? 'p' [+-]? [0-9]+;
370 FLT_DEC_NUM = "0" | DEC_CONST;
371 FLT_DEC_CONST = (FLT_DEC_NUM ("." [0-9]*)? 'e' [+-]? [0-9]+) | (FLT_DEC_NUM "." [0-9]*) | ("." [0-9]+);
372 FLT_CONST = (FLT_DEC_CONST | FLT_HEX_CONST);
373
374 [+-]? INT_CONST { NEWTOKEN(PSI_T_NUMBER); token->flags = PSI_NUMBER_INT; goto start; }
375 [+-]? INT_CONST / 'u' { NEWTOKEN(PSI_T_NUMBER); token->flags = PSI_NUMBER_INT | PSI_NUMBER_U; cur += 1; goto start; }
376 [+-]? INT_CONST / 'l' { NEWTOKEN(PSI_T_NUMBER); token->flags = PSI_NUMBER_INT | PSI_NUMBER_L; cur += 1; goto start; }
377 [+-]? INT_CONST / ('lu' | 'ul') { NEWTOKEN(PSI_T_NUMBER); token->flags = PSI_NUMBER_INT | PSI_NUMBER_UL; cur += 2; goto start; }
378 [+-]? INT_CONST / ('llu' | 'ull') { NEWTOKEN(PSI_T_NUMBER); token->flags = PSI_NUMBER_INT | PSI_NUMBER_ULL; cur += 3; goto start; }
379
380 [+-]? FLT_CONST { NEWTOKEN(PSI_T_NUMBER); token->flags = PSI_NUMBER_FLT; goto start; }
381 [+-]? FLT_CONST / 'f' { NEWTOKEN(PSI_T_NUMBER); token->flags = PSI_NUMBER_FLT | PSI_NUMBER_F; cur += 1; goto start; }
382 [+-]? FLT_CONST / 'l' { NEWTOKEN(PSI_T_NUMBER); token->flags = PSI_NUMBER_FLT | PSI_NUMBER_L; cur += 1; goto start; }
383 [+-]? FLT_CONST / 'df' { NEWTOKEN(PSI_T_NUMBER); token->flags = PSI_NUMBER_FLT | PSI_NUMBER_DF; cur += 2; goto start; }
384 [+-]? FLT_CONST / 'dd' { NEWTOKEN(PSI_T_NUMBER); token->flags = PSI_NUMBER_FLT | PSI_NUMBER_DD; cur += 2; goto start; }
385 [+-]? FLT_CONST / 'dl' { NEWTOKEN(PSI_T_NUMBER); token->flags = PSI_NUMBER_FLT | PSI_NUMBER_DL; cur += 2; goto start; }
386
387 "'" { escaped = false; tok += 1; goto character; }
388 "\"" { escaped = false; tok += 1; goto string; }
389 "u8" / "\"" { char_width = 1; }
390 "u" / ['"] { char_width = 2; }
391 "U" / ['"] { char_width = 4; }
392 "L" / ['"] { char_width = sizeof(wchar_t)/8; }
393
394 "/*" { goto comment; }
395 "//" { goto comment_sl; }
396
397 "##" { NEWTOKEN(PSI_T_CPP_PASTE); goto start; }
398 "#" { NEWTOKEN(PSI_T_HASH); goto start; }
399 "(" { NEWTOKEN(PSI_T_LPAREN); goto start; }
400 ")" { NEWTOKEN(PSI_T_RPAREN); goto start; }
401 ";" { NEWTOKEN(PSI_T_EOS); goto start; }
402 "," { NEWTOKEN(PSI_T_COMMA); goto start; }
403 ":" { NEWTOKEN(PSI_T_COLON); goto start; }
404 "{" { NEWTOKEN(PSI_T_LBRACE); goto start; }
405 "}" { NEWTOKEN(PSI_T_RBRACE); goto start; }
406 "[" { NEWTOKEN(PSI_T_LBRACKET); goto start; }
407 "]" { NEWTOKEN(PSI_T_RBRACKET); goto start; }
408 "!=" { NEWTOKEN(PSI_T_CMP_NE); goto start; }
409 "==" { NEWTOKEN(PSI_T_CMP_EQ); goto start; }
410 "&&" { NEWTOKEN(PSI_T_AND); goto start; }
411 "||" { NEWTOKEN(PSI_T_OR); goto start; }
412 "=" { NEWTOKEN(PSI_T_EQUALS); goto start; }
413 "*" { NEWTOKEN(PSI_T_ASTERISK); goto start; }
414 "~" { NEWTOKEN(PSI_T_TILDE); goto start; }
415 "!" { NEWTOKEN(PSI_T_NOT); goto start; }
416 "%" { NEWTOKEN(PSI_T_MODULO); goto start; }
417 "&" { NEWTOKEN(PSI_T_AMPERSAND); goto start; }
418 "+" { NEWTOKEN(PSI_T_PLUS); goto start; }
419 "-" { NEWTOKEN(PSI_T_MINUS); goto start; }
420 "/" { NEWTOKEN(PSI_T_SLASH); goto start; }
421 "\\" { NEWTOKEN(PSI_T_BSLASH); goto start; }
422 "|" { NEWTOKEN(PSI_T_PIPE); goto start; }
423 "^" { NEWTOKEN(PSI_T_CARET); goto start; }
424 "<<" { NEWTOKEN(PSI_T_LSHIFT); goto start; }
425 ">>" { NEWTOKEN(PSI_T_RSHIFT); goto start; }
426 "<=" { NEWTOKEN(PSI_T_CMP_LE); goto start; }
427 ">=" { NEWTOKEN(PSI_T_CMP_GE); goto start; }
428 "<" { NEWTOKEN(PSI_T_LCHEVR); goto start; }
429 ">" { NEWTOKEN(PSI_T_RCHEVR); goto start; }
430 "." { NEWTOKEN(PSI_T_PERIOD); goto start; }
431 "..." { NEWTOKEN(PSI_T_ELLIPSIS); goto start; }
432 "?" { NEWTOKEN(PSI_T_IIF); goto start; }
433 "pragma" { NEWTOKEN(PSI_T_PRAGMA); goto start; }
434 "pragma" W+ "once" { NEWTOKEN(PSI_T_PRAGMA_ONCE); goto start; }
435 "__inline" { NEWTOKEN(PSI_T_CPP_INLINE); goto start; }
436 "__restrict" { NEWTOKEN(PSI_T_CPP_RESTRICT); goto start; }
437 "__extension__" { NEWTOKEN(PSI_T_CPP_EXTENSION); goto start; }
438 "__asm__" { NEWTOKEN(PSI_T_CPP_ASM); goto start; }
439 "volatile" { NEWTOKEN(PSI_T_VOLATILE); goto start; }
440 "sizeof" { NEWTOKEN(PSI_T_SIZEOF); goto start; }
441 "line" { NEWTOKEN(PSI_T_LINE); goto start; }
442 "typedef" { NEWTOKEN(PSI_T_TYPEDEF); goto start; }
443 "struct" { NEWTOKEN(PSI_T_STRUCT); goto start; }
444 "union" { NEWTOKEN(PSI_T_UNION); goto start; }
445 "enum" { NEWTOKEN(PSI_T_ENUM); goto start; }
446 "const" { NEWTOKEN(PSI_T_CONST); goto start; }
447 "void" { NEWTOKEN(PSI_T_VOID); goto start; }
448 "bool" { NEWTOKEN(PSI_T_BOOL); goto start; }
449 "char" { NEWTOKEN(PSI_T_CHAR); goto start; }
450 "short" { NEWTOKEN(PSI_T_SHORT); goto start; }
451 "int" { NEWTOKEN(PSI_T_INT); goto start; }
452 "long" { NEWTOKEN(PSI_T_LONG); goto start; }
453 "float" { NEWTOKEN(PSI_T_FLOAT); goto start; }
454 "double" { NEWTOKEN(PSI_T_DOUBLE); goto start; }
455 "unsigned" { NEWTOKEN(PSI_T_UNSIGNED); goto start; }
456 "signed" { NEWTOKEN(PSI_T_SIGNED); goto start; }
457 'IF' { NEWTOKEN(PSI_T_IF); goto start; }
458 'IFDEF' { NEWTOKEN(PSI_T_IFDEF); goto start; }
459 'IFNDEF' { NEWTOKEN(PSI_T_IFNDEF); goto start; }
460 'ELSE' { NEWTOKEN(PSI_T_ELSE); goto start; }
461 'ELIF' { NEWTOKEN(PSI_T_ELIF); goto start; }
462 'ENDIF' { NEWTOKEN(PSI_T_ENDIF); goto start; }
463 'DEFINE' { NEWTOKEN(PSI_T_DEFINE); goto start; }
464 'DEFINED' { NEWTOKEN(PSI_T_DEFINED); goto start; }
465 'UNDEF' { NEWTOKEN(PSI_T_UNDEF); goto start; }
466 'WARNING' { NEWTOKEN(PSI_T_WARNING); goto start; }
467 'ERROR' { NEWTOKEN(PSI_T_ERROR); goto start; }
468 'INCLUDE' { NEWTOKEN(PSI_T_INCLUDE); goto start; }
469 'INCLUDE_NEXT' { NEWTOKEN(PSI_T_INCLUDE_NEXT); goto start; }
470 'TRUE' { NEWTOKEN(PSI_T_TRUE); goto start; }
471 'FALSE' { NEWTOKEN(PSI_T_FALSE); goto start; }
472 'NULL' { NEWTOKEN(PSI_T_NULL); goto start; }
473 'MIXED' { NEWTOKEN(PSI_T_MIXED); goto start; }
474 'CALLABLE' { NEWTOKEN(PSI_T_CALLABLE); goto start; }
475 'STRING' { NEWTOKEN(PSI_T_STRING); goto start; }
476 'ARRAY' { NEWTOKEN(PSI_T_ARRAY); goto start; }
477 'OBJECT' { NEWTOKEN(PSI_T_OBJECT); goto start; }
478 'CALLBACK' { NEWTOKEN(PSI_T_CALLBACK); goto start; }
479 'STATIC' { NEWTOKEN(PSI_T_STATIC); goto start; }
480 'FUNCTION' { NEWTOKEN(PSI_T_FUNCTION); goto start; }
481 'LIB' { NEWTOKEN(PSI_T_LIB); goto start; }
482 'LET' { NEWTOKEN(PSI_T_LET); goto start; }
483 'SET' { NEWTOKEN(PSI_T_SET); goto start; }
484 'PRE_ASSERT' { NEWTOKEN(PSI_T_PRE_ASSERT); goto start; }
485 'POST_ASSERT' { NEWTOKEN(PSI_T_POST_ASSERT); goto start; }
486 'RETURN' { NEWTOKEN(PSI_T_RETURN); goto start; }
487 'AS' { NEWTOKEN(PSI_T_AS); goto start; }
488 'FREE' { NEWTOKEN(PSI_T_FREE); goto start; }
489 'TEMP' { NEWTOKEN(PSI_T_TEMP); goto start; }
490 'STRLEN' { NEWTOKEN(PSI_T_STRLEN); goto start; }
491 'STRVAL' { NEWTOKEN(PSI_T_STRVAL); goto start; }
492 'PATHVAL' { NEWTOKEN(PSI_T_PATHVAL); goto start; }
493 'INTVAL' { NEWTOKEN(PSI_T_INTVAL); goto start; }
494 'FLOATVAL' { NEWTOKEN(PSI_T_FLOATVAL); goto start; }
495 'BOOLVAL' { NEWTOKEN(PSI_T_BOOLVAL); goto start; }
496 'ARRVAL' { NEWTOKEN(PSI_T_ARRVAL); goto start; }
497 'OBJVAL' { NEWTOKEN(PSI_T_OBJVAL); goto start; }
498 'ZVAL' { NEWTOKEN(PSI_T_ZVAL); goto start; }
499 'COUNT' { NEWTOKEN(PSI_T_COUNT); goto start; }
500 'CALLOC' { NEWTOKEN(PSI_T_CALLOC); goto start; }
501 'TO_OBJECT' { NEWTOKEN(PSI_T_TO_OBJECT); goto start; }
502 'TO_ARRAY' { NEWTOKEN(PSI_T_TO_ARRAY); goto start; }
503 'TO_STRING' { NEWTOKEN(PSI_T_TO_STRING); goto start; }
504 'TO_INT' { NEWTOKEN(PSI_T_TO_INT); goto start; }
505 'TO_FLOAT' { NEWTOKEN(PSI_T_TO_FLOAT); goto start; }
506 'TO_BOOL' { NEWTOKEN(PSI_T_TO_BOOL); goto start; }
507 NAME { NEWTOKEN(PSI_T_NAME); goto start; }
508 NSNAME { NEWTOKEN(PSI_T_NSNAME); goto start; }
509 DOLLAR_NAME { NEWTOKEN(PSI_T_DOLLAR_NAME); goto start; }
510 CPP_HEADER { tok += 1; cur -= 1; NEWTOKEN(PSI_T_CPP_HEADER); cur += 1; goto start; }
511 CPP_ATTRIBUTE { parens = 2; goto cpp_attribute; }
512 EOL { NEWTOKEN(PSI_T_EOL); NEWLINE(); goto start; }
513 SP+ { NEWTOKEN(PSI_T_WHITESPACE); goto start; }
514 [^] { NEWTOKEN(-2); goto error; }
515 * { NEWTOKEN(-1); goto error; }
516
517 */
518
519 character: ;
520 /*!re2c
521
522 EOL { NEWLINE(); goto character; }
523 "\\" { escaped = !escaped; goto character; }
524 "'" {
525 if (escaped) {
526 escaped = false;
527 goto character;
528 }
529 cur -= 1;
530 NEWTOKEN(PSI_T_QUOTED_CHAR);
531 cur += 1;
532 token->flags = char_width;
533 goto start;
534 }
535 * { escaped = false; goto character; }
536
537 */
538
539 string: ;
540 /*!re2c
541
542 EOL { NEWLINE(); goto string; }
543 "\\" { escaped = !escaped; goto string; }
544 "\"" {
545 if (escaped) {
546 escaped = false;
547 goto string;
548 }
549 cur -= 1;
550 NEWTOKEN(PSI_T_QUOTED_STRING);
551 cur += 1;
552 token->flags = char_width;
553 goto start;
554 }
555 * { escaped = false; goto string; }
556
557 */
558
559 comment: ;
560 /*!re2c
561
562 EOL { NEWLINE(); goto comment; }
563 "*" "/" { NEWTOKEN(PSI_T_COMMENT); goto start; }
564 * { goto comment; }
565
566 */
567
568 comment_sl: ;
569 /*!re2c
570
571 EOL { NEWTOKEN(PSI_T_COMMENT); NEWLINE(); goto start; }
572 * { goto comment_sl; }
573
574 */
575
576 cpp_attribute: ;
577
578 /*!re2c
579
580 "(" { ++parens; goto cpp_attribute; }
581 ")" { if (parens == 1) { NEWTOKEN(PSI_T_CPP_ATTRIBUTE); goto start; } else { --parens; goto cpp_attribute; } }
582 EOL { NEWLINE(); goto cpp_attribute; }
583 * { goto cpp_attribute; }
584
585 */
586 error: ;
587
588 P->error(PSI_DATA(P), token, PSI_WARNING, "PSI syntax error: unexpected input (%d) '%.*s' at col %tu",
589 token->type, token->size, token->text, tok - eol + 1);
590 psi_plist_free(tokens);
591 return NULL;
592
593 done:
594
595 PSI_DEBUG_PRINT(P, "PSI: EOF cur=%p lim=%p\n", cur, lim);
596
597 return tokens;
598 }