pgc.l 24.8 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
 *
 *
B
Bruce Momjian 已提交
10
 * Portions Copyright (c) 1996-2002, 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.101 2002/11/07 06:06:17 tgl 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"
27

28

M
Marc G. Fournier 已提交
29
extern YYSTYPE yylval;
30

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

33 34 35 36 37 38
/*
 * 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.
 */
39 40 41
static char    *literalbuf = NULL;		/* expandable buffer */
static int		literallen;				/* actual current length */
static int		literalalloc;			/* current allocated buffer size */
42

43
#define startlit()	(literalbuf[0] = '\0', literallen = 0)
44
static void addlit(char *ytext, int yleng);
45
static void addlitchar (unsigned char);
46

M
Michael Meskes 已提交
47
char *token_start;
M
Michael Meskes 已提交
48
int state_before;
M
Marc G. Fournier 已提交
49

50 51 52 53 54 55 56
struct _yy_buffer 
{ 
	YY_BUFFER_STATE		buffer;
	long				lineno;
	char		  		*filename;
	struct _yy_buffer 	*next;
} *yy_buffer = NULL;
57

M
 
Marc G. Fournier 已提交
58 59
static char *old;

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

69
%}
M
Michael Meskes 已提交
70

71 72 73 74 75
%option 8bit
%option never-interactive
%option nounput
%option noyywrap

76
%option yylineno
77

M
 
Marc G. Fournier 已提交
78
%s C SQL incl def def_ident
M
Michael Meskes 已提交
79 80 81

/*
 * OK, here is a short description of lex/flex rules behavior.
M
Marc G. Fournier 已提交
82 83
 * 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 已提交
84 85 86
 * 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 已提交
87
 *
M
Michael Meskes 已提交
88 89
 * We use exclusive states for quoted strings, extended comments,
 * and to eliminate parsing troubles for numeric strings.
M
Marc G. Fournier 已提交
90
 * Exclusive states:
M
Michael Meskes 已提交
91
 *	<xb> bit string literal
92 93 94 95
 *	<xc> extended C-style comments - thomas 1997-07-12
 *	<xd> delimited identifiers (double-quoted identifiers) - thomas 1997-10-27
 *	<xh> hexadecimal numeric string - thomas 1997-11-16
 *	<xq> quoted strings - thomas 1997-07-30
M
Marc G. Fournier 已提交
96 97
 */

M
Michael Meskes 已提交
98
%x xb
M
Marc G. Fournier 已提交
99 100
%x xc
%x xd
101
%x xdc
M
Marc G. Fournier 已提交
102 103
%x xh
%x xq
104 105 106
%x xpre
%x xcond
%x xskip
M
Marc G. Fournier 已提交
107

M
Michael Meskes 已提交
108
/* Bit string
M
Marc G. Fournier 已提交
109
 */
