pgc.l 25.9 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.75 2001/02/09 15:13:49 momjian Exp $
16 17 18
 *
 *-------------------------------------------------------------------------
 */
M
Marc G. Fournier 已提交
19
#include <ctype.h>
M
Marc G. Fournier 已提交
20
#include <sys/types.h>
21
#include <limits.h>
22
#include <errno.h>
23

24
#include "postgres.h"
M
Marc G. Fournier 已提交
25 26
#include "miscadmin.h"
#include "nodes/parsenodes.h"
27
#include "nodes/pg_list.h"
M
Marc G. Fournier 已提交
28
#include "parser/scansup.h"
M
 
Marc G. Fournier 已提交
29
#include "extern.h"
M
 
Marc G. Fournier 已提交
30
#include "preproc.h"
M
Marc G. Fournier 已提交
31
#include "utils/builtins.h"
32

M
Marc G. Fournier 已提交
33 34 35 36 37
/* some versions of lex define this as a macro */
#if defined(yywrap)
#undef yywrap
#endif /* yywrap */

38 39
#define YY_NO_UNPUT

M
Marc G. Fournier 已提交
40
extern YYSTYPE yylval;
41 42 43 44 45 46 47 48 49 50 51

/*
 * 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 */

M
Michael Meskes 已提交
52 53
static int             xcdepth = 0; 

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

M
Michael Meskes 已提交
57
int state_before;
M
Marc G. Fournier 已提交
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;

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

67 68 69 70 71 72 73 74
#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];

75
%}
M
Michael Meskes 已提交
76

77
%option yylineno
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
 *  <xbit> bit string literal
92 93
 *  <xc> extended C-style comments - thomas 1997-07-12
 *  <xd> delimited identifiers (double-quoted identifiers) - thomas 1997-10-27
M
Marc G. Fournier 已提交
94
 *  <xh> hexadecimal numeric string - thomas 1997-11-16
95
 *  <xq> quoted strings - thomas 1997-07-30
M
Marc G. Fournier 已提交
96 97
 */

M
Michael Meskes 已提交
98
%x xbit
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
xbitstart		[bB]{quote}
xbitstop		{quote}
xbitinside		[^']*
xbitcat			{quote}{whitespace_with_newline}{quote}
M
Marc G. Fournier 已提交
114 115 116 117 118

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

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

M
Marc G. Fournier 已提交
126 127 128 129 130 131 132 133
/* 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 已提交
134
xqinside		[^\\']+
M
Marc G. Fournier 已提交
135
xqliteral		[\\](.|\n)
M
Michael Meskes 已提交
136
xqcat			{quote}{whitespace_with_newline}{quote}
M
Marc G. Fournier 已提交
137 138 139 140 141 142 143

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

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

153 154
/* C-style comments
 *
M
Michael Meskes 已提交
155 156 157
 * 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
158 159 160
 * 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 已提交
161
 * The solution is two-fold:
162
 * 1. append {op_chars}* to xcstart so that it matches as much text as
M
Michael Meskes 已提交
163 164 165 166 167 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.
 * 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 已提交
171
 */
172
xcstart			\/\*{op_chars}*
M
Michael Meskes 已提交
173
xcstop			\*+\/
M
Michael Meskes 已提交
174
xcinside 		[^*/]+
M
Marc G. Fournier 已提交
175 176 177

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

identifier		{letter}{letter_or_digit}*

typecast		"::"

184 185 186 187 188 189 190 191 192 193
/*
 * "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 已提交
194
self			[,()\[\].;$\:\+\-\*\/\%\^\<\>\=]
M
Michael Meskes 已提交
195
op_chars		[\~\!\@\#\^\&\|\`\?\$\+\-\*\/\%\<\>\=]
196
operator		{op_chars}+
M
Marc G. Fournier 已提交
197

198 199 200
/* 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 已提交
201
 */
202

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

param			\${integer}

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

226 227
space			[ \t\r\f]
space_or_nl		[ \t\r\f\n]
M
Michael Meskes 已提交
228 229 230 231 232
line_end                {space}*\n
horiz_space		[ \t\f]
newline                 [\n\r]
non_newline		[^\n\r]

233
comment         ("--"{non_newline}*)
M
Michael Meskes 已提交
234 235 236 237 238 239 240 241 242 243 244 245 246

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 已提交
247 248 249 250
other			.

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

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]

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

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

