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