M
Michael Meskes 已提交
110 111 112 113
xbstart			[bB]{quote}
xbstop			{quote}
xbinside		[^']*
xbcat			{quote}{whitespace_with_newline}{quote}
M
Marc G. Fournier 已提交
114 115 116 117 118

/* Hexadecimal number
 */
xhstart			[xX]{quote}
xhstop			{quote}
119
xhinside		[^']*
M
Michael Meskes 已提交
120
xhcat			{quote}{whitespace_with_newline}{quote}
M
Marc G. Fournier 已提交
121

M
Michael Meskes 已提交
122 123 124 125
/* National character
 */
xnstart                        [nN]{quote}

126
/* C version of hex number
M
Michael Meskes 已提交
127 128 129
 */
xch			0[xX][0-9A-Fa-f]*

M
Marc G. Fournier 已提交
130 131 132 133 134 135 136 137
/* 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 已提交
138
xqinside		[^\\']+
139 140
xqescape                [\\][^0-7]
xqoctesc                [\\][0-7]{1,3}
M
Michael Meskes 已提交
141
xqcat			{quote}{whitespace_with_newline}{quote}
M
Marc G. Fournier 已提交
142

143
/* Double quote
M
Marc G. Fournier 已提交
144 145 146 147 148
 * Allows embedded spaces and other special characters into identifiers.
 */
dquote			\"
xdstart			{dquote}
xdstop			{dquote}
149
xddouble				{dquote}{dquote}
M
Michael Meskes 已提交
150
xdinside		[^"]+
M
Michael Meskes 已提交
151 152 153 154 155 156

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

158 159
/* C-style comments
 *
M
Michael Meskes 已提交
160 161 162
 * 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
163
 * a longer match --- remember lex will prefer a longer match!	Also, if we
164 165
 * 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 已提交
166
 * The solution is two-fold:
167
 * 1. append {op_chars}* to xcstart so that it matches as much text as
168 169 170
 *	  {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.
M
Michael Meskes 已提交
171
 * 2. In the operator rule, check for slash-star within the operator, and
172 173
 *	  if found throw it back with yyless().  This handles the plus-slash-star
 *	  problem.
M
Michael Meskes 已提交
174 175
 * SQL92-style comments, which start with dash-dash, have similar interactions
 * with the operator rule.
M
Marc G. Fournier 已提交
176
 */
177
xcstart			\/\*{op_chars}*
M
Michael Meskes 已提交
178
xcstop			\*+\/
179
xcinside		[^*/]+
M
Marc G. Fournier 已提交
180 181 182

digit			[0-9]
letter			[\200-\377_A-Za-z]
183
letter_or_digit [\200-\377_A-Za-z0-9]
M
Marc G. Fournier 已提交
184 185 186 187 188

identifier		{letter}{letter_or_digit}*

typecast		"::"

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 193 194 195 196 197 198
 * 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 已提交
199
self			[,()\[\].;$\:\+\-\*\/\%\^\<\>\=]
M
Michael Meskes 已提交
200
op_chars		[\~\!\@\#\^\&\|\`\?\$\+\-\*\/\%\<\>\=]
201
operator		{op_chars}+
M
Marc G. Fournier 已提交
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
M
Michael Meskes 已提交
206
 */
207

M
Michael Meskes 已提交
208 209
integer			{digit}+
decimal			(({digit}*\.{digit}+)|({digit}+\.{digit}*))
210
real			((({digit}*\.{digit}+)|({digit}+\.{digit}*)|({digit}+))([Ee][-+]?{digit}+))
M
Marc G. Fournier 已提交
211 212 213

param			\${integer}

M
Michael Meskes 已提交
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
/*
 * 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 已提交
229
ccomment		"//".*\n
M
Marc G. Fournier 已提交
230

231
space			[ \t\n\r\f]
M
Michael Meskes 已提交
232
horiz_space		[ \t\f]
233
newline					[\n\r]
M
Michael Meskes 已提交
234 235
non_newline		[^\n\r]

236
comment			("--"{non_newline}*)
M
Michael Meskes 已提交
237

238
whitespace		({space}+|{comment})
M
Michael Meskes 已提交
239 240 241 242 243 244 245 246 247

/*
 * 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})
248
whitespace_with_newline ({horiz_whitespace}*{newline}{whitespace}*)
M
Michael Meskes 已提交
249

M
Marc G. Fournier 已提交
250 251 252
other			.

/* some stuff needed for ecpg */
253 254
exec	[eE][xX][eE][cC]
sql		[sS][qQ][lL]
M
 
Marc G. Fournier 已提交
255
define	[dD][eE][fF][iI][nN][eE]
256
include [iI][nN][cC][lL][uU][dD][eE]
M
Marc G. Fournier 已提交
257

258 259 260 261 262 263
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]

264
exec_sql		{exec}{space}*{sql}{space}*
M
Michael Meskes 已提交
265 266
ipdigit			({digit}|{digit}{digit}|{digit}{digit}{digit})
ip			{ipdigit}\.{ipdigit}\.{ipdigit}\.{ipdigit}
267 268

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

271
/*
M
Marc G. Fournier 已提交
272
 * Quoted strings must allow some special characters such as single-quote
273
 *	and newline.
M
Michael Meskes 已提交
274
 * Embedded single-quotes are implemented both in the SQL92-standard
275 276
 *	style of two adjacent single quotes "''" and in the Postgres/Java style
 *	of escaped-quote "\'".
M
Marc G. Fournier 已提交
277
 * Other embedded escaped characters are matched explicitly and the leading
278
 *	backslash is dropped from the string. - thomas 1997-09-24
M
Michael Meskes 已提交
279
 * Note that xcstart must appear before operator, as explained above!
280
 *	Also whitespace (comment) must appear before operator.
M
Marc G. Fournier 已提交
281 282
 */

283
%%
284 285 286 287 288 289

%{
                                       /* code to execute during start of each call of yylex() */
                                       token_start = NULL;
%}

M
Michael Meskes 已提交
290
<SQL>{whitespace}	{ /* ignore */ }
M
Marc G. Fournier 已提交
291

292
{xcstart}			{
293
						token_start = yytext;
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
						state_before = YYSTATE;
						xcdepth = 0;
						BEGIN(xc);
						/* Put back any characters past slash-star; see above */
						yyless(2);
						fputs("/*", yyout);
					}
<xc>{xcstart}		{
						xcdepth++;
				 		/* Put back any characters past slash-star; see above */
				 		yyless(2);
						fputs("/*", yyout);
					}

<xc>{xcstop}		{
						ECHO;
						if (xcdepth <= 0)
311
						{
M
Michael Meskes 已提交
312
							BEGIN(state_before);
313 314
							token_start = NULL;
						}
315 316 317 318 319 320 321 322 323
						else
							xcdepth--;
					}

<xc>{xcinside}		{ ECHO; }
<xc>{op_chars}		{ ECHO; }

<xc><<EOF>>			{ mmerror(PARSE_ERROR, ET_ERROR, "Unterminated /* comment"); }

M
Michael Meskes 已提交
324
<SQL>{xbstart}	{
325
						token_start = yytext;
M
Michael Meskes 已提交
326
						BEGIN(xb);
327
						startlit();
328
						addlitchar('b');
329
					}
M
Michael Meskes 已提交
330
<xb>{xbstop}	{
331 332 333 334
						BEGIN(SQL);
						if (literalbuf[strspn(literalbuf, "01") + 1] != '\0')
							mmerror(PARSE_ERROR, ET_ERROR, "invalid bit string input.");
						yylval.str = literalbuf;
335
						return BCONST;
336
					}
M
Marc G. Fournier 已提交
337 338

<xh>{xhinside}	|
M
Michael Meskes 已提交
339
<xb>{xbinside}	{ addlit(yytext, yyleng); }
M
Marc G. Fournier 已提交
340
<xh>{xhcat}		|
M
Michael Meskes 已提交
341 342
<xb>{xbcat}		{ /* ignore */ }
<xb><<EOF>>		{ mmerror(PARSE_ERROR, ET_ERROR, "Unterminated bit string"); }
M
Marc G. Fournier 已提交
343 344

<SQL>{xhstart}		{
345
						token_start = yytext;
346 347
						BEGIN(xh);
						startlit();
348
						addlitchar('x');
349 350
					}
<xh>{xhstop}		{
351 352
						yylval.str = literalbuf;
						return XCONST;
353 354 355
					}

<xh><<EOF>>			{ mmerror(PARSE_ERROR, ET_ERROR, "Unterminated hexadecimal integer"); }
M
Michael Meskes 已提交
356 357 358 359 360 361 362 363 364
<SQL>{xnstart}              {
				/* National character.
				 * Need to remember type info to flow it forward into the parser.
		                 * Not yet implemented. - thomas 2002-06-17
		                 */
			        token_start = yytext;
				BEGIN(xq);
				startlit();
			}
365
<C,SQL>{xqstart}	{
366
						token_start = yytext;
367 368 369 370 371 372 373 374 375
						state_before = YYSTATE;
						BEGIN(xq);
						startlit();
					}
<xq>{xqstop}		{
						BEGIN(state_before);
						yylval.str = mm_strdup(literalbuf);
						return SCONST;
					}
376 377
<xq>{xqdouble}		{ addlitchar('\''); }
<xq>{xqinside}		{ addlit(yytext, yyleng); }
M
Michael Meskes 已提交
378
<xq>{xqescape}  	{ addlit(yytext, yyleng); }
379
<xq>{xqoctesc}          { addlit(yytext, yyleng); }
380 381 382 383 384 385 386 387 388
<xq>{xqcat}			{ /* ignore */ }

<xq><<EOF>>			{ mmerror(PARSE_ERROR, ET_ERROR, "Unterminated quoted string"); }

<SQL>{xdstart}		{
						state_before = YYSTATE;
						BEGIN(xd);
						startlit();
					}
M
Michael Meskes 已提交
389
<xd>{xdstop}		{
390
						BEGIN(state_before);
391 392 393
						if (literallen == 0)
							mmerror(PARSE_ERROR, ET_ERROR, "zero-length delimited identifier");
						if (literallen >= NAMEDATALEN)
394
						{
395
							snprintf(errortext, sizeof(errortext), "identifier \"%s\" will be truncated to \"%.*s\"",
396 397 398 399 400 401 402 403 404 405 406 407 408
									literalbuf, NAMEDATALEN-1, literalbuf);
							literalbuf[NAMEDATALEN-1] = '\0';
							mmerror(PARSE_ERROR, ET_WARNING, errortext);
						}
					
						yylval.str = mm_strdup(literalbuf);
						return CSTRING;
					}
<xdc>{xdstop}		{
						BEGIN(state_before);
						yylval.str = mm_strdup(literalbuf);
						return CSTRING;
					}
409
<xd>{xddouble}		{ addlitchar('"'); }
410 411 412 413 414 415
<xd>{xdinside}		{ addlit(yytext, yyleng); }
<xd,xdc><<EOF>>		{ mmerror(PARSE_ERROR, ET_ERROR, "Unterminated quoted identifier"); }
<C,SQL>{xdstart}	{
						state_before = YYSTATE;
						BEGIN(xdc);
						startlit();
M
Michael Meskes 已提交
416
					}
417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
<xdc>{xdcinside}	{ addlit(yytext, yyleng); }
<SQL>{typecast}		{ return TYPECAST; }
<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];
					}
<SQL>{operator}		{
						/*
						 * 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;
436 437
						char   *slashstar = strstr(yytext, "/*");
						char   *dashdash = strstr(yytext, "--");
438 439

						if (slashstar && dashdash)
440
						{
441 442 443
							/* if both appear, take the first one */
							if (slashstar > dashdash)
								slashstar = dashdash;
444
						}
445 446 447
						else if (!slashstar)
							slashstar = dashdash;
						if (slashstar)
448
							nchars = slashstar - yytext;
449 450

						/*
451 452 453 454 455 456
						 * 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.
M
Michael Meskes 已提交
457
						 */
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
						while (nchars > 1 &&
							   (yytext[nchars-1] == '+' ||
								yytext[nchars-1] == '-'))
						{
							int		ic;

							for (ic = nchars-2; ic >= 0; ic--)
							{
								if (strchr("~!@#^&|`?$%", yytext[ic]))
									break;
							}
							if (ic >= 0)
								break; /* found a char that makes it OK */
							nchars--; /* else remove the +/-, and check again */
						}

						if (nchars < yyleng)
						{
							/* Strip the unwanted chars from the token */
							yyless(nchars);
							/*
							 * If what we have left is only one char, and it's
							 * 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 &&
								strchr(",()[].;$:+-*/%^<>=", yytext[0]))
								return yytext[0];
						}

						/* Convert "!=" operator to "<>" for compatibility */
490
						if (strcmp(yytext, "!=") == 0)
491 492
							yylval.str = mm_strdup("<>");
						else
493
							yylval.str = mm_strdup(yytext);
494
						return Op;
M
Michael Meskes 已提交
495
					}