M
Marc G. Fournier 已提交
268 269
/* DO NOT PUT ANY COMMENTS IN THE FOLLOWING SECTION.
 * AT&T lex does not properly handle C-style comments in this second lex block.
270
 * So, put comments here. thomas - 1997-09-08
M
Marc G. Fournier 已提交
271 272 273
 *
 * Quoted strings must allow some special characters such as single-quote
 *  and newline.
M
Michael Meskes 已提交
274
 * Embedded single-quotes are implemented both in the SQL92-standard
M
Marc G. Fournier 已提交
275 276 277 278
 *  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 已提交
279 280
 * Note that xcstart must appear before operator, as explained above!
 *  Also whitespace (comment) must appear before operator.
M
Marc G. Fournier 已提交
281 282
 */

283
%%
M
Michael Meskes 已提交
284
<SQL>{whitespace}	{ /* ignore */ }
M
Marc G. Fournier 已提交
285

286
{xcstart}		{
M
Michael Meskes 已提交
287
				state_before = YYSTATE;
M
Michael Meskes 已提交
288
				xcdepth = 0;
289
	 			BEGIN(xc);
M
Michael Meskes 已提交
290 291
				/* Put back any characters past slash-star; see above */
				yyless(2);
M
Michael Meskes 已提交
292
				fputs("/*", yyout);
293
			}
M
Marc G. Fournier 已提交
294

M
Michael Meskes 已提交
295 296 297 298 299 300 301 302 303 304 305 306 307 308
<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 已提交
309

M
Michael Meskes 已提交
310
<xc>{xcinside}	{ ECHO; }
M
Michael Meskes 已提交
311
<xc>{op_chars}  { ECHO; }
M
Marc G. Fournier 已提交
312

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

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

<SQL>{xhstart}		{
					BEGIN(xh);
339
					startlit();
M
Marc G. Fournier 已提交
340
				}
M
Michael Meskes 已提交
341
<xh>{xhstop}			{
M
Marc G. Fournier 已提交
342 343 344 345
					char* endptr;

					BEGIN(SQL);
					errno = 0;
346
					yylval.ival = strtol(literalbuf, &endptr, 16);
M
Marc G. Fournier 已提交
347
					if (*endptr != '\0' || errno == ERANGE)
M
Michael Meskes 已提交
348
						mmerror(ET_ERROR, "Bad hexadecimal integer input");
349
					return ICONST;
M
Marc G. Fournier 已提交
350 351
				}

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

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

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

M
Michael Meskes 已提交
375
<SQL>{xdstart}			{
M
Michael Meskes 已提交
376
					state_before = YYSTATE;
M
Marc G. Fournier 已提交
377
					BEGIN(xd);
378
					startlit();
M
Marc G. Fournier 已提交
379
				}
M
Michael Meskes 已提交
380
<xd>{xdstop}		{
M
Michael Meskes 已提交
381
					BEGIN(state_before);
M
Michael Meskes 已提交
382 383
					if (strlen(literalbuf) >= NAMEDATALEN)
       			                {
384
#ifdef MULTIBYTE_NOTUSED
M
Michael Meskes 已提交
385 386 387 388 389 390 391 392 393 394 395
                                                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
396
 						mmerror(ET_NOTICE, errortext);
M
Michael Meskes 已提交
397 398 399 400 401 402 403
                                        }

					yylval.str = mm_strdup(literalbuf);
					return CSTRING;
				}
