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