496
<SQL>{param}		{
497
						yylval.ival = atol(yytext+1);
498 499 500 501 502
						return PARAM;
					}
<C,SQL>{integer}	{
						long val;
						char* endptr;
M
Michael Meskes 已提交
503

M
Marc G. Fournier 已提交
504
						errno = 0;
505 506 507 508 509 510 511 512 513
						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
							)
						{
							errno = 0;
514
							yylval.str = mm_strdup(yytext);
515 516 517 518 519 520
							return FCONST;
						}
						yylval.ival = val;
						return ICONST;
					}
<SQL>{ip}			{
521
						yylval.str = mm_strdup(yytext);
522 523 524
						return IP;
					}
{decimal}			{
525
						yylval.str = mm_strdup(yytext);
526 527 528
						return FCONST;
					}
<C,SQL>{real}		{
529
						yylval.str = mm_strdup(yytext);
M
Michael Meskes 已提交
530
						return FCONST;
M
Marc G. Fournier 已提交
531
					}
532
<SQL>:{identifier}(("->"|\.){identifier})*	{
533
						yylval.str = mm_strdup(yytext+1);
534 535
						return(CVARIABLE);
					}
M
Marc G. Fournier 已提交
536
<SQL>{identifier}	{
537 538 539 540
						ScanKeyword    *keyword;
						struct _defines *ptr;

						/* Is it an SQL keyword? */
541
						keyword = ScanKeywordLookup(yytext);
542 543 544 545
						if (keyword != NULL)
							return keyword->value;

						/* Is it an ECPG keyword? */
546
						keyword = ScanECPGKeywordLookup( yytext);
547 548 549 550 551
						if (keyword != NULL)
							return keyword->value;

						/* How about a DEFINE? */
						for (ptr = defines; ptr; ptr = ptr->next)
M
Marc G. Fournier 已提交
552
						{
553 554 555
							if (strcmp(yytext, ptr->old) == 0)
							{
								struct _yy_buffer *yb;
M
 
Marc G. Fournier 已提交
556

557 558 559 560 561 562
								yb = mm_alloc(sizeof(struct _yy_buffer));

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

564
								yy_buffer = yb;
M
 
Marc G. Fournier 已提交
565

566 567 568 569
								yy_scan_string(ptr->new);
								break;
							}
						}
M
 
Marc G. Fournier 已提交
570

571 572 573 574 575 576 577 578 579 580
						/*
						 * 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)
						{
M
Michael Meskes 已提交
581
							yylval.str = mm_strdup(yytext);
582
							return IDENT;
M
Marc G. Fournier 已提交
583 584
						}
					}
585 586 587
<SQL>{other}		{ return yytext[0]; }
<C>{exec_sql}		{ BEGIN SQL; return SQL_START; }
<C>{ccomment}		{ /* ignore */ }
M
Michael Meskes 已提交
588
<C>{xch}			{
589
						char* endptr;
M
Michael Meskes 已提交
590 591

						errno = 0;
592 593 594 595
						yylval.ival = strtol((char *)yytext,&endptr,16);
						if (*endptr != '\0' || errno == ERANGE)
						{
							errno = 0;
596
							yylval.str = mm_strdup(yytext);
597 598 599 600 601
							return SCONST;
						}
						return ICONST;
					}