<xdc>{xdstop}			{
					BEGIN(state_before);   
404
					yylval.str = mm_strdup(literalbuf);
405
					return CSTRING;
406
				}
M
Michael Meskes 已提交
407 408 409
<xd>{xddouble} 			{
					addlit(yytext, yyleng-1);
				}
M
Michael Meskes 已提交
410
<xd>{xdinside}			{
411
					addlit(yytext, yyleng);
412
				}
M
Michael Meskes 已提交
413 414 415 416 417 418 419 420 421
<xd,xdc><<EOF>> 	 	        { mmerror(ET_ERROR, "Unterminated quoted identifier"); }
{xdstart}			{
					state_before = YYSTATE;
					BEGIN(xdc);
					startlit();
				}
<xdc>{xdcinside}		{
 					addlit(yytext, yyleng);
				}
M
Marc G. Fournier 已提交
422
<SQL>{typecast}			{ 	return TYPECAST; }
M
Michael Meskes 已提交
423 424 425 426 427 428 429 430 431
<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 已提交
432
<SQL>{operator}			{
433 434 435 436 437 438 439 440 441
					/*
					 * 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 已提交
442 443 444

					if (slashstar && dashdash)
					{
445
						/* if both appear, take the first one */
M
Michael Meskes 已提交
446 447 448 449 450 451
						if (slashstar > dashdash)
							slashstar = dashdash;
					}
					else if (!slashstar)
						slashstar = dashdash;
					if (slashstar)
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
						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 已提交
470
							if (strchr("~!@#^&|`?$%", yytext[ic]))
471 472 473 474 475 476 477 478
								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 已提交
479
					{
480
						/* Strip the unwanted chars from the token */
M
Michael Meskes 已提交
481
						yyless(nchars);
482 483
						/*
						 * If what we have left is only one char, and it's
M
Michael Meskes 已提交
484 485 486 487 488
						 * 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 已提交
489
							strchr(",()[].;$:+-*/%^<>=", yytext[0]))
M
Michael Meskes 已提交
490 491 492
							return yytext[0];
					}

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

					errno = 0;
M
Michael Meskes 已提交
508
					yylval.ival = strtol((char *)yytext, &endptr,10);
M
Marc G. Fournier 已提交
509 510 511
					if (*endptr != '\0' || errno == ERANGE)
					{
						errno = 0;
M
Michael Meskes 已提交
512
						yylval.str = mm_strdup((char*)yytext);
M
Michael Meskes 已提交
513
						return FCONST;
M
Marc G. Fournier 已提交
514
					}
515
					return ICONST;
M
Marc G. Fournier 已提交
516
				}
M
Michael Meskes 已提交
517 518 519 520
<SQL>{ip}			{
					yylval.str = mm_strdup((char*)yytext);
					return IP;
				}
521 522
{decimal}		{
					yylval.str = mm_strdup((char*)yytext);
M
Michael Meskes 已提交
523
					return FCONST;
524
				}
M
Michael Meskes 已提交
525
<C,SQL>{real}			{
M
Michael Meskes 已提交
526
					yylval.str = mm_strdup((char*)yytext);
527
					return FCONST;
M
Marc G. Fournier 已提交
528
				}
529
<SQL>:{identifier}(("->"|\.){identifier})*	{
M
 
Marc G. Fournier 已提交
530
					yylval.str = mm_strdup((char*)yytext+1);
531 532
					return(CVARIABLE);
			}
