pgc.l 25.5 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.91 2002/05/19 20:00:53 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
/*
 * 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.
 */
46 47 48
static char    *literalbuf = NULL;		/* expandable buffer */
static int		literallen;				/* actual current length */
static int		literalalloc;			/* current allocated buffer size */
49

50
#define startlit()	(literalbuf[0] = '\0', literallen = 0)
51
static void addlit(char *ytext, int yleng);
52 53
static void addlitchar (unsigned char);
static unsigned char unescape_single_char(unsigned char);
54

55
static char        *token_start;
M
Michael Meskes 已提交
56
int state_before;
M
Marc G. Fournier 已提交
57

58 59 60 61 62 63 64
struct _yy_buffer 
{ 
	YY_BUFFER_STATE		buffer;
	long				lineno;
	char		  		*filename;
	struct _yy_buffer 	*next;
} *yy_buffer = NULL;
65

M
 
Marc G. Fournier 已提交
66 67
static char *old;

68 69 70
#define MAX_NESTED_IF 128
static short preproc_tos;
static short ifcond;
71 72 73 74
static struct _if_value 
{
	short condition;
	short else_branch;
75 76
} stacked_if_value[MAX_NESTED_IF];

77
%}
M
Michael Meskes 已提交
78

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

/*
 * OK, here is a short description of lex/flex rules behavior.
M
Marc G. Fournier 已提交
84 85
 * 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 已提交
86 87 88
 * 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 已提交
89
 *
M
Michael Meskes 已提交
90 91
 * We use exclusive states for quoted strings, extended comments,
 * and to eliminate parsing troubles for numeric strings.
M
Marc G. Fournier 已提交
92
 * Exclusive states:
93 94 95 96 97
 *	<xbit> bit string literal
 *	<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 已提交
98 99
 */

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

M
Michael Meskes 已提交
110
/* Bit string
M
Marc G. Fournier 已提交
111
 */
M
Michael Meskes 已提交
112 113 114 115
xbitstart		[bB]{quote}
xbitstop		{quote}
xbitinside		[^']*
xbitcat			{quote}{whitespace_with_newline}{quote}
M
Marc G. Fournier 已提交
116 117 118 119 120

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

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

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

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

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

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

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

identifier		{letter}{letter_or_digit}*

typecast		"::"

187 188
/*
 * "self" is the set of chars that should be returned as single-character
189
 * tokens.	"op_chars" is the set of chars that can make up "Op" tokens,
190 191 192 193 194 195 196
 * 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 已提交
197
self			[,()\[\].;$\:\+\-\*\/\%\^\<\>\=]
M
Michael Meskes 已提交
198
op_chars		[\~\!\@\#\^\&\|\`\?\$\+\-\*\/\%\<\>\=]
199
operator		{op_chars}+
M
Marc G. Fournier 已提交
200

201
/* we no longer allow unary minus in numbers.
202
 * instead we pass it separately to parser. there it gets
203
 * coerced via doNegate() -- Leon aug 20 1999
M
Michael Meskes 已提交
204
 */
205

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

param			\${integer}

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

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

234
comment			("--"{non_newline}*)
M
Michael Meskes 已提交
235

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

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

M
Marc G. Fournier 已提交
248 249 250
other			.

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

256 257 258 259 260 261
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]

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

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

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

281
%%
282 283 284 285 286 287

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

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

290
{xcstart}			{
291
						token_start = yytext;
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
						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)
309 310 311 312
						{
							BEGIN(INITIAL);
							token_start = NULL;
						}
313 314 315 316 317 318 319 320 321 322
						else
							xcdepth--;
					}

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

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

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

<xh>{xhinside}	|
337
<xbit>{xbitinside}	{ addlit(yytext, yyleng); }
M
Marc G. Fournier 已提交
338
<xh>{xhcat}		|
339
<xbit>{xbitcat}		{ /* ignore */ }
340
<xbit><<EOF>>		{ mmerror(PARSE_ERROR, ET_ERROR, "Unterminated bit string"); }
M
Marc G. Fournier 已提交
341 342

<SQL>{xhstart}		{
343
						token_start = yytext;
344 345 346 347 348 349 350 351 352 353 354
						BEGIN(xh);
						startlit();
					}
<xh>{xhstop}		{
						long val;
						char* endptr;

						BEGIN(SQL);
						errno = 0;
						val = strtol(literalbuf, &endptr, 16);
						if (*endptr != '\0' || errno == ERANGE
355
#ifdef HAVE_LONG_INT_64
356 357
							/* if long > 32 bits, check for overflow of int4 */
							|| val != (long) ((int32) val)
358
#endif
359 360 361 362 363 364 365 366 367
							)
							mmerror(PARSE_ERROR, ET_ERROR, "Bad hexadecimal integer input");
						yylval.ival = val;
						return ICONST;
					}

<xh><<EOF>>			{ mmerror(PARSE_ERROR, ET_ERROR, "Unterminated hexadecimal integer"); }

<C,SQL>{xqstart}	{
368
						token_start = yytext;
369 370 371 372 373 374 375 376 377
						state_before = YYSTATE;
						BEGIN(xq);
						startlit();
					}
<xq>{xqstop}		{
						BEGIN(state_before);
						yylval.str = mm_strdup(literalbuf);
						return SCONST;
					}