<C>{cppline}		{
602
						yylval.str = mm_strdup(yytext);
603
						return(CPP_LINE);
M
Michael Meskes 已提交
604
					}
605 606
<C>{identifier} 	{
						ScanKeyword		*keyword;
M
 
Marc G. Fournier 已提交
607

608
						keyword = ScanCKeywordLookup(yytext);
609 610 611 612
						if (keyword != NULL) {
							return keyword->value;
						}
						else
M
 
Marc G. Fournier 已提交
613
						{
614 615 616
							struct _defines *ptr;

							for (ptr = defines; ptr; ptr = ptr->next)
M
 
Marc G. Fournier 已提交
617
							{
618 619 620
								if (strcmp(yytext, ptr->old) == 0)
								{
									struct _yy_buffer *yb;
M
 
Marc G. Fournier 已提交
621

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

624 625 626 627
												yb->buffer =  YY_CURRENT_BUFFER;
												yb->lineno = yylineno;
												yb->filename = mm_strdup(input_filename);
												yb->next = yy_buffer;
M
 
Marc G. Fournier 已提交
628

629
												yy_buffer = yb;
M
 
Marc G. Fournier 已提交
630

631 632 633 634 635 636
									yy_scan_string(ptr->new);
									break;
								}
							}
							if (ptr == NULL)
							{
637
								yylval.str = mm_strdup(yytext);
638
								return IDENT;
M
 
Marc G. Fournier 已提交
639 640
							}
						}
M
Marc G. Fournier 已提交
641
					}
