2 /*-------------------------------------------------------------------------
5 * lexical scanner for ecpg
7 * This is a modified version of src/backend/parser/scan.l
10 * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
11 * Portions Copyright (c) 1994, Regents of the University of California
15 * $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/pgc.l,v 1.171 2010/01/02 16:58:11 momjian Exp $
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 #define startlit() (literalbuf[0] = '\0', literallen = 0)
45 static void addlit(char *ytext, int yleng);
46 static void addlitchar (unsigned char);
47 static void parse_include (void);
48 static bool ecpg_isspace(char ch);
49 static bool isdefine(void);
50 static bool isinformixdefine(void);
57 YY_BUFFER_STATE buffer;
60 struct _yy_buffer *next;
65 #define MAX_NESTED_IF 128
66 static short preproc_tos;
68 static struct _if_value
72 } stacked_if_value[MAX_NESTED_IF];
77 %option never-interactive
84 %x C SQL incl def def_ident undef
87 * OK, here is a short description of lex/flex rules behavior.
88 * The longest pattern which matches an input string is always chosen.
89 * For equal-length patterns, the first occurring in the rules list is chosen.
90 * INITIAL is the starting state, to which all non-conditional rules apply.
91 * Exclusive states change parsing rules while the state is active. When in
92 * an exclusive state, only those rules defined for that state apply.
94 * We use exclusive states for quoted strings, extended comments,
95 * and to eliminate parsing troubles for numeric strings.
97 * <xb> bit string literal
98 * <xc> extended C-style comments - thomas 1997-07-12
99 * <xd> delimited identifiers (double-quoted identifiers) - thomas 1997-10-27
100 * <xh> hexadecimal numeric string - thomas 1997-11-16
101 * <xq> standard quoted strings - thomas 1997-07-30
102 * <xqc> standard quoted strings in C - michael
103 * <xe> extended quoted strings (support backslash escape sequences)
104 * <xn> national character quoted strings
105 * <xdolq> $foo$ quoted strings
106 * <xui> quoted identifier with Unicode escapes
107 * <xus> quoted string with Unicode escapes
130 /* Hexadecimal number */
134 /* National character */
137 /* Quoted string that allows backslash escapes */
141 xeoctesc [\\][0-7]{1,3}
142 xehexesc [\\]x[0-9A-Fa-f]{1,2}
144 /* C version of hex number */
145 xch 0[xX][0-9A-Fa-f]*
148 * xqdouble implements embedded quote, ''''
151 xqdouble {quote}{quote}
155 /* $foo$ style quotes ("dollar quoting")
156 * The quoted string starts with $foo$ where "foo" is an optional string
157 * in the form of an identifier, except that it may not contain "$",
158 * and extends to the first occurrence of an identical string.
159 * There is *no* processing of the quoted text.
161 * {dolqfailed} is an error rule to avoid scanner backup when {dolqdelim}
162 * fails to match its trailing "$".
164 dolq_start [A-Za-z\200-\377_]
165 dolq_cont [A-Za-z\200-\377_0-9]
166 dolqdelim \$({dolq_start}{dolq_cont}*)?\$
167 dolqfailed \${dolq_start}{dolq_cont}*
171 * Allows embedded spaces and other special characters into identifiers.
176 xddouble {dquote}{dquote}
179 /* Unicode escapes */
180 /* (The ecpg scanner is not backup-free, so the fail rules in scan.l are not needed here, but could be added if desired.) */
181 uescape [uU][eE][sS][cC][aA][pP][eE]{whitespace}*{quote}[^']{quote}
183 /* Quoted identifier with Unicode escapes */
184 xuistart [uU]&{dquote}
185 xuistop {dquote}({whitespace}*{uescape})?
187 /* Quoted string with Unicode escapes */
188 xusstart [uU]&{quote}
189 xusstop {quote}({whitespace}*{uescape})?
191 /* special stuff for C strings */
195 xdcinside ({xdcqq}|{xdcqdq}|{xdcother})
199 * The "extended comment" syntax closely resembles allowable operator syntax.
200 * The tricky part here is to get lex to recognize a string starting with
201 * slash-star as a comment, when interpreting it as an operator would produce
202 * a longer match --- remember lex will prefer a longer match! Also, if we
203 * have something like plus-slash-star, lex will think this is a 3-character
204 * operator whereas we want to see it as a + operator and a comment start.
205 * The solution is two-fold:
206 * 1. append {op_chars}* to xcstart so that it matches as much text as
207 * {operator} would. Then the tie-breaker (first matching rule of same
208 * length) ensures xcstart wins. We put back the extra stuff with yyless()
209 * in case it contains a star-slash that should terminate the comment.
210 * 2. In the operator rule, check for slash-star within the operator, and
211 * if found throw it back with yyless(). This handles the plus-slash-star
213 * Dash-dash comments have similar interactions with the operator rule.
215 xcstart \/\*{op_chars}*
220 ident_start [A-Za-z\200-\377_]
221 ident_cont [A-Za-z\200-\377_0-9\$]
223 identifier {ident_start}{ident_cont}*
225 array ({ident_cont}|{whitespace}|[\[\]\+\-\*\%\/\(\)\>\.])*
229 * "self" is the set of chars that should be returned as single-character
230 * tokens. "op_chars" is the set of chars that can make up "Op" tokens,
231 * which can be one or more characters long (but if a single-char token
232 * appears in the "self" set, it is not to be returned as an Op). Note
233 * that the sets overlap, but each has some chars that are not in the other.
235 * If you change either set, adjust the character lists appearing in the
236 * rule for "operator"!
238 self [,()\[\].;\:\+\-\*\/\%\^\<\>\=]
239 op_chars [\~\!\@\#\^\&\|\`\?\+\-\*\/\%\<\>\=]
242 /* we no longer allow unary minus in numbers.
243 * instead we pass it separately to parser. there it gets
244 * coerced via doNegate() -- Leon aug 20 1999
246 * {realfail1} and {realfail2} are added to prevent the need for scanner
247 * backup when the {real} rule fails to match completely.
251 decimal (({digit}*\.{digit}+)|({digit}+\.{digit}*))
252 real ({integer}|{decimal})[Ee][-+]?{digit}+
253 realfail1 ({integer}|{decimal})[Ee]
254 realfail2 ({integer}|{decimal})[Ee][-+]
259 * In order to make the world safe for Windows and Mac clients as well as
260 * Unix ones, we accept either \n or \r as a newline. A DOS-style \r\n
261 * sequence will be seen as two successive newlines, but that doesn't cause
262 * any problems. SQL92-style comments, which start with -- and extend to the
263 * next newline, are treated as equivalent to a single whitespace character.
265 * NOTE a fine point: if there is no newline following --, we will absorb
266 * everything to the end of the input as a comment. This is correct. Older
267 * versions of Postgres failed to recognize -- as a comment if the input
268 * did not end with a newline.
270 * XXX perhaps \f (formfeed) should be treated as a newline as well?
272 * XXX if you change the set of whitespace characters, fix ecpg_isspace()
283 comment ("--"{non_newline}*)
285 whitespace ({space}+|{comment})
288 * SQL92 requires at least one newline in the whitespace separating
289 * string literals that are to be concatenated. Silly, but who are we
290 * to argue? Note that {whitespace_with_newline} should not have * after
291 * it, whereas {whitespace} should generally have a * after it...
294 horiz_whitespace ({horiz_space}|{comment})
295 whitespace_with_newline ({horiz_whitespace}*{newline}{whitespace}*)
298 quotestop {quote}{whitespace}*
299 quotecontinue {quote}{whitespace_with_newline}{quote}
300 quotefail {quote}{whitespace}*"-"
302 /* special characters for other dbms */
303 /* we have to react differently in compat mode */
304 informix_special [\$]
308 /* some stuff needed for ecpg */
309 exec [eE][xX][eE][cC]
311 define [dD][eE][fF][iI][nN][eE]
312 include [iI][nN][cC][lL][uU][dD][eE]
313 undef [uU][nN][dD][eE][fF]
315 ifdef [iI][fF][dD][eE][fF]
316 ifndef [iI][fF][nN][dD][eE][fF]
317 else [eE][lL][sS][eE]
318 elif [eE][lL][iI][fF]
319 endif [eE][nN][dD][iI][fF]
321 struct [sS][tT][rR][uU][cC][tT]
323 exec_sql {exec}{space}*{sql}{space}*
324 ipdigit ({digit}|{digit}{digit}|{digit}{digit}{digit})
325 ip {ipdigit}\.{ipdigit}\.{ipdigit}\.{ipdigit}
327 /* we might want to parse all cpp include files */
328 cppinclude {space}*#{include}{space}*
330 /* Take care of cpp lines, they may also be continuated */
331 cppline {space}*#(.*\\{space})*.*{newline}
334 * Dollar quoted strings are totally opaque, and no escaping is done on them.
335 * Other quoted strings must allow some special characters such as single-quote
337 * Embedded single-quotes are implemented both in the SQL standard
338 * style of two adjacent single quotes "''" and in the Postgres/Java style
339 * of escaped-quote "\'".
340 * Other embedded escaped characters are matched explicitly and the leading
341 * backslash is dropped from the string. - thomas 1997-09-24
342 * Note that xcstart must appear before operator, as explained above!
343 * Also whitespace (comment) must appear before operator.
349 /* code to execute during start of each call of yylex() */
353 <SQL>{whitespace} { /* ignore */ }
356 token_start = yytext;
357 state_before = YYSTATE;
360 /* Put back any characters past slash-star; see above */
366 /* Put back any characters past slash-star; see above */
382 <xc>{xcinside} { ECHO; }
383 <xc>{op_chars} { ECHO; }
386 <xc><<EOF>> { mmerror(PARSE_ERROR, ET_FATAL, "unterminated /* comment"); }
389 token_start = yytext;
398 if (literalbuf[strspn(literalbuf, "01") + 1] != '\0')
399 mmerror(PARSE_ERROR, ET_ERROR, "invalid bit string literal");
400 yylval.str = mm_strdup(literalbuf);
405 <xb>{xbinside} { addlit(yytext, yyleng); }
406 <xh>{quotecontinue} |
407 <xb>{quotecontinue} { /* ignore */ }
408 <xb><<EOF>> { mmerror(PARSE_ERROR, ET_FATAL, "unterminated bit string literal"); }
411 token_start = yytext;
420 yylval.str = mm_strdup(literalbuf);
424 <xh><<EOF>> { mmerror(PARSE_ERROR, ET_FATAL, "unterminated hexadecimal string literal"); }
426 /* National character.
427 * Transfer it as-is to the backend.
429 token_start = yytext;
430 state_before = YYSTATE;
435 token_start = yytext;
436 state_before = YYSTATE;
441 token_start = yytext;
442 state_before = YYSTATE;
447 token_start = yytext;
448 state_before = YYSTATE;
453 token_start = yytext;
454 state_before = YYSTATE;
457 addlit(yytext, yyleng);
459 <xq,xqc>{quotestop} |
460 <xq,xqc>{quotefail} {
463 yylval.str = mm_strdup(literalbuf);
470 yylval.str = mm_strdup(literalbuf);
477 yylval.str = mm_strdup(literalbuf);
481 addlit(yytext, yyleng);
483 yylval.str = mm_strdup(literalbuf);
486 <xq,xe,xn,xus>{xqdouble} { addlitchar('\''); }
491 <xq,xqc,xn,xus>{xqinside} { addlit(yytext, yyleng); }
492 <xe>{xeinside} { addlit(yytext, yyleng); }
493 <xe>{xeescape} { addlit(yytext, yyleng); }
494 <xe>{xeoctesc} { addlit(yytext, yyleng); }
495 <xe>{xehexesc} { addlit(yytext, yyleng); }
496 <xq,xqc,xe,xn,xus>{quotecontinue} { /* ignore */ }
498 /* This is only needed for \ just before EOF */
499 addlitchar(yytext[0]);
501 <xq,xqc,xe,xn,xus><<EOF>> { mmerror(PARSE_ERROR, ET_FATAL, "unterminated quoted string"); }
503 /* throw back all but the initial "$" */
505 /* and treat it as {other} */
509 token_start = yytext;
510 dolqstart = mm_strdup(yytext);
513 addlit(yytext, yyleng);
516 if (strcmp(yytext, dolqstart) == 0)
518 addlit(yytext, yyleng);
521 yylval.str = mm_strdup(literalbuf);
527 * When we fail to match $...$ to dolqstart, transfer
528 * the $... part to the output, but put back the final
529 * $ for rescanning. Consider $delim$...$junk$delim$
531 addlit(yytext, yyleng-1);
535 <xdolq>{dolqinside} { addlit(yytext, yyleng); }
536 <xdolq>{dolqfailed} { addlit(yytext, yyleng); }
538 /* single quote or dollar sign */
539 addlitchar(yytext[0]);
541 <xdolq><<EOF>> { base_yyerror("unterminated dollar-quoted string"); }
543 state_before = YYSTATE;
548 state_before = YYSTATE;
551 addlit(yytext, yyleng);
556 mmerror(PARSE_ERROR, ET_ERROR, "zero-length delimited identifier");
557 /* The backend will truncate the identifier here. We do not as it does not change the result. */
558 yylval.str = mm_strdup(literalbuf);
563 yylval.str = mm_strdup(literalbuf);
568 if (literallen == 2) /* "U&" */
569 mmerror(PARSE_ERROR, ET_ERROR, "zero-length delimited identifier");
570 /* The backend will truncate the identifier here. We do not as it does not change the result. */
571 addlit(yytext, yyleng);
572 yylval.str = mm_strdup(literalbuf);
575 <xd,xui>{xddouble} { addlitchar('"'); }
576 <xd,xui>{xdinside} { addlit(yytext, yyleng); }
577 <xd,xdc,xui><<EOF>> { mmerror(PARSE_ERROR, ET_FATAL, "unterminated quoted identifier"); }
579 state_before = YYSTATE;
583 <xdc>{xdcinside} { addlit(yytext, yyleng); }
584 <SQL>{typecast} { return TYPECAST; }
585 <SQL>{informix_special} {
586 /* are we simulating Informix? */
595 * We may find a ';' inside a structure
596 * definition in a TYPE or VAR statement.
597 * This is not an EOL marker.
599 if (yytext[0] == ';' && struct_level == 0)
605 * Check for embedded slash-star or dash-dash; those
606 * are comment starts, so operator must stop there.
607 * Note that slash-star or dash-dash at the first
608 * character will match a prior rule, not this one.
611 char *slashstar = strstr(yytext, "/*");
612 char *dashdash = strstr(yytext, "--");
614 if (slashstar && dashdash)
616 /* if both appear, take the first one */
617 if (slashstar > dashdash)
618 slashstar = dashdash;
621 slashstar = dashdash;
623 nchars = slashstar - yytext;
626 * For SQL compatibility, '+' and '-' cannot be the
627 * last char of a multi-char operator unless the operator
628 * contains chars that are not in SQL operators.
629 * The idea is to lex '=-' as two operators, but not
630 * to forbid operator names like '?-' that could not be
631 * sequences of SQL operators.
634 (yytext[nchars-1] == '+' ||
635 yytext[nchars-1] == '-'))
639 for (ic = nchars-2; ic >= 0; ic--)
641 if (strchr("~!@#^&|`?%", yytext[ic]))
645 break; /* found a char that makes it OK */
646 nchars--; /* else remove the +/-, and check again */
651 /* Strip the unwanted chars from the token */
654 * If what we have left is only one char, and it's
655 * one of the characters matching "self", then
656 * return it as a character token the same way
657 * that the "self" rule would have.
660 strchr(",()[].;:+-*/%^<>=", yytext[0]))
664 /* Convert "!=" operator to "<>" for compatibility */
665 if (strcmp(yytext, "!=") == 0)
666 yylval.str = mm_strdup("<>");
668 yylval.str = mm_strdup(yytext);
672 yylval.ival = atol(yytext+1);
680 val = strtol((char *)yytext, &endptr,10);
681 if (*endptr != '\0' || errno == ERANGE
682 #ifdef HAVE_LONG_INT_64
683 /* if long > 32 bits, check for overflow of int4 */
684 || val != (long) ((int32) val)
689 yylval.str = mm_strdup(yytext);
696 yylval.str = mm_strdup(yytext);
700 yylval.str = mm_strdup(yytext);
704 yylval.str = mm_strdup(yytext);
709 yylval.str = mm_strdup(yytext);
714 yylval.str = mm_strdup(yytext);
717 <SQL>:{identifier}((("->"|\.){identifier})|(\[{array}\]))* {
718 yylval.str = mm_strdup(yytext+1);
722 const ScanKeyword *keyword;
726 /* Is it an SQL/ECPG keyword? */
727 keyword = ScanECPGKeywordLookup(yytext);
729 return keyword->value;
731 /* Is it a C keyword? */
732 keyword = ScanCKeywordLookup(yytext);
734 return keyword->value;
737 * None of the above. Return it as an identifier.
739 * The backend will attempt to truncate and case-fold
740 * the identifier, but I see no good reason for ecpg
741 * to do so; that's just another way that ecpg could get
742 * out of step with the backend.
744 yylval.str = mm_strdup(yytext);
748 <SQL>{other} { return yytext[0]; }
749 <C>{exec_sql} { BEGIN(SQL); return SQL_START; }
750 <C>{informix_special} {
751 /* are we simulating Informix? */
760 <C>{ccomment} { ECHO; }
765 yylval.ival = strtoul((char *)yytext,&endptr,16);
766 if (*endptr != '\0' || errno == ERANGE)
769 yylval.str = mm_strdup(yytext);
781 yylval.str = mm_strdup(yytext);
786 yylval.str = mm_strdup(yytext);
790 const ScanKeyword *keyword;
792 /* Informix uses SQL defines only in SQL space */
793 /* however, some defines have to be taken care of for compatibility */
794 if ((!INFORMIX_MODE || !isinformixdefine()) && !isdefine())
796 keyword = ScanCKeywordLookup(yytext);
798 return keyword->value;
801 yylval.str = mm_strdup(yytext);
806 <C>":" { return(':'); }
807 <C>";" { return(';'); }
808 <C>"," { return(','); }
809 <C>"*" { return('*'); }
810 <C>"%" { return('%'); }
811 <C>"/" { return('/'); }
812 <C>"+" { return('+'); }
813 <C>"-" { return('-'); }
814 <C>"(" { return('('); }
815 <C>")" { return(')'); }
816 <C,xskip>{space} { ECHO; }
817 <C>\{ { return('{'); }
818 <C>\} { return('}'); }
819 <C>\[ { return('['); }
820 <C>\] { return(']'); }
821 <C>\= { return('='); }
822 <C>"->" { return(S_MEMBER); }
823 <C>">>" { return(S_RSHIFT); }
824 <C>"<<" { return(S_LSHIFT); }
825 <C>"||" { return(S_OR); }
826 <C>"&&" { return(S_AND); }
827 <C>"++" { return(S_INC); }
828 <C>"--" { return(S_DEC); }
829 <C>"==" { return(S_EQUAL); }
830 <C>"!=" { return(S_NEQUAL); }
831 <C>"+=" { return(S_ADD); }
832 <C>"-=" { return(S_SUB); }
833 <C>"*=" { return(S_MUL); }
834 <C>"/=" { return(S_DIV); }
835 <C>"%=" { return(S_MOD); }
836 <C>"->*" { return(S_MEMPOINT); }
837 <C>".*" { return(S_DOTPOINT); }
838 <C>{other} { return S_ANYTHING; }
839 <C>{exec_sql}{define}{space}* { BEGIN(def_ident); }
840 <C>{informix_special}{define}{space}* {
841 /* are we simulating Informix? */
852 <C>{exec_sql}{undef}{space}* { BEGIN(undef); }
853 <C>{informix_special}{undef}{space}* {
854 /* are we simulating Informix? */
865 <undef>{identifier}{space}*";" {
866 struct _defines *ptr, *ptr2 = NULL;
870 * Skip the ";" and trailing whitespace. Note that yytext
871 * contains at least one non-space character plus the ";"
873 for (i = strlen(yytext)-2;
874 i > 0 && ecpg_isspace(yytext[i]);
880 for (ptr = defines; ptr != NULL; ptr2 = ptr, ptr = ptr->next)
882 if (strcmp(yytext, ptr->old) == 0)
887 ptr2->next = ptr->next;
898 mmerror(PARSE_ERROR, ET_FATAL, "missing identifier in EXEC SQL UNDEF command");
901 <C>{exec_sql}{include}{space}* { BEGIN(incl); }
902 <C>{informix_special}{include}{space}* {
903 /* are we simulating Informix? */
914 <C,xskip>{exec_sql}{ifdef}{space}* { ifcond = TRUE; BEGIN(xcond); }
915 <C,xskip>{informix_special}{ifdef}{space}* {
916 /* are we simulating Informix? */
928 <C,xskip>{exec_sql}{ifndef}{space}* { ifcond = FALSE; BEGIN(xcond); }
929 <C,xskip>{informix_special}{ifndef}{space}* {
930 /* are we simulating Informix? */
942 <C,xskip>{exec_sql}{elif}{space}* { /* pop stack */
943 if ( preproc_tos == 0 ) {
944 mmerror(PARSE_ERROR, ET_FATAL, "missing matching \"EXEC SQL IFDEF\" / \"EXEC SQL IFNDEF\"");
946 else if ( stacked_if_value[preproc_tos].else_branch )
947 mmerror(PARSE_ERROR, ET_FATAL, "missing \"EXEC SQL ENDIF;\"");
951 ifcond = TRUE; BEGIN(xcond);
953 <C,xskip>{informix_special}{elif}{space}* {
954 /* are we simulating Informix? */
957 if (preproc_tos == 0)
958 mmerror(PARSE_ERROR, ET_FATAL, "missing matching \"EXEC SQL IFDEF\" / \"EXEC SQL IFNDEF\"");
959 else if (stacked_if_value[preproc_tos].else_branch)
960 mmerror(PARSE_ERROR, ET_FATAL, "missing \"EXEC SQL ENDIF;\"");
974 <C,xskip>{exec_sql}{else}{space}*";" { /* only exec sql endif pops the stack, so take care of duplicated 'else' */
975 if (stacked_if_value[preproc_tos].else_branch)
976 mmerror(PARSE_ERROR, ET_FATAL, "more than one EXEC SQL ELSE");
979 stacked_if_value[preproc_tos].else_branch = TRUE;
980 stacked_if_value[preproc_tos].condition =
981 (stacked_if_value[preproc_tos-1].condition &&
982 !stacked_if_value[preproc_tos].condition);
984 if (stacked_if_value[preproc_tos].condition)
990 <C,xskip>{informix_special}{else}{space}*";" {
991 /* are we simulating Informix? */
994 if (stacked_if_value[preproc_tos].else_branch)
995 mmerror(PARSE_ERROR, ET_FATAL, "more than one EXEC SQL ELSE");
998 stacked_if_value[preproc_tos].else_branch = TRUE;
999 stacked_if_value[preproc_tos].condition =
1000 (stacked_if_value[preproc_tos-1].condition &&
1001 !stacked_if_value[preproc_tos].condition);
1003 if (stacked_if_value[preproc_tos].condition)
1012 return (S_ANYTHING);
1015 <C,xskip>{exec_sql}{endif}{space}*";" {
1016 if (preproc_tos == 0)
1017 mmerror(PARSE_ERROR, ET_FATAL, "unmatched EXEC SQL ENDIF");
1021 if (stacked_if_value[preproc_tos].condition)
1026 <C,xskip>{informix_special}{endif}{space}*";" {
1027 /* are we simulating Informix? */
1030 if (preproc_tos == 0)
1031 mmerror(PARSE_ERROR, ET_FATAL, "unmatched EXEC SQL ENDIF");
1035 if (stacked_if_value[preproc_tos].condition)
1043 return (S_ANYTHING);
1047 <xskip>{other} { /* ignore */ }
1049 <xcond>{identifier}{space}*";" {
1050 if (preproc_tos >= MAX_NESTED_IF-1)
1051 mmerror(PARSE_ERROR, ET_FATAL, "too many nested EXEC SQL IFDEF conditions");
1054 struct _defines *defptr;
1058 * Skip the ";" and trailing whitespace. Note that yytext
1059 * contains at least one non-space character plus the ";"
1061 for (i = strlen(yytext)-2;
1062 i > 0 && ecpg_isspace(yytext[i]);
1067 for (defptr = defines;
1068 defptr != NULL && strcmp(yytext, defptr->old) != 0;
1069 defptr = defptr->next);
1072 stacked_if_value[preproc_tos].else_branch = FALSE;
1073 stacked_if_value[preproc_tos].condition =
1074 (defptr ? ifcond : !ifcond) && stacked_if_value[preproc_tos-1].condition;
1077 if (stacked_if_value[preproc_tos].condition)
1084 mmerror(PARSE_ERROR, ET_FATAL, "missing identifier in EXEC SQL IFDEF command");
1087 <def_ident>{identifier} {
1088 old = mm_strdup(yytext);
1092 <def_ident>{other}|\n {
1093 mmerror(PARSE_ERROR, ET_FATAL, "missing identifier in EXEC SQL DEFINE command");
1097 struct _defines *ptr, *this;
1099 for (ptr = defines; ptr != NULL; ptr = ptr->next)
1101 if (strcmp(old, ptr->old) == 0)
1104 ptr->new = mm_strdup(literalbuf);
1109 this = (struct _defines *) mm_alloc(sizeof(struct _defines));
1111 /* initial definition */
1113 this->new = mm_strdup(literalbuf);
1114 this->next = defines;
1121 <def>[^;] { addlit(yytext, yyleng); }
1122 <incl>\<[^\>]+\>{space}*";"? { parse_include(); }
1123 <incl>{dquote}{xdinside}{dquote}{space}*";"? { parse_include(); }
1124 <incl>[^;\<\>\"]+";" { parse_include(); }
1126 mmerror(PARSE_ERROR, ET_FATAL, "syntax error in EXEC SQL INCLUDE command");
1131 if (yy_buffer == NULL)
1133 if ( preproc_tos > 0 )
1136 mmerror(PARSE_ERROR, ET_FATAL, "missing \"EXEC SQL ENDIF;\"");
1142 struct _yy_buffer *yb = yy_buffer;
1144 struct _defines *ptr;
1146 for (ptr = defines; ptr; ptr = ptr->next)
1147 if (ptr->used == yy_buffer)
1156 yy_delete_buffer( YY_CURRENT_BUFFER );
1157 yy_switch_to_buffer(yy_buffer->buffer);
1159 yylineno = yy_buffer->lineno;
1161 /* We have to output the filename only if we change files here */
1162 i = strcmp(input_filename, yy_buffer->filename);
1164 free(input_filename);
1165 input_filename = yy_buffer->filename;
1167 yy_buffer = yy_buffer->next;
1171 output_line_number();
1175 <INITIAL>{other}|\n { mmerror(PARSE_ERROR, ET_FATAL, "internal error: unreachable state; please report this to <pgsql-bugs@postgresql.org>"); }
1185 stacked_if_value[preproc_tos].condition = ifcond;
1186 stacked_if_value[preproc_tos].else_branch = FALSE;
1188 /* initialize literal buffer to a reasonable but expansible size */
1189 if (literalbuf == NULL)
1191 literalalloc = 1024;
1192 literalbuf = (char *) malloc(literalalloc);
1200 addlit(char *ytext, int yleng)
1202 /* enlarge buffer if needed */
1203 if ((literallen+yleng) >= literalalloc)
1207 while ((literallen+yleng) >= literalalloc);
1208 literalbuf = (char *) realloc(literalbuf, literalalloc);
1210 /* append new data, add trailing null */
1211 memcpy(literalbuf+literallen, ytext, yleng);
1212 literallen += yleng;
1213 literalbuf[literallen] = '\0';
1217 addlitchar(unsigned char ychar)
1219 /* enlarge buffer if needed */
1220 if ((literallen+1) >= literalalloc)
1223 literalbuf = (char *) realloc(literalbuf, literalalloc);
1225 /* append new data, add trailing null */
1226 literalbuf[literallen] = ychar;
1228 literalbuf[literallen] = '\0';
1234 /* got the include file name */
1235 struct _yy_buffer *yb;
1236 struct _include_path *ip;
1237 char inc_file[MAXPGPATH];
1240 yb = mm_alloc(sizeof(struct _yy_buffer));
1242 yb->buffer = YY_CURRENT_BUFFER;
1243 yb->lineno = yylineno;
1244 yb->filename = input_filename;
1245 yb->next = yy_buffer;
1250 * skip the ";" if there is one and trailing whitespace. Note that
1251 * yytext contains at least one non-space character plus the ";"
1253 for (i = strlen(yytext)-2;
1254 i > 0 && ecpg_isspace(yytext[i]);
1258 if (yytext[i] == ';')
1265 /* If file name is enclosed in '"' remove these and look only in '.' */
1266 /* Informix does look into all include paths though, except filename starts with '/' */
1267 if (yytext[0] == '"' && yytext[i] == '"' &&
1268 ((compat != ECPG_COMPAT_INFORMIX && compat != ECPG_COMPAT_INFORMIX_SE) || yytext[1] == '/'))
1271 memmove(yytext, yytext+1, strlen(yytext));
1273 strncpy(inc_file, yytext, sizeof(inc_file));
1274 yyin = fopen(inc_file, "r");
1277 if (strcmp(inc_file + strlen(inc_file) - 2, ".h"))
1279 strcat(inc_file, ".h");
1280 yyin = fopen(inc_file, "r");
1287 if ((yytext[0] == '"' && yytext[i] == '"') || (yytext[0] == '<' && yytext[i] == '>'))
1290 memmove(yytext, yytext+1, strlen(yytext));
1293 for (ip = include_paths; yyin == NULL && ip != NULL; ip = ip->next)
1295 if (strlen(ip->path) + strlen(yytext) + 3 > MAXPGPATH)
1297 fprintf(stderr, _("Error: include path \"%s/%s\" is too long on line %d, skipping\n"), ip->path, yytext, yylineno);
1300 snprintf (inc_file, sizeof(inc_file), "%s/%s", ip->path, yytext);
1301 yyin = fopen(inc_file, "r");
1304 if (strcmp(inc_file + strlen(inc_file) - 2, ".h"))
1306 strcat(inc_file, ".h");
1307 yyin = fopen( inc_file, "r" );
1313 mmerror(NO_INCLUDE_FILE, ET_FATAL, "could not open include file \"%s\" on line %d", yytext, yylineno);
1315 input_filename = mm_strdup(inc_file);
1316 yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE ));
1318 output_line_number();
1324 * ecpg_isspace() --- return TRUE if flex scanner considers char whitespace
1327 ecpg_isspace(char ch)
1338 static bool isdefine(void)
1340 struct _defines *ptr;
1342 /* is it a define? */
1343 for (ptr = defines; ptr; ptr = ptr->next)
1345 if (strcmp(yytext, ptr->old) == 0 && ptr->used == NULL)
1347 struct _yy_buffer *yb;
1349 yb = mm_alloc(sizeof(struct _yy_buffer));
1351 yb->buffer = YY_CURRENT_BUFFER;
1352 yb->lineno = yylineno;
1353 yb->filename = mm_strdup(input_filename);
1354 yb->next = yy_buffer;
1356 ptr->used = yy_buffer = yb;
1358 yy_scan_string(ptr->new);
1366 static bool isinformixdefine(void)
1368 const char *new = NULL;
1370 if (strcmp(yytext, "dec_t") == 0)
1372 else if (strcmp(yytext, "intrvl_t") == 0)
1374 else if (strcmp(yytext, "dtime_t") == 0)
1379 struct _yy_buffer *yb;
1381 yb = mm_alloc(sizeof(struct _yy_buffer));
1383 yb->buffer = YY_CURRENT_BUFFER;
1384 yb->lineno = yylineno;
1385 yb->filename = mm_strdup(input_filename);
1386 yb->next = yy_buffer;
1389 yy_scan_string(new);
1397 * Called before any actual parsing is done
1400 scanner_init(const char *str)
1402 Size slen = strlen(str);
1405 * Might be left over after ereport()
1407 if (YY_CURRENT_BUFFER)
1408 yy_delete_buffer(YY_CURRENT_BUFFER);
1411 * Make a scan buffer with special termination needed by flex.
1413 scanbuf = mm_alloc(slen + 2);
1414 memcpy(scanbuf, str, slen);
1415 scanbuf[slen] = scanbuf[slen + 1] = YY_END_OF_BUFFER_CHAR;
1416 scanbufhandle = yy_scan_buffer(scanbuf, slen + 2);
1418 /* initialize literal buffer to a reasonable but expansible size */
1420 literalbuf = (char *) mm_alloc(literalalloc);
1428 * Called after parsing is done to clean up after scanner_init()
1431 scanner_finish(void)
1433 yy_delete_buffer(scanbufhandle);