]> granicus.if.org Git - postgresql/blob - src/interfaces/ecpg/preproc/pgc.l
Update copyright for the year 2010.
[postgresql] / src / interfaces / ecpg / preproc / pgc.l
1 %{
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-2010, PostgreSQL Global Development Group
11  * Portions Copyright (c) 1994, Regents of the University of California
12  *
13  *
14  * IDENTIFICATION
15  *        $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/pgc.l,v 1.171 2010/01/02 16:58:11 momjian Exp $
16  *
17  *-------------------------------------------------------------------------
18  */
19 #include "postgres_fe.h"
20
21 #include <ctype.h>
22 #include <sys/types.h>
23 #include <limits.h>
24
25 #include "extern.h"
26
27 extern YYSTYPE yylval;
28
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;
32 static char *scanbuf;
33
34 /*
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.
39  */
40 static char    *literalbuf = NULL;              /* expandable buffer */
41 static int              literallen;                             /* actual current length */
42 static int              literalalloc;                   /* current allocated buffer size */
43
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);
51
52 char *token_start;
53 int state_before;
54
55 struct _yy_buffer 
56
57         YY_BUFFER_STATE         buffer;
58         long                            lineno;
59         char                            *filename;
60         struct _yy_buffer       *next;
61 } *yy_buffer = NULL;
62
63 static char *old;
64
65 #define MAX_NESTED_IF 128
66 static short preproc_tos;
67 static short ifcond;
68 static struct _if_value 
69 {
70         short condition;
71         short else_branch;
72 } stacked_if_value[MAX_NESTED_IF];
73
74 %}
75
76 %option 8bit
77 %option never-interactive
78 %option nodefault
79 %option noinput
80 %option noyywrap
81
82 %option yylineno
83
84 %x C SQL incl def def_ident undef 
85
86 /*
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.
93  *
94  * We use exclusive states for quoted strings, extended comments,
95  * and to eliminate parsing troubles for numeric strings.
96  * Exclusive states:
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
108  */
109
110 %x xb
111 %x xc
112 %x xd
113 %x xdc
114 %x xh
115 %x xe
116 %x xn
117 %x xq
118 %x xqc
119 %x xdolq
120 %x xcond
121 %x xskip
122 %x xui
123 %x xus
124
125 /* Bit string
126  */
127 xbstart                 [bB]{quote}
128 xbinside                [^']*
129
130 /* Hexadecimal number */
131 xhstart                 [xX]{quote}
132 xhinside                [^']*
133
134 /* National character */
135 xnstart                 [nN]{quote}
136
137 /* Quoted string that allows backslash escapes */
138 xestart                 [eE]{quote}
139 xeinside                [^\\']+
140 xeescape                [\\][^0-7]
141 xeoctesc                [\\][0-7]{1,3}
142 xehexesc                [\\]x[0-9A-Fa-f]{1,2}
143
144 /* C version of hex number */
145 xch                             0[xX][0-9A-Fa-f]*
146
147 /* Extended quote
148  * xqdouble implements embedded quote, ''''
149  */
150 xqstart                 {quote}
151 xqdouble                {quote}{quote}
152 xqcquote                [\\]{quote}
153 xqinside                [^']+
154
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.
160  *
161  * {dolqfailed} is an error rule to avoid scanner backup when {dolqdelim}
162  * fails to match its trailing "$".
163  */
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}*
168 dolqinside              [^$]+
169
170 /* Double quote
171  * Allows embedded spaces and other special characters into identifiers.
172  */
173 dquote                  \"
174 xdstart                 {dquote}
175 xdstop                  {dquote}
176 xddouble                {dquote}{dquote}
177 xdinside                [^"]+
178
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}
182
183 /* Quoted identifier with Unicode escapes */
184 xuistart                [uU]&{dquote}
185 xuistop                 {dquote}({whitespace}*{uescape})?
186
187 /* Quoted string with Unicode escapes */
188 xusstart                [uU]&{quote}
189 xusstop                 {quote}({whitespace}*{uescape})?
190
191 /* special stuff for C strings */
192 xdcqq                   \\\\
193 xdcqdq                  \\\"
194 xdcother                [^"]
195 xdcinside               ({xdcqq}|{xdcqdq}|{xdcother})
196
197 /* C-style comments
198  *
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
212  *        problem.
213  * Dash-dash comments have similar interactions with the operator rule.
214  */
215 xcstart                 \/\*{op_chars}*
216 xcstop                  \*+\/
217 xcinside                [^*/]+
218
219 digit                   [0-9]
220 ident_start             [A-Za-z\200-\377_]
221 ident_cont              [A-Za-z\200-\377_0-9\$]
222
223 identifier              {ident_start}{ident_cont}*
224
225 array                   ({ident_cont}|{whitespace}|[\[\]\+\-\*\%\/\(\)\>\.])*
226 typecast                "::"
227
228 /*
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.
234  *
235  * If you change either set, adjust the character lists appearing in the
236  * rule for "operator"!
237  */
238 self                    [,()\[\].;\:\+\-\*\/\%\^\<\>\=]
239 op_chars                [\~\!\@\#\^\&\|\`\?\+\-\*\/\%\<\>\=]
240 operator                {op_chars}+
241
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
245  *
246  * {realfail1} and {realfail2} are added to prevent the need for scanner
247  * backup when the {real} rule fails to match completely.
248  */
249
250 integer                 {digit}+
251 decimal                 (({digit}*\.{digit}+)|({digit}+\.{digit}*))
252 real                    ({integer}|{decimal})[Ee][-+]?{digit}+
253 realfail1               ({integer}|{decimal})[Ee]
254 realfail2               ({integer}|{decimal})[Ee][-+]
255
256 param                   \${integer}
257
258 /*
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.
264  *
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.
269  *
270  * XXX perhaps \f (formfeed) should be treated as a newline as well?
271  *
272  * XXX if you change the set of whitespace characters, fix ecpg_isspace()
273  * to agree.
274  */
275
276 ccomment                "//".*\n
277
278 space                   [ \t\n\r\f]
279 horiz_space             [ \t\f]
280 newline                 [\n\r]
281 non_newline             [^\n\r]
282
283 comment                 ("--"{non_newline}*)
284
285 whitespace              ({space}+|{comment})
286
287 /*
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...
292  */
293
294 horiz_whitespace        ({horiz_space}|{comment})
295 whitespace_with_newline ({horiz_whitespace}*{newline}{whitespace}*)
296
297 quote                   '
298 quotestop               {quote}{whitespace}*
299 quotecontinue   {quote}{whitespace_with_newline}{quote}
300 quotefail               {quote}{whitespace}*"-"
301
302 /* special characters for other dbms */
303 /* we have to react differently in compat mode */
304 informix_special        [\$]
305
306 other                   .
307
308 /* some stuff needed for ecpg */
309 exec                    [eE][xX][eE][cC]
310 sql                             [sS][qQ][lL]
311 define                  [dD][eE][fF][iI][nN][eE]
312 include                 [iI][nN][cC][lL][uU][dD][eE]
313 undef                   [uU][nN][dD][eE][fF]
314
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]
320
321 struct                  [sS][tT][rR][uU][cC][tT]
322
323 exec_sql                {exec}{space}*{sql}{space}*
324 ipdigit                 ({digit}|{digit}{digit}|{digit}{digit}{digit})
325 ip                              {ipdigit}\.{ipdigit}\.{ipdigit}\.{ipdigit}
326
327 /* we might want to parse all cpp include files */
328 cppinclude              {space}*#{include}{space}*
329
330 /* Take care of cpp lines, they may also be continuated */
331 cppline                 {space}*#(.*\\{space})*.*{newline}
332
333 /*
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
336  *      and newline.
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.
344  */
345
346 %%
347
348 %{
349                 /* code to execute during start of each call of yylex() */
350                 token_start = NULL;
351 %}
352
353 <SQL>{whitespace}       { /* ignore */ }
354
355 <C,SQL>{xcstart}                {
356                                         token_start = yytext;
357                                         state_before = YYSTATE;
358                                         xcdepth = 0;
359                                         BEGIN(xc);
360                                         /* Put back any characters past slash-star; see above */
361                                         yyless(2);
362                                         fputs("/*", yyout);
363                                 }
364 <xc>{xcstart}   {
365                                         xcdepth++;
366                                         /* Put back any characters past slash-star; see above */
367                                         yyless(2);
368                                         fputs("/*", yyout);
369                                 }
370
371 <xc>{xcstop}    {
372                                         ECHO;
373                                         if (xcdepth <= 0)
374                                         {
375                                                 BEGIN(state_before);
376                                                 token_start = NULL;
377                                         }
378                                         else
379                                                 xcdepth--;
380                                 }
381
382 <xc>{xcinside}  { ECHO; }
383 <xc>{op_chars}  { ECHO; }
384 <xc>\*+                 { ECHO; }
385
386 <xc><<EOF>>             { mmerror(PARSE_ERROR, ET_FATAL, "unterminated /* comment"); }
387
388 <SQL>{xbstart}  {
389                                         token_start = yytext;
390                                         BEGIN(xb);
391                                         startlit();
392                                         addlitchar('b');
393                                 }
394 <xb>{quotestop} |
395 <xb>{quotefail} {
396                                         yyless(1);
397                                         BEGIN(SQL);
398                                         if (literalbuf[strspn(literalbuf, "01") + 1] != '\0')
399                                                 mmerror(PARSE_ERROR, ET_ERROR, "invalid bit string literal");
400                                         yylval.str = mm_strdup(literalbuf);
401                                         return BCONST;
402                                 }
403
404 <xh>{xhinside}  |
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"); }
409
410 <SQL>{xhstart}  {
411                                         token_start = yytext;
412                                         BEGIN(xh);
413                                         startlit();
414                                         addlitchar('x');
415                                 }
416 <xh>{quotestop} |
417 <xh>{quotefail}         {
418                                 yyless(1);
419                                 BEGIN(SQL);
420                                 yylval.str = mm_strdup(literalbuf);
421                                 return XCONST;
422                         }
423
424 <xh><<EOF>>             { mmerror(PARSE_ERROR, ET_FATAL, "unterminated hexadecimal string literal"); }
425 <SQL>{xnstart}              {
426                                 /* National character.
427                                  * Transfer it as-is to the backend.
428                                  */
429                                 token_start = yytext;
430                                 state_before = YYSTATE;
431                                 BEGIN(xn);
432                                 startlit();
433                         }
434 <C>{xqstart}    {
435                                 token_start = yytext;
436                                 state_before = YYSTATE;
437                                 BEGIN(xqc);
438                                 startlit();
439                         }
440 <SQL>{xqstart}  {
441                                 token_start = yytext;
442                                 state_before = YYSTATE;
443                                 BEGIN(xq);
444                                 startlit();
445                         }
446 <SQL>{xestart}  {
447                                 token_start = yytext;
448                                 state_before = YYSTATE;
449                                 BEGIN(xe);
450                                 startlit();
451                         }
452 <SQL>{xusstart} {
453                                 token_start = yytext;
454                                 state_before = YYSTATE;
455                                 BEGIN(xus);
456                                 startlit();
457                                 addlit(yytext, yyleng);
458                         }
459 <xq,xqc>{quotestop} |
460 <xq,xqc>{quotefail} {
461                                 yyless(1);
462                                 BEGIN(state_before);
463                                 yylval.str = mm_strdup(literalbuf);
464                                 return SCONST;
465                         }
466 <xe>{quotestop} |
467 <xe>{quotefail} {
468                                 yyless(1);
469                                 BEGIN(state_before);
470                                 yylval.str = mm_strdup(literalbuf);
471                                 return ECONST;
472                         }
473 <xn>{quotestop} |
474 <xn>{quotefail} {
475                                 yyless(1);
476                                 BEGIN(state_before);
477                                 yylval.str = mm_strdup(literalbuf);
478                                 return NCONST;
479                         }
480 <xus>{xusstop} {
481                                 addlit(yytext, yyleng);
482                                 BEGIN(state_before);
483                                 yylval.str = mm_strdup(literalbuf);
484                                 return UCONST;
485                         }
486 <xq,xe,xn,xus>{xqdouble}        { addlitchar('\''); }
487 <xqc>{xqcquote}         {
488                                 addlitchar('\\');
489                                 addlitchar('\'');
490                         }
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 */ }
497 <xe>.                   {
498                            /* This is only needed for \ just before EOF */
499                            addlitchar(yytext[0]);
500                         }
501 <xq,xqc,xe,xn,xus><<EOF>>       { mmerror(PARSE_ERROR, ET_FATAL, "unterminated quoted string"); }
502 <SQL>{dolqfailed}       {
503                                 /* throw back all but the initial "$" */
504                                 yyless(1);
505                                 /* and treat it as {other} */
506                                 return yytext[0];       
507                         }
508 <SQL>{dolqdelim}        {
509                                 token_start = yytext;
510                                 dolqstart = mm_strdup(yytext);
511                                 BEGIN(xdolq);
512                                 startlit();
513                                 addlit(yytext, yyleng);
514                         }
515 <xdolq>{dolqdelim}      {
516                                 if (strcmp(yytext, dolqstart) == 0)
517                                 {
518                                         addlit(yytext, yyleng);
519                                         free(dolqstart);
520                                         BEGIN(SQL);
521                                         yylval.str = mm_strdup(literalbuf);
522                                         return DOLCONST;
523                                 }
524                                 else
525                                 {
526                                 /*
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$
530                                  */
531                                 addlit(yytext, yyleng-1);
532                                 yyless(yyleng-1);
533                                 }
534                         }
535 <xdolq>{dolqinside}     { addlit(yytext, yyleng); }
536 <xdolq>{dolqfailed}     { addlit(yytext, yyleng); }
537 <xdolq>{other}          {
538                                 /* single quote or dollar sign */
539                                 addlitchar(yytext[0]);
540                         }
541 <xdolq><<EOF>>          { base_yyerror("unterminated dollar-quoted string"); }
542 <SQL>{xdstart}          {
543                                                 state_before = YYSTATE;
544                                                 BEGIN(xd);
545                                                 startlit();
546                                         }
547 <SQL>{xuistart}         {
548                                                 state_before = YYSTATE;
549                                                 BEGIN(xui);
550                                                 startlit();
551                                                 addlit(yytext, yyleng);
552                                         }
553 <xd>{xdstop}            {
554                                                 BEGIN(state_before);
555                                                 if (literallen == 0)
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);
559                                                 return CSTRING;
560                                         }
561 <xdc>{xdstop}           {
562                                                 BEGIN(state_before);
563                                                 yylval.str = mm_strdup(literalbuf);
564                                                 return CSTRING;
565                                         }
566 <xui>{xuistop}          {
567                                                 BEGIN(state_before);
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);
573                                                 return UIDENT;
574                                         }
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"); }
578 <C,SQL>{xdstart}        {
579                                                 state_before = YYSTATE;
580                                                 BEGIN(xdc);
581                                                 startlit();
582                                         }
583 <xdc>{xdcinside}        { addlit(yytext, yyleng); }
584 <SQL>{typecast}         { return TYPECAST; }
585 <SQL>{informix_special} {
586                           /* are we simulating Informix? */
587                                 if (INFORMIX_MODE)
588                                 {
589                                         unput(':');
590                                 }
591                                 else
592                                         return yytext[0];
593                                 }
594 <SQL>{self}                     { /*
595                                            * We may find a ';' inside a structure
596                                            * definition in a TYPE or VAR statement.
597                                            * This is not an EOL marker.
598                                            */
599                                           if (yytext[0] == ';' && struct_level == 0)
600                                                  BEGIN(C);
601                                           return yytext[0];
602                                         }
603 <SQL>{operator}         {
604                                                 /*
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.
609                                                  */
610                                                 int             nchars = yyleng;
611                                                 char   *slashstar = strstr(yytext, "/*");
612                                                 char   *dashdash = strstr(yytext, "--");
613
614                                                 if (slashstar && dashdash)
615                                                 {
616                                                         /* if both appear, take the first one */
617                                                         if (slashstar > dashdash)
618                                                                 slashstar = dashdash;
619                                                 }
620                                                 else if (!slashstar)
621                                                         slashstar = dashdash;
622                                                 if (slashstar)
623                                                         nchars = slashstar - yytext;
624
625                                                 /*
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.
632                                                  */
633                                                 while (nchars > 1 &&
634                                                            (yytext[nchars-1] == '+' ||
635                                                                 yytext[nchars-1] == '-'))
636                                                 {
637                                                         int             ic;
638
639                                                         for (ic = nchars-2; ic >= 0; ic--)
640                                                         {
641                                                                 if (strchr("~!@#^&|`?%", yytext[ic]))
642                                                                         break;
643                                                         }
644                                                         if (ic >= 0)
645                                                                 break; /* found a char that makes it OK */
646                                                         nchars--; /* else remove the +/-, and check again */
647                                                 }
648
649                                                 if (nchars < yyleng)
650                                                 {
651                                                         /* Strip the unwanted chars from the token */
652                                                         yyless(nchars);
653                                                         /*
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.
658                                                          */
659                                                         if (nchars == 1 &&
660                                                                 strchr(",()[].;:+-*/%^<>=", yytext[0]))
661                                                                 return yytext[0];
662                                                 }
663
664                                                 /* Convert "!=" operator to "<>" for compatibility */
665                                                 if (strcmp(yytext, "!=") == 0)
666                                                         yylval.str = mm_strdup("<>");
667                                                 else
668                                                         yylval.str = mm_strdup(yytext);
669                                                 return Op;
670                                         }
671 <SQL>{param}            {
672                                                 yylval.ival = atol(yytext+1);
673                                                 return PARAM;
674                                         }
675 <C,SQL>{integer}        {
676                                                 long val;
677                                                 char* endptr;
678
679                                                 errno = 0;
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)
685 #endif
686                                                         )
687                                                 {
688                                                         errno = 0;
689                                                         yylval.str = mm_strdup(yytext);
690                                                         return FCONST;
691                                                 }
692                                                 yylval.ival = val;
693                                                 return ICONST;
694                                         }
695 <SQL>{ip}                       {
696                                                 yylval.str = mm_strdup(yytext);
697                                                 return IP;
698                                 }
699 <C,SQL>{decimal}        {
700                                                 yylval.str = mm_strdup(yytext);
701                                                 return FCONST;
702                         }
703 <C,SQL>{real}           {
704                                                 yylval.str = mm_strdup(yytext);
705                                                 return FCONST;
706                         }
707 <SQL>{realfail1}        {
708                                                 yyless(yyleng-1);
709                                                 yylval.str = mm_strdup(yytext);
710                                                 return FCONST;
711                                         }
712 <SQL>{realfail2}        {
713                                                 yyless(yyleng-2);
714                                                 yylval.str = mm_strdup(yytext);
715                                                 return FCONST;
716                                         }
717 <SQL>:{identifier}((("->"|\.){identifier})|(\[{array}\]))*      {
718                                                 yylval.str = mm_strdup(yytext+1);
719                                                 return(CVARIABLE);
720                                         }
721 <SQL>{identifier}       {
722                                                 const ScanKeyword    *keyword;
723                                                 
724                                                 if (!isdefine())
725                                                 {
726                                                         /* Is it an SQL/ECPG keyword? */
727                                                         keyword = ScanECPGKeywordLookup(yytext);
728                                                         if (keyword != NULL)
729                                                                 return keyword->value;
730
731                                                         /* Is it a C keyword? */
732                                                         keyword = ScanCKeywordLookup(yytext);
733                                                         if (keyword != NULL)
734                                                                 return keyword->value;
735
736                                                         /*
737                                                          * None of the above.  Return it as an identifier.
738                                                          *
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.
743                                                          */
744                                                         yylval.str = mm_strdup(yytext);
745                                                         return IDENT;
746                                                 }
747                                         }
748 <SQL>{other}            { return yytext[0]; }
749 <C>{exec_sql}           { BEGIN(SQL); return SQL_START; }
750 <C>{informix_special}   { 
751                                                 /* are we simulating Informix? */
752                                                 if (INFORMIX_MODE)
753                                                 {
754                                                         BEGIN(SQL);
755                                                         return SQL_START;
756                                                 }
757                                                 else
758                                                         return S_ANYTHING;
759                                          }
760 <C>{ccomment}           { ECHO; }
761 <C>{xch}                        {
762                                                 char* endptr;
763
764                                                 errno = 0;
765                                                 yylval.ival = strtoul((char *)yytext,&endptr,16);
766                                                 if (*endptr != '\0' || errno == ERANGE)
767                                                 {
768                                                         errno = 0;
769                                                         yylval.str = mm_strdup(yytext);
770                                                         return SCONST;
771                                                 }
772                                                 return ICONST;
773                                         }
774 <C>{cppinclude}         {
775                                                 if (system_includes)
776                                                 {
777                                                         BEGIN(incl);
778                                                 }
779                                                 else
780                                                 {
781                                                         yylval.str = mm_strdup(yytext);
782                                                         return(CPP_LINE);
783                                                 }
784                                         }
785 <C,SQL>{cppline}        {
786                                                 yylval.str = mm_strdup(yytext);
787                                                 return(CPP_LINE);
788                                         }
789 <C>{identifier}         {
790                                                 const ScanKeyword               *keyword;
791                                                         
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())
795                                                 {
796                                                         keyword = ScanCKeywordLookup(yytext);
797                                                         if (keyword != NULL)
798                                                                 return keyword->value;
799                                                         else
800                                                         {
801                                                                 yylval.str = mm_strdup(yytext);
802                                                                 return IDENT;
803                                                         }
804                                                 }
805                                         }
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? */
842                                                 if (INFORMIX_MODE)
843                                                 {
844                                                         BEGIN(def_ident);
845                                                 }
846                                                 else
847                                                 {
848                                                         yyless(1);
849                                                         return (S_ANYTHING);
850                                                 }
851                                         }
852 <C>{exec_sql}{undef}{space}*            { BEGIN(undef); }
853 <C>{informix_special}{undef}{space}*    {
854                                                 /* are we simulating Informix? */
855                                                 if (INFORMIX_MODE)
856                                                 {
857                                                         BEGIN(undef);
858                                                 }
859                                                 else
860                                                 {
861                                                         yyless(1);
862                                                         return (S_ANYTHING);
863                                                 }
864                                         }
865 <undef>{identifier}{space}*";" {
866                                         struct _defines *ptr, *ptr2 = NULL;
867                                         int i;
868
869                                         /*
870                                          *      Skip the ";" and trailing whitespace. Note that yytext
871                                          *      contains at least one non-space character plus the ";"
872                                          */
873                                         for (i = strlen(yytext)-2;
874                                                  i > 0 && ecpg_isspace(yytext[i]);
875                                                  i-- )
876                                                 ;
877                                         yytext[i+1] = '\0';
878
879
880                                         for (ptr = defines; ptr != NULL; ptr2 = ptr, ptr = ptr->next)
881                                         {
882                                                 if (strcmp(yytext, ptr->old) == 0)
883                                                 {
884                                                         if (ptr2 == NULL)
885                                                                 defines = ptr->next;
886                                                         else
887                                                                 ptr2->next = ptr->next;
888                                                         free(ptr->new);
889                                                         free(ptr->old);
890                                                         free(ptr);
891                                                         break;
892                                                 }
893                                         }
894
895                                         BEGIN(C);
896                                 }
897 <undef>{other}|\n               {
898                                         mmerror(PARSE_ERROR, ET_FATAL, "missing identifier in EXEC SQL UNDEF command");
899                                         yyterminate();
900                                 }
901 <C>{exec_sql}{include}{space}*  { BEGIN(incl); }
902 <C>{informix_special}{include}{space}* { 
903                                           /* are we simulating Informix? */
904                                           if (INFORMIX_MODE)
905                                           {
906                                                   BEGIN(incl);
907                                           }
908                                           else
909                                           {
910                                                   yyless(1);
911                                                   return (S_ANYTHING);
912                                           }
913                                         }
914 <C,xskip>{exec_sql}{ifdef}{space}*      { ifcond = TRUE; BEGIN(xcond); }
915 <C,xskip>{informix_special}{ifdef}{space}* { 
916                                           /* are we simulating Informix? */
917                                           if (INFORMIX_MODE)
918                                           {
919                                                   ifcond = TRUE;
920                                                   BEGIN(xcond);
921                                           }
922                                           else
923                                           {
924                                                   yyless(1);
925                                                   return (S_ANYTHING);
926                                           }
927                                         }
928 <C,xskip>{exec_sql}{ifndef}{space}* { ifcond = FALSE; BEGIN(xcond); }
929 <C,xskip>{informix_special}{ifndef}{space}* { 
930                                           /* are we simulating Informix? */
931                                           if (INFORMIX_MODE)
932                                           {
933                                                   ifcond = FALSE;
934                                                   BEGIN(xcond);
935                                           }
936                                           else
937                                           {
938                                                   yyless(1);
939                                                   return (S_ANYTHING);
940                                           }
941                                         }
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\"");
945                                                 }
946                                                 else if ( stacked_if_value[preproc_tos].else_branch )
947                                                         mmerror(PARSE_ERROR, ET_FATAL, "missing \"EXEC SQL ENDIF;\"");
948                                                 else
949                                                         preproc_tos--;
950
951                                                 ifcond = TRUE; BEGIN(xcond);
952                                         }
953 <C,xskip>{informix_special}{elif}{space}* { 
954                                         /* are we simulating Informix? */
955                                         if (INFORMIX_MODE)
956                                         {
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;\"");
961                                                 else
962                                                         preproc_tos--;
963
964                                                 ifcond = TRUE;
965                                                 BEGIN(xcond);
966                                         }
967                                         else
968                                         {
969                                                 yyless(1);
970                                                 return (S_ANYTHING);
971                                         }
972                                 }
973
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");
977                                         else
978                                         {
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);
983
984                                                 if (stacked_if_value[preproc_tos].condition)
985                                                         BEGIN(C);
986                                                 else
987                                                         BEGIN(xskip);
988                                         }
989                                 }
990 <C,xskip>{informix_special}{else}{space}*";"    {
991                                         /* are we simulating Informix? */
992                                         if (INFORMIX_MODE)
993                                         {
994                                                 if (stacked_if_value[preproc_tos].else_branch)
995                                                         mmerror(PARSE_ERROR, ET_FATAL, "more than one EXEC SQL ELSE");
996                                                 else
997                                                 {
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);
1002
1003                                                         if (stacked_if_value[preproc_tos].condition)
1004                                                                 BEGIN(C);
1005                                                         else
1006                                                                 BEGIN(xskip);
1007                                                 }
1008                                         }
1009                                         else
1010                                         {
1011                                                 yyless(1);
1012                                                 return (S_ANYTHING);
1013                                         }
1014                                 }
1015 <C,xskip>{exec_sql}{endif}{space}*";" {
1016                                         if (preproc_tos == 0)
1017                                                 mmerror(PARSE_ERROR, ET_FATAL, "unmatched EXEC SQL ENDIF");
1018                                         else
1019                                                 preproc_tos--;
1020
1021                                         if (stacked_if_value[preproc_tos].condition)
1022                                            BEGIN(C);
1023                                         else
1024                                            BEGIN(xskip);
1025                                 }
1026 <C,xskip>{informix_special}{endif}{space}*";"   {
1027                                         /* are we simulating Informix? */
1028                                         if (INFORMIX_MODE)
1029                                         {
1030                                                 if (preproc_tos == 0)
1031                                                         mmerror(PARSE_ERROR, ET_FATAL, "unmatched EXEC SQL ENDIF");
1032                                                 else
1033                                                         preproc_tos--;
1034
1035                                                 if (stacked_if_value[preproc_tos].condition)
1036                                                         BEGIN(C);
1037                                                 else
1038                                                         BEGIN(xskip);
1039                                         }
1040                                         else
1041                                         {
1042                                                 yyless(1);
1043                                                 return (S_ANYTHING);
1044                                         }
1045                                 }
1046
1047 <xskip>{other}          { /* ignore */ }
1048
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");
1052                                         else 
1053                                         {
1054                                                 struct _defines *defptr;
1055                                                 unsigned int i;
1056
1057                                                 /*
1058                                                  *      Skip the ";" and trailing whitespace. Note that yytext
1059                                                  *      contains at least one non-space character plus the ";"
1060                                                  */
1061                                                 for (i = strlen(yytext)-2;
1062                                                          i > 0 && ecpg_isspace(yytext[i]);
1063                                                          i-- )
1064                                                         ;
1065                                                 yytext[i+1] = '\0';
1066
1067                                                 for (defptr = defines;
1068                                                          defptr != NULL && strcmp(yytext, defptr->old) != 0;
1069                                                          defptr = defptr->next);
1070
1071                                                 preproc_tos++;
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;
1075                                         }
1076
1077                                         if (stacked_if_value[preproc_tos].condition)
1078                                                 BEGIN(C);
1079                                         else
1080                                                 BEGIN(xskip);
1081                                 }
1082
1083 <xcond>{other}|\n       {
1084                                 mmerror(PARSE_ERROR, ET_FATAL, "missing identifier in EXEC SQL IFDEF command");
1085                                 yyterminate();
1086                         }
1087 <def_ident>{identifier} {
1088                                 old = mm_strdup(yytext);
1089                                 BEGIN(def);
1090                                 startlit();
1091                         }
1092 <def_ident>{other}|\n   {
1093                                 mmerror(PARSE_ERROR, ET_FATAL, "missing identifier in EXEC SQL DEFINE command");
1094                                 yyterminate();
1095                         }       
1096 <def>{space}*";"        {
1097                                                 struct _defines *ptr, *this;
1098
1099                                                 for (ptr = defines; ptr != NULL; ptr = ptr->next)
1100                                                 {
1101                                                          if (strcmp(old, ptr->old) == 0)
1102                                                          {
1103                                                                 free(ptr->new);
1104                                                                 ptr->new = mm_strdup(literalbuf);
1105                                                          }
1106                                                 }
1107                                                 if (ptr == NULL)
1108                                                 {
1109                                                         this = (struct _defines *) mm_alloc(sizeof(struct _defines));
1110
1111                                                         /* initial definition */
1112                                                         this->old = old;
1113                                                         this->new = mm_strdup(literalbuf);
1114                                                         this->next = defines;
1115                                                         this->used = NULL;
1116                                                         defines = this;
1117                                                 }
1118
1119                                                 BEGIN(C);
1120                                         }
1121 <def>[^;]                       { addlit(yytext, yyleng); }
1122 <incl>\<[^\>]+\>{space}*";"?            {       parse_include(); }
1123 <incl>{dquote}{xdinside}{dquote}{space}*";"?    {       parse_include(); }
1124 <incl>[^;\<\>\"]+";"            { parse_include(); }
1125 <incl>{other}|\n                {
1126                                         mmerror(PARSE_ERROR, ET_FATAL, "syntax error in EXEC SQL INCLUDE command");
1127                                         yyterminate();
1128                                 }
1129
1130 <<EOF>>                         {
1131                                         if (yy_buffer == NULL)
1132                                         {
1133                                                 if ( preproc_tos > 0 ) 
1134                                                 {
1135                                                         preproc_tos = 0;
1136                                                         mmerror(PARSE_ERROR, ET_FATAL, "missing \"EXEC SQL ENDIF;\"");
1137                                                 }
1138                                                 yyterminate();
1139                                         }
1140                                         else
1141                                         {
1142                                                 struct _yy_buffer *yb = yy_buffer;
1143                                                 int i;
1144                                                 struct _defines *ptr;
1145
1146                                                 for (ptr = defines; ptr; ptr = ptr->next)
1147                                                         if (ptr->used == yy_buffer)
1148                                                         {
1149                                                                 ptr->used = NULL;
1150                                                                 break;
1151                                                         }
1152                                                                 
1153                                                 if (yyin != NULL)
1154                                                         fclose(yyin);
1155
1156                                                 yy_delete_buffer( YY_CURRENT_BUFFER );
1157                                                 yy_switch_to_buffer(yy_buffer->buffer);
1158
1159                                                 yylineno = yy_buffer->lineno;
1160
1161                                                 /* We have to output the filename only if we change files here */
1162                                                 i = strcmp(input_filename, yy_buffer->filename);
1163
1164                                                 free(input_filename);
1165                                                 input_filename = yy_buffer->filename;
1166
1167                                                 yy_buffer = yy_buffer->next;
1168                                                 free(yb);
1169
1170                                                 if (i != 0)
1171                                                         output_line_number();
1172                                                 
1173                                         }
1174                                 }
1175 <INITIAL>{other}|\n             { mmerror(PARSE_ERROR, ET_FATAL, "internal error: unreachable state; please report this to <pgsql-bugs@postgresql.org>"); }
1176 %%
1177 void
1178 lex_init(void)
1179 {
1180         braces_open = 0;
1181
1182         preproc_tos = 0;
1183         yylineno = 1;
1184         ifcond = TRUE;
1185         stacked_if_value[preproc_tos].condition = ifcond;
1186         stacked_if_value[preproc_tos].else_branch = FALSE;
1187
1188         /* initialize literal buffer to a reasonable but expansible size */
1189         if (literalbuf == NULL)
1190         {
1191                 literalalloc = 1024;
1192                 literalbuf = (char *) malloc(literalalloc);
1193         }
1194         startlit();
1195
1196         BEGIN(C);
1197 }
1198
1199 static void
1200 addlit(char *ytext, int yleng)
1201 {
1202         /* enlarge buffer if needed */
1203         if ((literallen+yleng) >= literalalloc)
1204         {
1205                 do 
1206                         literalalloc *= 2;
1207                 while ((literallen+yleng) >= literalalloc);
1208                 literalbuf = (char *) realloc(literalbuf, literalalloc);
1209         }
1210         /* append new data, add trailing null */
1211         memcpy(literalbuf+literallen, ytext, yleng);
1212         literallen += yleng;
1213         literalbuf[literallen] = '\0';
1214 }
1215
1216 static void
1217 addlitchar(unsigned char ychar)
1218 {
1219         /* enlarge buffer if needed */
1220         if ((literallen+1) >= literalalloc)
1221         {
1222                 literalalloc *= 2;
1223                 literalbuf = (char *) realloc(literalbuf, literalalloc);
1224         }
1225         /* append new data, add trailing null */
1226         literalbuf[literallen] = ychar;
1227         literallen += 1;
1228         literalbuf[literallen] = '\0';
1229 }
1230
1231 static void
1232 parse_include(void)
1233 {
1234         /* got the include file name */
1235         struct _yy_buffer *yb;
1236         struct _include_path *ip;
1237         char inc_file[MAXPGPATH];
1238         unsigned int i;
1239
1240         yb = mm_alloc(sizeof(struct _yy_buffer));
1241
1242         yb->buffer =    YY_CURRENT_BUFFER;
1243         yb->lineno = yylineno;
1244         yb->filename = input_filename;
1245         yb->next = yy_buffer;
1246
1247         yy_buffer = yb;
1248
1249         /*
1250          * skip the ";" if there is one and trailing whitespace. Note that
1251          * yytext contains at least one non-space character plus the ";" 
1252          */
1253         for (i = strlen(yytext)-2;
1254                  i > 0 && ecpg_isspace(yytext[i]);
1255                  i--)
1256                 ;
1257
1258         if (yytext[i] == ';')
1259                 i--;
1260
1261         yytext[i+1] = '\0';
1262         
1263         yyin = NULL;
1264
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] == '/'))
1269         {
1270                 yytext[i] = '\0';
1271                 memmove(yytext, yytext+1, strlen(yytext));
1272         
1273                 strncpy(inc_file, yytext, sizeof(inc_file));
1274                 yyin = fopen(inc_file, "r");
1275                 if (!yyin)
1276                 {
1277                         if (strcmp(inc_file + strlen(inc_file) - 2, ".h"))
1278                         {
1279                                 strcat(inc_file, ".h");
1280                                 yyin = fopen(inc_file, "r");
1281                         }
1282                 }
1283                 
1284         }
1285         else
1286         {
1287                 if ((yytext[0] == '"' && yytext[i] == '"') || (yytext[0] == '<' && yytext[i] == '>'))
1288                 {
1289                         yytext[i] = '\0';
1290                         memmove(yytext, yytext+1, strlen(yytext));
1291                 }
1292                 
1293                 for (ip = include_paths; yyin == NULL && ip != NULL; ip = ip->next)
1294                 {
1295                         if (strlen(ip->path) + strlen(yytext) + 3 > MAXPGPATH)
1296                         {
1297                                 fprintf(stderr, _("Error: include path \"%s/%s\" is too long on line %d, skipping\n"), ip->path, yytext, yylineno);
1298                                 continue;
1299                         }
1300                         snprintf (inc_file, sizeof(inc_file), "%s/%s", ip->path, yytext);
1301                         yyin = fopen(inc_file, "r");
1302                         if (!yyin)
1303                         {
1304                                 if (strcmp(inc_file + strlen(inc_file) - 2, ".h"))
1305                                 {
1306                                         strcat(inc_file, ".h");
1307                                         yyin = fopen( inc_file, "r" );
1308                                 }
1309                         }
1310                 }
1311         }
1312         if (!yyin)
1313                 mmerror(NO_INCLUDE_FILE, ET_FATAL, "could not open include file \"%s\" on line %d", yytext, yylineno);
1314
1315         input_filename = mm_strdup(inc_file);
1316         yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE ));
1317         yylineno = 1;
1318         output_line_number();
1319
1320         BEGIN(C);
1321 }
1322
1323 /*
1324  * ecpg_isspace() --- return TRUE if flex scanner considers char whitespace
1325  */
1326 static bool
1327 ecpg_isspace(char ch)
1328 {
1329         if (ch == ' ' ||
1330                 ch == '\t' ||
1331                 ch == '\n' ||
1332                 ch == '\r' ||
1333                 ch == '\f')
1334                 return true;
1335         return false;
1336 }
1337
1338 static bool isdefine(void)
1339 {
1340         struct _defines *ptr;
1341
1342         /* is it a define? */
1343         for (ptr = defines; ptr; ptr = ptr->next)
1344         {
1345                 if (strcmp(yytext, ptr->old) == 0 && ptr->used == NULL)
1346                 {
1347                         struct _yy_buffer *yb;
1348
1349                         yb = mm_alloc(sizeof(struct _yy_buffer));
1350
1351                         yb->buffer =  YY_CURRENT_BUFFER;
1352                         yb->lineno = yylineno;
1353                         yb->filename = mm_strdup(input_filename);
1354                         yb->next = yy_buffer;
1355
1356                         ptr->used = yy_buffer = yb;
1357
1358                         yy_scan_string(ptr->new);
1359                         return true;
1360                 }
1361         }
1362
1363         return false;
1364 }
1365
1366 static bool isinformixdefine(void)
1367 {
1368         const char *new = NULL;
1369
1370         if (strcmp(yytext, "dec_t") == 0)
1371                 new = "decimal";
1372         else if (strcmp(yytext, "intrvl_t") == 0)
1373                 new = "interval";
1374         else if (strcmp(yytext, "dtime_t") == 0)
1375                 new = "timestamp";
1376
1377         if (new)
1378         {
1379                 struct _yy_buffer *yb;
1380
1381                 yb = mm_alloc(sizeof(struct _yy_buffer));
1382
1383                 yb->buffer =  YY_CURRENT_BUFFER;
1384                 yb->lineno = yylineno;
1385                 yb->filename = mm_strdup(input_filename);
1386                 yb->next = yy_buffer;
1387                 yy_buffer = yb;
1388
1389                 yy_scan_string(new);
1390                 return true;
1391         }
1392
1393         return false;
1394 }
1395
1396 /*
1397  * Called before any actual parsing is done
1398  */
1399 void
1400 scanner_init(const char *str)
1401 {
1402         Size    slen = strlen(str);
1403
1404         /*
1405          * Might be left over after ereport()
1406          */
1407         if (YY_CURRENT_BUFFER)
1408                 yy_delete_buffer(YY_CURRENT_BUFFER);
1409
1410         /*
1411          * Make a scan buffer with special termination needed by flex.
1412          */
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);
1417
1418         /* initialize literal buffer to a reasonable but expansible size */
1419         literalalloc = 128;
1420         literalbuf = (char *) mm_alloc(literalalloc);
1421         startlit();
1422
1423         BEGIN(INITIAL);
1424 }
1425
1426
1427 /*
1428  * Called after parsing is done to clean up after scanner_init()
1429  */
1430 void
1431 scanner_finish(void)
1432 {
1433         yy_delete_buffer(scanbufhandle);
1434         free(scanbuf);
1435 }