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