2 /*-------------------------------------------------------------------------
5 * lexical scanner for ecpg
7 * This is a modified version of src/backend/parser/scan.l
10 * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
11 * Portions Copyright (c) 1994, Regents of the University of California
15 * src/interfaces/ecpg/preproc/pgc.l
17 *-------------------------------------------------------------------------
19 #include "postgres_fe.h"
22 #include <sys/types.h>
27 extern YYSTYPE yylval;
29 static int xcdepth = 0; /* depth of nesting in slash-star comments */
30 static char *dolqstart; /* current $foo$ quote start string */
31 static YY_BUFFER_STATE scanbufhandle;
35 * literalbuf is used to accumulate literal values when multiple rules
36 * are needed to parse a single literal. Call startlit to reset buffer
37 * to empty, addlit to add text. Note that the buffer is permanently
38 * malloc'd to the largest size needed so far in the current run.
40 static char *literalbuf = NULL; /* expandable buffer */
41 static int literallen; /* actual current length */
42 static int literalalloc; /* current allocated buffer size */
44 /* Used for detecting global state together with braces_open */
45 static int parenths_open;
47 /* Used to tell parse_include() whether the command was #include or #include_next */
48 static bool include_next;
50 #define startlit() (literalbuf[0] = '\0', literallen = 0)
51 static void addlit(char *ytext, int yleng);
52 static void addlitchar (unsigned char);
53 static void parse_include (void);
54 static bool ecpg_isspace(char ch);
55 static bool isdefine(void);
56 static bool isinformixdefine(void);
63 YY_BUFFER_STATE buffer;
66 struct _yy_buffer *next;
71 #define MAX_NESTED_IF 128
72 static short preproc_tos;
74 static struct _if_value
78 } stacked_if_value[MAX_NESTED_IF];
83 %option never-interactive
91 %x C SQL incl def def_ident undef
94 * OK, here is a short description of lex/flex rules behavior.
95 * The longest pattern which matches an input string is always chosen.
96 * For equal-length patterns, the first occurring in the rules list is chosen.
97 * INITIAL is the starting state, to which all non-conditional rules apply.
98 * Exclusive states change parsing rules while the state is active. When in
99 * an exclusive state, only those rules defined for that state apply.
101 * We use exclusive states for quoted strings, extended comments,
102 * and to eliminate parsing troubles for numeric strings.
104 * <xb> bit string literal
105 * <xc> extended C-style comments - thomas 1997-07-12
106 * <xd> delimited identifiers (double-quoted identifiers) - thomas 1997-10-27
107 * <xh> hexadecimal numeric string - thomas 1997-11-16
108 * <xq> standard quoted strings - thomas 1997-07-30
109 * <xqc> standard quoted strings in C - michael
110 * <xe> extended quoted strings (support backslash escape sequences)
111 * <xn> national character quoted strings
112 * <xdolq> $foo$ quoted strings
113 * <xui> quoted identifier with Unicode escapes
114 * <xus> quoted string with Unicode escapes
137 /* Hexadecimal number */
141 /* National character */
144 /* Quoted string that allows backslash escapes */
148 xeoctesc [\\][0-7]{1,3}
149 xehexesc [\\]x[0-9A-Fa-f]{1,2}
150 xeunicode [\\](u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})
152 /* C version of hex number */
153 xch 0[xX][0-9A-Fa-f]*
156 * xqdouble implements embedded quote, ''''
159 xqdouble {quote}{quote}
163 /* $foo$ style quotes ("dollar quoting")
164 * The quoted string starts with $foo$ where "foo" is an optional string
165 * in the form of an identifier, except that it may not contain "$",
166 * and extends to the first occurrence of an identical string.
167 * There is *no* processing of the quoted text.
169 * {dolqfailed} is an error rule to avoid scanner backup when {dolqdelim}
170 * fails to match its trailing "$".
172 dolq_start [A-Za-z\200-\377_]
173 dolq_cont [A-Za-z\200-\377_0-9]
174 dolqdelim \$({dolq_start}{dolq_cont}*)?\$
175 dolqfailed \${dolq_start}{dolq_cont}*
179 * Allows embedded spaces and other special characters into identifiers.
184 xddouble {dquote}{dquote}
187 /* Unicode escapes */
188 /* (The ecpg scanner is not backup-free, so the fail rules in scan.l are not needed here, but could be added if desired.) */
189 uescape [uU][eE][sS][cC][aA][pP][eE]{whitespace}*{quote}[^']{quote}
191 /* Quoted identifier with Unicode escapes */
192 xuistart [uU]&{dquote}
193 xuistop {dquote}({whitespace}*{uescape})?
195 /* Quoted string with Unicode escapes */
196 xusstart [uU]&{quote}
197 xusstop {quote}({whitespace}*{uescape})?
199 /* special stuff for C strings */
203 xdcinside ({xdcqq}|{xdcqdq}|{xdcother})
207 * The "extended comment" syntax closely resembles allowable operator syntax.
208 * The tricky part here is to get lex to recognize a string starting with
209 * slash-star as a comment, when interpreting it as an operator would produce
210 * a longer match --- remember lex will prefer a longer match! Also, if we
211 * have something like plus-slash-star, lex will think this is a 3-character
212 * operator whereas we want to see it as a + operator and a comment start.
213 * The solution is two-fold:
214 * 1. append {op_chars}* to xcstart so that it matches as much text as
215 * {operator} would. Then the tie-breaker (first matching rule of same
216 * length) ensures xcstart wins. We put back the extra stuff with yyless()
217 * in case it contains a star-slash that should terminate the comment.
218 * 2. In the operator rule, check for slash-star within the operator, and
219 * if found throw it back with yyless(). This handles the plus-slash-star
221 * Dash-dash comments have similar interactions with the operator rule.
223 xcstart \/\*{op_chars}*
228 ident_start [A-Za-z\200-\377_]
229 ident_cont [A-Za-z\200-\377_0-9\$]
231 identifier {ident_start}{ident_cont}*
233 array ({ident_cont}|{whitespace}|[\[\]\+\-\*\%\/\(\)\>\.])*
239 * "self" is the set of chars that should be returned as single-character
240 * tokens. "op_chars" is the set of chars that can make up "Op" tokens,
241 * which can be one or more characters long (but if a single-char token
242 * appears in the "self" set, it is not to be returned as an Op). Note
243 * that the sets overlap, but each has some chars that are not in the other.
245 * If you change either set, adjust the character lists appearing in the
246 * rule for "operator"!
248 self [,()\[\].;\:\+\-\*\/\%\^\<\>\=]
249 op_chars [\~\!\@\#\^\&\|\`\?\+\-\*\/\%\<\>\=]
252 /* we no longer allow unary minus in numbers.
253 * instead we pass it separately to parser. there it gets
254 * coerced via doNegate() -- Leon aug 20 1999
256 * {realfail1} and {realfail2} are added to prevent the need for scanner
257 * backup when the {real} rule fails to match completely.
261 decimal (({digit}*\.{digit}+)|({digit}+\.{digit}*))
262 real ({integer}|{decimal})[Ee][-+]?{digit}+
263 realfail1 ({integer}|{decimal})[Ee]
264 realfail2 ({integer}|{decimal})[Ee][-+]
269 * In order to make the world safe for Windows and Mac clients as well as
270 * Unix ones, we accept either \n or \r as a newline. A DOS-style \r\n
271 * sequence will be seen as two successive newlines, but that doesn't cause
272 * any problems. SQL92-style comments, which start with -- and extend to the
273 * next newline, are treated as equivalent to a single whitespace character.
275 * NOTE a fine point: if there is no newline following --, we will absorb
276 * everything to the end of the input as a comment. This is correct. Older
277 * versions of Postgres failed to recognize -- as a comment if the input
278 * did not end with a newline.
280 * XXX perhaps \f (formfeed) should be treated as a newline as well?
282 * XXX if you change the set of whitespace characters, fix ecpg_isspace()
293 comment ("--"{non_newline}*)
295 whitespace ({space}+|{comment})
298 * SQL92 requires at least one newline in the whitespace separating
299 * string literals that are to be concatenated. Silly, but who are we
300 * to argue? Note that {whitespace_with_newline} should not have * after
301 * it, whereas {whitespace} should generally have a * after it...
304 horiz_whitespace ({horiz_space}|{comment})
305 whitespace_with_newline ({horiz_whitespace}*{newline}{whitespace}*)
308 quotestop {quote}{whitespace}*
309 quotecontinue {quote}{whitespace_with_newline}{quote}
310 quotefail {quote}{whitespace}*"-"
312 /* special characters for other dbms */
313 /* we have to react differently in compat mode */
314 informix_special [\$]
318 /* some stuff needed for ecpg */
319 exec [eE][xX][eE][cC]
321 define [dD][eE][fF][iI][nN][eE]
322 include [iI][nN][cC][lL][uU][dD][eE]
323 include_next [iI][nN][cC][lL][uU][dD][eE]_[nN][eE][xX][tT]
324 import [iI][mM][pP][oO][rR][tT]
325 undef [uU][nN][dD][eE][fF]
328 ifdef [iI][fF][dD][eE][fF]
329 ifndef [iI][fF][nN][dD][eE][fF]
330 else [eE][lL][sS][eE]
331 elif [eE][lL][iI][fF]
332 endif [eE][nN][dD][iI][fF]
334 struct [sS][tT][rR][uU][cC][tT]
336 exec_sql {exec}{space}*{sql}{space}*
337 ipdigit ({digit}|{digit}{digit}|{digit}{digit}{digit})
338 ip {ipdigit}\.{ipdigit}\.{ipdigit}\.{ipdigit}
340 /* we might want to parse all cpp include files */
341 cppinclude {space}*#{include}{space}*
342 cppinclude_next {space}*#{include_next}{space}*
344 /* take care of cpp lines, they may also be continuated */
345 /* first a general line for all commands not starting with "i" */
346 /* and then the other commands starting with "i", we have to add these
347 * separately because the cppline production would match on "include" too */
348 cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})(.*\\{space})*.*{newline}
351 * Dollar quoted strings are totally opaque, and no escaping is done on them.
352 * Other quoted strings must allow some special characters such as single-quote
354 * Embedded single-quotes are implemented both in the SQL standard
355 * style of two adjacent single quotes "''" and in the Postgres/Java style
356 * of escaped-quote "\'".
357 * Other embedded escaped characters are matched explicitly and the leading
358 * backslash is dropped from the string. - thomas 1997-09-24
359 * Note that xcstart must appear before operator, as explained above!
360 * Also whitespace (comment) must appear before operator.
366 /* code to execute during start of each call of yylex() */
370 <SQL>{whitespace} { /* ignore */ }
373 token_start = yytext;
374 state_before = YYSTATE;
377 /* Put back any characters past slash-star; see above */
383 /* Put back any characters past slash-star; see above */
399 <xc>{xcinside} { ECHO; }
400 <xc>{op_chars} { ECHO; }
403 <xc><<EOF>> { mmerror(PARSE_ERROR, ET_FATAL, "unterminated /* comment"); }
406 token_start = yytext;
415 if (literalbuf[strspn(literalbuf, "01") + 1] != '\0')
416 mmerror(PARSE_ERROR, ET_ERROR, "invalid bit string literal");
417 yylval.str = mm_strdup(literalbuf);
422 <xb>{xbinside} { addlit(yytext, yyleng); }
423 <xh>{quotecontinue} |
424 <xb>{quotecontinue} { /* ignore */ }
425 <xb><<EOF>> { mmerror(PARSE_ERROR, ET_FATAL, "unterminated bit string literal"); }
428 token_start = yytext;
437 yylval.str = mm_strdup(literalbuf);
441 <xh><<EOF>> { mmerror(PARSE_ERROR, ET_FATAL, "unterminated hexadecimal string literal"); }
443 /* National character.
444 * Transfer it as-is to the backend.
446 token_start = yytext;
447 state_before = YYSTATE;
452 token_start = yytext;
453 state_before = YYSTATE;
458 token_start = yytext;
459 state_before = YYSTATE;
464 token_start = yytext;
465 state_before = YYSTATE;
470 token_start = yytext;
471 state_before = YYSTATE;
474 addlit(yytext, yyleng);
476 <xq,xqc>{quotestop} |
477 <xq,xqc>{quotefail} {
480 yylval.str = mm_strdup(literalbuf);
487 yylval.str = mm_strdup(literalbuf);
494 yylval.str = mm_strdup(literalbuf);
498 addlit(yytext, yyleng);
500 yylval.str = mm_strdup(literalbuf);
503 <xq,xe,xn,xus>{xqdouble} { addlitchar('\''); }
508 <xq,xqc,xn,xus>{xqinside} { addlit(yytext, yyleng); }
509 <xe>{xeinside} { addlit(yytext, yyleng); }
510 <xe>{xeunicode} { addlit(yytext, yyleng); }
511 <xe>{xeescape} { addlit(yytext, yyleng); }
512 <xe>{xeoctesc} { addlit(yytext, yyleng); }
513 <xe>{xehexesc} { addlit(yytext, yyleng); }
514 <xq,xqc,xe,xn,xus>{quotecontinue} { /* ignore */ }
516 /* This is only needed for \ just before EOF */
517 addlitchar(yytext[0]);
519 <xq,xqc,xe,xn,xus><<EOF>> { mmerror(PARSE_ERROR, ET_FATAL, "unterminated quoted string"); }
521 /* throw back all but the initial "$" */
523 /* and treat it as {other} */
527 token_start = yytext;
528 dolqstart = mm_strdup(yytext);
531 addlit(yytext, yyleng);
534 if (strcmp(yytext, dolqstart) == 0)
536 addlit(yytext, yyleng);
539 yylval.str = mm_strdup(literalbuf);
545 * When we fail to match $...$ to dolqstart, transfer
546 * the $... part to the output, but put back the final
547 * $ for rescanning. Consider $delim$...$junk$delim$
549 addlit(yytext, yyleng-1);
553 <xdolq>{dolqinside} { addlit(yytext, yyleng); }
554 <xdolq>{dolqfailed} { addlit(yytext, yyleng); }
556 /* single quote or dollar sign */
557 addlitchar(yytext[0]);
559 <xdolq><<EOF>> { base_yyerror("unterminated dollar-quoted string"); }
561 state_before = YYSTATE;
566 state_before = YYSTATE;
569 addlit(yytext, yyleng);
574 mmerror(PARSE_ERROR, ET_ERROR, "zero-length delimited identifier");
575 /* The backend will truncate the identifier here. We do not as it does not change the result. */
576 yylval.str = mm_strdup(literalbuf);
581 yylval.str = mm_strdup(literalbuf);
586 if (literallen == 2) /* "U&" */
587 mmerror(PARSE_ERROR, ET_ERROR, "zero-length delimited identifier");
588 /* The backend will truncate the identifier here. We do not as it does not change the result. */
589 addlit(yytext, yyleng);
590 yylval.str = mm_strdup(literalbuf);
593 <xd,xui>{xddouble} { addlitchar('"'); }
594 <xd,xui>{xdinside} { addlit(yytext, yyleng); }
595 <xd,xdc,xui><<EOF>> { mmerror(PARSE_ERROR, ET_FATAL, "unterminated quoted identifier"); }
597 state_before = YYSTATE;
601 <xdc>{xdcinside} { addlit(yytext, yyleng); }
602 <SQL>{typecast} { return TYPECAST; }
603 <SQL>{dot_dot} { return DOT_DOT; }
604 <SQL>{colon_equals} { return COLON_EQUALS; }
605 <SQL>{informix_special} {
606 /* are we simulating Informix? */
615 * We may find a ';' inside a structure
616 * definition in a TYPE or VAR statement.
617 * This is not an EOL marker.
619 if (yytext[0] == ';' && struct_level == 0)
625 * Check for embedded slash-star or dash-dash; those
626 * are comment starts, so operator must stop there.
627 * Note that slash-star or dash-dash at the first
628 * character will match a prior rule, not this one.
631 char *slashstar = strstr(yytext, "/*");
632 char *dashdash = strstr(yytext, "--");
634 if (slashstar && dashdash)
636 /* if both appear, take the first one */
637 if (slashstar > dashdash)
638 slashstar = dashdash;
641 slashstar = dashdash;
643 nchars = slashstar - yytext;
646 * For SQL compatibility, '+' and '-' cannot be the
647 * last char of a multi-char operator unless the operator
648 * contains chars that are not in SQL operators.
649 * The idea is to lex '=-' as two operators, but not
650 * to forbid operator names like '?-' that could not be
651 * sequences of SQL operators.
654 (yytext[nchars-1] == '+' ||
655 yytext[nchars-1] == '-'))
659 for (ic = nchars-2; ic >= 0; ic--)
661 if (strchr("~!@#^&|`?%", yytext[ic]))
665 break; /* found a char that makes it OK */
666 nchars--; /* else remove the +/-, and check again */
671 /* Strip the unwanted chars from the token */
674 * If what we have left is only one char, and it's
675 * one of the characters matching "self", then
676 * return it as a character token the same way
677 * that the "self" rule would have.
680 strchr(",()[].;:+-*/%^<>=", yytext[0]))
684 /* Convert "!=" operator to "<>" for compatibility */
685 if (strcmp(yytext, "!=") == 0)
686 yylval.str = mm_strdup("<>");
688 yylval.str = mm_strdup(yytext);
692 yylval.ival = atol(yytext+1);
700 val = strtol((char *)yytext, &endptr,10);
701 if (*endptr != '\0' || errno == ERANGE
702 #ifdef HAVE_LONG_INT_64
703 /* if long > 32 bits, check for overflow of int4 */
704 || val != (long) ((int32) val)
709 yylval.str = mm_strdup(yytext);
716 yylval.str = mm_strdup(yytext);
720 yylval.str = mm_strdup(yytext);
724 yylval.str = mm_strdup(yytext);
729 yylval.str = mm_strdup(yytext);
734 yylval.str = mm_strdup(yytext);
737 <SQL>:{identifier}((("->"|\.){identifier})|(\[{array}\]))* {
738 yylval.str = mm_strdup(yytext+1);
742 const ScanKeyword *keyword;
746 /* Is it an SQL/ECPG keyword? */
747 keyword = ScanECPGKeywordLookup(yytext);
749 return keyword->value;
751 /* Is it a C keyword? */
752 keyword = ScanCKeywordLookup(yytext);
754 return keyword->value;
757 * None of the above. Return it as an identifier.
759 * The backend will attempt to truncate and case-fold
760 * the identifier, but I see no good reason for ecpg
761 * to do so; that's just another way that ecpg could get
762 * out of step with the backend.
764 yylval.str = mm_strdup(yytext);
768 <SQL>{other} { return yytext[0]; }
769 <C>{exec_sql} { BEGIN(SQL); return SQL_START; }
770 <C>{informix_special} {
771 /* are we simulating Informix? */
780 <C>{ccomment} { ECHO; }
785 yylval.ival = strtoul((char *)yytext,&endptr,16);
786 if (*endptr != '\0' || errno == ERANGE)
789 yylval.str = mm_strdup(yytext);
797 include_next = false;
802 yylval.str = mm_strdup(yytext);
806 <C>{cppinclude_next} {
814 yylval.str = mm_strdup(yytext);
819 yylval.str = mm_strdup(yytext);
823 const ScanKeyword *keyword;
826 * Try to detect a function name:
827 * look for identifiers at the global scope
828 * keep the last identifier before the first '(' and '{' */
829 if (braces_open == 0 && parenths_open == 0)
831 if (current_function)
832 free(current_function);
833 current_function = mm_strdup(yytext);
835 /* Informix uses SQL defines only in SQL space */
836 /* however, some defines have to be taken care of for compatibility */
837 if ((!INFORMIX_MODE || !isinformixdefine()) && !isdefine())
839 keyword = ScanCKeywordLookup(yytext);
841 return keyword->value;
844 yylval.str = mm_strdup(yytext);
849 <C>":" { return(':'); }
850 <C>";" { return(';'); }
851 <C>"," { return(','); }
852 <C>"*" { return('*'); }
853 <C>"%" { return('%'); }
854 <C>"/" { return('/'); }
855 <C>"+" { return('+'); }
856 <C>"-" { return('-'); }
857 <C>"(" { parenths_open++; return('('); }
858 <C>")" { parenths_open--; return(')'); }
859 <C,xskip>{space} { ECHO; }
860 <C>\{ { return('{'); }
861 <C>\} { return('}'); }
862 <C>\[ { return('['); }
863 <C>\] { return(']'); }
864 <C>\= { return('='); }
865 <C>"->" { return(S_MEMBER); }
866 <C>">>" { return(S_RSHIFT); }
867 <C>"<<" { return(S_LSHIFT); }
868 <C>"||" { return(S_OR); }
869 <C>"&&" { return(S_AND); }
870 <C>"++" { return(S_INC); }
871 <C>"--" { return(S_DEC); }
872 <C>"==" { return(S_EQUAL); }
873 <C>"!=" { return(S_NEQUAL); }
874 <C>"+=" { return(S_ADD); }
875 <C>"-=" { return(S_SUB); }
876 <C>"*=" { return(S_MUL); }
877 <C>"/=" { return(S_DIV); }
878 <C>"%=" { return(S_MOD); }
879 <C>"->*" { return(S_MEMPOINT); }
880 <C>".*" { return(S_DOTPOINT); }
881 <C>{other} { return S_ANYTHING; }
882 <C>{exec_sql}{define}{space}* { BEGIN(def_ident); }
883 <C>{informix_special}{define}{space}* {
884 /* are we simulating Informix? */
895 <C>{exec_sql}{undef}{space}* { BEGIN(undef); }
896 <C>{informix_special}{undef}{space}* {
897 /* are we simulating Informix? */
908 <undef>{identifier}{space}*";" {
909 struct _defines *ptr, *ptr2 = NULL;
913 * Skip the ";" and trailing whitespace. Note that yytext
914 * contains at least one non-space character plus the ";"
916 for (i = strlen(yytext)-2;
917 i > 0 && ecpg_isspace(yytext[i]);
923 for (ptr = defines; ptr != NULL; ptr2 = ptr, ptr = ptr->next)
925 if (strcmp(yytext, ptr->old) == 0)
930 ptr2->next = ptr->next;
941 mmerror(PARSE_ERROR, ET_FATAL, "missing identifier in EXEC SQL UNDEF command");
944 <C>{exec_sql}{include}{space}* { BEGIN(incl); }
945 <C>{informix_special}{include}{space}* {
946 /* are we simulating Informix? */
957 <C,xskip>{exec_sql}{ifdef}{space}* { ifcond = TRUE; BEGIN(xcond); }
958 <C,xskip>{informix_special}{ifdef}{space}* {
959 /* are we simulating Informix? */
971 <C,xskip>{exec_sql}{ifndef}{space}* { ifcond = FALSE; BEGIN(xcond); }
972 <C,xskip>{informix_special}{ifndef}{space}* {
973 /* are we simulating Informix? */
985 <C,xskip>{exec_sql}{elif}{space}* { /* pop stack */
986 if ( preproc_tos == 0 ) {
987 mmerror(PARSE_ERROR, ET_FATAL, "missing matching \"EXEC SQL IFDEF\" / \"EXEC SQL IFNDEF\"");
989 else if ( stacked_if_value[preproc_tos].else_branch )
990 mmerror(PARSE_ERROR, ET_FATAL, "missing \"EXEC SQL ENDIF;\"");
994 ifcond = TRUE; BEGIN(xcond);
996 <C,xskip>{informix_special}{elif}{space}* {
997 /* are we simulating Informix? */
1000 if (preproc_tos == 0)
1001 mmerror(PARSE_ERROR, ET_FATAL, "missing matching \"EXEC SQL IFDEF\" / \"EXEC SQL IFNDEF\"");
1002 else if (stacked_if_value[preproc_tos].else_branch)
1003 mmerror(PARSE_ERROR, ET_FATAL, "missing \"EXEC SQL ENDIF;\"");
1013 return (S_ANYTHING);
1017 <C,xskip>{exec_sql}{else}{space}*";" { /* only exec sql endif pops the stack, so take care of duplicated 'else' */
1018 if (stacked_if_value[preproc_tos].else_branch)
1019 mmerror(PARSE_ERROR, ET_FATAL, "more than one EXEC SQL ELSE");
1022 stacked_if_value[preproc_tos].else_branch = TRUE;
1023 stacked_if_value[preproc_tos].condition =
1024 (stacked_if_value[preproc_tos-1].condition &&
1025 !stacked_if_value[preproc_tos].condition);
1027 if (stacked_if_value[preproc_tos].condition)
1033 <C,xskip>{informix_special}{else}{space}*";" {
1034 /* are we simulating Informix? */
1037 if (stacked_if_value[preproc_tos].else_branch)
1038 mmerror(PARSE_ERROR, ET_FATAL, "more than one EXEC SQL ELSE");
1041 stacked_if_value[preproc_tos].else_branch = TRUE;
1042 stacked_if_value[preproc_tos].condition =
1043 (stacked_if_value[preproc_tos-1].condition &&
1044 !stacked_if_value[preproc_tos].condition);
1046 if (stacked_if_value[preproc_tos].condition)
1055 return (S_ANYTHING);
1058 <C,xskip>{exec_sql}{endif}{space}*";" {
1059 if (preproc_tos == 0)
1060 mmerror(PARSE_ERROR, ET_FATAL, "unmatched EXEC SQL ENDIF");
1064 if (stacked_if_value[preproc_tos].condition)
1069 <C,xskip>{informix_special}{endif}{space}*";" {
1070 /* are we simulating Informix? */
1073 if (preproc_tos == 0)
1074 mmerror(PARSE_ERROR, ET_FATAL, "unmatched EXEC SQL ENDIF");
1078 if (stacked_if_value[preproc_tos].condition)
1086 return (S_ANYTHING);
1090 <xskip>{other} { /* ignore */ }
1092 <xcond>{identifier}{space}*";" {
1093 if (preproc_tos >= MAX_NESTED_IF-1)
1094 mmerror(PARSE_ERROR, ET_FATAL, "too many nested EXEC SQL IFDEF conditions");
1097 struct _defines *defptr;
1101 * Skip the ";" and trailing whitespace. Note that yytext
1102 * contains at least one non-space character plus the ";"
1104 for (i = strlen(yytext)-2;
1105 i > 0 && ecpg_isspace(yytext[i]);
1110 for (defptr = defines;
1111 defptr != NULL && strcmp(yytext, defptr->old) != 0;
1112 defptr = defptr->next);
1115 stacked_if_value[preproc_tos].else_branch = FALSE;
1116 stacked_if_value[preproc_tos].condition =
1117 (defptr ? ifcond : !ifcond) && stacked_if_value[preproc_tos-1].condition;
1120 if (stacked_if_value[preproc_tos].condition)
1127 mmerror(PARSE_ERROR, ET_FATAL, "missing identifier in EXEC SQL IFDEF command");
1130 <def_ident>{identifier} {
1131 old = mm_strdup(yytext);
1135 <def_ident>{other}|\n {
1136 mmerror(PARSE_ERROR, ET_FATAL, "missing identifier in EXEC SQL DEFINE command");
1140 struct _defines *ptr, *this;
1142 for (ptr = defines; ptr != NULL; ptr = ptr->next)
1144 if (strcmp(old, ptr->old) == 0)
1147 ptr->new = mm_strdup(literalbuf);
1152 this = (struct _defines *) mm_alloc(sizeof(struct _defines));
1154 /* initial definition */
1156 this->new = mm_strdup(literalbuf);
1157 this->next = defines;
1164 <def>[^;] { addlit(yytext, yyleng); }
1165 <incl>\<[^\>]+\>{space}*";"? { parse_include(); }
1166 <incl>{dquote}{xdinside}{dquote}{space}*";"? { parse_include(); }
1167 <incl>[^;\<\>\"]+";" { parse_include(); }
1169 mmerror(PARSE_ERROR, ET_FATAL, "syntax error in EXEC SQL INCLUDE command");
1174 if (yy_buffer == NULL)
1176 if ( preproc_tos > 0 )
1179 mmerror(PARSE_ERROR, ET_FATAL, "missing \"EXEC SQL ENDIF;\"");
1185 struct _yy_buffer *yb = yy_buffer;
1187 struct _defines *ptr;
1189 for (ptr = defines; ptr; ptr = ptr->next)
1190 if (ptr->used == yy_buffer)
1199 yy_delete_buffer( YY_CURRENT_BUFFER );
1200 yy_switch_to_buffer(yy_buffer->buffer);
1202 yylineno = yy_buffer->lineno;
1204 /* We have to output the filename only if we change files here */
1205 i = strcmp(input_filename, yy_buffer->filename);
1207 free(input_filename);
1208 input_filename = yy_buffer->filename;
1210 yy_buffer = yy_buffer->next;
1214 output_line_number();
1218 <INITIAL>{other}|\n { mmerror(PARSE_ERROR, ET_FATAL, "internal error: unreachable state; please report this to <pgsql-bugs@postgresql.org>"); }
1225 current_function = NULL;
1230 stacked_if_value[preproc_tos].condition = ifcond;
1231 stacked_if_value[preproc_tos].else_branch = FALSE;
1233 /* initialize literal buffer to a reasonable but expansible size */
1234 if (literalbuf == NULL)
1236 literalalloc = 1024;
1237 literalbuf = (char *) malloc(literalalloc);
1245 addlit(char *ytext, int yleng)
1247 /* enlarge buffer if needed */
1248 if ((literallen+yleng) >= literalalloc)
1252 while ((literallen+yleng) >= literalalloc);
1253 literalbuf = (char *) realloc(literalbuf, literalalloc);
1255 /* append new data, add trailing null */
1256 memcpy(literalbuf+literallen, ytext, yleng);
1257 literallen += yleng;
1258 literalbuf[literallen] = '\0';
1262 addlitchar(unsigned char ychar)
1264 /* enlarge buffer if needed */
1265 if ((literallen+1) >= literalalloc)
1268 literalbuf = (char *) realloc(literalbuf, literalalloc);
1270 /* append new data, add trailing null */
1271 literalbuf[literallen] = ychar;
1273 literalbuf[literallen] = '\0';
1279 /* got the include file name */
1280 struct _yy_buffer *yb;
1281 struct _include_path *ip;
1282 char inc_file[MAXPGPATH];
1285 yb = mm_alloc(sizeof(struct _yy_buffer));
1287 yb->buffer = YY_CURRENT_BUFFER;
1288 yb->lineno = yylineno;
1289 yb->filename = input_filename;
1290 yb->next = yy_buffer;
1295 * skip the ";" if there is one and trailing whitespace. Note that
1296 * yytext contains at least one non-space character plus the ";"
1298 for (i = strlen(yytext)-2;
1299 i > 0 && ecpg_isspace(yytext[i]);
1303 if (yytext[i] == ';')
1310 /* If file name is enclosed in '"' remove these and look only in '.' */
1311 /* Informix does look into all include paths though, except filename starts with '/' */
1312 if (yytext[0] == '"' && yytext[i] == '"' &&
1313 ((compat != ECPG_COMPAT_INFORMIX && compat != ECPG_COMPAT_INFORMIX_SE) || yytext[1] == '/'))
1316 memmove(yytext, yytext+1, strlen(yytext));
1318 strncpy(inc_file, yytext, sizeof(inc_file));
1319 yyin = fopen(inc_file, "r");
1322 if (strcmp(inc_file + strlen(inc_file) - 2, ".h") != 0)
1324 strcat(inc_file, ".h");
1325 yyin = fopen(inc_file, "r");
1332 if ((yytext[0] == '"' && yytext[i] == '"') || (yytext[0] == '<' && yytext[i] == '>'))
1335 memmove(yytext, yytext+1, strlen(yytext));
1338 for (ip = include_paths; yyin == NULL && ip != NULL; ip = ip->next)
1340 if (strlen(ip->path) + strlen(yytext) + 3 > MAXPGPATH)
1342 fprintf(stderr, _("Error: include path \"%s/%s\" is too long on line %d, skipping\n"), ip->path, yytext, yylineno);
1345 snprintf (inc_file, sizeof(inc_file), "%s/%s", ip->path, yytext);
1346 yyin = fopen(inc_file, "r");
1349 if (strcmp(inc_file + strlen(inc_file) - 2, ".h") != 0)
1351 strcat(inc_file, ".h");
1352 yyin = fopen( inc_file, "r" );
1355 /* if the command was "include_next" we have to disregard the first hit */
1356 if (yyin && include_next)
1359 include_next = false;
1364 mmerror(NO_INCLUDE_FILE, ET_FATAL, "could not open include file \"%s\" on line %d", yytext, yylineno);
1366 input_filename = mm_strdup(inc_file);
1367 yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE ));
1369 output_line_number();
1375 * ecpg_isspace() --- return TRUE if flex scanner considers char whitespace
1378 ecpg_isspace(char ch)
1389 static bool isdefine(void)
1391 struct _defines *ptr;
1393 /* is it a define? */
1394 for (ptr = defines; ptr; ptr = ptr->next)
1396 if (strcmp(yytext, ptr->old) == 0 && ptr->used == NULL)
1398 struct _yy_buffer *yb;
1400 yb = mm_alloc(sizeof(struct _yy_buffer));
1402 yb->buffer = YY_CURRENT_BUFFER;
1403 yb->lineno = yylineno;
1404 yb->filename = mm_strdup(input_filename);
1405 yb->next = yy_buffer;
1407 ptr->used = yy_buffer = yb;
1409 yy_scan_string(ptr->new);
1417 static bool isinformixdefine(void)
1419 const char *new = NULL;
1421 if (strcmp(yytext, "dec_t") == 0)
1423 else if (strcmp(yytext, "intrvl_t") == 0)
1425 else if (strcmp(yytext, "dtime_t") == 0)
1430 struct _yy_buffer *yb;
1432 yb = mm_alloc(sizeof(struct _yy_buffer));
1434 yb->buffer = YY_CURRENT_BUFFER;
1435 yb->lineno = yylineno;
1436 yb->filename = mm_strdup(input_filename);
1437 yb->next = yy_buffer;
1440 yy_scan_string(new);
1448 * Called before any actual parsing is done
1451 scanner_init(const char *str)
1453 Size slen = strlen(str);
1456 * Might be left over after ereport()
1458 if (YY_CURRENT_BUFFER)
1459 yy_delete_buffer(YY_CURRENT_BUFFER);
1462 * Make a scan buffer with special termination needed by flex.
1464 scanbuf = mm_alloc(slen + 2);
1465 memcpy(scanbuf, str, slen);
1466 scanbuf[slen] = scanbuf[slen + 1] = YY_END_OF_BUFFER_CHAR;
1467 scanbufhandle = yy_scan_buffer(scanbuf, slen + 2);
1469 /* initialize literal buffer to a reasonable but expansible size */
1471 literalbuf = (char *) mm_alloc(literalalloc);
1479 * Called after parsing is done to clean up after scanner_init()
1482 scanner_finish(void)
1484 yy_delete_buffer(scanbufhandle);