]> granicus.if.org Git - postgresql/blob - src/interfaces/ecpg/preproc/pgc.l
*** empty log message ***
[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-2000, PostgreSQL, Inc
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.54 2000/03/15 19:09:10 meskes Exp $
16  *
17  *-------------------------------------------------------------------------
18  */
19 #include <ctype.h>
20 #include <sys/types.h>
21 #include <limits.h>
22 #include <errno.h>
23
24 #include "postgres.h"
25
26 #include "miscadmin.h"
27 #include "nodes/parsenodes.h"
28 #include "nodes/pg_list.h"
29 #include "parser/scansup.h"
30 #include "extern.h"
31 #include "preproc.h"
32 #include "utils/builtins.h"
33
34 /* some versions of lex define this as a macro */
35 #if defined(yywrap)
36 #undef yywrap
37 #endif /* yywrap */
38
39 extern YYSTYPE yylval;
40
41 /*
42  * literalbuf is used to accumulate literal values when multiple rules
43  * are needed to parse a single literal.  Call startlit to reset buffer
44  * to empty, addlit to add text.  Note that the buffer is permanently
45  * malloc'd to the largest size needed so far in the current run.
46  */
47 static char        *literalbuf = NULL;          /* expandable buffer */
48 static int              literallen;             /* actual current length */
49 static int              literalalloc;   /* current allocated buffer size */
50
51 #define startlit()  (literalbuf[0] = '\0', literallen = 0)
52 static void addlit(char *ytext, int yleng);
53
54 int state_before;
55
56 struct _yy_buffer { YY_BUFFER_STATE     buffer;
57                     long                lineno;
58                     char              * filename;
59                     struct _yy_buffer * next;
60                   } *yy_buffer = NULL;
61
62 static char *old;
63
64 #define MAX_NESTED_IF 128
65 static short preproc_tos;
66 static short ifcond;
67 static struct _if_value {
68     short condition;
69     short else_branch;
70 } stacked_if_value[MAX_NESTED_IF];
71
72 %}
73
74 %option yylineno
75 %s C SQL incl def def_ident
76
77 /*
78  * OK, here is a short description of lex/flex rules behavior.
79  * The longest pattern which matches an input string is always chosen.
80  * For equal-length patterns, the first occurring in the rules list is chosen.
81  * INITIAL is the starting state, to which all non-conditional rules apply.
82  * Exclusive states change parsing rules while the state is active.  When in
83  * an exclusive state, only those rules defined for that state apply.
84  *
85  * We use exclusive states for quoted strings, extended comments,
86  * and to eliminate parsing troubles for numeric strings.
87  * Exclusive states:
88  *  <xb> binary numeric string - thomas 1997-11-16
89  *  <xc> extended C-style comments - tgl 1997-07-12
90  *  <xd> delimited identifiers (double-quoted identifiers) - tgl 1997-10-27
91  *  <xh> hexadecimal numeric string - thomas 1997-11-16
92  *  <xq> quoted strings - tgl 1997-07-30
93  */
94
95 %x xb
96 %x xc
97 %x xd
98 %x xdc
99 %x xh
100 %x xq
101 %x xpre
102 %x xcond
103 %x xskip
104
105 /* Binary number
106  */
107 xbstart                 [bB]{quote}
108 xbstop                  {quote}
109 xbinside                [^']+
110 xbcat                   {quote}{whitespace_with_newline}{quote}
111
112 /* Hexadecimal number
113  */
114 xhstart                 [xX]{quote}
115 xhstop                  {quote}
116 xhinside                [^']+
117 xhcat                   {quote}{whitespace_with_newline}{quote}
118
119 /* C version of hex number 
120  */
121 xch                     0[xX][0-9A-Fa-f]*
122
123 /* Extended quote
124  * xqdouble implements SQL92 embedded quote
125  * xqcat allows strings to cross input lines
126  */
127 quote                   '
128 xqstart                 {quote}
129 xqstop                  {quote}
130 xqdouble                {quote}{quote}
131 xqinside                [^\\']+
132 xqliteral               [\\](.|\n)
133 xqcat                   {quote}{whitespace_with_newline}{quote}
134
135 /* Delimited quote
136  * Allows embedded spaces and other special characters into identifiers.
137  */
138 dquote                  \"
139 xdstart                 {dquote}
140 xdstop                  {dquote}
141 xdinside                [^"]+
142
143 /* special stuff for C strings */
144 xdcqq                   \\\\
145 xdcqdq                  \\\"
146 xdcother                [^"]
147 xdcinside               ({xdcqq}|{xdcqdq}|{xdcother})
148
149 /* C-Style Comments
150  * The "extended comment" syntax closely resembles allowable operator syntax.
151  * The tricky part here is to get lex to recognize a string starting with
152  * slash-star as a comment, when interpreting it as an operator would produce
153  * a longer match --- remember lex will prefer a longer match!  Also, if we 
154  * have tor whereas we want to see it as a + operator and a comment start.
155  * The solution is two-fold:
156  * 1. append {op_and_self}* to xcstart so that it matches as much text as
157  *    {operator} would. Then the tie-breaker (first matching rule of same
158  *    length) ensures xcstart wins.  We put back the extra stuff with yyless()
159  *    in case it contains a star-slash that should terminate the comment.
160  * 2. In the operator rule, check for slash-star within the operator, and
161  *    if found throw it back with yyless().  This handles the plus-slash-star
162  *    problem.
163  * SQL92-style comments, which start with dash-dash, have similar interactions
164  * with the operator rule.
165  */
166 xcstart                 \/\*{op_and_self}*
167 xcstop                  \*+\/
168 xcinside                ([^*]+)|(\*+[^/])
169
170 digit                   [0-9]
171 letter                  [\200-\377_A-Za-z]
172 letter_or_digit         [\200-\377_A-Za-z0-9]
173
174 identifier              {letter}{letter_or_digit}*
175
176 typecast                "::"
177
178 /* NB: if you change "self", fix the copy in the operator rule too! */
179 self                    [,()\[\].;$\:\+\-\*\/\%\^\<\>\=\|]
180 op_and_self             [\~\!\@\#\^\&\|\`\?\$\:\+\-\*\/\%\<\>\=]
181 operator                {op_and_self}+
182
183 /* we no longer allow unary minus in numbers. 
184  * instead we pass it separately to parser. there it gets
185  * coerced via doNegate() -- Leon aug 20 1999 
186  */
187
188 integer                 {digit}+
189 decimal                 (({digit}*\.{digit}+)|({digit}+\.{digit}*))
190 real                    ((({digit}*\.{digit}+)|({digit}+\.{digit}*)|({digit}+))([Ee][-+]?{digit}+))
191
192 param                   \${integer}
193
194 /*
195  * In order to make the world safe for Windows and Mac clients as well as
196  * Unix ones, we accept either \n or \r as a newline.  A DOS-style \r\n
197  * sequence will be seen as two successive newlines, but that doesn't cause
198  * any problems.  SQL92-style comments, which start with -- and extend to the
199  * next newline, are treated as equivalent to a single whitespace character.
200  *
201  * NOTE a fine point: if there is no newline following --, we will absorb
202  * everything to the end of the input as a comment.  This is correct.  Older
203  * versions of Postgres failed to recognize -- as a comment if the input
204  * did not end with a newline.
205  *
206  * XXX perhaps \f (formfeed) should be treated as a newline as well?
207  */
208
209 ccomment                "//".*\n
210
211 space                   [ \t\r\f]
212 space_or_nl             [ \t\r\f\n]
213 line_end                {space}*\n
214 horiz_space             [ \t\f]
215 newline                 [\n\r]
216 non_newline             [^\n\r]
217
218 comment                 (("--"|"//"){non_newline}*)
219
220 whitespace              ({space}|{comment})
221
222 /*
223  * SQL92 requires at least one newline in the whitespace separating
224  * string literals that are to be concatenated.  Silly, but who are we
225  * to argue?  Note that {whitespace_with_newline} should not have * after
226  * it, whereas {whitespace} should generally have a * after it...
227  */
228
229 horiz_whitespace        ({horiz_space}|{comment})
230 whitespace_with_newline ({horiz_whitespace}*{newline}{whitespace}*)
231
232 other                   .
233
234 /* some stuff needed for ecpg */
235 exec    [eE][xX][eE][cC]
236 sql     [sS][qQ][lL]
237 define  [dD][eE][fF][iI][nN][eE]
238 include [iI][nN][cC][lL][uU][dD][eE]
239
240 ifdef   [iI][fF][dD][eE][fF]
241 ifndef  [iI][fF][nN][dD][eE][fF]
242 else    [eE][lL][sS][eE]
243 elif    [eE][lL][iI][fF]
244 endif   [eE][nN][dD][iI][fF]
245
246 exec_sql                {exec}{space_or_nl}*{sql}{space_or_nl}*
247
248 /* Take care of cpp continuation lines */
249 cppline                 {space}*#(.*\\{line_end})*.*
250
251 /* DO NOT PUT ANY COMMENTS IN THE FOLLOWING SECTION.
252  * AT&T lex does not properly handle C-style comments in this second lex block.
253  * So, put comments here. tgl - 1997-09-08
254  *
255  * Quoted strings must allow some special characters such as single-quote
256  *  and newline.
257  * Embedded single-quotes are implemented both in the SQL92-standard
258  *  style of two adjacent single quotes "''" and in the Postgres/Java style
259  *  of escaped-quote "\'".
260  * Other embedded escaped characters are matched explicitly and the leading
261  *  backslash is dropped from the string. - thomas 1997-09-24
262  * Note that xcstart must appear before operator, as explained above!
263  *  Also whitespace (comment) must appear before operator.
264  */
265
266 %%
267 <SQL>{whitespace}       { /* ignore */ }
268
269 {xcstart}               {
270                                 state_before = YYSTATE;
271                                 ECHO;
272                                 BEGIN(xc);
273                                 /* Put back any characters past slash-star; see above */
274                                 yyless(2);
275                         }
276
277 <xc>{xcstop}    { ECHO; BEGIN(state_before); }
278
279 <xc>{xcinside}  { ECHO; }
280
281 <xc><<EOF>>            { mmerror(ET_ERROR, "Unterminated /* comment"); }
282
283 <SQL>{xbstart}          {
284                                         BEGIN(xb);
285                                         startlit();
286                                 }
287 <xb>{xbstop}    {
288                                         char* endptr;
289
290                                         BEGIN(SQL);
291                                         errno = 0;
292                                         yylval.ival = strtol(literalbuf, &endptr, 2);
293                                         if (*endptr != '\0' || errno == ERANGE)
294                                                 mmerror(ET_ERROR, "Bad binary integer input!");
295                                         return ICONST;
296                                 }
297 <xb><<EOF>>            { mmerror(ET_ERROR, "Unterminated binary integer"); }
298  
299 <xh>{xhinside}  |
300 <xb>{xbinside}  {
301                                         addlit(yytext, yyleng);
302                                 }
303 <xh>{xhcat}             |
304 <xb>{xbcat}             {               /* ignore */
305                                 }
306
307 <SQL>{xhstart}          {
308                                         BEGIN(xh);
309                                         startlit();
310                                 }
311 <xh>{xhstop}                    {
312                                         char* endptr;
313
314                                         BEGIN(SQL);
315                                         errno = 0;
316                                         yylval.ival = strtol(literalbuf, &endptr, 16);
317                                         if (*endptr != '\0' || errno == ERANGE)
318                                                 mmerror(ET_ERROR, "Bad hexadecimal integer input");
319                                         return ICONST;
320                                 }
321
322 <xb><<EOF>>            { mmerror(ET_ERROR, "Unterminated hexadecimal integer"); }
323
324 {xqstart}                       {
325                                         state_before = YYSTATE;
326                                         BEGIN(xq);
327                                         startlit();
328                                 }
329 <xq>{xqstop}                    {
330                                         BEGIN(state_before);
331                                         yylval.str = mm_strdup(literalbuf);
332                                         return SCONST;
333                                 }
334 <xq>{xqdouble}  |
335 <xq>{xqinside}  |
336 <xq>{xqliteral}                 {
337                                         addlit(yytext, yyleng);
338                                 }
339 <xq>{xqcat}                     {
340                                         /* ignore */
341                                 }
342
343 <xq><<EOF>>                     { mmerror(ET_ERROR, "Unterminated quoted string"); }
344
345 {xdstart}                       {
346                                         state_before = YYSTATE;
347                                         BEGIN(xd);
348                                         startlit();
349                                 }
350 <xd>{xdstop}                    {
351                                         BEGIN(state_before);
352                                         yylval.str = mm_strdup(literalbuf);
353                                         return CSTRING;
354                                 }
355 <xd>{xdinside}                  {
356                                         addlit(yytext, yyleng);
357                                 }
358 <xq><<EOF>>                     { mmerror(ET_ERROR, "Unterminated quoted identifier"); }
359 <SQL>{typecast}                 {       return TYPECAST; }
360 <SQL>{self}                     { /* 
361                                    * We may find a ';' inside a structure
362                                    * definition in a TYPE or VAR statement.
363                                    * This is not an EOL marker.
364                                    */
365                                   if (yytext[0] == ';' && struct_level == 0)
366                                          BEGIN C;
367                                   return yytext[0];
368                                 }
369 <SQL>{operator}                 {
370                                         /* Check for embedded slash-star or dash-dash */
371                                         char *slashstar = strstr((char*)yytext, "/*");
372                                         char *dashdash = strstr((char*)yytext, "--");
373
374                                         if (slashstar && dashdash)
375                                         {
376                                                 if (slashstar > dashdash)
377                                                         slashstar = dashdash;
378                                         }
379                                         else if (!slashstar)
380                                                 slashstar = dashdash;
381
382                                         if (slashstar)
383                                         {
384                                                 int nchars = slashstar - ((char*)yytext);
385                                                 yyless(nchars);
386                                                 /* If what we have left is only one char, and it's
387                                                  * one of the characters matching "self", then
388                                                  * return it as a character token the same way
389                                                  * that the "self" rule would have.
390                                                  */
391                                                 if (nchars == 1 &&
392                                                         strchr(",()[].;$:+-*/%^<>=|", yytext[0]))
393                                                         return yytext[0];
394                                         }
395
396                                         if (strcmp((char*)yytext, "!=") == 0)
397                                                 yylval.str = mm_strdup("<>"); /* compatability */
398                                         else
399                                                 yylval.str = mm_strdup((char*)yytext);
400                                         return Op;
401                                 }
402 <SQL>{param}                    {
403                                         yylval.ival = atol((char*)&yytext[1]);
404                                         return PARAM;
405                                 }
406 <C,SQL>{integer}                {
407                                         char* endptr;
408
409                                         errno = 0;
410                                         yylval.ival = strtol((char *)yytext, &endptr,10);
411                                         if (*endptr != '\0' || errno == ERANGE)
412                                         {
413                                                 errno = 0;
414                                                 yylval.str = mm_strdup((char*)yytext);
415                                                 return FCONST;
416                                         }
417                                         return ICONST;
418                                 }
419 {decimal}               {
420                                         yylval.str = mm_strdup((char*)yytext);
421                                         return FCONST;
422                                 }
423 <C,SQL>{real}                   {
424                                         yylval.str = mm_strdup((char*)yytext);
425                                         return FCONST;
426                                 }
427 <SQL>:{identifier}(("->"|\.){identifier})*      {
428                                         yylval.str = mm_strdup((char*)yytext+1);
429                                         return(CVARIABLE);
430                         }
431 <SQL>{identifier}       {
432                                         int i;
433                                         ScanKeyword             *keyword;
434                                         char lower_text[NAMEDATALEN];
435
436                                         /* this should leave the last byte set to '\0' */
437                                         strncpy(lower_text, yytext, NAMEDATALEN-1);
438                                         for(i = 0; lower_text[i]; i++)
439                                                 if (isascii((unsigned char)lower_text[i]) && isupper(lower_text[i]))
440                                                         lower_text[i] = tolower(lower_text[i]);
441
442                                         if (i >= NAMEDATALEN)
443                                         {
444                                                 sprintf(errortext, "Identifier \"%s\" will be truncated to \"%.*s\"", yytext, NAMEDATALEN-1, yytext);
445                                                 mmerror (ET_WARN, errortext);
446                                                 yytext[NAMEDATALEN-1] = '\0';
447                                         }
448
449                                         keyword = ScanKeywordLookup((char*)lower_text);
450                                         if (keyword != NULL) {
451                                                 return keyword->value;
452                                         }
453                                         else
454                                         {
455                                                 keyword = ScanECPGKeywordLookup((char*)lower_text);
456                                                 if (keyword != NULL) {
457                                                         return keyword->value;
458                                                 }
459                                                 else
460                                                 {
461                                                         struct _defines *ptr;
462
463                                                         for (ptr = defines; ptr; ptr = ptr->next)
464                                                         {
465                                                                 if (strcmp(yytext, ptr->old) == 0)
466                                                                 {
467                                                                         struct _yy_buffer *yb;
468
469                                                                         yb = mm_alloc(sizeof(struct _yy_buffer));
470
471                                                                         yb->buffer =  YY_CURRENT_BUFFER;
472                                                                         yb->lineno = yylineno;
473                                                                         yb->filename = mm_strdup(input_filename);
474                                                                         yb->next = yy_buffer;
475
476                                                                         yy_buffer = yb;
477
478                                                                         yy_scan_string(ptr->new);
479                                                                         break;
480                                                                 }
481                                                         }
482                                                         if (ptr == NULL) 
483                                                         {
484                                                                 yylval.str = mm_strdup((char*)yytext);
485                                                                 return IDENT;
486                                                         }
487                                                 }
488                                         }
489                                 }
490 <SQL>{other}                    { return yytext[0]; }
491 <C>{exec_sql}                   { BEGIN SQL; return SQL_START; }
492 <C>{ccomment}                   { /* ignore */ } 
493 <C>{xch}                        {
494                                         char* endptr;
495
496                                         errno = 0;
497                                         yylval.ival = strtol((char *)yytext,&endptr,16);
498                                         if (*endptr != '\0' || errno == ERANGE)
499                                         {
500                                                 errno = 0;
501                                                 yylval.str = mm_strdup((char*)yytext);
502                                                 return SCONST;
503                                         }
504                                         return ICONST;
505                                 }
506 <C>{cppline}                    {
507                                         yylval.str = mm_strdup((char*)yytext);
508                                         return(CPP_LINE);
509                                 }
510 <C>{identifier} {
511                                         ScanKeyword             *keyword;
512
513                                         keyword = ScanCKeywordLookup((char*)yytext);
514                                         if (keyword != NULL) {
515                                                 return keyword->value;
516                                         }
517                                         else
518                                         {
519                                                 struct _defines *ptr;
520
521                                                 for (ptr = defines; ptr; ptr = ptr->next)
522                                                 {
523                                                         if (strcmp(yytext, ptr->old) == 0)
524                                                         {
525                                                                 struct _yy_buffer *yb;
526
527                                                                 yb = mm_alloc(sizeof(struct _yy_buffer));
528
529                                                                 yb->buffer =  YY_CURRENT_BUFFER;
530                                                                 yb->lineno = yylineno;
531                                                                 yb->filename = mm_strdup(input_filename);
532                                                                 yb->next = yy_buffer;
533
534                                                                 yy_buffer = yb;
535
536                                                                 yy_scan_string(ptr->new);
537                                                                 break;
538                                                         }
539                                                 }
540                                                 if (ptr == NULL) 
541                                                 {
542                                                         yylval.str = mm_strdup((char*)yytext);
543                                                         return IDENT;
544                                                 }
545                                         }
546                                 }
547 <C>";"                  { return(';'); }
548 <C>","                  { return(','); }
549 <C>"*"                  { return('*'); }
550 <C>"%"                  { return('%'); }
551 <C>"/"                  { return('/'); }
552 <C>"+"                  { return('+'); }
553 <C>"-"                  { return('-'); }
554 <C>"("                  { return('('); }
555 <C>")"                  { return(')'); }
556 <C>{space_or_nl}        { ECHO; }
557 <C>\{                   { return('{'); }
558 <C>\}                   { return('}'); }
559 <C>\[                   { return('['); }
560 <C>\]                   { return(']'); }
561 <C>\=                   { return('='); }
562 <C>{other}              { return S_ANYTHING; }
563
564 <C>{exec_sql}{define}{space_or_nl}*     { BEGIN(def_ident); }
565 <C>{exec_sql}{include}{space_or_nl}*    { BEGIN(incl); }
566
567 <C,xskip>{exec_sql}{ifdef}{space_or_nl}*        { ifcond = TRUE; BEGIN(xcond); }
568 <C,xskip>{exec_sql}{ifndef}{space_or_nl}*       { ifcond = FALSE; BEGIN(xcond); }
569
570 <C,xskip>{exec_sql}{elif}{space_or_nl}* {       /* pop stack */
571                                                 if ( preproc_tos == 0 ) {
572                                                     mmerror(ET_FATAL, "Missing matching 'EXEC SQL IFDEF / EXEC SQL IFNDEF'");
573                                                 }
574                                                 else if ( stacked_if_value[preproc_tos].else_branch ) {
575                                                     mmerror(ET_FATAL, "Missing 'EXEC SQL ENDIF;'");
576                                                 }
577                                                 else {
578                                                     preproc_tos--;
579                                                 }
580
581                                                 ifcond = TRUE; BEGIN(xcond);
582                                         }
583
584 <C,xskip>{exec_sql}{else}{space_or_nl}*";" {    /* only exec sql endif pops the stack, so take care of duplicated 'else' */
585                                                 if ( stacked_if_value[preproc_tos].else_branch ) {
586                                                     mmerror(ET_FATAL, "Duplicated 'EXEC SQL ELSE;'");
587                                                 }
588                                                 else {
589                                                     stacked_if_value[preproc_tos].else_branch = TRUE;
590                                                     stacked_if_value[preproc_tos].condition = 
591                                                         (stacked_if_value[preproc_tos-1].condition &&
592                                                          ! stacked_if_value[preproc_tos].condition);
593
594                                                     if ( stacked_if_value[preproc_tos].condition ) {
595                                                         BEGIN(C);
596                                                     }
597                                                     else {
598                                                         BEGIN(xskip);
599                                                     }
600                                                 }
601                                         }
602 <C,xskip>{exec_sql}{endif}{space_or_nl}*";" { 
603                                                 if ( preproc_tos == 0 ) {
604                                                     mmerror(ET_FATAL, "Unmatched 'EXEC SQL ENDIF;'");
605                                                 }
606                                                 else {
607                                                     preproc_tos--;
608                                                 }
609
610                                                 if ( stacked_if_value[preproc_tos].condition ) {
611                                                    BEGIN(C);
612                                                 }
613                                                 else {
614                                                    BEGIN(xskip);
615                                                 }
616                                         }
617
618 <xskip>{other}                  { /* ignore */ }
619
620 <xcond>{identifier}{space_or_nl}*";" {
621                                         if ( preproc_tos >= MAX_NESTED_IF-1 ) {
622                                             mmerror(ET_FATAL, "Too many nested 'EXEC SQL IFDEF' conditions");
623                                         }
624                                         else {
625                                             struct _defines *defptr;
626                                             unsigned int i;
627
628                                             /* skip the ";" and trailing whitespace. Note that yytext contains
629                                                at least one non-space character plus the ";" */
630                                             for ( i = strlen(yytext)-2; i > 0 && isspace(yytext[i]); i-- ) {}
631                                             yytext[i+1] = '\0';
632
633                                             for ( defptr = defines; defptr != NULL &&
634                                                       ( strcmp((char*)yytext, defptr->old) != 0 ); defptr = defptr->next );
635
636                                             preproc_tos++;
637                                             stacked_if_value[preproc_tos].else_branch = FALSE;
638                                             stacked_if_value[preproc_tos].condition = 
639                                                 ( (defptr ? ifcond : !ifcond) && stacked_if_value[preproc_tos-1].condition );
640                                         }
641
642                                         if ( stacked_if_value[preproc_tos].condition ) {
643                                            BEGIN C;
644                                         }
645                                         else {
646                                            BEGIN(xskip);
647                                         }
648                                 }
649
650 <def_ident>{identifier} {
651                                 old = mm_strdup(yytext);
652                                 BEGIN(def);
653                                 startlit();
654                         }
655 <def>{space_or_nl}*";"  {
656                                 struct _defines *ptr, *this;
657         
658                                 for (ptr = defines; ptr != NULL; ptr = ptr->next)
659                                 {
660                                      if (strcmp(old, ptr->old) == 0)
661                                      {
662                                         free(ptr->new);
663                                         /* ptr->new = mm_strdup(scanstr(literalbuf));*/
664                                         ptr->new = mm_strdup(literalbuf);
665                                      }
666                                 }
667                                 if (ptr == NULL)
668                                 {                        
669                                         this = (struct _defines *) mm_alloc(sizeof(struct _defines));
670
671                                         /* initial definition */
672                                         this->old = old;
673                                         /* this->new = mm_strdup(scanstr(literalbuf));*/
674                                         this->new = mm_strdup(literalbuf);
675                                         this->next = defines;
676                                         defines = this;
677                                 }
678
679                                 BEGIN(C);
680                         }
681 <def>[^";"]             {
682                                 addlit(yytext, yyleng);
683                         }
684
685 <incl>[^";"]+";"        { /* got the include file name */
686                           struct _yy_buffer *yb;
687                           struct _include_path *ip;
688                           char inc_file[MAXPGPATH];
689                           unsigned int i;
690
691                           yb = mm_alloc(sizeof(struct _yy_buffer));
692
693                           yb->buffer =  YY_CURRENT_BUFFER;
694                           yb->lineno = yylineno;
695                           yb->filename = input_filename;
696                           yb->next = yy_buffer;
697
698                           yy_buffer = yb;
699
700                           /* skip the ";" and trailing whitespace. Note that yytext contains
701                              at least one non-space character plus the ";" */
702                           for ( i = strlen(yytext)-2; i > 0 && isspace(yytext[i]); i-- ) {}
703                           yytext[i+1] = '\0';
704
705                           yyin = NULL;
706                           for (ip = include_paths; yyin == NULL && ip != NULL; ip = ip->next)
707                           {
708                                 if (strlen(ip->path) + strlen(yytext) + 3 > MAXPGPATH)
709                                 {
710                                         fprintf(stderr, "Error: Path %s/%s is too long in line %d, skipping.\n", ip->path, yytext, yylineno);
711                                         continue;
712                                 }
713                                 sprintf (inc_file, "%s/%s", ip->path, yytext);
714                                 yyin = fopen( inc_file, "r" );
715                                 if (!yyin)
716                                 {
717                                         if (strcmp(inc_file + strlen(inc_file) - 2, ".h"))
718                                         {
719                                                 strcat(inc_file, ".h");
720                                                 yyin = fopen( inc_file, "r" );
721                                         }
722
723                                 }
724                           }
725                           if (!yyin)
726                           {
727                                 fprintf(stderr, "Error: Cannot open include file %s in line %d\n", yytext, yylineno);
728                                 exit(NO_INCLUDE_FILE); 
729                           }
730
731                           input_filename = mm_strdup(inc_file);
732                           yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE ));
733                           yylineno = 1;
734                           output_line_number();
735
736                           BEGIN C;
737                         }
738
739 <<EOF>>                 {
740                           if ( preproc_tos > 0 ) {
741                               preproc_tos = 0;
742
743                               mmerror(ET_FATAL, "Missing 'EXEC SQL ENDIF;'");
744                           }
745
746                           if (yy_buffer == NULL)
747                                 yyterminate();
748                           else
749                           {
750                                 struct _yy_buffer *yb = yy_buffer;
751
752                                 if (yyin != NULL)
753                                         fclose(yyin);
754
755                                 yy_delete_buffer( YY_CURRENT_BUFFER );
756                                 yy_switch_to_buffer(yy_buffer->buffer);
757
758                                 yylineno = yy_buffer->lineno;
759
760                                 free(input_filename);
761                                 input_filename = yy_buffer->filename;
762
763                                 yy_buffer = yy_buffer->next;
764                                 free(yb);
765                                 output_line_number();
766                           }
767                         }
768 %%
769 void
770 lex_init(void)
771 {
772         braces_open = 0;
773
774         preproc_tos = 0;
775         ifcond = TRUE;
776         stacked_if_value[preproc_tos].condition = ifcond;
777         stacked_if_value[preproc_tos].else_branch = FALSE;
778
779         /* initialize literal buffer to a reasonable but expansible size */
780         if (literalbuf == NULL)
781         {
782                 literalalloc = 128;
783                 literalbuf = (char *) malloc(literalalloc);
784         }
785         startlit();
786
787     BEGIN C;
788 }
789
790 static void
791 addlit(char *ytext, int yleng)
792 {
793         /* enlarge buffer if needed */
794         if ((literallen+yleng) >= literalalloc)
795         {
796                 do {
797                         literalalloc *= 2;
798                 } while ((literallen+yleng) >= literalalloc);
799                 literalbuf = (char *) realloc(literalbuf, literalalloc);
800         }
801         /* append data --- note we assume ytext is null-terminated */
802         memcpy(literalbuf+literallen, ytext, yleng+1);
803         literallen += yleng;
804 }
805
806 int yywrap(void) 
807 {
808     return 1;
809 }