642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673
<C>";"				{ return(';'); }
<C>","				{ return(','); }
<C>"*"				{ return('*'); }
<C>"%"				{ return('%'); }
<C>"/"				{ return('/'); }
<C>"+"				{ return('+'); }
<C>"-"				{ return('-'); }
<C>"("				{ return('('); }
<C>")"				{ return(')'); }
<C>{space}			{ ECHO; }
<C>\{				{ return('{'); }
<C>\}				{ return('}'); }
<C>\[				{ return('['); }
<C>\]				{ return(']'); }
<C>\=				{ return('='); }
<C>"->"				{ return(S_MEMBER); }
<C>">>"				{ return(S_RSHIFT); }
<C>"<<"				{ return(S_LSHIFT); }
<C>"||"				{ return(S_OR); }
<C>"&&"				{ return(S_AND); }
<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); }
<C>{other}			{ return S_ANYTHING; }
674

675 676
<C>{exec_sql}{define}{space}*	{ BEGIN(def_ident); }
<C>{exec_sql}{include}{space}*	{ BEGIN(incl); }
677

678 679
<C,xskip>{exec_sql}{ifdef}{space}*	{ ifcond = TRUE; BEGIN(xcond); }
<C,xskip>{exec_sql}{ifndef}{space}* { ifcond = FALSE; BEGIN(xcond); }
680

