pgc.l 25.3 KB
Newer Older
1
%{
2 3 4 5 6 7 8 9
/*-------------------------------------------------------------------------
 *
 * pgc.l
 *	  lexical scanner for ecpg
 *
 * This is a modified version of src/backend/parser/scan.l
 *
 *
10
 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
B
Add:  
Bruce Momjian 已提交
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.83 2001/12/23 12:17:41 meskes Exp $
16 17 18
 *
 *-------------------------------------------------------------------------
 */
19 20
#include "postgres_fe.h"

M
Marc G. Fournier 已提交
21
#include <ctype.h>
M
Marc G. Fournier 已提交
22
#include <sys/types.h>
23
#include <limits.h>
24
#include <errno.h>
25

M
 
Marc G. Fournier 已提交
26
#include "extern.h"
M
 
Marc G. Fournier 已提交
27
#include "preproc.h"
28

M
Marc G. Fournier 已提交
29 30 31 32 33
/* some versions of lex define this as a macro */
#if defined(yywrap)
#undef yywrap
#endif /* yywrap */

34 35
#define YY_NO_UNPUT

M
Marc G. Fournier 已提交
36
extern YYSTYPE yylval;
37

38 39
static int		xcdepth = 0;	/* depth of nesting in slash-star comments */

40 41 42 43 44 45 46 47 48 49 50 51 52
/*
 * literalbuf is used to accumulate literal values when multiple rules
 * are needed to parse a single literal.  Call startlit to reset buffer
 * to empty, addlit to add text.  Note that the buffer is permanently
 * malloc'd to the largest size needed so far in the current run.
 */
static char	   *literalbuf = NULL;		/* expandable buffer */
static int		literallen;		/* actual current length */
static int		literalalloc;	/* current allocated buffer size */

#define startlit()  (literalbuf[0] = '\0', literallen = 0)
static void addlit(char *ytext, int yleng);

M
Michael Meskes 已提交
53
int state_before;
M
Marc G. Fournier 已提交
54

55 56 57 58 59 60
struct _yy_buffer { YY_BUFFER_STATE 	buffer;
		    long		lineno;
		    char	      * filename;
		    struct _yy_buffer * next;
		  } *yy_buffer = NULL;

M
 
Marc G. Fournier 已提交
61 62
static char *old;

63 64 65 66 67 68 69 70
#define MAX_NESTED_IF 128
static short preproc_tos;
static short ifcond;
static struct _if_value {
    short condition;
    short else_branch;
} stacked_if_value[MAX_NESTED_IF];

71
%}
M
Michael Meskes 已提交
72

73
%option yylineno
M
 
Marc G. Fournier 已提交
74
%s C SQL incl def def_ident
M
Michael Meskes 已提交
75 76 77

/*
 * OK, here is a short description of lex/flex rules behavior.
M
Marc G. Fournier 已提交
78 79
 * The longest pattern which matches an input string is always chosen.
 * For equal-length patterns, the first occurring in the rules list is chosen.
M
Michael Meskes 已提交
80 81 82
 * INITIAL is the starting state, to which all non-conditional rules apply.
 * Exclusive states change parsing rules while the state is active.  When in
 * an exclusive state, only those rules defined for that state apply.
M
Marc G. Fournier 已提交
83
 *
M
Michael Meskes 已提交
84 85
 * We use exclusive states for quoted strings, extended comments,
 * and to eliminate parsing troubles for numeric strings.
M
Marc G. Fournier 已提交
86
 * Exclusive states:
M
Michael Meskes 已提交
87
 *  <xbit> bit string literal
88 89
 *  <xc> extended C-style comments - thomas 1997-07-12
 *  <xd> delimited identifiers (double-quoted identifiers) - thomas 1997-10-27
M
Marc G. Fournier 已提交
90
 *  <xh> hexadecimal numeric string - thomas 1997-11-16
91
 *  <xq> quoted strings - thomas 1997-07-30
M
Marc G. Fournier 已提交
92 93
 */

M
Michael Meskes 已提交
94
%x xbit
M
Marc G. Fournier 已提交
95 96
%x xc
%x xd
97
%x xdc
M
Marc G. Fournier 已提交
98 99
%x xh
%x xq
100 101 102
%x xpre
%x xcond
%x xskip
M
Marc G. Fournier 已提交
103

M
Michael Meskes 已提交
104
/* Bit string
M
Marc G. Fournier 已提交
105
 */