M
Marc G. Fournier 已提交
533 534 535
<SQL>{identifier}	{
					int i;
					ScanKeyword		*keyword;
M
 
Marc G. Fournier 已提交
536
					char lower_text[NAMEDATALEN];
M
Marc G. Fournier 已提交
537

M
 
Marc G. Fournier 已提交
538 539 540
					/* this should leave the last byte set to '\0' */
					strncpy(lower_text, yytext, NAMEDATALEN-1);
					for(i = 0; lower_text[i]; i++)
541 542
						if (isupper((unsigned char) lower_text[i]))
							lower_text[i] = tolower((unsigned char) lower_text[i]);
M
 
Marc G. Fournier 已提交
543

M
Michael Meskes 已提交
544 545
					if (i >= NAMEDATALEN)
					{
546
#ifdef MULTIBYTE_NOTUSED
M
Michael Meskes 已提交
547 548 549 550 551 552 553 554 555 556 557
                                                int len;

	                                        len = pg_mbcliplen(lower_text,strlen(lower_text),NAMEDATALEN-1);
						sprintf(errortext, "identifier \"%s\" will be truncated to \"%.*s\"",
                                                        lower_text, len, lower_text);
	                                        lower_text[len] = '\0';
#else
						sprintf(errortext, "identifier \"%s\" will be truncated to \"%.*s\"",
                                                        lower_text, NAMEDATALEN-1, lower_text);
                                                lower_text[NAMEDATALEN-1] = '\0';
#endif
558
 						mmerror(ET_NOTICE, errortext);
M
Michael Meskes 已提交
559 560 561
                                                yytext[NAMEDATALEN-1] = '\0';
					}

M
 
Marc G. Fournier 已提交
562
					keyword = ScanKeywordLookup((char*)lower_text);
M
Marc G. Fournier 已提交
563
					if (keyword != NULL) {
564
						return keyword->value;
M
Marc G. Fournier 已提交
565 566 567
					}
					else
					{
M
 
Marc G. Fournier 已提交
568
						keyword = ScanECPGKeywordLookup((char*)lower_text);
M
Marc G. Fournier 已提交
569
						if (keyword != NULL) {
570
							return keyword->value;
M
Marc G. Fournier 已提交
571 572 573
						}
						else
						{
M
 
Marc G. Fournier 已提交
574 575 576 577 578 579 580 581 582 583 584 585
							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 已提交
586
						                        yb->filename = mm_strdup(input_filename);
M
 
Marc G. Fournier 已提交
587 588 589 590 591 592 593 594 595 596
						                        yb->next = yy_buffer;

						                        yy_buffer = yb;

 									yy_scan_string(ptr->new);
									break;
								}
							}
							if (ptr == NULL) 
							{
M
 
Marc G. Fournier 已提交
597
								yylval.str = mm_strdup((char*)yytext);
598
								return IDENT;
M
 
Marc G. Fournier 已提交
599
							}
M
Marc G. Fournier 已提交
600 601 602
						}
					}
				}
603
<SQL>{other}			{ return yytext[0]; }
604
<C>{exec_sql}			{ BEGIN SQL; return SQL_START; }
605
<C>{ccomment}			{ /* ignore */ } 
M
Michael Meskes 已提交
606 607 608 609 610 611 612 613 614
<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);
615
						return SCONST;
M
Michael Meskes 已提交
616 617 618
					}
					return ICONST;
				}
M
 
Marc G. Fournier 已提交
619
<C>{cppline}			{
M
 
Marc G. Fournier 已提交
620
					yylval.str = mm_strdup((char*)yytext);
M
 
Marc G. Fournier 已提交
621 622
					return(CPP_LINE);
				}
M
Marc G. Fournier 已提交
623 624 625 626 627
<C>{identifier}	{
					ScanKeyword		*keyword;

					keyword = ScanCKeywordLookup((char*)yytext);
					if (keyword != NULL) {
628
						return keyword->value;
M
Marc G. Fournier 已提交
629 630 631
					}
					else
					{
M
 
Marc G. Fournier 已提交
632 633 634 635 636 637 638 639 640 641 642 643
						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 已提交
644
					                        yb->filename = mm_strdup(input_filename);
M
 
Marc G. Fournier 已提交
645 646 647 648 649 650 651 652 653 654
					                        yb->next = yy_buffer;

					                        yy_buffer = yb;

								yy_scan_string(ptr->new);
								break;
							}
						}
						if (ptr == NULL) 
						{
M
 
Marc G. Fournier 已提交
655
							yylval.str = mm_strdup((char*)yytext);
656
							return IDENT;
M
 
Marc G. Fournier 已提交
657
						}
