OSDN Git Service

d29e75a52b0bfb9bc8343d0df967dfd8b58abf48
[pg-rex/syncrep.git] / 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-2002, PostgreSQL Global Development Group
11  * Portions Copyright (c) 1994, Regents of the University of California
12  *
13  *
14  * IDENTIFICATION
15  *        $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/pgc.l,v 1.119 2003/07/25 05:42:27 meskes Exp $
16  *
17  *-------------------------------------------------------------------------
18  */
19 #include "postgres_fe.h"
20
21 #include <ctype.h>
22 #include <sys/types.h>
23 #include <limits.h>
24 #include <errno.h>
25
26 #include "extern.h"
27
28 extern YYSTYPE yylval;
29
30 static int              xcdepth = 0;    /* depth of nesting in slash-star comments */
31
32 /*
33  * literalbuf is used to accumulate literal values when multiple rules
34  * are needed to parse a single literal.  Call startlit to reset buffer
35  * to empty, addlit to add text.  Note that the buffer is permanently
36  * malloc'd to the largest size needed so far in the current run.
37  */
38 static char    *literalbuf = NULL;              /* expandable buffer */
39 static int              literallen;                             /* actual current length */
40 static int              literalalloc;                   /* current allocated buffer size */
41
42 #define startlit()      (literalbuf[0] = '\0', literallen = 0)
43 static void addlit(char *ytext, int yleng);
44 static void addlitchar (unsigned char);
45 static void parse_include (void);
46
47 char *token_start;
48 int state_before;
49
50 struct _yy_buffer 
51
52         YY_BUFFER_STATE         buffer;
53         long                            lineno;
54         char                            *filename;
55         struct _yy_buffer       *next;
56 } *yy_buffer = NULL;
57
58 static char *old;
59
60 #define MAX_NESTED_IF 128
61 static short preproc_tos;
62 static short ifcond;
63 static struct _if_value 
64 {
65         short condition;
66         short else_branch;
67 } stacked_if_value[MAX_NESTED_IF];
68
69 %}
70
71 %option 8bit
72 %option never-interactive
73 %option noyywrap
74
75 %option yylineno
76
77 %s C SQL incl def def_ident
78
79 /*
80  * OK, here is a short description of lex/flex rules behavior.
81  * The longest pattern which matches an input string is always chosen.
82  * For equal-length patterns, the first occurring in the rules list is chosen.
83  * INITIAL is the starting state, to which all non-conditional rules apply.
84  * Exclusive states change parsing rules while the state is active.  When in
85  * an exclusive state, only those rules defined for that state apply.
86  *
87  * We use exclusive states for quoted strings, extended comments,
88  * and to eliminate parsing troubles for numeric strings.
89  * Exclusive states:
90  *      <xb> bit string literal
91  *      <xc> extended C-style comments - thomas 1997-07-12
92  *      <xd> delimited identifiers (double-quoted identifiers) - thomas 1997-10-27
93  *      <xh> hexadecimal numeric string - thomas 1997-11-16
94  *      <xq> quoted strings - thomas 1997-07-30
95  */
96
97 %x xb
98 %x xc
99 %x xd
100 %x xdc
101 %x xh
102 %x xq
103 %x xpre
104 %x xcond
105 %x xskip
106
107 /* Bit string
108  */
109 xbstart                 [bB]{quote}
110 xbstop                  {quote}
111 xbinside                [^']*
112 xbcat                   {quote}{whitespace_with_newline}{quote}
113
114 /* Hexadecimal number
115  */
116 xhstart                 [xX]{quote}
117 xhstop                  {quote}
118 xhinside                [^']*
119 xhcat                   {quote}{whitespace_with_newline}{quote}
120
121 /* National character
122  */
123 xnstart                        [nN]{quote}
124
125 /* C version of hex number
126  */
127 xch                     0[xX][0-9A-Fa-f]*
128
129 /* Extended quote
130  * xqdouble implements SQL92 embedded quote
131  * xqcat allows strings to cross input lines
132  */
133 quote                   '
134 xqstart                 {quote}
135 xqstop                  {quote}
136 xqdouble                {quote}{quote}
137 xqinside                [^\\']+
138 xqescape                [\\][^0-7]
139 xqoctesc                [\\][0-7]{1,3}
140 xqcat                   {quote}{whitespace_with_newline}{quote}
141
142 /* Double quote
143  * Allows embedded spaces and other special characters into identifiers.
144  */
145 dquote                  \"
146 xdstart                 {dquote}
147 xdstop                  {dquote}
148 xddouble                                {dquote}{dquote}
149 xdinside                [^"]+
150
151 /* special stuff for C strings */
152 xdcqq                   \\\\
153 xdcqdq                  \\\"
154 xdcother                [^"]
155 xdcinside               ({xdcqq}|{xdcqdq}|{xdcother})
156
157 /* C-style comments
158  *
159  * The "extended comment" syntax closely resembles allowable operator syntax.
160  * The tricky part here is to get lex to recognize a string starting with
161  * slash-star as a comment, when interpreting it as an operator would produce
162  * a longer match --- remember lex will prefer a longer match!  Also, if we
163  * have something like plus-slash-star, lex will think this is a 3-character
164  * operator whereas we want to see it as a + operator and a comment start.
165  * The solution is two-fold:
166  * 1. append {op_chars}* to xcstart so that it matches as much text as
167  *        {operator} would. Then the tie-breaker (first matching rule of same
168  *        length) ensures xcstart wins.  We put back the extra stuff with yyless()
169  *        in case it contains a star-slash that should terminate the comment.
170  * 2. In the operator rule, check for slash-star within the operator, and
171  *        if found throw it back with yyless().  This handles the plus-slash-star
172  *        problem.
173  * SQL92-style comments, which start with dash-dash, have similar interactions
174  * with the operator rule.
175  */
176 xcstart                 \/\*{op_chars}*
177 xcstop                  \*+\/
178 xcinside                [^*/]+
179
180 digit                   [0-9]
181 ident_start             [A-Za-z\200-\377_]
182 ident_cont              [A-Za-z\200-\377_0-9\$]
183
184 identifier              {ident_start}{ident_cont}*
185
186 array                   ({ident_cont}|[\+\-\*\%\/\(\)])*
187 typecast                "::"
188
189 /*
190  * "self" is the set of chars that should be returned as single-character
191  * tokens.      "op_chars" is the set of chars that can make up "Op" tokens,
192  * which can be one or more characters long (but if a single-char token
193  * appears in the "self" set, it is not to be returned as an Op).  Note
194  * that the sets overlap, but each has some chars that are not in the other.
195  *
196  * If you change either set, adjust the character lists appearing in the
197  * rule for "operator"!
198  */
199 self                    [,()\[\].;\:\+\-\*\/\%\^\<\>\=]
200 op_chars                [\~\!\@\#\^\&\|\`\?\+\-\*\/\%\<\>\=]
201 operator                {op_chars}+
202
203 /* we no longer allow unary minus in numbers.
204  * instead we pass it separately to parser. there it gets
205  * coerced via doNegate() -- Leon aug 20 1999
206  */
207
208 integer                 {digit}+
209 decimal                 (({digit}*\.{digit}+)|({digit}+\.{digit}*))
210 real                    ((({digit}*\.{digit}+)|({digit}+\.{digit}*)|({digit}+))([Ee][-+]?{digit}+))
211
212 param                   \${integer}
213
214 /*
215  * In order to make the world safe for Windows and Mac clients as well as
216  * Unix ones, we accept either \n or \r as a newline.  A DOS-style \r\n
217  * sequence will be seen as two successive newlines, but that doesn't cause
218  * any problems.  SQL92-style comments, which start with -- and extend to the
219  * next newline, are treated as equivalent to a single whitespace character.
220  *
221  * NOTE a fine point: if there is no newline following --, we will absorb
222  * everything to the end of the input as a comment.  This is correct.  Older
223  * versions of Postgres failed to recognize -- as a comment if the input
224  * did not end with a newline.
225  *
226  * XXX perhaps \f (formfeed) should be treated as a newline as well?
227  */
228
229 ccomment                "//".*\n
230
231 space                   [ \t\n\r\f]
232 horiz_space             [ \t\f]
233 newline                 [\n\r]
234 non_newline             [^\n\r]
235
236 comment                 ("--"{non_newline}*)
237
238 whitespace              ({space}+|{comment})
239
240 /*
241  * SQL92 requires at least one newline in the whitespace separating
242  * string literals that are to be concatenated.  Silly, but who are we
243  * to argue?  Note that {whitespace_with_newline} should not have * after
244  * it, whereas {whitespace} should generally have a * after it...
245  */
246
247 horiz_whitespace        ({horiz_space}|{comment})
248 whitespace_with_newline ({horiz_whitespace}*{newline}{whitespace}*)
249
250 /* special characters for other dbms */
251 /* we have to react differently in compat mode */
252 informix_special        [\$]
253
254 other                   .
255
256 /* some stuff needed for ecpg */
257 exec    [eE][xX][eE][cC]
258 sql             [sS][qQ][lL]
259 define  [dD][eE][fF][iI][nN][eE]
260 include [iI][nN][cC][lL][uU][dD][eE]
261
262 ifdef   [iI][fF][dD][eE][fF]
263 ifndef  [iI][fF][nN][dD][eE][fF]
264 else    [eE][lL][sS][eE]
265 elif    [eE][lL][iI][fF]
266 endif   [eE][nN][dD][iI][fF]
267
268 struct  [sS][tT][rR][uU][cC][tT]
269
270 exec_sql                {exec}{space}*{sql}{space}*
271 ipdigit                 ({digit}|{digit}{digit}|{digit}{digit}{digit})
272 ip                      {ipdigit}\.{ipdigit}\.{ipdigit}\.{ipdigit}
273
274 /* we might want to parse all cpp include files */
275 cppinclude              {space}*#{include}{space}*
276
277 /* Take care of cpp continuation lines */
278 cppline                 {space}*#(.*\\{space})+.*
279
280 /*
281  * Quoted strings must allow some special characters such as single-quote
282  *      and newline.
283  * Embedded single-quotes are implemented both in the SQL92-standard
284  *      style of two adjacent single quotes "''" and in the Postgres/Java style
285  *      of escaped-quote "\'".
286  * Other embedded escaped characters are matched explicitly and the leading
287  *      backslash is dropped from the string. - thomas 1997-09-24
288  * Note that xcstart must appear before operator, as explained above!
289  *      Also whitespace (comment) must appear before operator.
290  */
291
292 %%
293
294 %{
295                                        /* code to execute during start of each call of yylex() */
296                                        token_start = NULL;
297 %}
298
299 <SQL>{whitespace}       { /* ignore */ }
300
301 {xcstart}                       {
302                                                 token_start = yytext;
303                                                 state_before = YYSTATE;
304                                                 xcdepth = 0;
305                                                 BEGIN(xc);
306                                                 /* Put back any characters past slash-star; see above */
307                                                 yyless(2);
308                                                 fputs("/*", yyout);
309                                         }
310 <xc>{xcstart}           {
311                                                 xcdepth++;
312                                                 /* Put back any characters past slash-star; see above */
313                                                 yyless(2);
314                                                 fputs("/*", yyout);
315                                         }
316
317 <xc>{xcstop}            {
318                                                 ECHO;
319                                                 if (xcdepth <= 0)
320                                                 {
321                                                         BEGIN(state_before);
322                                                         token_start = NULL;
323                                                 }
324                                                 else
325                                                         xcdepth--;
326                                         }
327
328 <xc>{xcinside}          { ECHO; }
329 <xc>{op_chars}          { ECHO; }
330
331 <xc><<EOF>>                     { mmerror(PARSE_ERROR, ET_ERROR, "Unterminated /* comment"); }
332
333 <SQL>{xbstart}  {
334                                                 token_start = yytext;
335                                                 BEGIN(xb);
336                                                 startlit();
337                                                 addlitchar('b');
338                                         }
339 <xb>{xbstop}    {
340                                                 BEGIN(SQL);
341                                                 if (literalbuf[strspn(literalbuf, "01") + 1] != '\0')
342                                                         mmerror(PARSE_ERROR, ET_ERROR, "invalid bit string input.");
343                                                 yylval.str = literalbuf;
344                                                 return BCONST;
345                                         }
346
347 <xh>{xhinside}  |
348 <xb>{xbinside}  { addlit(yytext, yyleng); }
349 <xh>{xhcat}             |
350 <xb>{xbcat}             { /* ignore */ }
351 <xb><<EOF>>             { mmerror(PARSE_ERROR, ET_ERROR, "Unterminated bit string"); }
352
353 <SQL>{xhstart}          {
354                                                 token_start = yytext;
355                                                 BEGIN(xh);
356                                                 startlit();
357                                                 addlitchar('x');
358                                         }
359 <xh>{xhstop}            {
360                                                 yylval.str = literalbuf;
361                                                 return XCONST;
362                                         }
363
364 <xh><<EOF>>                     { mmerror(PARSE_ERROR, ET_ERROR, "Unterminated hexadecimal integer"); }
365 <SQL>{xnstart}              {
366                                 /* National character.
367                                  * Need to remember type info to flow it forward into the parser.
368                                  * Not yet implemented. - thomas 2002-06-17
369                                  */
370                                 token_start = yytext;
371                                 BEGIN(xq);
372                                 startlit();
373                         }
374 <C,SQL>{xqstart}        {
375                                                 token_start = yytext;
376                                                 state_before = YYSTATE;
377                                                 BEGIN(xq);
378                                                 startlit();
379                                         }
380 <xq>{xqstop}            {
381                                                 BEGIN(state_before);
382                                                 yylval.str = mm_strdup(literalbuf);
383                                                 return SCONST;
384                                         }
385 <xq>{xqdouble}          { addlitchar('\''); }
386 <xq>{xqinside}          { addlit(yytext, yyleng); }
387 <xq>{xqescape}          { addlit(yytext, yyleng); }
388 <xq>{xqoctesc}          { addlit(yytext, yyleng); }
389 <xq>{xqcat}                     { /* ignore */ }
390
391 <xq><<EOF>>                     { mmerror(PARSE_ERROR, ET_ERROR, "Unterminated quoted string"); }
392
393 <SQL>{xdstart}          {
394                                                 state_before = YYSTATE;
395                                                 BEGIN(xd);
396                                                 startlit();
397                                         }
398 <xd>{xdstop}            {
399                                                 BEGIN(state_before);
400                                                 if (literallen == 0)
401                                                         mmerror(PARSE_ERROR, ET_ERROR, "zero-length delimited identifier");
402                                                 yylval.str = mm_strdup(literalbuf);
403                                                 return CSTRING;
404                                         }
405 <xdc>{xdstop}           {
406                                                 BEGIN(state_before);
407                                                 yylval.str = mm_strdup(literalbuf);
408                                                 return CSTRING;
409                                         }
410 <xd>{xddouble}          { addlitchar('"'); }
411 <xd>{xdinside}          { addlit(yytext, yyleng); }
412 <xd,xdc><<EOF>>         { mmerror(PARSE_ERROR, ET_ERROR, "Unterminated quoted identifier"); }
413 <C,SQL>{xdstart}        {
414                                                 state_before = YYSTATE;
415                                                 BEGIN(xdc);
416                                                 startlit();
417                                         }
418 <xdc>{xdcinside}        { addlit(yytext, yyleng); }
419 <SQL>{typecast}         { return TYPECAST; }
420 <SQL>{informix_special} {
421                           /* are we simulating Informix? */
422                           if (INFORMIX_MODE)
423                           {
424                                 unput(':');
425                           }
426                           else
427                                 return yytext[0];
428                         }
429 <SQL>{self}                     { /*
430                                            * We may find a ';' inside a structure
431                                            * definition in a TYPE or VAR statement.
432                                            * This is not an EOL marker.
433                                            */
434                                           if (yytext[0] == ';' && struct_level == 0)
435                                                  BEGIN C;
436                                           return yytext[0];
437                                         }
438 <SQL>{operator}         {
439                                                 /*
440                                                  * Check for embedded slash-star or dash-dash; those
441                                                  * are comment starts, so operator must stop there.
442                                                  * Note that slash-star or dash-dash at the first
443                                                  * character will match a prior rule, not this one.
444                                                  */
445                                                 int             nchars = yyleng;
446                                                 char   *slashstar = strstr(yytext, "/*");
447                                                 char   *dashdash = strstr(yytext, "--");
448
449                                                 if (slashstar && dashdash)
450                                                 {
451                                                         /* if both appear, take the first one */
452                                                         if (slashstar > dashdash)
453                                                                 slashstar = dashdash;
454                                                 }
455                                                 else if (!slashstar)
456                                                         slashstar = dashdash;
457                                                 if (slashstar)
458                                                         nchars = slashstar - yytext;
459
460                                                 /*
461                                                  * For SQL92 compatibility, '+' and '-' cannot be the
462                                                  * last char of a multi-char operator unless the operator
463                                                  * contains chars that are not in SQL92 operators.
464                                                  * The idea is to lex '=-' as two operators, but not
465                                                  * to forbid operator names like '?-' that could not be
466                                                  * sequences of SQL92 operators.
467                                                  */
468                                                 while (nchars > 1 &&
469                                                            (yytext[nchars-1] == '+' ||
470                                                                 yytext[nchars-1] == '-'))
471                                                 {
472                                                         int             ic;
473
474                                                         for (ic = nchars-2; ic >= 0; ic--)
475                                                         {
476                                                                 if (strchr("~!@#^&|`?%", yytext[ic]))
477                                                                         break;
478                                                         }
479                                                         if (ic >= 0)
480                                                                 break; /* found a char that makes it OK */
481                                                         nchars--; /* else remove the +/-, and check again */
482                                                 }
483
484                                                 if (nchars < yyleng)
485                                                 {
486                                                         /* Strip the unwanted chars from the token */
487                                                         yyless(nchars);
488                                                         /*
489                                                          * If what we have left is only one char, and it's
490                                                          * one of the characters matching "self", then
491                                                          * return it as a character token the same way
492                                                          * that the "self" rule would have.
493                                                          */
494                                                         if (nchars == 1 &&
495                                                                 strchr(",()[].;:+-*/%^<>=", yytext[0]))
496                                                                 return yytext[0];
497                                                 }
498
499                                                 /* Convert "!=" operator to "<>" for compatibility */
500                                                 if (strcmp(yytext, "!=") == 0)
501                                                         yylval.str = mm_strdup("<>");
502                                                 else
503                                                         yylval.str = mm_strdup(yytext);
504                                                 return Op;
505                                         }
506 <SQL>{param}            {
507                                                 yylval.ival = atol(yytext+1);
508                                                 return PARAM;
509                                         }
510 <C,SQL>{integer}        {
511                                                 long val;
512                                                 char* endptr;
513
514                                                 errno = 0;
515                                                 val = strtol((char *)yytext, &endptr,10);
516                                                 if (*endptr != '\0' || errno == ERANGE
517 #ifdef HAVE_LONG_INT_64
518                                                         /* if long > 32 bits, check for overflow of int4 */
519                                                         || val != (long) ((int32) val)
520 #endif
521                                                         )
522                                                 {
523                                                         errno = 0;
524                                                         yylval.str = mm_strdup(yytext);
525                                                         return FCONST;
526                                                 }
527                                                 yylval.ival = val;
528                                                 return ICONST;
529                                         }
530 <SQL>{ip}                       {
531                                                 yylval.str = mm_strdup(yytext);
532                                                 return IP;
533                                         }
534 {decimal}                       {
535                                                 yylval.str = mm_strdup(yytext);
536                                                 return FCONST;
537                                         }
538 <C,SQL>{real}           {
539                                                 yylval.str = mm_strdup(yytext);
540                                                 return FCONST;
541                                         }
542 <SQL>:{identifier}((("->"|\.){identifier})|(\[{array}\]))*      {
543                                                 yylval.str = mm_strdup(yytext+1);
544                                                 return(CVARIABLE);
545                                         }
546 <SQL>{identifier}       {
547                                                 ScanKeyword    *keyword;
548                                                 struct _defines *ptr;
549
550                                                 /* How about a DEFINE? */
551                                                 for (ptr = defines; ptr; ptr = ptr->next)
552                                                 {
553                                                         if (strcmp(yytext, ptr->old) == 0)
554                                                         {
555                                                                 struct _yy_buffer *yb;
556
557                                                                 yb = mm_alloc(sizeof(struct _yy_buffer));
558
559                                                                 yb->buffer =  YY_CURRENT_BUFFER;
560                                                                 yb->lineno = yylineno;
561                                                                 yb->filename = mm_strdup(input_filename);
562                                                                 yb->next = yy_buffer;
563
564                                                                 yy_buffer = yb;
565
566                                                                 yy_scan_string(ptr->new);
567                                                                 break;
568                                                         }
569                                                 }
570
571                                                 if (ptr == NULL)
572                                                 {
573                                                         /* Is it an SQL keyword? */
574                                                         keyword = ScanKeywordLookup(yytext);
575                                                         if (keyword != NULL)
576                                                                 return keyword->value;
577
578                                                         /* Is it an ECPG keyword? */
579                                                         keyword = ScanECPGKeywordLookup( yytext);
580                                                         if (keyword != NULL)
581                                                                 return keyword->value;
582
583                                                         /* Is it a C keyword? */
584                                                         keyword = ScanCKeywordLookup(yytext);
585                                                         if (keyword != NULL)
586                                                                 return keyword->value;
587
588                                                         /*
589                                                          * None of the above.  Return it as an identifier.
590                                                          *
591                                                          * The backend would attempt to truncate and case-fold
592                                                          * the identifier, but I see no good reason for ecpg
593                                                          * to do so; that's just another way that ecpg could get
594                                                          * out of step with the backend.
595                                                          */
596                                                         if (ptr == NULL)
597                                                         {
598                                                                 yylval.str = mm_strdup(yytext);
599                                                                 return IDENT;
600                                                         }
601                                                 }
602                                         }
603 <SQL>{other}            { return yytext[0]; }
604 <C>{exec_sql}           { BEGIN SQL; return SQL_START; }
605 <C>{informix_special}   { 
606                           /* are we simulating Informix? */
607                           if (INFORMIX_MODE)
608                           {
609                                 BEGIN SQL;
610                                 return SQL_START;
611                           }
612                           else
613                                 return S_ANYTHING;
614                          }
615 <C>{ccomment}            { ECHO; }
616 <C>{xch}                        {
617                                                 char* endptr;
618
619                                                 errno = 0;
620                                                 yylval.ival = strtoul((char *)yytext,&endptr,16);
621                                                 if (*endptr != '\0' || errno == ERANGE)
622                                                 {
623                                                         errno = 0;
624                                                         yylval.str = mm_strdup(yytext);
625                                                         return SCONST;
626                                                 }
627                                                 return ICONST;
628                                         }
629 <C>{cppinclude}         {
630                                           if (system_includes)
631                                           {
632                                                 BEGIN(incl);
633                                           }
634                                           else
635                                           {
636                                                 yylval.str = mm_strdup(yytext);
637                                                 return(CPP_LINE);
638                                           }
639                         }
640 <C>{cppline}            {
641                                                 yylval.str = mm_strdup(yytext);
642                                                 return(CPP_LINE);
643                                         }
644 <C>{identifier}         {
645                                                 ScanKeyword             *keyword;
646                                                 struct _defines *ptr;
647
648                                                 /* is it a define? */
649                                                 for (ptr = defines; ptr; ptr = ptr->next)
650                                                 {
651                                                         if (strcmp(yytext, ptr->old) == 0)
652                                                         {
653                                                                 struct _yy_buffer *yb;
654
655                                                                 yb = mm_alloc(sizeof(struct _yy_buffer));
656
657                                                                 yb->buffer =  YY_CURRENT_BUFFER;
658                                                                 yb->lineno = yylineno;
659                                                                 yb->filename = mm_strdup(input_filename);
660                                                                 yb->next = yy_buffer;
661
662                                                                 yy_buffer = yb;
663
664                                                                 yy_scan_string(ptr->new);
665                                                                 break;
666                                                         }
667                                                 }
668
669                                                 if (ptr == NULL)
670                                                 {
671                                                         keyword = ScanCKeywordLookup(yytext);
672                                                         if (keyword != NULL)
673                                                                 return keyword->value;
674
675                                                         else {
676                                                                 yylval.str = mm_strdup(yytext);
677                                                                 return IDENT;
678                                                         }
679                                                 }
680                                         }
681 <C>";"                          { return(';'); }
682 <C>","                          { return(','); }
683 <C>"*"                          { return('*'); }
684 <C>"%"                          { return('%'); }
685 <C>"/"                          { return('/'); }
686 <C>"+"                          { return('+'); }
687 <C>"-"                          { return('-'); }
688 <C>"("                          { return('('); }
689 <C>")"                          { return(')'); }
690 <C>{space}                      { ECHO; }
691 <C>\{                           { return('{'); }
692 <C>\}                           { return('}'); }
693 <C>\[                           { return('['); }
694 <C>\]                           { return(']'); }
695 <C>\=                           { return('='); }
696 <C>"->"                         { return(S_MEMBER); }
697 <C>">>"                         { return(S_RSHIFT); }
698 <C>"<<"                         { return(S_LSHIFT); }
699 <C>"||"                         { return(S_OR); }
700 <C>"&&"                         { return(S_AND); }
701 <C>"++"                         { return(S_INC); }
702 <C>"--"                         { return(S_DEC); }
703 <C>"=="                         { return(S_EQUAL); }
704 <C>"!="                         { return(S_NEQUAL); }
705 <C>"+="                         { return(S_ADD); }
706 <C>"-="                         { return(S_SUB); }
707 <C>"*="                         { return(S_MUL); }
708 <C>"/="                         { return(S_DIV); }
709 <C>"%="                         { return(S_MOD); }
710 <C>"->*"                        { return(S_MEMPOINT); }
711 <C>".*"                         { return(S_DOTPOINT); }
712 <C>{other}                      { return S_ANYTHING; }
713
714 <C>{exec_sql}{define}{space}*   { BEGIN(def_ident); }
715 <C>{informix_special}{define}{space}*   {
716                                                 /* are we simulating Informix? */
717                                                 if (INFORMIX_MODE)
718                                                 {
719                                                         BEGIN(def_ident);
720                                                 }
721                                                 else
722                                                 {
723                                                         yyless(1);
724                                                         return (S_ANYTHING);
725                                                 }
726                                         }
727 <C>{exec_sql}{include}{space}*  { BEGIN(incl); }
728 <C>{informix_special}{include}{space}* { 
729                                           /* are we simulating Informix? */
730                                           if (INFORMIX_MODE)
731                                           {
732                                                   BEGIN(incl);
733                                           }
734                                           else
735                                           {
736                                                   yyless(1);
737                                                   return (S_ANYTHING);
738                                           }
739                                         }
740 <C,xskip>{exec_sql}{ifdef}{space}*      { ifcond = TRUE; BEGIN(xcond); }
741 <C,xskip>{informix_special}{ifdef}{space}* { 
742                                           /* are we simulating Informix? */
743                                           if (INFORMIX_MODE)
744                                           {
745                                                   ifcond = TRUE;
746                                                   BEGIN(xcond);
747                                           }
748                                           else
749                                           {
750                                                   yyless(1);
751                                                   return (S_ANYTHING);
752                                           }
753                                         }
754 <C,xskip>{exec_sql}{ifndef}{space}* { ifcond = FALSE; BEGIN(xcond); }
755 <C,xskip>{informix_special}{ifndef}{space}* { 
756                                           /* are we simulating Informix? */
757                                           if (INFORMIX_MODE)
758                                           {
759                                                   ifcond = FALSE;
760                                                   BEGIN(xcond);
761                                           }
762                                           else
763                                           {
764                                                   yyless(1);
765                                                   return (S_ANYTHING);
766                                           }
767                                         }
768 <C,xskip>{exec_sql}{elif}{space}*       {       /* pop stack */
769                                                 if ( preproc_tos == 0 ) {
770                                                         mmerror(PARSE_ERROR, ET_FATAL, "Missing matching 'EXEC SQL IFDEF / EXEC SQL IFNDEF'");
771                                                 }
772                                                 else if ( stacked_if_value[preproc_tos].else_branch )
773                                                         mmerror(PARSE_ERROR, ET_FATAL, "Missing 'EXEC SQL ENDIF;'");
774                                                 else
775                                                         preproc_tos--;
776
777                                                 ifcond = TRUE; BEGIN(xcond);
778                                         }
779 <C,xskip>{informix_special}{elif}{space}* { 
780                                           /* are we simulating Informix? */
781                                           if (INFORMIX_MODE)
782                                           {
783                                                 if ( preproc_tos == 0 ) {
784                                                         mmerror(PARSE_ERROR, ET_FATAL, "Missing matching 'EXEC SQL IFDEF / EXEC SQL IFNDEF'");
785                                                 }
786                                                 else if ( stacked_if_value[preproc_tos].else_branch )
787                                                         mmerror(PARSE_ERROR, ET_FATAL, "Missing 'EXEC SQL ENDIF;'");
788                                                 else
789                                                         preproc_tos--;
790
791                                                 ifcond = TRUE; BEGIN(xcond);
792                                           }
793                                           else
794                                           {
795                                                   yyless(1);
796                                                   return (S_ANYTHING);
797                                           }
798                                         }
799
800 <C,xskip>{exec_sql}{else}{space}*";" {  /* only exec sql endif pops the stack, so take care of duplicated 'else' */
801                                                 if ( stacked_if_value[preproc_tos].else_branch ) {
802                                                         mmerror(PARSE_ERROR, ET_FATAL, "Duplicated 'EXEC SQL ELSE;'");
803                                                 }
804                                                 else {
805                                                         stacked_if_value[preproc_tos].else_branch = TRUE;
806                                                         stacked_if_value[preproc_tos].condition =
807                                                         (stacked_if_value[preproc_tos-1].condition &&
808                                                          ! stacked_if_value[preproc_tos].condition);
809
810                                                         if ( stacked_if_value[preproc_tos].condition )
811                                                                 BEGIN(C);
812                                                         else
813                                                                 BEGIN(xskip);
814                                                 }
815                                         }
816 <C,xskip>{informix_special}{else}{space}*       {
817                                           /* are we simulating Informix? */
818                                           if (INFORMIX_MODE)
819                                           {
820                                                 if ( stacked_if_value[preproc_tos].else_branch ) {
821                                                         mmerror(PARSE_ERROR, ET_FATAL, "Duplicated 'EXEC SQL ELSE;'");
822                                                 }
823                                                 else {
824                                                         stacked_if_value[preproc_tos].else_branch = TRUE;
825                                                         stacked_if_value[preproc_tos].condition =
826                                                         (stacked_if_value[preproc_tos-1].condition &&
827                                                          ! stacked_if_value[preproc_tos].condition);
828
829                                                         if ( stacked_if_value[preproc_tos].condition )
830                                                                 BEGIN(C);
831                                                         else
832                                                                 BEGIN(xskip);
833                                                 }
834                                           }
835                                           else
836                                           {
837                                                   yyless(1);
838                                                   return (S_ANYTHING);
839                                           }
840                                         }
841 <C,xskip>{exec_sql}{endif}{space}*";" {
842                                                 if ( preproc_tos == 0 )
843                                                         mmerror(PARSE_ERROR, ET_FATAL, "Unmatched 'EXEC SQL ENDIF;'");
844                                                 else
845                                                         preproc_tos--;
846
847                                                 if ( stacked_if_value[preproc_tos].condition )
848                                                    BEGIN(C);
849                                                 else
850                                                    BEGIN(xskip);
851                                         }
852 <C,xskip>{informix_special}{endif}{space}*";"   {
853                                           /* are we simulating Informix? */
854                                           if (INFORMIX_MODE)
855                                           {
856                                                 if ( preproc_tos == 0 )
857                                                         mmerror(PARSE_ERROR, ET_FATAL, "Unmatched 'EXEC SQL ENDIF;'");
858                                                 else
859                                                         preproc_tos--;
860
861                                                 if ( stacked_if_value[preproc_tos].condition )
862                                                    BEGIN(C);
863                                                 else
864                                                    BEGIN(xskip);
865                                           }
866                                           else
867                                           {
868                                                   yyless(1);
869                                                   return (S_ANYTHING);
870                                           }
871                                         }
872
873 <xskip>{other}          { /* ignore */ }
874
875 <xcond>{identifier}{space}*";" {
876                                                 if ( preproc_tos >= MAX_NESTED_IF-1 ) {
877                                                         mmerror(PARSE_ERROR, ET_FATAL, "Too many nested 'EXEC SQL IFDEF' conditions");
878                                                 }
879                                                 else 
880                                                 {
881                                                         struct _defines *defptr;
882                                                         unsigned int i;
883
884                                                         /* skip the ";" and trailing whitespace. Note that yytext contains
885                                                            at least one non-space character plus the ";" */
886                                                         for ( i = strlen(yytext)-2;
887                                                                   i > 0 && isspace((unsigned char) yytext[i]);
888                                                                   i-- )
889                                                         {}
890                                                         yytext[i+1] = '\0';
891
892                                                         for ( defptr = defines; defptr != NULL &&
893                                                                   ( strcmp(yytext, defptr->old) != 0 ); defptr = defptr->next );
894
895                                                         preproc_tos++;
896                                                         stacked_if_value[preproc_tos].else_branch = FALSE;
897                                                         stacked_if_value[preproc_tos].condition =
898                                                         ( (defptr ? ifcond : !ifcond) && stacked_if_value[preproc_tos-1].condition );
899                                                 }
900
901                                                 if ( stacked_if_value[preproc_tos].condition )
902                                                    BEGIN C;
903                                                 else
904                                                    BEGIN(xskip);
905                                         }
906
907 <def_ident>{identifier} {
908                                 old = mm_strdup(yytext);
909                                 BEGIN(def);
910                                 startlit();
911                         }
912 <def>{space}*";"        {
913                                                 struct _defines *ptr, *this;
914
915                                                 for (ptr = defines; ptr != NULL; ptr = ptr->next)
916                                                 {
917                                                          if (strcmp(old, ptr->old) == 0)
918                                                          {
919                                                                 free(ptr->new);
920                                                                 /* ptr->new = mm_strdup(scanstr(literalbuf));*/
921                                                                 ptr->new = mm_strdup(literalbuf);
922                                                          }
923                                                 }
924                                                 if (ptr == NULL)
925                                                 {
926                                                                                                 this = (struct _defines *) mm_alloc(sizeof(struct _defines));
927
928                                                                                                 /* initial definition */
929                                                                                                 this->old = old;
930                                                                                                 this->new = mm_strdup(literalbuf);
931                                                         this->next = defines;
932                                                         defines = this;
933                                                 }
934
935                                                 BEGIN(C);
936                                         }
937 <def>[^;]                       { addlit(yytext, yyleng); }
938
939 <incl>\<[^\>]+\>{space}*";"?            {       parse_include(); }
940 <incl>{dquote}{xdinside}{dquote}{space}*";"?    {       parse_include(); }
941 <incl>[^;\<\>\"]+";"            { parse_include(); }
942
943 <<EOF>>                         {
944                                                 if (yy_buffer == NULL) {
945                                                 if ( preproc_tos > 0 ) 
946                                                 {
947                                                         preproc_tos = 0;
948                                                         mmerror(PARSE_ERROR, ET_FATAL, "Missing 'EXEC SQL ENDIF;'");
949                                                 }
950                                                         yyterminate();
951                                                         }
952                                                 else
953                                                 {
954                                                         struct _yy_buffer *yb = yy_buffer;
955                                                         int i;
956
957                                                         if (yyin != NULL)
958                                                                 fclose(yyin);
959
960                                                         yy_delete_buffer( YY_CURRENT_BUFFER );
961                                                         yy_switch_to_buffer(yy_buffer->buffer);
962
963                                                         yylineno = yy_buffer->lineno;
964
965                                                         /* We have to output the filename only if we change files here */
966                                                         i = strcmp(input_filename, yy_buffer->filename);
967
968                                                         free(input_filename);
969                                                         input_filename = yy_buffer->filename;
970
971                                                         yy_buffer = yy_buffer->next;
972                                                         free(yb);
973
974                                                         if (i != 0)
975                                                                 output_line_number();
976                                                 }
977                                         }
978 %%
979 void
980 lex_init(void)
981 {
982         braces_open = 0;
983
984         preproc_tos = 0;
985         yylineno = 1;
986         ifcond = TRUE;
987         stacked_if_value[preproc_tos].condition = ifcond;
988         stacked_if_value[preproc_tos].else_branch = FALSE;
989
990         /* initialize literal buffer to a reasonable but expansible size */
991         if (literalbuf == NULL)
992         {
993                 literalalloc = 128;
994                 literalbuf = (char *) malloc(literalalloc);
995         }
996         startlit();
997
998         BEGIN C;
999 }
1000
1001 static void
1002 addlit(char *ytext, int yleng)
1003 {
1004         /* enlarge buffer if needed */
1005         if ((literallen+yleng) >= literalalloc)
1006         {
1007                 do 
1008                         literalalloc *= 2;
1009                 while ((literallen+yleng) >= literalalloc);
1010                 literalbuf = (char *) realloc(literalbuf, literalalloc);
1011         }
1012         /* append new data, add trailing null */
1013         memcpy(literalbuf+literallen, ytext, yleng);
1014         literallen += yleng;
1015         literalbuf[literallen] = '\0';
1016 }
1017
1018 static void
1019 addlitchar(unsigned char ychar)
1020 {
1021         /* enlarge buffer if needed */
1022         if ((literallen+1) >= literalalloc)
1023         {
1024                 literalalloc *= 2;
1025                 literalbuf = (char *) realloc(literalbuf, literalalloc);
1026         }
1027         /* append new data, add trailing null */
1028         literalbuf[literallen] = ychar;
1029         literallen += 1;
1030         literalbuf[literallen] = '\0';
1031 }
1032
1033 static void
1034 parse_include(void)
1035 {
1036         /* got the include file name */
1037         struct _yy_buffer *yb;
1038         struct _include_path *ip;
1039         char inc_file[MAXPGPATH];
1040         unsigned int i;
1041
1042         yb = mm_alloc(sizeof(struct _yy_buffer));
1043
1044         yb->buffer =    YY_CURRENT_BUFFER;
1045         yb->lineno = yylineno;
1046         yb->filename = input_filename;
1047         yb->next = yy_buffer;
1048
1049         yy_buffer = yb;
1050
1051         /*
1052          * skip the ";" if there is one and trailing whitespace. Note that
1053          * yytext contains at least one non-space character plus the ";" 
1054          */
1055         for ( i = strlen(yytext)-2;
1056                 i > 0 && isspace((unsigned char) yytext[i]);
1057                 i-- )
1058                 {}
1059
1060         if (yytext[i] == ';')
1061                 i--;
1062
1063         yytext[i+1] = '\0';
1064         
1065         yyin = NULL;
1066
1067         /* If file name is enclosed in '"' remove these and look only in '.' */
1068         /* Informix does look into all include paths though, except filename starts with '/' */
1069         if ((yytext[0] == '"' && yytext[i] == '"') && (compat != ECPG_COMPAT_INFORMIX || yytext[1] == '/'))
1070         {
1071                 yytext[i] = '\0';
1072                 memmove(yytext, yytext+1, strlen(yytext));
1073         
1074                 strncpy(inc_file, yytext, sizeof(inc_file));
1075                 yyin = fopen(inc_file, "r");
1076                 if (!yyin)
1077                 {
1078                         if (strcmp(inc_file + strlen(inc_file) - 2, ".h"))
1079                         {
1080                                 strcat(inc_file, ".h");
1081                                 yyin = fopen(inc_file, "r");
1082                         }
1083                 }
1084                 
1085         }
1086         else
1087         {
1088                 if ((yytext[0] == '"' && yytext[i] == '"') || (yytext[0] == '<' && yytext[i] == '>'))
1089                 {
1090                         yytext[i] = '\0';
1091                         memmove(yytext, yytext+1, strlen(yytext));
1092                 }
1093                 
1094                 for (ip = include_paths; yyin == NULL && ip != NULL; ip = ip->next)
1095                 {
1096                         if (strlen(ip->path) + strlen(yytext) + 3 > MAXPGPATH)
1097                         {
1098                                 fprintf(stderr, "Error: Path %s/%s is too long in line %d, skipping.\n", ip->path, yytext, yylineno);
1099                                 continue;
1100                         }
1101                         snprintf (inc_file, sizeof(inc_file), "%s/%s", ip->path, yytext);
1102                         yyin = fopen(inc_file, "r");
1103                         if (!yyin)
1104                         {
1105                                 if (strcmp(inc_file + strlen(inc_file) - 2, ".h"))
1106                                 {
1107                                         strcat(inc_file, ".h");
1108                                         yyin = fopen( inc_file, "r" );
1109                                 }
1110                         }
1111                 }
1112         }
1113         if (!yyin)
1114         {
1115                 snprintf(errortext, sizeof(errortext), "Cannot open include file %s in line %d\n", yytext, yylineno);
1116                 mmerror(NO_INCLUDE_FILE, ET_FATAL, errortext);
1117         }
1118
1119         input_filename = mm_strdup(inc_file);
1120         yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE ));
1121         yylineno = 1;
1122         output_line_number();
1123
1124         BEGIN C;
1125 }