1 %top{ 2 /*------------------------------------------------------------------------- 3 * 4 * pgc.l 5 * lexical scanner for ecpg 6 * 7 * This is a modified version of src/backend/parser/scan.l 8 * 9 * The ecpg scanner is not backup-free, so the fail rules are 10 * only here to simplify syncing this file with scan.l. 11 * 12 * 13 * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group 14 * Portions Copyright (c) 1994, Regents of the University of California 15 * 16 * IDENTIFICATION 17 * src/interfaces/ecpg/preproc/pgc.l 18 * 19 *------------------------------------------------------------------------- 20 */ 21 #include "postgres_fe.h" 22 23 #include <ctype.h> 24 #include <limits.h> 25 26 #include "common/string.h" 27 28 #include "preproc_extern.h" 29 #include "preproc.h" 30 } 31 32 %{ 33 34 /* LCOV_EXCL_START */ 35 36 extern YYSTYPE base_yylval; 37 38 static int xcdepth = 0; /* depth of nesting in slash-star comments */ 39 static char *dolqstart = NULL; /* current $foo$ quote start string */ 40 41 /* 42 * literalbuf is used to accumulate literal values when multiple rules 43 * are needed to parse a single literal. Call startlit to reset buffer 44 * to empty, addlit to add text. Note that the buffer is permanently 45 * malloc'd to the largest size needed so far in the current run. 46 */ 47 static char *literalbuf = NULL; /* expandable buffer */ 48 static int literallen; /* actual current length */ 49 static int literalalloc; /* current allocated buffer size */ 50 51 /* Used for detecting global state together with braces_open */ 52 static int parenths_open; 53 54 /* Used to tell parse_include() whether the command was #include or #include_next */ 55 static bool include_next; 56 57 #define startlit() (literalbuf[0] = '\0', literallen = 0) 58 static void addlit(char *ytext, int yleng); 59 static void addlitchar(unsigned char); 60 static int process_integer_literal(const char *token, YYSTYPE *lval); 61 static void parse_include(void); 62 static bool ecpg_isspace(char ch); 63 static bool isdefine(void); 64 static bool isinformixdefine(void); 65 66 char *token_start; 67 68 /* vars to keep track of start conditions when scanning literals */ 69 static int state_before_str_start; 70 static int state_before_str_stop; 71 72 struct _yy_buffer 73 { 74 YY_BUFFER_STATE buffer; 75 long lineno; 76 char *filename; 77 struct _yy_buffer *next; 78 } *yy_buffer = NULL; 79 80 static char *old; 81 82 /* 83 * Vars for handling ifdef/elif/endif constructs. preproc_tos is the current 84 * nesting depth of such constructs, and stacked_if_value[preproc_tos] is the 85 * state for the innermost level. (For convenience, stacked_if_value[0] is 86 * initialized as though we are in the active branch of some outermost IF.) 87 * The active field is true if the current branch is active (being expanded). 88 * The saw_active field is true if we have found any successful branch, 89 * so that all subsequent branches of this level should be skipped. 90 * The else_branch field is true if we've found an 'else' (so that another 91 * 'else' or 'elif' at this level is an error.) 92 * For IFs nested within an inactive branch, all branches always have active 93 * set to false, but saw_active and else_branch are maintained normally. 94 * ifcond is valid only while evaluating an if-condition; it's true if we 95 * are doing ifdef, false if ifndef. 96 */ 97 #define MAX_NESTED_IF 128 98 static short preproc_tos; 99 static bool ifcond; 100 static struct _if_value 101 { 102 bool active; 103 bool saw_active; 104 bool else_branch; 105 } stacked_if_value[MAX_NESTED_IF]; 106 107 %} 108 109 %option 8bit 110 %option never-interactive 111 %option nodefault 112 %option noinput 113 %option noyywrap 114 %option warn 115 %option yylineno 116 %option prefix="base_yy" 117 118 /* 119 * OK, here is a short description of lex/flex rules behavior. 120 * The longest pattern which matches an input string is always chosen. 121 * For equal-length patterns, the first occurring in the rules list is chosen. 122 * INITIAL is the starting state, to which all non-conditional rules apply. 123 * Exclusive states change parsing rules while the state is active. When in 124 * an exclusive state, only those rules defined for that state apply. 125 * 126 * We use exclusive states for quoted strings, extended comments, 127 * and to eliminate parsing troubles for numeric strings. 128 * Exclusive states: 129 * <xb> bit string literal 130 * <xc> extended C-style comments 131 * <xd> delimited identifiers (double-quoted identifiers) 132 * <xdc> double-quoted strings in C 133 * <xh> hexadecimal numeric string 134 * <xn> national character quoted strings 135 * <xq> standard quoted strings 136 * <xqs> quote stop (detect continued strings) 137 * <xe> extended quoted strings (support backslash escape sequences) 138 * <xqc> single-quoted strings in C 139 * <xdolq> $foo$ quoted strings 140 * <xui> quoted identifier with Unicode escapes 141 * <xus> quoted string with Unicode escapes 142 * <xcond> condition of an EXEC SQL IFDEF construct 143 * <xskip> skipping the inactive part of an EXEC SQL IFDEF construct 144 * 145 * Note: we intentionally don't mimic the backend's <xeu> state; we have 146 * no need to distinguish it from <xe> state. 147 * 148 * Remember to add an <<EOF>> case whenever you add a new exclusive state! 149 * The default one is probably not the right thing. 150 */ 151 152 %x xb 153 %x xc 154 %x xd 155 %x xdc 156 %x xh 157 %x xn 158 %x xq 159 %x xqs 160 %x xe 161 %x xqc 162 %x xdolq 163 %x xui 164 %x xus 165 %x xcond 166 %x xskip 167 168 /* Additional exclusive states that are specific to ECPG */ 169 %x C SQL incl def def_ident undef 170 171 /* 172 * In order to make the world safe for Windows and Mac clients as well as 173 * Unix ones, we accept either \n or \r as a newline. A DOS-style \r\n 174 * sequence will be seen as two successive newlines, but that doesn't cause 175 * any problems. SQL-style comments, which start with -- and extend to the 176 * next newline, are treated as equivalent to a single whitespace character. 177 * 178 * NOTE a fine point: if there is no newline following --, we will absorb 179 * everything to the end of the input as a comment. This is correct. Older 180 * versions of Postgres failed to recognize -- as a comment if the input 181 * did not end with a newline. 182 * 183 * XXX perhaps \f (formfeed) should be treated as a newline as well? 184 * 185 * XXX if you change the set of whitespace characters, fix ecpg_isspace() 186 * to agree. 187 */ 188 189 space [ \t\n\r\f] 190 horiz_space [ \t\f] 191 newline [\n\r] 192 non_newline [^\n\r] 193 194 comment ("--"{non_newline}*) 195 196 whitespace ({space}+|{comment}) 197 198 /* 199 * SQL requires at least one newline in the whitespace separating 200 * string literals that are to be concatenated. Silly, but who are we 201 * to argue? Note that {whitespace_with_newline} should not have * after 202 * it, whereas {whitespace} should generally have a * after it... 203 */ 204 205 horiz_whitespace ({horiz_space}|{comment}) 206 whitespace_with_newline ({horiz_whitespace}*{newline}{whitespace}*) 207 208 quote ' 209 /* If we see {quote} then {quotecontinue}, the quoted string continues */ 210 quotecontinue {whitespace_with_newline}{quote} 211 212 /* 213 * {quotecontinuefail} is needed to avoid lexer backup when we fail to match 214 * {quotecontinue}. It might seem that this could just be {whitespace}*, 215 * but if there's a dash after {whitespace_with_newline}, it must be consumed 216 * to see if there's another dash --- which would start a {comment} and thus 217 * allow continuation of the {quotecontinue} token. 218 */ 219 quotecontinuefail {whitespace}*"-"? 220 221 /* Bit string 222 */ 223 xbstart [bB]{quote} 224 xbinside [^']* 225 226 /* Hexadecimal number */ 227 xhstart [xX]{quote} 228 xhinside [^']* 229 230 /* National character */ 231 xnstart [nN]{quote} 232 233 /* Quoted string that allows backslash escapes */ 234 xestart [eE]{quote} 235 xeinside [^\\']+ 236 xeescape [\\][^0-7] 237 xeoctesc [\\][0-7]{1,3} 238 xehexesc [\\]x[0-9A-Fa-f]{1,2} 239 xeunicode [\\](u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8}) 240 241 /* Extended quote 242 * xqdouble implements embedded quote, '''' 243 */ 244 xqstart {quote} 245 xqdouble {quote}{quote} 246 xqcquote [\\]{quote} 247 xqinside [^']+ 248 249 /* $foo$ style quotes ("dollar quoting") 250 * The quoted string starts with $foo$ where "foo" is an optional string 251 * in the form of an identifier, except that it may not contain "$", 252 * and extends to the first occurrence of an identical string. 253 * There is *no* processing of the quoted text. 254 * 255 * {dolqfailed} is an error rule to avoid scanner backup when {dolqdelim} 256 * fails to match its trailing "$". 257 */ 258 dolq_start [A-Za-z\200-\377_] 259 dolq_cont [A-Za-z\200-\377_0-9] 260 dolqdelim \$({dolq_start}{dolq_cont}*)?\$ 261 dolqfailed \${dolq_start}{dolq_cont}* 262 dolqinside [^$]+ 263 264 /* Double quote 265 * Allows embedded spaces and other special characters into identifiers. 266 */ 267 dquote \" 268 xdstart {dquote} 269 xdstop {dquote} 270 xddouble {dquote}{dquote} 271 xdinside [^"]+ 272 273 /* Quoted identifier with Unicode escapes */ 274 xuistart [uU]&{dquote} 275 276 /* Quoted string with Unicode escapes */ 277 xusstart [uU]&{quote} 278 279 /* special stuff for C strings */ 280 xdcqq \\\\ 281 xdcqdq \\\" 282 xdcother [^"] 283 xdcinside ({xdcqq}|{xdcqdq}|{xdcother}) 284 285 286 /* C-style comments 287 * 288 * The "extended comment" syntax closely resembles allowable operator syntax. 289 * The tricky part here is to get lex to recognize a string starting with 290 * slash-star as a comment, when interpreting it as an operator would produce 291 * a longer match --- remember lex will prefer a longer match! Also, if we 292 * have something like plus-slash-star, lex will think this is a 3-character 293 * operator whereas we want to see it as a + operator and a comment start. 294 * The solution is two-fold: 295 * 1. append {op_chars}* to xcstart so that it matches as much text as 296 * {operator} would. Then the tie-breaker (first matching rule of same 297 * length) ensures xcstart wins. We put back the extra stuff with yyless() 298 * in case it contains a star-slash that should terminate the comment. 299 * 2. In the operator rule, check for slash-star within the operator, and 300 * if found throw it back with yyless(). This handles the plus-slash-star 301 * problem. 302 * Dash-dash comments have similar interactions with the operator rule. 303 */ 304 xcstart \/\*{op_chars}* 305 xcstop \*+\/ 306 xcinside [^*/]+ 307 308 digit [0-9] 309 ident_start [A-Za-z\200-\377_] 310 ident_cont [A-Za-z\200-\377_0-9\$] 311 312 identifier {ident_start}{ident_cont}* 313 314 array ({ident_cont}|{whitespace}|[\[\]\+\-\*\%\/\(\)\>\.])* 315 316 /* Assorted special-case operators and operator-like tokens */ 317 typecast "::" 318 dot_dot \.\. 319 colon_equals ":=" 320 321 /* 322 * These operator-like tokens (unlike the above ones) also match the {operator} 323 * rule, which means that they might be overridden by a longer match if they 324 * are followed by a comment start or a + or - character. Accordingly, if you 325 * add to this list, you must also add corresponding code to the {operator} 326 * block to return the correct token in such cases. (This is not needed in 327 * psqlscan.l since the token value is ignored there.) 328 */ 329 equals_greater "=>" 330 less_equals "<=" 331 greater_equals ">=" 332 less_greater "<>" 333 not_equals "!=" 334 335 /* 336 * "self" is the set of chars that should be returned as single-character 337 * tokens. "op_chars" is the set of chars that can make up "Op" tokens, 338 * which can be one or more characters long (but if a single-char token 339 * appears in the "self" set, it is not to be returned as an Op). Note 340 * that the sets overlap, but each has some chars that are not in the other. 341 * 342 * If you change either set, adjust the character lists appearing in the 343 * rule for "operator"! 344 */ 345 self [,()\[\].;\:\+\-\*\/\%\^\<\>\=] 346 op_chars [\~\!\@\#\^\&\|\`\?\+\-\*\/\%\<\>\=] 347 operator {op_chars}+ 348 349 /* we no longer allow unary minus in numbers. 350 * instead we pass it separately to parser. there it gets 351 * coerced via doNegate() -- Leon aug 20 1999 352 * 353 * {decimalfail} is used because we would like "1..10" to lex as 1, dot_dot, 10. 354 * 355 * {realfail1} and {realfail2} are added to prevent the need for scanner 356 * backup when the {real} rule fails to match completely. 357 */ 358 359 integer {digit}+ 360 decimal (({digit}*\.{digit}+)|({digit}+\.{digit}*)) 361 decimalfail {digit}+\.\. 362 real ({integer}|{decimal})[Ee][-+]?{digit}+ 363 realfail1 ({integer}|{decimal})[Ee] 364 realfail2 ({integer}|{decimal})[Ee][-+] 365 366 param \${integer} 367 368 /* special characters for other dbms */ 369 /* we have to react differently in compat mode */ 370 informix_special [\$] 371 372 other . 373 374 /* 375 * Dollar quoted strings are totally opaque, and no escaping is done on them. 376 * Other quoted strings must allow some special characters such as single-quote 377 * and newline. 378 * Embedded single-quotes are implemented both in the SQL standard 379 * style of two adjacent single quotes "''" and in the Postgres/Java style 380 * of escaped-quote "\'". 381 * Other embedded escaped characters are matched explicitly and the leading 382 * backslash is dropped from the string. 383 * Note that xcstart must appear before operator, as explained above! 384 * Also whitespace (comment) must appear before operator. 385 */ 386 387 /* some stuff needed for ecpg */ 388 exec [eE][xX][eE][cC] 389 sql [sS][qQ][lL] 390 define [dD][eE][fF][iI][nN][eE] 391 include [iI][nN][cC][lL][uU][dD][eE] 392 include_next [iI][nN][cC][lL][uU][dD][eE]_[nN][eE][xX][tT] 393 import [iI][mM][pP][oO][rR][tT] 394 undef [uU][nN][dD][eE][fF] 395 396 /* C version of hex number */ 397 xch 0[xX][0-9A-Fa-f]* 398 399 ccomment "//".*\n 400 401 if [iI][fF] 402 ifdef [iI][fF][dD][eE][fF] 403 ifndef [iI][fF][nN][dD][eE][fF] 404 else [eE][lL][sS][eE] 405 elif [eE][lL][iI][fF] 406 endif [eE][nN][dD][iI][fF] 407 408 struct [sS][tT][rR][uU][cC][tT] 409 410 exec_sql {exec}{space}*{sql}{space}* 411 ipdigit ({digit}|{digit}{digit}|{digit}{digit}{digit}) 412 ip {ipdigit}\.{ipdigit}\.{ipdigit}\.{ipdigit} 413 414 /* we might want to parse all cpp include files */ 415 cppinclude {space}*#{include}{space}* 416 cppinclude_next {space}*#{include_next}{space}* 417 418 /* take care of cpp lines, they may also be continued */ 419 /* first a general line for all commands not starting with "i" */ 420 /* and then the other commands starting with "i", we have to add these 421 * separately because the cppline production would match on "include" too 422 */ 423 cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+\/)|.|\\{space}*{newline})*{newline} 424 425 %% 426 427 %{ 428 /* code to execute during start of each call of yylex() */ 429 token_start = NULL; 430 %} 431 432 <SQL>{ 433 {whitespace} { 434 /* ignore */ 435 } 436 } /* <SQL> */ 437 438 <C,SQL>{ 439 {xcstart} { 440 token_start = yytext; 441 state_before_str_start = YYSTATE; 442 xcdepth = 0; 443 BEGIN(xc); 444 /* Put back any characters past slash-star; see above */ 445 yyless(2); 446 fputs("/*", yyout); 447 } 448 } /* <C,SQL> */ 449 450 <xc>{ 451 {xcstart} { 452 if (state_before_str_start == SQL) 453 { 454 xcdepth++; 455 /* Put back any characters past slash-star; see above */ 456 yyless(2); 457 fputs("/_*", yyout); 458 } 459 else if (state_before_str_start == C) 460 { 461 ECHO; 462 } 463 } 464 465 {xcstop} { 466 if (state_before_str_start == SQL) 467 { 468 if (xcdepth <= 0) 469 { 470 ECHO; 471 BEGIN(SQL); 472 token_start = NULL; 473 } 474 else 475 { 476 xcdepth--; 477 fputs("*_/", yyout); 478 } 479 } 480 else if (state_before_str_start == C) 481 { 482 ECHO; 483 BEGIN(C); 484 token_start = NULL; 485 } 486 } 487 488 {xcinside} { 489 ECHO; 490 } 491 492 {op_chars} { 493 ECHO; 494 } 495 496 \*+ { 497 ECHO; 498 } 499 500 <<EOF>> { 501 mmfatal(PARSE_ERROR, "unterminated /* comment"); 502 } 503 } /* <xc> */ 504 505 <SQL>{ 506 {xbstart} { 507 token_start = yytext; 508 state_before_str_start = YYSTATE; 509 BEGIN(xb); 510 startlit(); 511 } 512 } /* <SQL> */ 513 514 <xh>{xhinside} | 515 <xb>{xbinside} { 516 addlit(yytext, yyleng); 517 } 518 <xb><<EOF>> { mmfatal(PARSE_ERROR, "unterminated bit string literal"); } 519 520 <SQL>{xhstart} { 521 token_start = yytext; 522 state_before_str_start = YYSTATE; 523 BEGIN(xh); 524 startlit(); 525 } 526 <xh><<EOF>> { mmfatal(PARSE_ERROR, "unterminated hexadecimal string literal"); } 527 528 <C>{xqstart} { 529 token_start = yytext; 530 state_before_str_start = YYSTATE; 531 BEGIN(xqc); 532 startlit(); 533 } 534 535 <SQL>{ 536 {xnstart} { 537 /* National character. 538 * Transfer it as-is to the backend. 539 */ 540 token_start = yytext; 541 state_before_str_start = YYSTATE; 542 BEGIN(xn); 543 startlit(); 544 } 545 546 {xqstart} { 547 token_start = yytext; 548 state_before_str_start = YYSTATE; 549 BEGIN(xq); 550 startlit(); 551 } 552 {xestart} { 553 token_start = yytext; 554 state_before_str_start = YYSTATE; 555 BEGIN(xe); 556 startlit(); 557 } 558 {xusstart} { 559 token_start = yytext; 560 state_before_str_start = YYSTATE; 561 BEGIN(xus); 562 startlit(); 563 } 564 } /* <SQL> */ 565 566 <xb,xh,xq,xqc,xe,xn,xus>{quote} { 567 /* 568 * When we are scanning a quoted string and see an end 569 * quote, we must look ahead for a possible continuation. 570 * If we don't see one, we know the end quote was in fact 571 * the end of the string. To reduce the lexer table size, 572 * we use a single "xqs" state to do the lookahead for all 573 * types of strings. 574 */ 575 state_before_str_stop = YYSTATE; 576 BEGIN(xqs); 577 } 578 <xqs>{quotecontinue} { 579 /* 580 * Found a quote continuation, so return to the in-quote 581 * state and continue scanning the literal. Nothing is 582 * added to the literal's contents. 583 */ 584 BEGIN(state_before_str_stop); 585 } 586 <xqs>{quotecontinuefail} | 587 <xqs>{other} | 588 <xqs><<EOF>> { 589 /* 590 * Failed to see a quote continuation. Throw back 591 * everything after the end quote, and handle the string 592 * according to the state we were in previously. 593 */ 594 yyless(0); 595 BEGIN(state_before_str_start); 596 597 switch (state_before_str_stop) 598 { 599 case xb: 600 if (literalbuf[strspn(literalbuf, "01")] != '\0') 601 mmerror(PARSE_ERROR, ET_ERROR, "invalid bit string literal"); 602 base_yylval.str = psprintf("b'%s'", literalbuf); 603 return BCONST; 604 case xh: 605 if (literalbuf[strspn(literalbuf, "0123456789abcdefABCDEF")] != '\0') 606 mmerror(PARSE_ERROR, ET_ERROR, "invalid hex string literal"); 607 base_yylval.str = psprintf("x'%s'", literalbuf); 608 return XCONST; 609 case xq: 610 /* fallthrough */ 611 case xqc: 612 base_yylval.str = psprintf("'%s'", literalbuf); 613 return SCONST; 614 case xe: 615 base_yylval.str = psprintf("E'%s'", literalbuf); 616 return SCONST; 617 case xn: 618 base_yylval.str = psprintf("N'%s'", literalbuf); 619 return SCONST; 620 case xus: 621 base_yylval.str = psprintf("U&'%s'", literalbuf); 622 return USCONST; 623 default: 624 mmfatal(PARSE_ERROR, "unhandled previous state in xqs\n"); 625 } 626 } 627 628 <xq,xe,xn,xus>{xqdouble} { addlit(yytext, yyleng); } 629 <xqc>{xqcquote} { addlit(yytext, yyleng); } 630 <xq,xqc,xn,xus>{xqinside} { addlit(yytext, yyleng); } 631 <xe>{xeinside} { 632 addlit(yytext, yyleng); 633 } 634 <xe>{xeunicode} { 635 addlit(yytext, yyleng); 636 } 637 <xe>{xeescape} { 638 addlit(yytext, yyleng); 639 } 640 <xe>{xeoctesc} { 641 addlit(yytext, yyleng); 642 } 643 <xe>{xehexesc} { 644 addlit(yytext, yyleng); 645 } 646 <xe>. { 647 /* This is only needed for \ just before EOF */ 648 addlitchar(yytext[0]); 649 } 650 <xq,xqc,xe,xn,xus><<EOF>> { mmfatal(PARSE_ERROR, "unterminated quoted string"); } 651 652 <SQL>{ 653 {dolqdelim} { 654 token_start = yytext; 655 if (dolqstart) 656 free(dolqstart); 657 dolqstart = mm_strdup(yytext); 658 BEGIN(xdolq); 659 startlit(); 660 addlit(yytext, yyleng); 661 } 662 {dolqfailed} { 663 /* throw back all but the initial "$" */ 664 yyless(1); 665 /* and treat it as {other} */ 666 return yytext[0]; 667 } 668 } /* <SQL> */ 669 670 <xdolq>{dolqdelim} { 671 if (strcmp(yytext, dolqstart) == 0) 672 { 673 addlit(yytext, yyleng); 674 free(dolqstart); 675 dolqstart = NULL; 676 BEGIN(SQL); 677 base_yylval.str = mm_strdup(literalbuf); 678 return SCONST; 679 } 680 else 681 { 682 /* 683 * When we fail to match $...$ to dolqstart, transfer 684 * the $... part to the output, but put back the final 685 * $ for rescanning. Consider $delim$...$junk$delim$ 686 */ 687 addlit(yytext, yyleng - 1); 688 yyless(yyleng - 1); 689 } 690 } 691 <xdolq>{dolqinside} { 692 addlit(yytext, yyleng); 693 } 694 <xdolq>{dolqfailed} { 695 addlit(yytext, yyleng); 696 } 697 <xdolq>. { 698 /* single quote or dollar sign */ 699 addlitchar(yytext[0]); 700 } 701 <xdolq><<EOF>> { mmfatal(PARSE_ERROR, "unterminated dollar-quoted string"); } 702 703 <SQL>{ 704 {xdstart} { 705 state_before_str_start = YYSTATE; 706 BEGIN(xd); 707 startlit(); 708 } 709 {xuistart} { 710 state_before_str_start = YYSTATE; 711 BEGIN(xui); 712 startlit(); 713 } 714 } /* <SQL> */ 715 716 <xd>{xdstop} { 717 BEGIN(state_before_str_start); 718 if (literallen == 0) 719 mmerror(PARSE_ERROR, ET_ERROR, "zero-length delimited identifier"); 720 /* 721 * The server will truncate the identifier here. We do 722 * not, as (1) it does not change the result; (2) we don't 723 * know what NAMEDATALEN the server might use; (3) this 724 * code path is also taken for literal query strings in 725 * PREPARE and EXECUTE IMMEDIATE, which can certainly be 726 * longer than NAMEDATALEN. 727 */ 728 base_yylval.str = mm_strdup(literalbuf); 729 return CSTRING; 730 } 731 <xdc>{xdstop} { 732 BEGIN(state_before_str_start); 733 base_yylval.str = mm_strdup(literalbuf); 734 return CSTRING; 735 } 736 <xui>{dquote} { 737 BEGIN(state_before_str_start); 738 if (literallen == 2) /* "U&" */ 739 mmerror(PARSE_ERROR, ET_ERROR, "zero-length delimited identifier"); 740 /* The backend will truncate the identifier here. We do not as it does not change the result. */ 741 base_yylval.str = psprintf("U&\"%s\"", literalbuf); 742 return UIDENT; 743 } 744 <xd,xui>{xddouble} { 745 addlit(yytext, yyleng); 746 } 747 <xd,xui>{xdinside} { 748 addlit(yytext, yyleng); 749 } 750 <xd,xui><<EOF>> { mmfatal(PARSE_ERROR, "unterminated quoted identifier"); } 751 <C>{xdstart} { 752 state_before_str_start = YYSTATE; 753 BEGIN(xdc); 754 startlit(); 755 } 756 <xdc>{xdcinside} { 757 addlit(yytext, yyleng); 758 } 759 <xdc><<EOF>> { mmfatal(PARSE_ERROR, "unterminated quoted string"); } 760 761 <SQL>{ 762 {typecast} { 763 return TYPECAST; 764 } 765 766 {dot_dot} { 767 return DOT_DOT; 768 } 769 770 {colon_equals} { 771 return COLON_EQUALS; 772 } 773 774 {equals_greater} { 775 return EQUALS_GREATER; 776 } 777 778 {less_equals} { 779 return LESS_EQUALS; 780 } 781 782 {greater_equals} { 783 return GREATER_EQUALS; 784 } 785 786 {less_greater} { 787 /* We accept both "<>" and "!=" as meaning NOT_EQUALS */ 788 return NOT_EQUALS; 789 } 790 791 {not_equals} { 792 /* We accept both "<>" and "!=" as meaning NOT_EQUALS */ 793 return NOT_EQUALS; 794 } 795 796 {informix_special} { 797 /* are we simulating Informix? */ 798 if (INFORMIX_MODE) 799 { 800 unput(':'); 801 } 802 else 803 return yytext[0]; 804 } 805 806 {self} { 807 /* 808 * We may find a ';' inside a structure 809 * definition in a TYPE or VAR statement. 810 * This is not an EOL marker. 811 */ 812 if (yytext[0] == ';' && struct_level == 0) 813 BEGIN(C); 814 return yytext[0]; 815 } 816 817 {operator} { 818 /* 819 * Check for embedded slash-star or dash-dash; those 820 * are comment starts, so operator must stop there. 821 * Note that slash-star or dash-dash at the first 822 * character will match a prior rule, not this one. 823 */ 824 int nchars = yyleng; 825 char *slashstar = strstr(yytext, "/*"); 826 char *dashdash = strstr(yytext, "--"); 827 828 if (slashstar && dashdash) 829 { 830 /* if both appear, take the first one */ 831 if (slashstar > dashdash) 832 slashstar = dashdash; 833 } 834 else if (!slashstar) 835 slashstar = dashdash; 836 if (slashstar) 837 nchars = slashstar - yytext; 838 839 /* 840 * For SQL compatibility, '+' and '-' cannot be the 841 * last char of a multi-char operator unless the operator 842 * contains chars that are not in SQL operators. 843 * The idea is to lex '=-' as two operators, but not 844 * to forbid operator names like '?-' that could not be 845 * sequences of SQL operators. 846 */ 847 if (nchars > 1 && 848 (yytext[nchars - 1] == '+' || 849 yytext[nchars - 1] == '-')) 850 { 851 int ic; 852 853 for (ic = nchars - 2; ic >= 0; ic--) 854 { 855 char c = yytext[ic]; 856 if (c == '~' || c == '!' || c == '@' || 857 c == '#' || c == '^' || c == '&' || 858 c == '|' || c == '`' || c == '?' || 859 c == '%') 860 break; 861 } 862 if (ic < 0) 863 { 864 /* 865 * didn't find a qualifying character, so remove 866 * all trailing [+-] 867 */ 868 do { 869 nchars--; 870 } while (nchars > 1 && 871 (yytext[nchars - 1] == '+' || 872 yytext[nchars - 1] == '-')); 873 } 874 } 875 876 if (nchars < yyleng) 877 { 878 /* Strip the unwanted chars from the token */ 879 yyless(nchars); 880 /* 881 * If what we have left is only one char, and it's 882 * one of the characters matching "self", then 883 * return it as a character token the same way 884 * that the "self" rule would have. 885 */ 886 if (nchars == 1 && 887 strchr(",()[].;:+-*/%^<>=", yytext[0])) 888 return yytext[0]; 889 /* 890 * Likewise, if what we have left is two chars, and 891 * those match the tokens ">=", "<=", "=>", "<>" or 892 * "!=", then we must return the appropriate token 893 * rather than the generic Op. 894 */ 895 if (nchars == 2) 896 { 897 if (yytext[0] == '=' && yytext[1] == '>') 898 return EQUALS_GREATER; 899 if (yytext[0] == '>' && yytext[1] == '=') 900 return GREATER_EQUALS; 901 if (yytext[0] == '<' && yytext[1] == '=') 902 return LESS_EQUALS; 903 if (yytext[0] == '<' && yytext[1] == '>') 904 return NOT_EQUALS; 905 if (yytext[0] == '!' && yytext[1] == '=') 906 return NOT_EQUALS; 907 } 908 } 909 910 base_yylval.str = mm_strdup(yytext); 911 return Op; 912 } 913 914 {param} { 915 base_yylval.ival = atol(yytext+1); 916 return PARAM; 917 } 918 919 {ip} { 920 base_yylval.str = mm_strdup(yytext); 921 return IP; 922 } 923 } /* <SQL> */ 924 925 <C,SQL>{ 926 {integer} { 927 return process_integer_literal(yytext, &base_yylval); 928 } 929 {decimal} { 930 base_yylval.str = mm_strdup(yytext); 931 return FCONST; 932 } 933 {decimalfail} { 934 /* throw back the .., and treat as integer */ 935 yyless(yyleng - 2); 936 return process_integer_literal(yytext, &base_yylval); 937 } 938 {real} { 939 base_yylval.str = mm_strdup(yytext); 940 return FCONST; 941 } 942 {realfail1} { 943 /* 944 * throw back the [Ee], and figure out whether what 945 * remains is an {integer} or {decimal}. 946 */ 947 yyless(yyleng - 1); 948 return process_integer_literal(yytext, &base_yylval); 949 } 950 {realfail2} { 951 /* throw back the [Ee][+-], and proceed as above */ 952 yyless(yyleng - 2); 953 return process_integer_literal(yytext, &base_yylval); 954 } 955 } /* <C,SQL> */ 956 957 <SQL>{ 958 :{identifier}((("->"|\.){identifier})|(\[{array}\]))* { 959 base_yylval.str = mm_strdup(yytext+1); 960 return CVARIABLE; 961 } 962 963 {identifier} { 964 if (!isdefine()) 965 { 966 int kwvalue; 967 968 /* Is it an SQL/ECPG keyword? */ 969 kwvalue = ScanECPGKeywordLookup(yytext); 970 if (kwvalue >= 0) 971 return kwvalue; 972 973 /* Is it a C keyword? */ 974 kwvalue = ScanCKeywordLookup(yytext); 975 if (kwvalue >= 0) 976 return kwvalue; 977 978 /* 979 * None of the above. Return it as an identifier. 980 * 981 * The backend will attempt to truncate and case-fold 982 * the identifier, but I see no good reason for ecpg 983 * to do so; that's just another way that ecpg could get 984 * out of step with the backend. 985 */ 986 base_yylval.str = mm_strdup(yytext); 987 return IDENT; 988 } 989 } 990 991 {other} { 992 return yytext[0]; 993 } 994 } /* <SQL> */ 995 996 /* 997 * Begin ECPG-specific rules 998 */ 999 1000 <C>{exec_sql} { BEGIN(SQL); return SQL_START; } 1001 <C>{informix_special} { 1002 /* are we simulating Informix? */ 1003 if (INFORMIX_MODE) 1004 { 1005 BEGIN(SQL); 1006 return SQL_START; 1007 } 1008 else 1009 return S_ANYTHING; 1010 } 1011 <C>{ccomment} { ECHO; } 1012 <C>{xch} { 1013 char* endptr; 1014 1015 errno = 0; 1016 base_yylval.ival = strtoul((char *)yytext,&endptr,16); 1017 if (*endptr != '\0' || errno == ERANGE) 1018 { 1019 errno = 0; 1020 base_yylval.str = mm_strdup(yytext); 1021 return SCONST; 1022 } 1023 return ICONST; 1024 } 1025 <C>{cppinclude} { 1026 if (system_includes) 1027 { 1028 include_next = false; 1029 BEGIN(incl); 1030 } 1031 else 1032 { 1033 base_yylval.str = mm_strdup(yytext); 1034 return CPP_LINE; 1035 } 1036 } 1037 <C>{cppinclude_next} { 1038 if (system_includes) 1039 { 1040 include_next = true; 1041 BEGIN(incl); 1042 } 1043 else 1044 { 1045 base_yylval.str = mm_strdup(yytext); 1046 return CPP_LINE; 1047 } 1048 } 1049 <C,SQL>{cppline} { 1050 base_yylval.str = mm_strdup(yytext); 1051 return CPP_LINE; 1052 } 1053 <C>{identifier} { 1054 /* 1055 * Try to detect a function name: 1056 * look for identifiers at the global scope 1057 * keep the last identifier before the first '(' and '{' 1058 */ 1059 if (braces_open == 0 && parenths_open == 0) 1060 { 1061 if (current_function) 1062 free(current_function); 1063 current_function = mm_strdup(yytext); 1064 } 1065 /* Informix uses SQL defines only in SQL space */ 1066 /* however, some defines have to be taken care of for compatibility */ 1067 if ((!INFORMIX_MODE || !isinformixdefine()) && !isdefine()) 1068 { 1069 int kwvalue; 1070 1071 kwvalue = ScanCKeywordLookup(yytext); 1072 if (kwvalue >= 0) 1073 return kwvalue; 1074 else 1075 { 1076 base_yylval.str = mm_strdup(yytext); 1077 return IDENT; 1078 } 1079 } 1080 } 1081 <C>{xcstop} { mmerror(PARSE_ERROR, ET_ERROR, "nested /* ... */ comments"); } 1082 <C>":" { return ':'; } 1083 <C>";" { return ';'; } 1084 <C>"," { return ','; } 1085 <C>"*" { return '*'; } 1086 <C>"%" { return '%'; } 1087 <C>"/" { return '/'; } 1088 <C>"+" { return '+'; } 1089 <C>"-" { return '-'; } 1090 <C>"(" { parenths_open++; return '('; } 1091 <C>")" { parenths_open--; return ')'; } 1092 <C,xskip>{space} { ECHO; } 1093 <C>\{ { return '{'; } 1094 <C>\} { return '}'; } 1095 <C>\[ { return '['; } 1096 <C>\] { return ']'; } 1097 <C>\= { return '='; } 1098 <C>"->" { return S_MEMBER; } 1099 <C>">>" { return S_RSHIFT; } 1100 <C>"<<" { return S_LSHIFT; } 1101 <C>"||" { return S_OR; } 1102 <C>"&&" { return S_AND; } 1103 <C>"++" { return S_INC; } 1104 <C>"--" { return S_DEC; } 1105 <C>"==" { return S_EQUAL; } 1106 <C>"!=" { return S_NEQUAL; } 1107 <C>"+=" { return S_ADD; } 1108 <C>"-=" { return S_SUB; } 1109 <C>"*=" { return S_MUL; } 1110 <C>"/=" { return S_DIV; } 1111 <C>"%=" { return S_MOD; } 1112 <C>"->*" { return S_MEMPOINT; } 1113 <C>".*" { return S_DOTPOINT; } 1114 <C>{other} { return S_ANYTHING; } 1115 <C>{exec_sql}{define}{space}* { BEGIN(def_ident); } 1116 <C>{informix_special}{define}{space}* { 1117 /* are we simulating Informix? */ 1118 if (INFORMIX_MODE) 1119 { 1120 BEGIN(def_ident); 1121 } 1122 else 1123 { 1124 yyless(1); 1125 return S_ANYTHING; 1126 } 1127 } 1128 <C>{exec_sql}{undef}{space}* { BEGIN(undef); } 1129 <C>{informix_special}{undef}{space}* { 1130 /* are we simulating Informix? */ 1131 if (INFORMIX_MODE) 1132 { 1133 BEGIN(undef); 1134 } 1135 else 1136 { 1137 yyless(1); 1138 return S_ANYTHING; 1139 } 1140 } 1141 <undef>{identifier}{space}*";" { 1142 struct _defines *ptr, *ptr2 = NULL; 1143 int i; 1144 1145 /* 1146 * Skip the ";" and trailing whitespace. Note that yytext 1147 * contains at least one non-space character plus the ";" 1148 */ 1149 for (i = strlen(yytext)-2; 1150 i > 0 && ecpg_isspace(yytext[i]); 1151 i-- ) 1152 ; 1153 yytext[i+1] = '\0'; 1154 1155 1156 for (ptr = defines; ptr != NULL; ptr2 = ptr, ptr = ptr->next) 1157 { 1158 if (strcmp(yytext, ptr->olddef) == 0) 1159 { 1160 if (ptr2 == NULL) 1161 defines = ptr->next; 1162 else 1163 ptr2->next = ptr->next; 1164 free(ptr->newdef); 1165 free(ptr->olddef); 1166 free(ptr); 1167 break; 1168 } 1169 } 1170 1171 BEGIN(C); 1172 } 1173 <undef>{other}|\n { 1174 mmfatal(PARSE_ERROR, "missing identifier in EXEC SQL UNDEF command"); 1175 yyterminate(); 1176 } 1177 <C>{exec_sql}{include}{space}* { BEGIN(incl); } 1178 <C>{informix_special}{include}{space}* { 1179 /* are we simulating Informix? */ 1180 if (INFORMIX_MODE) 1181 { 1182 BEGIN(incl); 1183 } 1184 else 1185 { 1186 yyless(1); 1187 return S_ANYTHING; 1188 } 1189 } 1190 <C,xskip>{exec_sql}{ifdef}{space}* { 1191 if (preproc_tos >= MAX_NESTED_IF-1) 1192 mmfatal(PARSE_ERROR, "too many nested EXEC SQL IFDEF conditions"); 1193 preproc_tos++; 1194 stacked_if_value[preproc_tos].active = false; 1195 stacked_if_value[preproc_tos].saw_active = false; 1196 stacked_if_value[preproc_tos].else_branch = false; 1197 ifcond = true; 1198 BEGIN(xcond); 1199 } 1200 <C,xskip>{informix_special}{ifdef}{space}* { 1201 /* are we simulating Informix? */ 1202 if (INFORMIX_MODE) 1203 { 1204 if (preproc_tos >= MAX_NESTED_IF-1) 1205 mmfatal(PARSE_ERROR, "too many nested EXEC SQL IFDEF conditions"); 1206 preproc_tos++; 1207 stacked_if_value[preproc_tos].active = false; 1208 stacked_if_value[preproc_tos].saw_active = false; 1209 stacked_if_value[preproc_tos].else_branch = false; 1210 ifcond = true; 1211 BEGIN(xcond); 1212 } 1213 else 1214 { 1215 yyless(1); 1216 return S_ANYTHING; 1217 } 1218 } 1219 <C,xskip>{exec_sql}{ifndef}{space}* { 1220 if (preproc_tos >= MAX_NESTED_IF-1) 1221 mmfatal(PARSE_ERROR, "too many nested EXEC SQL IFDEF conditions"); 1222 preproc_tos++; 1223 stacked_if_value[preproc_tos].active = false; 1224 stacked_if_value[preproc_tos].saw_active = false; 1225 stacked_if_value[preproc_tos].else_branch = false; 1226 ifcond = false; 1227 BEGIN(xcond); 1228 } 1229 <C,xskip>{informix_special}{ifndef}{space}* { 1230 /* are we simulating Informix? */ 1231 if (INFORMIX_MODE) 1232 { 1233 if (preproc_tos >= MAX_NESTED_IF-1) 1234 mmfatal(PARSE_ERROR, "too many nested EXEC SQL IFDEF conditions"); 1235 preproc_tos++; 1236 stacked_if_value[preproc_tos].active = false; 1237 stacked_if_value[preproc_tos].saw_active = false; 1238 stacked_if_value[preproc_tos].else_branch = false; 1239 ifcond = false; 1240 BEGIN(xcond); 1241 } 1242 else 1243 { 1244 yyless(1); 1245 return S_ANYTHING; 1246 } 1247 } 1248 <C,xskip>{exec_sql}{elif}{space}* { 1249 if (preproc_tos == 0) 1250 mmfatal(PARSE_ERROR, "missing matching \"EXEC SQL IFDEF\" / \"EXEC SQL IFNDEF\""); 1251 if (stacked_if_value[preproc_tos].else_branch) 1252 mmfatal(PARSE_ERROR, "missing \"EXEC SQL ENDIF;\""); 1253 ifcond = true; 1254 BEGIN(xcond); 1255 } 1256 <C,xskip>{informix_special}{elif}{space}* { 1257 /* are we simulating Informix? */ 1258 if (INFORMIX_MODE) 1259 { 1260 if (preproc_tos == 0) 1261 mmfatal(PARSE_ERROR, "missing matching \"EXEC SQL IFDEF\" / \"EXEC SQL IFNDEF\""); 1262 if (stacked_if_value[preproc_tos].else_branch) 1263 mmfatal(PARSE_ERROR, "missing \"EXEC SQL ENDIF;\""); 1264 ifcond = true; 1265 BEGIN(xcond); 1266 } 1267 else 1268 { 1269 yyless(1); 1270 return S_ANYTHING; 1271 } 1272 } 1273 1274 <C,xskip>{exec_sql}{else}{space}*";" { /* only exec sql endif pops the stack, so take care of duplicated 'else' */ 1275 if ( preproc_tos == 0 ) 1276 mmfatal(PARSE_ERROR, "missing matching \"EXEC SQL IFDEF\" / \"EXEC SQL IFNDEF\""); 1277 else if (stacked_if_value[preproc_tos].else_branch) 1278 mmfatal(PARSE_ERROR, "more than one EXEC SQL ELSE"); 1279 else 1280 { 1281 stacked_if_value[preproc_tos].else_branch = true; 1282 stacked_if_value[preproc_tos].active = 1283 (stacked_if_value[preproc_tos-1].active && 1284 !stacked_if_value[preproc_tos].saw_active); 1285 stacked_if_value[preproc_tos].saw_active = true; 1286 1287 if (stacked_if_value[preproc_tos].active) 1288 BEGIN(C); 1289 else 1290 BEGIN(xskip); 1291 } 1292 } 1293 <C,xskip>{informix_special}{else}{space}*";" { 1294 /* are we simulating Informix? */ 1295 if (INFORMIX_MODE) 1296 { 1297 if ( preproc_tos == 0 ) 1298 mmfatal(PARSE_ERROR, "missing matching \"EXEC SQL IFDEF\" / \"EXEC SQL IFNDEF\""); 1299 else if (stacked_if_value[preproc_tos].else_branch) 1300 mmfatal(PARSE_ERROR, "more than one EXEC SQL ELSE"); 1301 else 1302 { 1303 stacked_if_value[preproc_tos].else_branch = true; 1304 stacked_if_value[preproc_tos].active = 1305 (stacked_if_value[preproc_tos-1].active && 1306 !stacked_if_value[preproc_tos].saw_active); 1307 stacked_if_value[preproc_tos].saw_active = true; 1308 1309 if (stacked_if_value[preproc_tos].active) 1310 BEGIN(C); 1311 else 1312 BEGIN(xskip); 1313 } 1314 } 1315 else 1316 { 1317 yyless(1); 1318 return S_ANYTHING; 1319 } 1320 } 1321 <C,xskip>{exec_sql}{endif}{space}*";" { 1322 if (preproc_tos == 0) 1323 mmfatal(PARSE_ERROR, "unmatched EXEC SQL ENDIF"); 1324 else 1325 preproc_tos--; 1326 1327 if (stacked_if_value[preproc_tos].active) 1328 BEGIN(C); 1329 else 1330 BEGIN(xskip); 1331 } 1332 <C,xskip>{informix_special}{endif}{space}*";" { 1333 /* are we simulating Informix? */ 1334 if (INFORMIX_MODE) 1335 { 1336 if (preproc_tos == 0) 1337 mmfatal(PARSE_ERROR, "unmatched EXEC SQL ENDIF"); 1338 else 1339 preproc_tos--; 1340 1341 if (stacked_if_value[preproc_tos].active) 1342 BEGIN(C); 1343 else 1344 BEGIN(xskip); 1345 } 1346 else 1347 { 1348 yyless(1); 1349 return S_ANYTHING; 1350 } 1351 } 1352 1353 <xskip>{other} { /* ignore */ } 1354 1355 <xcond>{identifier}{space}*";" { 1356 { 1357 struct _defines *defptr; 1358 unsigned int i; 1359 bool this_active; 1360 1361 /* 1362 * Skip the ";" and trailing whitespace. Note that yytext 1363 * contains at least one non-space character plus the ";" 1364 */ 1365 for (i = strlen(yytext)-2; 1366 i > 0 && ecpg_isspace(yytext[i]); 1367 i-- ) 1368 ; 1369 yytext[i+1] = '\0'; 1370 1371 for (defptr = defines; 1372 defptr != NULL && 1373 strcmp(yytext, defptr->olddef) != 0; 1374 defptr = defptr->next) 1375 /* skip */ ; 1376 1377 this_active = (defptr ? ifcond : !ifcond); 1378 stacked_if_value[preproc_tos].active = 1379 (stacked_if_value[preproc_tos-1].active && 1380 !stacked_if_value[preproc_tos].saw_active && 1381 this_active); 1382 stacked_if_value[preproc_tos].saw_active |= this_active; 1383 } 1384 1385 if (stacked_if_value[preproc_tos].active) 1386 BEGIN(C); 1387 else 1388 BEGIN(xskip); 1389 } 1390 1391 <xcond>{other}|\n { 1392 mmfatal(PARSE_ERROR, "missing identifier in EXEC SQL IFDEF command"); 1393 yyterminate(); 1394 } 1395 <def_ident>{identifier} { 1396 old = mm_strdup(yytext); 1397 BEGIN(def); 1398 startlit(); 1399 } 1400 <def_ident>{other}|\n { 1401 mmfatal(PARSE_ERROR, "missing identifier in EXEC SQL DEFINE command"); 1402 yyterminate(); 1403 } 1404 <def>{space}*";" { 1405 struct _defines *ptr, *this; 1406 1407 for (ptr = defines; ptr != NULL; ptr = ptr->next) 1408 { 1409 if (strcmp(old, ptr->olddef) == 0) 1410 { 1411 free(ptr->newdef); 1412 ptr->newdef = mm_strdup(literalbuf); 1413 } 1414 } 1415 if (ptr == NULL) 1416 { 1417 this = (struct _defines *) mm_alloc(sizeof(struct _defines)); 1418 1419 /* initial definition */ 1420 this->olddef = old; 1421 this->newdef = mm_strdup(literalbuf); 1422 this->next = defines; 1423 this->used = NULL; 1424 defines = this; 1425 } 1426 1427 BEGIN(C); 1428 } 1429 <def>[^;] { addlit(yytext, yyleng); } 1430 <incl>\<[^\>]+\>{space}*";"? { parse_include(); } 1431 <incl>{dquote}{xdinside}{dquote}{space}*";"? { parse_include(); } 1432 <incl>[^;\<\>\"]+";" { parse_include(); } 1433 <incl>{other}|\n { 1434 mmfatal(PARSE_ERROR, "syntax error in EXEC SQL INCLUDE command"); 1435 yyterminate(); 1436 } 1437 1438 <<EOF>> { 1439 if (yy_buffer == NULL) 1440 { 1441 if ( preproc_tos > 0 ) 1442 { 1443 preproc_tos = 0; 1444 mmfatal(PARSE_ERROR, "missing \"EXEC SQL ENDIF;\""); 1445 } 1446 yyterminate(); 1447 } 1448 else 1449 { 1450 struct _yy_buffer *yb = yy_buffer; 1451 int i; 1452 struct _defines *ptr; 1453 1454 for (ptr = defines; ptr; ptr = ptr->next) 1455 if (ptr->used == yy_buffer) 1456 { 1457 ptr->used = NULL; 1458 break; 1459 } 1460 1461 if (yyin != NULL) 1462 fclose(yyin); 1463 1464 yy_delete_buffer( YY_CURRENT_BUFFER ); 1465 yy_switch_to_buffer(yy_buffer->buffer); 1466 1467 yylineno = yy_buffer->lineno; 1468 1469 /* We have to output the filename only if we change files here */ 1470 i = strcmp(input_filename, yy_buffer->filename); 1471 1472 free(input_filename); 1473 input_filename = yy_buffer->filename; 1474 1475 yy_buffer = yy_buffer->next; 1476 free(yb); 1477 1478 if (i != 0) 1479 output_line_number(); 1480 1481 } 1482 } 1483 1484 <INITIAL>{other}|\n { mmfatal(PARSE_ERROR, "internal error: unreachable state; please report this to <%s>", PACKAGE_BUGREPORT); } 1485 1486 %% 1487 1488 /* LCOV_EXCL_STOP */ 1489 1490 void 1491 lex_init(void) 1492 { 1493 braces_open = 0; 1494 parenths_open = 0; 1495 current_function = NULL; 1496 1497 yylineno = 1; 1498 1499 /* initialize state for if/else/endif */ 1500 preproc_tos = 0; 1501 stacked_if_value[preproc_tos].active = true; 1502 stacked_if_value[preproc_tos].saw_active = true; 1503 stacked_if_value[preproc_tos].else_branch = false; 1504 1505 /* initialize literal buffer to a reasonable but expansible size */ 1506 if (literalbuf == NULL) 1507 { 1508 literalalloc = 1024; 1509 literalbuf = (char *) mm_alloc(literalalloc); 1510 } 1511 startlit(); 1512 1513 BEGIN(C); 1514 } 1515 1516 static void 1517 addlit(char *ytext, int yleng) 1518 { 1519 /* enlarge buffer if needed */ 1520 if ((literallen+yleng) >= literalalloc) 1521 { 1522 do 1523 literalalloc *= 2; 1524 while ((literallen+yleng) >= literalalloc); 1525 literalbuf = (char *) realloc(literalbuf, literalalloc); 1526 } 1527 /* append new data, add trailing null */ 1528 memcpy(literalbuf+literallen, ytext, yleng); 1529 literallen += yleng; 1530 literalbuf[literallen] = '\0'; 1531 } 1532 1533 static void 1534 addlitchar(unsigned char ychar) 1535 { 1536 /* enlarge buffer if needed */ 1537 if ((literallen+1) >= literalalloc) 1538 { 1539 literalalloc *= 2; 1540 literalbuf = (char *) realloc(literalbuf, literalalloc); 1541 } 1542 /* append new data, add trailing null */ 1543 literalbuf[literallen] = ychar; 1544 literallen += 1; 1545 literalbuf[literallen] = '\0'; 1546 } 1547 1548 /* 1549 * Process {integer}. Note this will also do the right thing with {decimal}, 1550 * ie digits and a decimal point. 1551 */ 1552 static int 1553 process_integer_literal(const char *token, YYSTYPE *lval) 1554 { 1555 int val; 1556 char *endptr; 1557 1558 errno = 0; 1559 val = strtoint(token, &endptr, 10); 1560 if (*endptr != '\0' || errno == ERANGE) 1561 { 1562 /* integer too large (or contains decimal pt), treat it as a float */ 1563 lval->str = mm_strdup(token); 1564 return FCONST; 1565 } 1566 lval->ival = val; 1567 return ICONST; 1568 } 1569 1570 static void 1571 parse_include(void) 1572 { 1573 /* got the include file name */ 1574 struct _yy_buffer *yb; 1575 struct _include_path *ip; 1576 char inc_file[MAXPGPATH]; 1577 unsigned int i; 1578 1579 yb = mm_alloc(sizeof(struct _yy_buffer)); 1580 1581 yb->buffer = YY_CURRENT_BUFFER; 1582 yb->lineno = yylineno; 1583 yb->filename = input_filename; 1584 yb->next = yy_buffer; 1585 1586 yy_buffer = yb; 1587 1588 /* 1589 * skip the ";" if there is one and trailing whitespace. Note that 1590 * yytext contains at least one non-space character plus the ";" 1591 */ 1592 for (i = strlen(yytext)-2; 1593 i > 0 && ecpg_isspace(yytext[i]); 1594 i--) 1595 ; 1596 1597 if (yytext[i] == ';') 1598 i--; 1599 1600 yytext[i+1] = '\0'; 1601 1602 yyin = NULL; 1603 1604 /* If file name is enclosed in '"' remove these and look only in '.' */ 1605 /* Informix does look into all include paths though, except filename starts with '/' */ 1606 if (yytext[0] == '"' && yytext[i] == '"' && 1607 ((compat != ECPG_COMPAT_INFORMIX && compat != ECPG_COMPAT_INFORMIX_SE) || yytext[1] == '/')) 1608 { 1609 yytext[i] = '\0'; 1610 memmove(yytext, yytext+1, strlen(yytext)); 1611 1612 strlcpy(inc_file, yytext, sizeof(inc_file)); 1613 yyin = fopen(inc_file, "r"); 1614 if (!yyin) 1615 { 1616 if (strlen(inc_file) <= 2 || strcmp(inc_file + strlen(inc_file) - 2, ".h") != 0) 1617 { 1618 strcat(inc_file, ".h"); 1619 yyin = fopen(inc_file, "r"); 1620 } 1621 } 1622 1623 } 1624 else 1625 { 1626 if ((yytext[0] == '"' && yytext[i] == '"') || (yytext[0] == '<' && yytext[i] == '>')) 1627 { 1628 yytext[i] = '\0'; 1629 memmove(yytext, yytext+1, strlen(yytext)); 1630 } 1631 1632 for (ip = include_paths; yyin == NULL && ip != NULL; ip = ip->next) 1633 { 1634 if (strlen(ip->path) + strlen(yytext) + 4 > MAXPGPATH) 1635 { 1636 fprintf(stderr, _("Error: include path \"%s/%s\" is too long on line %d, skipping\n"), ip->path, yytext, yylineno); 1637 continue; 1638 } 1639 snprintf (inc_file, sizeof(inc_file), "%s/%s", ip->path, yytext); 1640 yyin = fopen(inc_file, "r"); 1641 if (!yyin) 1642 { 1643 if (strcmp(inc_file + strlen(inc_file) - 2, ".h") != 0) 1644 { 1645 strcat(inc_file, ".h"); 1646 yyin = fopen( inc_file, "r" ); 1647 } 1648 } 1649 /* if the command was "include_next" we have to disregard the first hit */ 1650 if (yyin && include_next) 1651 { 1652 fclose (yyin); 1653 yyin = NULL; 1654 include_next = false; 1655 } 1656 } 1657 } 1658 if (!yyin) 1659 mmfatal(NO_INCLUDE_FILE, "could not open include file \"%s\" on line %d", yytext, yylineno); 1660 1661 input_filename = mm_strdup(inc_file); 1662 yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE )); 1663 yylineno = 1; 1664 output_line_number(); 1665 1666 BEGIN(C); 1667 } 1668 1669 /* 1670 * ecpg_isspace() --- return true if flex scanner considers char whitespace 1671 */ 1672 static bool 1673 ecpg_isspace(char ch) 1674 { 1675 if (ch == ' ' || 1676 ch == '\t' || 1677 ch == '\n' || 1678 ch == '\r' || 1679 ch == '\f') 1680 return true; 1681 return false; 1682 } 1683 1684 static bool isdefine(void) 1685 { 1686 struct _defines *ptr; 1687 1688 /* is it a define? */ 1689 for (ptr = defines; ptr; ptr = ptr->next) 1690 { 1691 if (strcmp(yytext, ptr->olddef) == 0 && ptr->used == NULL) 1692 { 1693 struct _yy_buffer *yb; 1694 1695 yb = mm_alloc(sizeof(struct _yy_buffer)); 1696 1697 yb->buffer = YY_CURRENT_BUFFER; 1698 yb->lineno = yylineno; 1699 yb->filename = mm_strdup(input_filename); 1700 yb->next = yy_buffer; 1701 1702 ptr->used = yy_buffer = yb; 1703 1704 yy_scan_string(ptr->newdef); 1705 return true; 1706 } 1707 } 1708 1709 return false; 1710 } 1711 1712 static bool isinformixdefine(void) 1713 { 1714 const char *new = NULL; 1715 1716 if (strcmp(yytext, "dec_t") == 0) 1717 new = "decimal"; 1718 else if (strcmp(yytext, "intrvl_t") == 0) 1719 new = "interval"; 1720 else if (strcmp(yytext, "dtime_t") == 0) 1721 new = "timestamp"; 1722 1723 if (new) 1724 { 1725 struct _yy_buffer *yb; 1726 1727 yb = mm_alloc(sizeof(struct _yy_buffer)); 1728 1729 yb->buffer = YY_CURRENT_BUFFER; 1730 yb->lineno = yylineno; 1731 yb->filename = mm_strdup(input_filename); 1732 yb->next = yy_buffer; 1733 yy_buffer = yb; 1734 1735 yy_scan_string(new); 1736 return true; 1737 } 1738 1739 return false; 1740 } 1741