M
Marc G. Fournier 已提交
658 659 660
					}
				}
<C>";"	      	        { return(';'); }
661 662
<C>","	      	        { return(','); }
<C>"*"	      	        { return('*'); }
M
Michael Meskes 已提交
663 664 665 666 667 668
<C>"%"	      	        { return('%'); }
<C>"/"	      	        { return('/'); }
<C>"+"	      	        { return('+'); }
<C>"-"	      	        { return('-'); }
<C>"("	      	        { return('('); }
<C>")"	      	        { return(')'); }
669
<C>{space_or_nl}	{ ECHO; }
670 671 672 673 674
<C>\{			{ return('{'); }
<C>\}			{ return('}'); }
<C>\[			{ return('['); }
<C>\]			{ return(']'); }
<C>\=			{ return('='); }
675 676 677 678 679
<C>"->"			{ return(S_MEMBER); } 
<C>">>"			{ return(S_RSHIFT); } 
<C>"<<"			{ return(S_LSHIFT); } 
<C>"||"			{ return(S_OR); } 
<C>"&&"			{ return(S_AND); } 
680 681 682 683 684 685 686 687 688 689 690
<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 已提交
691
<C>{other}		{ return S_ANYTHING; }
692 693 694 695 696 697 698 699 700

<C>{exec_sql}{define}{space_or_nl}*	{ BEGIN(def_ident); }
<C>{exec_sql}{include}{space_or_nl}*	{ BEGIN(incl); }

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

<C,xskip>{exec_sql}{elif}{space_or_nl}*	{	/* pop stack */
						if ( preproc_tos == 0 ) {
M
Michael Meskes 已提交
701
						    mmerror(ET_FATAL, "Missing matching 'EXEC SQL IFDEF / EXEC SQL IFNDEF'");
702 703
						}
						else if ( stacked_if_value[preproc_tos].else_branch ) {
M
Michael Meskes 已提交
704
						    mmerror(ET_FATAL, "Missing 'EXEC SQL ENDIF;'");
705 706 707 708 709 710 711 712 713 714
						}
						else {
						    preproc_tos--;
						}

						ifcond = TRUE; BEGIN(xcond);
					}

<C,xskip>{exec_sql}{else}{space_or_nl}*";" {	/* only exec sql endif pops the stack, so take care of duplicated 'else' */
						if ( stacked_if_value[preproc_tos].else_branch ) {
M
Michael Meskes 已提交
715
						    mmerror(ET_FATAL, "Duplicated 'EXEC SQL ELSE;'");
716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732
						}
						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);
						    }
						}
					}