378 379 380 381 382
<xq>{xqdouble}		{ addlitchar('\''); }
<xq>{xqinside}		{ addlit(yytext, yyleng); }
<xq>{xqescape}  	{ addlitchar(unescape_single_char(yytext[1])); }
<xq>{xqoctesc}		{ unsigned char c = strtoul(yytext+1, NULL, 8);
                          addlitchar(c); }
383 384 385 386 387 388 389 390 391
<xq>{xqcat}			{ /* ignore */ }

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

<SQL>{xdstart}		{
						state_before = YYSTATE;
						BEGIN(xd);
						startlit();
					}
M
Michael Meskes 已提交
392
<xd>{xdstop}		{
393
						BEGIN(state_before);
394 395 396
						if (literallen == 0)
							mmerror(PARSE_ERROR, ET_ERROR, "zero-length delimited identifier");
						if (literallen >= NAMEDATALEN)
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
						{
							sprintf(errortext, "identifier \"%s\" will be truncated to \"%.*s\"",
									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;
					}
412
<xd>{xddouble}		{ addlitchar('"'); }
413 414 415 416 417 418
<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 已提交
419
					}
420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
<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;
439 440
						char   *slashstar = strstr(yytext, "/*");
						char   *dashdash = strstr(yytext, "--");
441 442

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

						/*
454 455 456 457 458 459
						 * 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 已提交
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 490 491 492
						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 */
493
						if (strcmp(yytext, "!=") == 0)
494 495
							yylval.str = mm_strdup("<>");
						else
496
							yylval.str = mm_strdup(yytext);
497
						return Op;
M
Michael Meskes 已提交
498
					}
499
<SQL>{param}		{
500
						yylval.ival = atol(yytext+1);
501 502 503 504 505
						return PARAM;
					}
<C,SQL>{integer}	{
						long val;
						char* endptr;
M
Michael Meskes 已提交
506

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

						/* Is it an SQL keyword? */
544
						keyword = ScanKeywordLookup(yytext);
545 546 547 548
						if (keyword != NULL)
							return keyword->value;

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

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

560 561 562 563 564 565
								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 已提交
566

567
								yy_buffer = yb;
M
 
Marc G. Fournier 已提交
568

569 570 571 572
								yy_scan_string(ptr->new);
								break;
							}
						}
M
 
Marc G. Fournier 已提交
573

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

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

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

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

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

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

632
												yy_buffer = yb;
M
 
Marc G. Fournier 已提交
633

634 635 636 637 638 639
									yy_scan_string(ptr->new);
									break;
								}
							}
							if (ptr == NULL)
							{
640
								yylval.str = mm_strdup(yytext);
641
								return IDENT;
M
 
Marc G. Fournier 已提交
642 643
							}
						}
M
Marc G. Fournier 已提交
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 674 675 676
<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; }
677

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

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

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

						ifcond = TRUE; BEGIN(xcond);
					}

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

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

718
						if ( stacked_if_value[preproc_tos].condition )
719
						   BEGIN(C);
720
						else
721 722 723
						   BEGIN(xskip);
					}

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

726
<xcond>{identifier}{space}*";" {
727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743
						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 &&
744
								  ( strcmp(yytext, defptr->old) != 0 ); defptr = defptr->next );
745 746 747 748 749 750

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

752 753 754 755
						if ( stacked_if_value[preproc_tos].condition )
						   BEGIN C;
						else
						   BEGIN(xskip);
756 757
					}

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

766 767 768 769 770 771 772 773 774 775 776 777
						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));
778

779 780 781 782 783 784
												/* initial definition */
												this->old = old;
												this->new = mm_strdup(literalbuf);
							this->next = defines;
							defines = this;
						}
785

786 787 788
						BEGIN(C);
					}
<def>[^;]			{ addlit(yytext, yyleng); }
789

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

797
					  	yb = mm_alloc(sizeof(struct _yy_buffer));
798

799 800 801 802
					  	yb->buffer =	YY_CURRENT_BUFFER;
					  	yb->lineno = yylineno;
					  	yb->filename = input_filename;
					  	yb->next = yy_buffer;
803

804
					  	yy_buffer = yb;
805

806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839
					  	/*
						 * 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;
							}
							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)
						{
							sprintf(errortext, "Cannot open include file %s in line %d\n", yytext, yylineno);
							mmerror(NO_INCLUDE_FILE, ET_FATAL, errortext);
					  	}
840

841 842 843 844
						input_filename = mm_strdup(inc_file);
						yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE ));
						yylineno = 1;
						output_line_number();
845

846 847 848 849
					  	BEGIN C;
					}

<<EOF>>				{
850
				  		if (yy_buffer == NULL) {
851 852 853 854 855 856
				  		if ( preproc_tos > 0 ) 
						{
					  		preproc_tos = 0;
							mmerror(PARSE_ERROR, ET_FATAL, "Missing 'EXEC SQL ENDIF;'");
				  		}
							yyterminate();
857
							}
858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883
				  		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();
				  		}
					}
884 885
%%
void
886
lex_init(void)
887
{
888 889 890
	braces_open = 0;

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

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

904
	BEGIN C;
905 906
}

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

924 925
static void
addlitchar(unsigned char ychar)
926
{
927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956
	/* 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';
}

unsigned char
unescape_single_char(unsigned char c)
{
        switch (c)
        {
                case 'b':
                        return '\b';
                case 'f':
                        return '\f';
                case 'n':
                        return '\n';
                case 'r':
                        return '\r';
                case 't':
                        return '\t';
                default:
                        return c;
	}
957
}