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