681
<C,xskip>{exec_sql}{elif}{space}*	{	/* pop stack */
682
						if ( preproc_tos == 0 ) {
683
							mmerror(PARSE_ERROR, ET_FATAL, "Missing matching 'EXEC SQL IFDEF / EXEC SQL IFNDEF'");
684
						}
685 686 687 688
						else if ( stacked_if_value[preproc_tos].else_branch )
							mmerror(PARSE_ERROR, ET_FATAL, "Missing 'EXEC SQL ENDIF;'");
						else
							preproc_tos--;
689 690 691 692

						ifcond = TRUE; BEGIN(xcond);
					}

693
<C,xskip>{exec_sql}{else}{space}*";" {	/* only exec sql endif pops the stack, so take care of duplicated 'else' */
694
						if ( stacked_if_value[preproc_tos].else_branch ) {
695
							mmerror(PARSE_ERROR, ET_FATAL, "Duplicated 'EXEC SQL ELSE;'");
696 697
						}
						else {
698 699
							stacked_if_value[preproc_tos].else_branch = TRUE;
							stacked_if_value[preproc_tos].condition =
700 701 702
							(stacked_if_value[preproc_tos-1].condition &&
							 ! stacked_if_value[preproc_tos].condition);

703 704 705 706
							if ( stacked_if_value[preproc_tos].condition )
								BEGIN(C);
							else
								BEGIN(xskip);
707 708
						}
					}
709 710 711 712 713
<C,xskip>{exec_sql}{endif}{space}*";" {
						if ( preproc_tos == 0 )
							mmerror(PARSE_ERROR, ET_FATAL, "Unmatched 'EXEC SQL ENDIF;'");
						else
							preproc_tos--;
714

715
						if ( stacked_if_value[preproc_tos].condition )
716
						   BEGIN(C);
717
						else
718 719 720
						   BEGIN(xskip);
					}

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

723
<xcond>{identifier}{space}*";" {
724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740
						if ( preproc_tos >= MAX_NESTED_IF-1 ) {
							mmerror(PARSE_ERROR, ET_FATAL, "Too many nested 'EXEC SQL IFDEF' conditions");
						}
						else 
						{
							struct _defines *defptr;
							unsigned int i;

							/* skip the ";" and trailing whitespace. Note that yytext contains
							   at least one non-space character plus the ";" */
							for ( i = strlen(yytext)-2;
								  i > 0 && isspace((unsigned char) yytext[i]);
								  i-- )
							{}
							yytext[i+1] = '\0';

							for ( defptr = defines; defptr != NULL &&
741
								  ( strcmp(yytext, defptr->old) != 0 ); defptr = defptr->next );
742 743 744 745 746 747

							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 );
						}
748

749 750 751 752
						if ( stacked_if_value[preproc_tos].condition )
						   BEGIN C;
						else
						   BEGIN(xskip);
753 754
					}

755
<def_ident>{identifier} {
M
 
Marc G. Fournier 已提交
756
				old = mm_strdup(yytext);
M
 
Marc G. Fournier 已提交
757
				BEGIN(def);
758
				startlit();
M
 
Marc G. Fournier 已提交
759
			}
760
<def>{space}*";"	{
761
						struct _defines *ptr, *this;
762

763 764 765 766 767 768 769 770 771 772 773 774
						for (ptr = defines; ptr != NULL; ptr = ptr->next)
						{
							 if (strcmp(old, ptr->old) == 0)
							 {
								free(ptr->new);
								/* ptr->new = mm_strdup(scanstr(literalbuf));*/
								ptr->new = mm_strdup(literalbuf);
							 }
						}
						if (ptr == NULL)
						{
												this = (struct _defines *) mm_alloc(sizeof(struct _defines));
775

776 777 778 779 780 781
												/* initial definition */
												this->old = old;
												this->new = mm_strdup(literalbuf);
							this->next = defines;
							defines = this;
						}
782

783 784 785
						BEGIN(C);
					}