<C,xskip>{exec_sql}{endif}{space_or_nl}*";" { 
						if ( preproc_tos == 0 ) {
M
Michael Meskes 已提交
733
						    mmerror(ET_FATAL, "Unmatched 'EXEC SQL ENDIF;'");
734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750
						}
						else {
						    preproc_tos--;
						}

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

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

<xcond>{identifier}{space_or_nl}*";" {
					if ( preproc_tos >= MAX_NESTED_IF-1 ) {
M
Michael Meskes 已提交
751
					    mmerror(ET_FATAL, "Too many nested 'EXEC SQL IFDEF' conditions");
752 753 754 755 756 757 758
					}
					else {
					    struct _defines *defptr;
					    unsigned int i;

					    /* skip the ";" and trailing whitespace. Note that yytext contains
					       at least one non-space character plus the ";" */
759 760 761 762
					    for ( i = strlen(yytext)-2;
							  i > 0 && isspace((unsigned char) yytext[i]);
							  i-- )
						{}
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781
					    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 已提交
782
<def_ident>{identifier}	{
M
 
Marc G. Fournier 已提交
783
				old = mm_strdup(yytext);
M
 
Marc G. Fournier 已提交
784
				BEGIN(def);
785
				startlit();
M
 
Marc G. Fournier 已提交
786
			}
787
<def>{space_or_nl}*";"	{
M
 
Marc G. Fournier 已提交
788 789 790 791 792 793 794
				struct _defines *ptr, *this;
        
                                for (ptr = defines; ptr != NULL; ptr = ptr->next)
                                {
                                     if (strcmp(old, ptr->old) == 0)
                                     {
					free(ptr->new);
795 796
					/* ptr->new = mm_strdup(scanstr(literalbuf));*/
					ptr->new = mm_strdup(literalbuf);
M
 
Marc G. Fournier 已提交
797 798 799 800 801 802 803 804
                                     }
                                }
				if (ptr == NULL)
				{                        
                                        this = (struct _defines *) mm_alloc(sizeof(struct _defines));

                                        /* initial definition */
                                        this->old = old;
805 806
                                        /* this->new = mm_strdup(scanstr(literalbuf));*/
                                        this->new = mm_strdup(literalbuf);
M
 
Marc G. Fournier 已提交
807 808 809 810 811 812 813
					this->next = defines;
					defines = this;
				}

				BEGIN(C);
			}
<def>[^";"]		{
814
				addlit(yytext, yyleng);
M
 
Marc G. Fournier 已提交
815
			}
816 817

<incl>[^";"]+";" 	{ /* got the include file name */
818 819
			  struct _yy_buffer *yb;
			  struct _include_path *ip;
820
			  char inc_file[MAXPGPATH];
821
			  unsigned int i;
822 823 824 825 826 827 828 829 830 831

			  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;

832 833
			  /* skip the ";" and trailing whitespace. Note that yytext contains
			     at least one non-space character plus the ";" */
834 835 836 837
			  for ( i = strlen(yytext)-2;
					i > 0 && isspace((unsigned char) yytext[i]);
					i-- )
			  {}
838
			  yytext[i+1] = '\0';
839 840 841 842

			  yyin = NULL;
			  for (ip = include_paths; yyin == NULL && ip != NULL; ip = ip->next)
			  {
843
				if (strlen(ip->path) + strlen(yytext) + 3 > MAXPGPATH)
844
				{
M
Marc G. Fournier 已提交
845
					fprintf(stderr, "Error: Path %s/%s is too long in line %d, skipping.\n", ip->path, yytext, yylineno);
846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861
					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 已提交
862
				fprintf(stderr, "Error: Cannot open include file %s in line %d\n", yytext, yylineno);
863
				exit(NO_INCLUDE_FILE); 
864 865
			  }

M
 
Marc G. Fournier 已提交
866
			  input_filename = mm_strdup(inc_file);
867
			  yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE ));
868
			  yylineno = 1;
M
Michael Meskes 已提交
869
			  output_line_number();
870 871 872

			  BEGIN C;
			}
873 874 875 876 877

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

M
Michael Meskes 已提交
878
			      mmerror(ET_FATAL, "Missing 'EXEC SQL ENDIF;'");
879 880 881
			  }

			  if (yy_buffer == NULL)
882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899
				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 已提交
900
				output_line_number();
901 902
			  }
			}
903 904
%%
void
905
lex_init(void)
906
{
907 908 909
	braces_open = 0;

	preproc_tos = 0;
M
Michael Meskes 已提交
910
	yylineno = 0;
911 912 913
	ifcond = TRUE;
	stacked_if_value[preproc_tos].condition = ifcond;
	stacked_if_value[preproc_tos].else_branch = FALSE;
914 915 916 917 918 919 920 921 922

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

923 924 925
    BEGIN C;
}

926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941
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);
	}
	/* append data --- note we assume ytext is null-terminated */
	memcpy(literalbuf+literallen, ytext, yleng+1);
	literallen += yleng;
}

942
int yywrap(void) 
943
{
944 945
    return 1;
}