M
Michael Meskes 已提交
106 107 108 109
xbitstart		[bB]{quote}
xbitstop		{quote}
xbitinside		[^']*
xbitcat			{quote}{whitespace_with_newline}{quote}
M
Marc G. Fournier 已提交
110 111 112 113 114

/* Hexadecimal number
 */
xhstart			[xX]{quote}
xhstop			{quote}
M
Michael Meskes 已提交
115 116
xhinside		[^']+
xhcat			{quote}{whitespace_with_newline}{quote}
M
Marc G. Fournier 已提交
117

M
Michael Meskes 已提交
118 119 120 121
/* C version of hex number 
 */
xch			0[xX][0-9A-Fa-f]*

M
Marc G. Fournier 已提交
122 123 124 125 126 127 128 129
/* Extended quote
 * xqdouble implements SQL92 embedded quote
 * xqcat allows strings to cross input lines
 */
quote			'
xqstart			{quote}
xqstop			{quote}
xqdouble		{quote}{quote}
M
Michael Meskes 已提交
130
xqinside		[^\\']+
M
Marc G. Fournier 已提交
131
xqliteral		[\\](.|\n)
M
Michael Meskes 已提交
132
xqcat			{quote}{whitespace_with_newline}{quote}
M
Marc G. Fournier 已提交
133 134 135 136 137 138 139

/* Delimited quote
 * Allows embedded spaces and other special characters into identifiers.
 */
dquote			\"
xdstart			{dquote}
xdstop			{dquote}
M
Michael Meskes 已提交
140
xddouble               	{dquote}{dquote}
M
Michael Meskes 已提交
141
xdinside		[^"]+
M
Michael Meskes 已提交
142 143 144 145 146 147

/* special stuff for C strings */
xdcqq			\\\\
xdcqdq			\\\"
xdcother		[^"]
xdcinside		({xdcqq}|{xdcqdq}|{xdcother})
M
Marc G. Fournier 已提交
148

149 150
/* C-style comments
 *
M
Michael Meskes 已提交
151 152 153
 * The "extended comment" syntax closely resembles allowable operator syntax.
 * The tricky part here is to get lex to recognize a string starting with
 * slash-star as a comment, when interpreting it as an operator would produce
154 155 156
 * a longer match --- remember lex will prefer a longer match!  Also, if we
 * have something like plus-slash-star, lex will think this is a 3-character
 * operator whereas we want to see it as a + operator and a comment start.
M
Michael Meskes 已提交
157
 * The solution is two-fold:
158
 * 1. append {op_chars}* to xcstart so that it matches as much text as
M
Michael Meskes 已提交
159 160 161 162 163 164 165 166
 *    {operator} would. Then the tie-breaker (first matching rule of same
 *    length) ensures xcstart wins.  We put back the extra stuff with yyless()
 *    in case it contains a star-slash that should terminate the comment.
 * 2. In the operator rule, check for slash-star within the operator, and
 *    if found throw it back with yyless().  This handles the plus-slash-star
 *    problem.
 * SQL92-style comments, which start with dash-dash, have similar interactions
 * with the operator rule.
M
Marc G. Fournier 已提交
167
 */
168
xcstart			\/\*{op_chars}*
M
Michael Meskes 已提交
169
xcstop			\*+\/
M
Michael Meskes 已提交
170
xcinside 		[^*/]+
M
Marc G. Fournier 已提交
171 172 173

digit			[0-9]
letter			[\200-\377_A-Za-z]
174
letter_or_digit	[\200-\377_A-Za-z0-9]
M
Marc G. Fournier 已提交
175 176 177 178 179

identifier		{letter}{letter_or_digit}*

typecast		"::"

180 181 182 183 184 185 186 187 188 189
/*
 * "self" is the set of chars that should be returned as single-character
 * tokens.  "op_chars" is the set of chars that can make up "Op" tokens,
 * which can be one or more characters long (but if a single-char token
 * appears in the "self" set, it is not to be returned as an Op).  Note
 * that the sets overlap, but each has some chars that are not in the other.
 *
 * If you change either set, adjust the character lists appearing in the
 * rule for "operator"!
 */
M
Michael Meskes 已提交
190
self			[,()\[\].;$\:\+\-\*\/\%\^\<\>\=]
M
Michael Meskes 已提交
191
op_chars		[\~\!\@\#\^\&\|\`\?\$\+\-\*\/\%\<\>\=]
192
operator		{op_chars}+
M
Marc G. Fournier 已提交
193

194 195 196
/* we no longer allow unary minus in numbers. 
 * instead we pass it separately to parser. there it gets
 * coerced via doNegate() -- Leon aug 20 1999 
M
Michael Meskes 已提交
197
 */
198

M
Michael Meskes 已提交
199 200
integer			{digit}+
decimal			(({digit}*\.{digit}+)|({digit}+\.{digit}*))
201
real			((({digit}*\.{digit}+)|({digit}+\.{digit}*)|({digit}+))([Ee][-+]?{digit}+))
M
Marc G. Fournier 已提交
202 203 204

param			\${integer}

M
Michael Meskes 已提交
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
/*
 * In order to make the world safe for Windows and Mac clients as well as
 * Unix ones, we accept either \n or \r as a newline.  A DOS-style \r\n
 * sequence will be seen as two successive newlines, but that doesn't cause
 * any problems.  SQL92-style comments, which start with -- and extend to the
 * next newline, are treated as equivalent to a single whitespace character.
 *
 * NOTE a fine point: if there is no newline following --, we will absorb
 * everything to the end of the input as a comment.  This is correct.  Older
 * versions of Postgres failed to recognize -- as a comment if the input
 * did not end with a newline.
 *
 * XXX perhaps \f (formfeed) should be treated as a newline as well?
 */

M
Michael Meskes 已提交
220
ccomment		"//".*\n
M
Marc G. Fournier 已提交
221

222
space			[ \t\n\r\f]
M
Michael Meskes 已提交
223 224 225 226
horiz_space		[ \t\f]
newline                 [\n\r]
non_newline		[^\n\r]

227
comment         ("--"{non_newline}*)
M
Michael Meskes 已提交
228 229 230 231 232 233 234 235 236 237 238 239 240

whitespace 		({space}|{comment})

/*
 * SQL92 requires at least one newline in the whitespace separating
 * string literals that are to be concatenated.  Silly, but who are we
 * to argue?  Note that {whitespace_with_newline} should not have * after
 * it, whereas {whitespace} should generally have a * after it...
 */

horiz_whitespace	({horiz_space}|{comment})
whitespace_with_newline	({horiz_whitespace}*{newline}{whitespace}*)

M
Marc G. Fournier 已提交
241 242 243 244
other			.

/* some stuff needed for ecpg */
exec    [eE][xX][eE][cC]
245
sql     [sS][qQ][lL]
M
 
Marc G. Fournier 已提交
246
define	[dD][eE][fF][iI][nN][eE]
247
include [iI][nN][cC][lL][uU][dD][eE]
M
Marc G. Fournier 已提交
248

249 250 251 252 253 254
ifdef	[iI][fF][dD][eE][fF]
ifndef	[iI][fF][nN][dD][eE][fF]
else	[eE][lL][sS][eE]
elif	[eE][lL][iI][fF]
endif	[eE][nN][dD][iI][fF]

255
exec_sql		{exec}{space}*{sql}{space}*
M
Michael Meskes 已提交
256 257
ipdigit			({digit}|{digit}{digit}|{digit}{digit}{digit})
ip			{ipdigit}\.{ipdigit}\.{ipdigit}\.{ipdigit}
258 259

/* Take care of cpp continuation lines */
260
cppline			{space}*#(.*\\{space})*.*
M
 
Marc G. Fournier 已提交
261

M
Marc G. Fournier 已提交
262 263
/* DO NOT PUT ANY COMMENTS IN THE FOLLOWING SECTION.
 * AT&T lex does not properly handle C-style comments in this second lex block.
264
 * So, put comments here. thomas - 1997-09-08
M
Marc G. Fournier 已提交
265 266 267
 *
 * Quoted strings must allow some special characters such as single-quote
 *  and newline.
M
Michael Meskes 已提交
268
 * Embedded single-quotes are implemented both in the SQL92-standard
M
Marc G. Fournier 已提交
269 270 271 272
 *  style of two adjacent single quotes "''" and in the Postgres/Java style
 *  of escaped-quote "\'".
 * Other embedded escaped characters are matched explicitly and the leading
 *  backslash is dropped from the string. - thomas 1997-09-24
M
Michael Meskes 已提交
273 274
 * Note that xcstart must appear before operator, as explained above!
 *  Also whitespace (comment) must appear before operator.
M
Marc G. Fournier 已提交
275 276
 */

277
%%
M
Michael Meskes 已提交
278
<SQL>{whitespace}	{ /* ignore */ }
M
Marc G. Fournier 已提交
279

280
{xcstart}		{
M
Michael Meskes 已提交
281
				state_before = YYSTATE;
M
Michael Meskes 已提交
282
				xcdepth = 0;
283
	 			BEGIN(xc);
M
Michael Meskes 已提交
284 285
				/* Put back any characters past slash-star; see above */
				yyless(2);
M
Michael Meskes 已提交
286
				fputs("/*", yyout);
287
			}
M
Marc G. Fournier 已提交
288

M
Michael Meskes 已提交
289 290 291 292 293 294 295 296 297 298 299 300 301 302
<xc>{xcstart}   {
                        xcdepth++;
                        /* Put back any characters past slash-star; see above */
                        yyless(2);
			fputs("/*", yyout);
                }

<xc>{xcstop}    {
			ECHO;
                        if (xcdepth <= 0)
                        	BEGIN(state_before);
                        else
                                xcdepth--;
		}
M
Marc G. Fournier 已提交
303

M
Michael Meskes 已提交
304
<xc>{xcinside}	{ ECHO; }
M
Michael Meskes 已提交
305
<xc>{op_chars}  { ECHO; }
M
Marc G. Fournier 已提交
306

307
<xc><<EOF>>            { mmerror(PARSE_ERROR, ET_ERROR, "Unterminated /* comment"); }
M
Michael Meskes 已提交
308

M
Michael Meskes 已提交
309 310
<SQL>{xbitstart}		{
					BEGIN(xbit);
311
					startlit();
M
Marc G. Fournier 已提交
312
				}
M
Michael Meskes 已提交
313
<xbit>{xbitstop}		{
M
Marc G. Fournier 已提交
314
					BEGIN(SQL);
M
Michael Meskes 已提交
315
					if (literalbuf[strspn(literalbuf, "01") + 1] != '\0')
316
						mmerror(PARSE_ERROR, ET_ERROR, "invalid bit string input.");
M
Michael Meskes 已提交
317 318
					yylval.str = literalbuf;
			                return BITCONST;
M
Marc G. Fournier 已提交
319
				}
M
Michael Meskes 已提交
320
 
M
Marc G. Fournier 已提交
321
<xh>{xhinside}	|
M
Michael Meskes 已提交
322
<xbit>{xbitinside}	{
323
					addlit(yytext, yyleng);
M
Marc G. Fournier 已提交
324 325
				}
<xh>{xhcat}		|
M
Michael Meskes 已提交
326
<xbit>{xbitcat}		{
327
					/* ignore */
M
Marc G. Fournier 已提交
328
				}
329
<xbit><<EOF>>		{ mmerror(PARSE_ERROR, ET_ERROR, "Unterminated bit string"); }
M
Marc G. Fournier 已提交
330 331 332

<SQL>{xhstart}		{
					BEGIN(xh);
333
					startlit();
M
Marc G. Fournier 已提交
334
				}
M
Michael Meskes 已提交
335
<xh>{xhstop}			{
M
Michael Meskes 已提交
336
					long val;
M
Marc G. Fournier 已提交
337 338 339 340
					char* endptr;

					BEGIN(SQL);
					errno = 0;
M
Michael Meskes 已提交
341 342 343 344 345 346 347
					val = strtol(literalbuf, &endptr, 16);
					if (*endptr != '\0' || errno == ERANGE
#ifdef HAVE_LONG_INT_64  
						/* if long > 32 bits, check for overflow of int4 */
	                                        || val != (long) ((int32) val)
#endif
						)
348
						mmerror(PARSE_ERROR, ET_ERROR, "Bad hexadecimal integer input");
M
Michael Meskes 已提交
349
					yylval.ival = val;
350
					return ICONST;
M
Marc G. Fournier 已提交
351 352
				}

353
<xh><<EOF>>		{ mmerror(PARSE_ERROR, ET_ERROR, "Unterminated hexadecimal integer"); }
M
Michael Meskes 已提交
354

M
Michael Meskes 已提交
355
{xqstart}			{
356
					state_before = YYSTATE;
M
Marc G. Fournier 已提交
357
					BEGIN(xq);
358
					startlit();
M
Marc G. Fournier 已提交
359
				}
M
Michael Meskes 已提交
360 361
<xq>{xqstop}			{
					BEGIN(state_before);
362
					yylval.str = mm_strdup(literalbuf);
363
					return SCONST;
M
Marc G. Fournier 已提交
364 365
				}
<xq>{xqdouble}	|
366
<xq>{xqinside}	|
M
Michael Meskes 已提交
367
<xq>{xqliteral} 		{
368
					addlit(yytext, yyleng);
M
Marc G. Fournier 已提交
369
				}
M
Michael Meskes 已提交
370 371
<xq>{xqcat}			{
					/* ignore */
M
Marc G. Fournier 已提交
372 373
				}

374
<xq><<EOF>> 	 	        { mmerror(PARSE_ERROR, ET_ERROR, "Unterminated quoted string"); }
M
Michael Meskes 已提交
375

M
Michael Meskes 已提交
376
<SQL>{xdstart}			{
M
Michael Meskes 已提交
377
					state_before = YYSTATE;
M
Marc G. Fournier 已提交
378
					BEGIN(xd);
379
					startlit();
M
Marc G. Fournier 已提交
380
				}
M
Michael Meskes 已提交
381
<xd>{xdstop}		{
M
Michael Meskes 已提交
382
					BEGIN(state_before);
M
Michael Meskes 已提交
383 384
					if (strlen(literalbuf) >= NAMEDATALEN)
       			                {
385
#ifdef MULTIBYTE_NOTUSED
M
Michael Meskes 已提交
386 387 388 389 390 391 392 393 394 395 396
                                                int len;

	                                        len = pg_mbcliplen(literalbuf,strlen(literalbuf),NAMEDATALEN-1);
						sprintf(errortext, "identifier \"%s\" will be truncated to \"%.*s\"",
                                                        literalbuf, len, literalbuf);
	                                        literalbuf[len] = '\0';
#else
						sprintf(errortext, "identifier \"%s\" will be truncated to \"%.*s\"",
                                                        literalbuf, NAMEDATALEN-1, literalbuf);
                                                literalbuf[NAMEDATALEN-1] = '\0';
#endif
397
 						mmerror(PARSE_ERROR, ET_NOTICE, errortext);
M
Michael Meskes 已提交
398 399 400 401 402 403 404
                                        }

					yylval.str = mm_strdup(literalbuf);
					return CSTRING;
				}
<xdc>{xdstop}			{
					BEGIN(state_before);   
405
					yylval.str = mm_strdup(literalbuf);
406
					return CSTRING;
407
				}
M
Michael Meskes 已提交
408 409 410
<xd>{xddouble} 			{
					addlit(yytext, yyleng-1);
				}
M
Michael Meskes 已提交
411
<xd>{xdinside}			{
412
					addlit(yytext, yyleng);
413
				}
414
<xd,xdc><<EOF>> 	 	        { mmerror(PARSE_ERROR, ET_ERROR, "Unterminated quoted identifier"); }
M
Michael Meskes 已提交
415 416 417 418 419 420 421 422
{xdstart}			{
					state_before = YYSTATE;
					BEGIN(xdc);
					startlit();
				}
<xdc>{xdcinside}		{
 					addlit(yytext, yyleng);
				}
M
Marc G. Fournier 已提交
423
<SQL>{typecast}			{ 	return TYPECAST; }
M
Michael Meskes 已提交
424 425 426 427 428 429 430 431 432
<SQL>{self}			{ /* 
				   * We may find a ';' inside a structure
				   * definition in a TYPE or VAR statement.
				   * This is not an EOL marker.
				   */
				  if (yytext[0] == ';' && struct_level == 0)
					 BEGIN C;
				  return yytext[0];
				}
M
Michael Meskes 已提交
433
<SQL>{operator}			{
434 435 436 437 438 439 440 441 442
					/*
					 * Check for embedded slash-star or dash-dash; those
					 * are comment starts, so operator must stop there.
					 * Note that slash-star or dash-dash at the first
					 * character will match a prior rule, not this one.
					 */
					int		nchars = yyleng;
					char   *slashstar = strstr((char*)yytext, "/*");
					char   *dashdash = strstr((char*)yytext, "--");
M
Michael Meskes 已提交
443 444 445

					if (slashstar && dashdash)
					{
446
						/* if both appear, take the first one */
M
Michael Meskes 已提交
447 448 449 450 451 452
						if (slashstar > dashdash)
							slashstar = dashdash;
					}
					else if (!slashstar)
						slashstar = dashdash;
					if (slashstar)
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470
						nchars = slashstar - ((char*)yytext);

					/*
					 * For SQL92 compatibility, '+' and '-' cannot be the
					 * last char of a multi-char operator unless the operator
					 * contains chars that are not in SQL92 operators.
					 * The idea is to lex '=-' as two operators, but not
					 * to forbid operator names like '?-' that could not be
					 * sequences of SQL92 operators.
					 */
					while (nchars > 1 &&
						   (yytext[nchars-1] == '+' ||
							yytext[nchars-1] == '-'))
					{
						int		ic;

						for (ic = nchars-2; ic >= 0; ic--)
						{
M
Michael Meskes 已提交
471
							if (strchr("~!@#^&|`?$%", yytext[ic]))
472 473 474 475 476 477 478 479
								break;
						}
						if (ic >= 0)
							break; /* found a char that makes it OK */
						nchars--; /* else remove the +/-, and check again */
					}

					if (nchars < yyleng)
M
Michael Meskes 已提交
480
					{
481
						/* Strip the unwanted chars from the token */
M
Michael Meskes 已提交
482
						yyless(nchars);
483 484
						/*
						 * If what we have left is only one char, and it's
M
Michael Meskes 已提交
485 486 487 488 489
						 * one of the characters matching "self", then
						 * return it as a character token the same way
						 * that the "self" rule would have.
						 */
						if (nchars == 1 &&
M
Michael Meskes 已提交
490
							strchr(",()[].;$:+-*/%^<>=", yytext[0]))
M
Michael Meskes 已提交
491 492 493
							return yytext[0];
					}

494
					/* Convert "!=" operator to "<>" for compatibility */
M
Michael Meskes 已提交
495
					if (strcmp((char*)yytext, "!=") == 0)
496
						yylval.str = mm_strdup("<>");
M
Marc G. Fournier 已提交
497
					else
M
 
Marc G. Fournier 已提交
498
						yylval.str = mm_strdup((char*)yytext);
499
					return Op;
M
Marc G. Fournier 已提交
500 501
				}
<SQL>{param}			{
M
Michael Meskes 已提交
502
					yylval.ival = atol((char*)&yytext[1]);
503
					return PARAM;
M
Marc G. Fournier 已提交
504
				}
M
Michael Meskes 已提交
505
<C,SQL>{integer}		{
M
Michael Meskes 已提交
506
					long val;
M
Marc G. Fournier 已提交
507 508 509
					char* endptr;

					errno = 0;
M
Michael Meskes 已提交
510 511 512 513 514 515 516
					val = strtol((char *)yytext, &endptr,10);
					if (*endptr != '\0' || errno == ERANGE
#ifdef HAVE_LONG_INT_64  
						/* if long > 32 bits, check for overflow of int4 */
	                                        || val != (long) ((int32) val)
#endif
						)
M
Marc G. Fournier 已提交
517 518
					{
						errno = 0;
M
Michael Meskes 已提交
519
						yylval.str = mm_strdup((char*)yytext);
M
Michael Meskes 已提交
520
						return FCONST;
M
Marc G. Fournier 已提交
521
					}
M
Michael Meskes 已提交
522
					yylval.ival = val;
523
					return ICONST;
M
Marc G. Fournier 已提交
524
				}
M
Michael Meskes 已提交
525 526 527 528
<SQL>{ip}			{
					yylval.str = mm_strdup((char*)yytext);
					return IP;
				}
529 530
{decimal}		{
					yylval.str = mm_strdup((char*)yytext);
M
Michael Meskes 已提交
531
					return FCONST;
532
				}
M
Michael Meskes 已提交
533
<C,SQL>{real}			{
M
Michael Meskes 已提交
534
					yylval.str = mm_strdup((char*)yytext);
535
					return FCONST;
M
Marc G. Fournier 已提交
536
				}
537
<SQL>:{identifier}(("->"|\.){identifier})*	{
M
 
Marc G. Fournier 已提交
538
					yylval.str = mm_strdup((char*)yytext+1);
539 540
					return(CVARIABLE);
			}
M
Marc G. Fournier 已提交
541
<SQL>{identifier}	{
542 543
					ScanKeyword	   *keyword;
					struct _defines *ptr;
M
 
Marc G. Fournier 已提交
544

545 546 547 548
					/* Is it an SQL keyword? */
					keyword = ScanKeywordLookup((char*) yytext);
					if (keyword != NULL)
						return keyword->value;
M
Michael Meskes 已提交
549

550 551 552
					/* Is it an ECPG keyword? */
					keyword = ScanECPGKeywordLookup((char*) yytext);
					if (keyword != NULL)
553
						return keyword->value;
554 555 556

					/* How about a DEFINE? */
					for (ptr = defines; ptr; ptr = ptr->next)
M
Marc G. Fournier 已提交
557
					{
558
						if (strcmp(yytext, ptr->old) == 0)
M
Marc G. Fournier 已提交
559
						{
560
							struct _yy_buffer *yb;
M
 
Marc G. Fournier 已提交
561

562
							yb = mm_alloc(sizeof(struct _yy_buffer));
M
 
Marc G. Fournier 已提交
563

564 565 566 567
							yb->buffer =  YY_CURRENT_BUFFER;
							yb->lineno = yylineno;
							yb->filename = mm_strdup(input_filename);
							yb->next = yy_buffer;
M
 
Marc G. Fournier 已提交
568

569
							yy_buffer = yb;
M
 
Marc G. Fournier 已提交
570

571 572
							yy_scan_string(ptr->new);
							break;
M
Marc G. Fournier 已提交
573 574
						}
					}
575 576 577 578 579 580 581 582 583 584 585 586 587 588

					/*
					 * None of the above.  Return it as an identifier.
					 *
					 * The backend would attempt to truncate and case-fold
					 * the identifier, but I see no good reason for ecpg
					 * to do so; that's just another way that ecpg could get
					 * out of step with the backend.
					 */
					if (ptr == NULL) 
					{
						yylval.str = mm_strdup((char*) yytext);
						return IDENT;
					}
M
Marc G. Fournier 已提交
589
				}
590
<SQL>{other}			{ return yytext[0]; }
591
<C>{exec_sql}			{ BEGIN SQL; return SQL_START; }
592
<C>{ccomment}			{ /* ignore */ } 
M
Michael Meskes 已提交
593 594 595 596 597 598 599 600 601
<C>{xch}			{
					char* endptr;

					errno = 0;
					yylval.ival = strtol((char *)yytext,&endptr,16);
					if (*endptr != '\0' || errno == ERANGE)
					{
						errno = 0;
						yylval.str = mm_strdup((char*)yytext);
602
						return SCONST;
M
Michael Meskes 已提交
603 604 605
					}
					return ICONST;
				}
M
 
Marc G. Fournier 已提交
606
<C>{cppline}			{
M
 
Marc G. Fournier 已提交
607
					yylval.str = mm_strdup((char*)yytext);
M
 
Marc G. Fournier 已提交
608 609
					return(CPP_LINE);
				}
M
Marc G. Fournier 已提交
610 611 612 613 614
<C>{identifier}	{
					ScanKeyword		*keyword;

					keyword = ScanCKeywordLookup((char*)yytext);
					if (keyword != NULL) {
615
						return keyword->value;
M
Marc G. Fournier 已提交
616 617 618
					}
					else
					{
M
 
Marc G. Fournier 已提交
619 620 621 622 623 624 625 626 627 628 629 630
						struct _defines *ptr;

						for (ptr = defines; ptr; ptr = ptr->next)
						{
							if (strcmp(yytext, ptr->old) == 0)
							{
								struct _yy_buffer *yb;

								yb = mm_alloc(sizeof(struct _yy_buffer));

					                        yb->buffer =  YY_CURRENT_BUFFER;
					                        yb->lineno = yylineno;
M
 
Marc G. Fournier 已提交
631
					                        yb->filename = mm_strdup(input_filename);
M
 
Marc G. Fournier 已提交
632 633 634 635 636 637 638 639 640 641
					                        yb->next = yy_buffer;

					                        yy_buffer = yb;

								yy_scan_string(ptr->new);
								break;
							}
						}
						if (ptr == NULL) 
						{
M
 
Marc G. Fournier 已提交
642
							yylval.str = mm_strdup((char*)yytext);
643
							return IDENT;
M
 
Marc G. Fournier 已提交
644
						}
M
Marc G. Fournier 已提交
645 646 647
					}
				}
<C>";"	      	        { return(';'); }
648 649
<C>","	      	        { return(','); }
<C>"*"	      	        { return('*'); }
M
Michael Meskes 已提交
650 651 652 653 654 655
<C>"%"	      	        { return('%'); }
<C>"/"	      	        { return('/'); }
<C>"+"	      	        { return('+'); }
<C>"-"	      	        { return('-'); }
<C>"("	      	        { return('('); }
<C>")"	      	        { return(')'); }
656
<C>{space}	{ ECHO; }
657 658 659 660 661
<C>\{			{ return('{'); }
<C>\}			{ return('}'); }
<C>\[			{ return('['); }
<C>\]			{ return(']'); }
<C>\=			{ return('='); }
662 663 664 665 666
<C>"->"			{ return(S_MEMBER); } 
<C>">>"			{ return(S_RSHIFT); } 
<C>"<<"			{ return(S_LSHIFT); } 
<C>"||"			{ return(S_OR); } 
<C>"&&"			{ return(S_AND); } 
667 668 669 670 671 672 673 674 675 676 677
<C>"++"			{ return(S_INC); } 
<C>"--"			{ return(S_DEC); } 
<C>"=="			{ return(S_EQUAL); } 
<C>"!="			{ return(S_NEQUAL); } 
<C>"+="			{ return(S_ADD); } 
<C>"-="			{ return(S_SUB); } 
<C>"*="			{ return(S_MUL); } 
<C>"/="			{ return(S_DIV); } 
<C>"%="			{ return(S_MOD); } 
<C>"->*"		{ return(S_MEMPOINT); } 
<C>".*"			{ return(S_DOTPOINT); } 
M
Michael Meskes 已提交
678
<C>{other}		{ return S_ANYTHING; }
679

680 681
<C>{exec_sql}{define}{space}*	{ BEGIN(def_ident); }
<C>{exec_sql}{include}{space}*	{ BEGIN(incl); }
682

683 684
<C,xskip>{exec_sql}{ifdef}{space}* 	{ ifcond = TRUE; BEGIN(xcond); }
<C,xskip>{exec_sql}{ifndef}{space}*	{ ifcond = FALSE; BEGIN(xcond); }
685

686
<C,xskip>{exec_sql}{elif}{space}*	{	/* pop stack */
687
						if ( preproc_tos == 0 ) {
688
						    mmerror(PARSE_ERROR, ET_FATAL, "Missing matching 'EXEC SQL IFDEF / EXEC SQL IFNDEF'");
689 690
						}
						else if ( stacked_if_value[preproc_tos].else_branch ) {
691
						    mmerror(PARSE_ERROR, ET_FATAL, "Missing 'EXEC SQL ENDIF;'");
692 693 694 695 696 697 698 699
						}
						else {
						    preproc_tos--;
						}

						ifcond = TRUE; BEGIN(xcond);
					}

700
<C,xskip>{exec_sql}{else}{space}*";" {	/* only exec sql endif pops the stack, so take care of duplicated 'else' */
701
						if ( stacked_if_value[preproc_tos].else_branch ) {
702
						    mmerror(PARSE_ERROR, ET_FATAL, "Duplicated 'EXEC SQL ELSE;'");
703 704 705 706 707 708 709 710 711 712 713 714 715 716 717
						}
						else {
						    stacked_if_value[preproc_tos].else_branch = TRUE;
						    stacked_if_value[preproc_tos].condition = 
							(stacked_if_value[preproc_tos-1].condition &&
							 ! stacked_if_value[preproc_tos].condition);

						    if ( stacked_if_value[preproc_tos].condition ) {
							BEGIN(C);
						    }
						    else {
							BEGIN(xskip);
						    }
						}
					}
718
<C,xskip>{exec_sql}{endif}{space}*";" { 
719
						if ( preproc_tos == 0 ) {
720
						    mmerror(PARSE_ERROR, ET_FATAL, "Unmatched 'EXEC SQL ENDIF;'");
721 722 723 724 725 726 727 728 729 730 731 732 733 734 735
						}
						else {
						    preproc_tos--;
						}

						if ( stacked_if_value[preproc_tos].condition ) {
						   BEGIN(C);
						}
						else {
						   BEGIN(xskip);
						}
					}

<xskip>{other}			{ /* ignore */ }

736
<xcond>{identifier}{space}*";" {
737
					if ( preproc_tos >= MAX_NESTED_IF-1 ) {
738
					    mmerror(PARSE_ERROR, ET_FATAL, "Too many nested 'EXEC SQL IFDEF' conditions");
739 740 741 742 743 744 745
					}
					else {
					    struct _defines *defptr;
					    unsigned int i;

					    /* skip the ";" and trailing whitespace. Note that yytext contains
					       at least one non-space character plus the ";" */
746 747 748 749
					    for ( i = strlen(yytext)-2;
							  i > 0 && isspace((unsigned char) yytext[i]);
							  i-- )
						{}
750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768
					    yytext[i+1] = '\0';

					    for ( defptr = defines; defptr != NULL &&
						      ( strcmp((char*)yytext, defptr->old) != 0 ); defptr = defptr->next );

					    preproc_tos++;
					    stacked_if_value[preproc_tos].else_branch = FALSE;
					    stacked_if_value[preproc_tos].condition = 
						( (defptr ? ifcond : !ifcond) && stacked_if_value[preproc_tos-1].condition );
					}

					if ( stacked_if_value[preproc_tos].condition ) {
					   BEGIN C;
					}
					else {
					   BEGIN(xskip);
					}
				}

M
 
Marc G. Fournier 已提交
769
<def_ident>{identifier}	{
M
 
Marc G. Fournier 已提交
770
				old = mm_strdup(yytext);
M
 
Marc G. Fournier 已提交
771
				BEGIN(def);
772
				startlit();
M
 
Marc G. Fournier 已提交
773
			}
774
<def>{space}*";"	{
M
 
Marc G. Fournier 已提交
775 776 777 778 779 780 781
				struct _defines *ptr, *this;
        
                                for (ptr = defines; ptr != NULL; ptr = ptr->next)
                                {
                                     if (strcmp(old, ptr->old) == 0)
                                     {
					free(ptr->new);
782 783
					/* ptr->new = mm_strdup(scanstr(literalbuf));*/
					ptr->new = mm_strdup(literalbuf);
M
 
Marc G. Fournier 已提交
784 785 786 787 788 789 790 791
                                     }
                                }
				if (ptr == NULL)
				{                        
                                        this = (struct _defines *) mm_alloc(sizeof(struct _defines));

                                        /* initial definition */
                                        this->old = old;
792 793
                                        /* this->new = mm_strdup(scanstr(literalbuf));*/
                                        this->new = mm_strdup(literalbuf);
M
 
Marc G. Fournier 已提交
794 795 796 797 798 799 800
					this->next = defines;
					defines = this;
				}

				BEGIN(C);
			}
<def>[^";"]		{
801
				addlit(yytext, yyleng);
M
 
Marc G. Fournier 已提交
802
			}
803 804

<incl>[^";"]+";" 	{ /* got the include file name */
805 806
			  struct _yy_buffer *yb;
			  struct _include_path *ip;
807
			  char inc_file[MAXPGPATH];
808
			  unsigned int i;
809 810 811 812 813 814 815 816 817 818

			  yb = mm_alloc(sizeof(struct _yy_buffer));

			  yb->buffer =  YY_CURRENT_BUFFER;
			  yb->lineno = yylineno;
			  yb->filename = input_filename;
			  yb->next = yy_buffer;

			  yy_buffer = yb;

819 820
			  /* skip the ";" and trailing whitespace. Note that yytext contains
			     at least one non-space character plus the ";" */
821 822 823 824
			  for ( i = strlen(yytext)-2;
					i > 0 && isspace((unsigned char) yytext[i]);
					i-- )
			  {}
825
			  yytext[i+1] = '\0';
826 827 828 829

			  yyin = NULL;
			  for (ip = include_paths; yyin == NULL && ip != NULL; ip = ip->next)
			  {
830
				if (strlen(ip->path) + strlen(yytext) + 3 > MAXPGPATH)
831
				{
M
Marc G. Fournier 已提交
832
					fprintf(stderr, "Error: Path %s/%s is too long in line %d, skipping.\n", ip->path, yytext, yylineno);
833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848
					continue;
				}
			  	sprintf (inc_file, "%s/%s", ip->path, yytext);
		          	yyin = fopen( inc_file, "r" );
			  	if (!yyin)
				{
					if (strcmp(inc_file + strlen(inc_file) - 2, ".h"))
					{
						strcat(inc_file, ".h");
						yyin = fopen( inc_file, "r" );
					}

				}
			  }
			  if (!yyin)
			  {
M
Marc G. Fournier 已提交
849
				fprintf(stderr, "Error: Cannot open include file %s in line %d\n", yytext, yylineno);
850
				exit(NO_INCLUDE_FILE); 
851 852
			  }

M
 
Marc G. Fournier 已提交
853
			  input_filename = mm_strdup(inc_file);
854
			  yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE ));
855
			  yylineno = 1;
M
Michael Meskes 已提交
856
			  output_line_number();
857 858 859

			  BEGIN C;
			}
860 861 862 863 864

<<EOF>>			{
			  if ( preproc_tos > 0 ) {
			      preproc_tos = 0;

865
			      mmerror(PARSE_ERROR, ET_FATAL, "Missing 'EXEC SQL ENDIF;'");
866 867 868
			  }

			  if (yy_buffer == NULL)
869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886
				yyterminate();
			  else
			  {
				struct _yy_buffer *yb = yy_buffer;

				if (yyin != NULL)
					fclose(yyin);

				yy_delete_buffer( YY_CURRENT_BUFFER );
				yy_switch_to_buffer(yy_buffer->buffer);

				yylineno = yy_buffer->lineno;

				free(input_filename);
				input_filename = yy_buffer->filename;

				yy_buffer = yy_buffer->next;
				free(yb);
M
Michael Meskes 已提交
887
				output_line_number();
888 889
			  }
			}
890 891
%%
void
892
lex_init(void)
893
{
894 895 896
	braces_open = 0;

	preproc_tos = 0;
M
Michael Meskes 已提交
897
	yylineno = 1;
898 899 900
	ifcond = TRUE;
	stacked_if_value[preproc_tos].condition = ifcond;
	stacked_if_value[preproc_tos].else_branch = FALSE;
901 902 903 904 905 906 907 908 909

	/* initialize literal buffer to a reasonable but expansible size */
	if (literalbuf == NULL)
	{
		literalalloc = 128;
		literalbuf = (char *) malloc(literalalloc);
	}
	startlit();

910 911 912
    BEGIN C;
}

913 914 915 916 917 918 919 920 921 922 923
static void
addlit(char *ytext, int yleng)
{
	/* enlarge buffer if needed */
	if ((literallen+yleng) >= literalalloc)
	{
		do {
			literalalloc *= 2;
		} while ((literallen+yleng) >= literalalloc);
		literalbuf = (char *) realloc(literalbuf, literalalloc);
	}
924 925
	/* append new data, add trailing null */
	memcpy(literalbuf+literallen, ytext, yleng);
926
	literallen += yleng;
927
	literalbuf[literallen] = '\0';
928 929
}

930
int yywrap(void) 
931
{
932 933
    return 1;
}