<def>[^;]			{ addlit(yytext, yyleng); }
786

787 788 789 790 791 792
<incl>[^;]+";"		{ 
						/* got the include file name */
						struct _yy_buffer *yb;
					  	struct _include_path *ip;
					  	char inc_file[MAXPGPATH];
					  	unsigned int i;
793

794
					  	yb = mm_alloc(sizeof(struct _yy_buffer));
795

796 797 798 799
					  	yb->buffer =	YY_CURRENT_BUFFER;
					  	yb->lineno = yylineno;
					  	yb->filename = input_filename;
					  	yb->next = yy_buffer;
800

801
					  	yy_buffer = yb;
802

803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820
					  	/*
						 * skip the ";" and trailing whitespace. Note that yytext contains
						 * at least one non-space character plus the ";" 
						 */
					  	for ( i = strlen(yytext)-2;
							i > 0 && isspace((unsigned char) yytext[i]);
							i-- )
					  		{}
					  	yytext[i+1] = '\0';

					  	yyin = NULL;
					  	for (ip = include_paths; yyin == NULL && ip != NULL; ip = ip->next)
					  	{
							if (strlen(ip->path) + strlen(yytext) + 3 > MAXPGPATH)
							{
								fprintf(stderr, "Error: Path %s/%s is too long in line %d, skipping.\n", ip->path, yytext, yylineno);
								continue;
							}
821
							snprintf (inc_file, sizeof(inc_file), "%s/%s", ip->path, yytext);
822 823 824 825 826 827 828 829 830 831 832 833
							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)
						{
834
							snprintf(errortext, sizeof(errortext), "Cannot open include file %s in line %d\n", yytext, yylineno);
835 836
							mmerror(NO_INCLUDE_FILE, ET_FATAL, errortext);
					  	}
837

838 839 840 841
						input_filename = mm_strdup(inc_file);
						yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE ));
						yylineno = 1;
						output_line_number();
842

843 844 845 846
					  	BEGIN C;
					}

<<EOF>>				{
847
				  		if (yy_buffer == NULL) {
848 849 850 851 852 853
				  		if ( preproc_tos > 0 ) 
						{
					  		preproc_tos = 0;
							mmerror(PARSE_ERROR, ET_FATAL, "Missing 'EXEC SQL ENDIF;'");
				  		}
							yyterminate();
854
							}
855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880
				  		else
				  		{
							struct _yy_buffer *yb = yy_buffer;
							int i;

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

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

							yylineno = yy_buffer->lineno;

							/* We have to output the filename only if we change files here */
							i = strcmp(input_filename, yy_buffer->filename);

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

							yy_buffer = yy_buffer->next;
							free(yb);

							if (i != 0)
								output_line_number();
				  		}
					}
881 882
%%
void
883
lex_init(void)
884
{
885 886 887
	braces_open = 0;

	preproc_tos = 0;
M
Michael Meskes 已提交
888
	yylineno = 1;
889 890 891
	ifcond = TRUE;
	stacked_if_value[preproc_tos].condition = ifcond;
	stacked_if_value[preproc_tos].else_branch = FALSE;
892 893 894 895 896 897 898 899 900

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

901
	BEGIN C;
902 903
}

904 905 906 907 908 909
static void
addlit(char *ytext, int yleng)
{
	/* enlarge buffer if needed */
	if ((literallen+yleng) >= literalalloc)
	{
910
		do 
911
			literalalloc *= 2;
912
		while ((literallen+yleng) >= literalalloc);
913 914
		literalbuf = (char *) realloc(literalbuf, literalalloc);
	}
915 916
	/* append new data, add trailing null */
	memcpy(literalbuf+literallen, ytext, yleng);
917
	literallen += yleng;
918
	literalbuf[literallen] = '\0';
919 920
}

921 922
static void
addlitchar(unsigned char ychar)
923
{
924 925 926 927 928 929 930 931 932 933 934
	/* enlarge buffer if needed */
        if ((literallen+1) >= literalalloc)
        {
                literalalloc *= 2;
                literalbuf = (char *) realloc(literalbuf, literalalloc);
        }
	/* append new data, add trailing null */
	literalbuf[literallen] = ychar;
	literallen += 1;
	literalbuf[literallen] = '\0';
}