pgc.l 32.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
 *
 *
P
 
PostgreSQL Daemon 已提交
10
 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
B
Add:  
Bruce Momjian 已提交
11
 * Portions Copyright (c) 1994, Regents of the University of California
12 13 14
 *
 *
 * IDENTIFICATION
15
 *	  $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/pgc.l,v 1.142 2006/02/04 20:54:42 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"
27

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

30
static int		xcdepth = 0;	/* depth of nesting in slash-star comments */
31 32 33
static char	   *dolqstart;      /* current $foo$ quote start string */
bool			escape_string_warning;
static bool		warn_on_first_escape;
34

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

45
#define startlit()	(literalbuf[0] = '\0', literallen = 0)
46
static void addlit(char *ytext, int yleng);
47
static void addlitchar (unsigned char);
48
static void parse_include (void);
49
static void check_escape_warning(void);
50

M
Michael Meskes 已提交
51
char *token_start;
M
Michael Meskes 已提交
52
int state_before;
M
Marc G. Fournier 已提交
53

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

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

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

73
%}
M
Michael Meskes 已提交
74

75 76
%option 8bit
%option never-interactive
77
%option nodefault
78 79
%option noyywrap

80
%option yylineno
81

M
 
Marc G. Fournier 已提交
82
%s C SQL incl def def_ident
M
Michael Meskes 已提交
83 84 85

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

M
Michael Meskes 已提交
103
%x xb
M
Marc G. Fournier 已提交
104 105
%x xc
%x xd
106
%x xdc
M
Marc G. Fournier 已提交
107 108
%x xh
%x xq
109
%x xdolq
110 111 112
%x xpre
%x xcond
%x xskip
M
Marc G. Fournier 已提交
113

M
Michael Meskes 已提交
114
/* Bit string
M
Marc G. Fournier 已提交
115
 */
M
Michael Meskes 已提交
116 117
xbstart			[bB]{quote}
xbinside		[^']*
M
Marc G. Fournier 已提交
118

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

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

126
/* Quoted string that allows backslash escapes */
B
Bruce Momjian 已提交
127
xestart 		[eE]{quote}
128 129

/* C version of hex number */
130
xch				0[xX][0-9A-Fa-f]*
M
Michael Meskes 已提交
131

M
Marc G. Fournier 已提交
132
/* Extended quote
133
 * xqdouble implements embedded quote, ''''
M
Marc G. Fournier 已提交
134 135 136
 */
xqstart			{quote}
xqdouble		{quote}{quote}
M
Michael Meskes 已提交
137
xqinside		[^\\']+
138 139 140
xqescape		[\\][^0-7]
xqoctesc		[\\][0-7]{1,3}
xqhexesc		[\\]x[0-9A-Fa-f]{1,2}
M
Marc G. Fournier 已提交
141

142 143 144 145 146
/* $foo$ style quotes ("dollar quoting")
 * The quoted string starts with $foo$ where "foo" is an optional string
 * in the form of an identifier, except that it may not contain "$",
 * and extends to the first occurrence of an identical string.
 * There is *no* processing of the quoted text.
147 148 149
 *
 * {dolqfailed} is an error rule to avoid scanner backup when {dolqdelim}
 * fails to match its trailing "$".
150
 */
151 152 153 154
dolq_start		[A-Za-z\200-\377_]
dolq_cont		[A-Za-z\200-\377_0-9]
dolqdelim		\$({dolq_start}{dolq_cont}*)?\$
dolqfailed		\${dolq_start}{dolq_cont}*
155
dolqinside		[^$']+
156

157
/* Double quote
M
Marc G. Fournier 已提交
158 159 160 161 162
 * Allows embedded spaces and other special characters into identifiers.
 */
dquote			\"
xdstart			{dquote}
xdstop			{dquote}
B
Bruce Momjian 已提交
163
xddouble		{dquote}{dquote}
M
Michael Meskes 已提交
164
xdinside		[^"]+
M
Michael Meskes 已提交
165 166 167 168 169 170

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

172 173
/* C-style comments
 *
M
Michael Meskes 已提交
174 175 176
 * 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
177
 * a longer match --- remember lex will prefer a longer match!	Also, if we
178 179
 * 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 已提交
180
 * The solution is two-fold:
181
 * 1. append {op_chars}* to xcstart so that it matches as much text as
182 183 184
 *	  {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 已提交
185
 * 2. In the operator rule, check for slash-star within the operator, and
186 187
 *	  if found throw it back with yyless().  This handles the plus-slash-star
 *	  problem.
188
 * Dash-dash comments have similar interactions with the operator rule.
M
Marc G. Fournier 已提交
189
 */
190
xcstart			\/\*{op_chars}*
M
Michael Meskes 已提交
191
xcstop			\*+\/
192
xcinside		[^*/]+
M
Marc G. Fournier 已提交
193 194

digit			[0-9]
M
Michael Meskes 已提交
195 196
ident_start		[A-Za-z\200-\377_]
ident_cont		[A-Za-z\200-\377_0-9\$]
M
Marc G. Fournier 已提交
197

M
Michael Meskes 已提交
198
identifier		{ident_start}{ident_cont}*
M
Marc G. Fournier 已提交
199

200
array			({ident_cont}|{whitespace}|[\[\]\+\-\*\%\/\(\)\>\.])*
M
Marc G. Fournier 已提交
201 202
typecast		"::"

203 204
/*
 * "self" is the set of chars that should be returned as single-character
205
 * tokens.	"op_chars" is the set of chars that can make up "Op" tokens,
206 207 208 209 210 211 212
 * 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 已提交
213 214
self			[,()\[\].;\:\+\-\*\/\%\^\<\>\=]
op_chars		[\~\!\@\#\^\&\|\`\?\+\-\*\/\%\<\>\=]
215
operator		{op_chars}+
M
Marc G. Fournier 已提交
216

217
/* we no longer allow unary minus in numbers.
218
 * instead we pass it separately to parser. there it gets
219
 * coerced via doNegate() -- Leon aug 20 1999
220 221 222
 *
 * {realfail1} and {realfail2} are added to prevent the need for scanner
 * backup when the {real} rule fails to match completely.
M
Michael Meskes 已提交
223
 */
224

M
Michael Meskes 已提交
225 226
integer			{digit}+
decimal			(({digit}*\.{digit}+)|({digit}+\.{digit}*))
227 228 229
real			({integer}|{decimal})[Ee][-+]?{digit}+
realfail1		({integer}|{decimal})[Ee]
realfail2		({integer}|{decimal})[Ee][-+]
M
Marc G. Fournier 已提交
230 231 232

param			\${integer}

M
Michael Meskes 已提交
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
/*
 * 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 已提交
248
ccomment		"//".*\n
M
Marc G. Fournier 已提交
249

250
space			[ \t\n\r\f]
M
Michael Meskes 已提交
251
horiz_space		[ \t\f]
252
newline			[\n\r]
M
Michael Meskes 已提交
253 254
non_newline		[^\n\r]

255
comment			("--"{non_newline}*)
M
Michael Meskes 已提交
256

257
whitespace		({space}+|{comment})
M
Michael Meskes 已提交
258 259 260 261 262 263 264 265 266

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

269 270
quote			'
quotestop		{quote}{whitespace}*
271
quotecontinue	{quote}{whitespace_with_newline}{quote}
272 273
quotefail		{quote}{whitespace}*"-"

274 275 276 277
/* special characters for other dbms */
/* we have to react differently in compat mode */
informix_special	[\$]

M
Marc G. Fournier 已提交
278 279 280
other			.

/* some stuff needed for ecpg */
B
Bruce Momjian 已提交
281 282 283 284
exec			[eE][xX][eE][cC]
sql				[sS][qQ][lL]
define			[dD][eE][fF][iI][nN][eE]
include 		[iI][nN][cC][lL][uU][dD][eE]
M
Marc G. Fournier 已提交
285

B
Bruce Momjian 已提交
286 287 288 289 290
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]
291

B
Bruce Momjian 已提交
292
struct			[sS][tT][rR][uU][cC][tT]
293

294
exec_sql		{exec}{space}*{sql}{space}*
M
Michael Meskes 已提交
295
ipdigit			({digit}|{digit}{digit}|{digit}{digit}{digit})
296
ip				{ipdigit}\.{ipdigit}\.{ipdigit}\.{ipdigit}
297

298 299 300
/* we might want to parse all cpp include files */
cppinclude 		{space}*#{include}{space}*

301 302
/* Take care of cpp lines, they may also be continuated */
cppline			{space}*#(.*\\{space})*.*{newline}
M
 
Marc G. Fournier 已提交
303

304
/*
305 306
 * Dollar quoted strings are totally opaque, and no escaping is done on them.
 * Other quoted strings must allow some special characters such as single-quote
307
 *	and newline.
308
 * Embedded single-quotes are implemented both in the SQL standard
309 310
 *	style of two adjacent single quotes "''" and in the Postgres/Java style
 *	of escaped-quote "\'".
M
Marc G. Fournier 已提交
311
 * Other embedded escaped characters are matched explicitly and the leading
312
 *	backslash is dropped from the string. - thomas 1997-09-24
M
Michael Meskes 已提交
313
 * Note that xcstart must appear before operator, as explained above!
314
 *	Also whitespace (comment) must appear before operator.
M
Marc G. Fournier 已提交
315 316
 */

317
%%
318 319

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

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

B
Bruce Momjian 已提交
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
{xcstart}		{
					token_start = yytext;
					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);
				}
341

B
Bruce Momjian 已提交
342 343 344 345 346 347
<xc>{xcstop}	{
					ECHO;
					if (xcdepth <= 0)
					{
						BEGIN(state_before);
						token_start = NULL;
348
					}
B
Bruce Momjian 已提交
349 350 351
					else
						xcdepth--;
				}
352

353 354
<xc>{xcinside}	{ ECHO; }
<xc>{op_chars}	{ ECHO; }
355
<xc>\*+ 		{ ECHO; }
356

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

M
Michael Meskes 已提交
359
<SQL>{xbstart}	{
360 361 362 363 364
					token_start = yytext;
					BEGIN(xb);
					startlit();
					addlitchar('b');
				}
365 366
<xb>{quotestop} |
<xb>{quotefail}	{
367 368 369 370 371 372 373
					yyless(1);
					BEGIN(SQL);
					if (literalbuf[strspn(literalbuf, "01") + 1] != '\0')
						mmerror(PARSE_ERROR, ET_ERROR, "invalid bit string input.");
					yylval.str = mm_strdup(literalbuf);
					return BCONST;
				}
M
Marc G. Fournier 已提交
374 375

<xh>{xhinside}	|
M
Michael Meskes 已提交
376
<xb>{xbinside}	{ addlit(yytext, yyleng); }
377 378
<xh>{quotecontinue}	|
<xb>{quotecontinue}	{ /* ignore */ }
379
<xb><<EOF>>		{ mmerror(PARSE_ERROR, ET_FATAL, "Unterminated bit string"); }
M
Marc G. Fournier 已提交
380

381 382 383 384 385 386
<SQL>{xhstart}	{
					token_start = yytext;
					BEGIN(xh);
					startlit();
					addlitchar('x');
				}
387 388 389 390 391 392 393
<xh>{quotestop}	|
<xh>{quotefail} 	{
				yyless(1);
				BEGIN(SQL);
				yylval.str = mm_strdup(literalbuf);
				return XCONST;
			}
394

395
<xh><<EOF>>		{ mmerror(PARSE_ERROR, ET_FATAL, "Unterminated hexadecimal integer"); }
M
Michael Meskes 已提交
396 397
<SQL>{xnstart}              {
				/* National character.
398 399 400
				 * Transfer it as-is to the backend.
				 */
		        token_start = yytext;
M
Michael Meskes 已提交
401 402 403
				BEGIN(xq);
				startlit();
			}
404
<C,SQL>{xqstart}	{
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424
				warn_on_first_escape = true;
				token_start = yytext;
				state_before = YYSTATE;
				BEGIN(xq);
				startlit();
			}
<C,SQL>{xestart}	{
				warn_on_first_escape = false;
				token_start = yytext;
				state_before = YYSTATE;
				BEGIN(xq);
				startlit();
			}
<xq>{quotestop} |
<xq>{quotefail}		{
				yyless(1);
				BEGIN(state_before);
				yylval.str = mm_strdup(literalbuf);
				return SCONST;
			}
425 426
<xq>{xqdouble}		{ addlitchar('\''); }
<xq>{xqinside}		{ addlit(yytext, yyleng); }
427 428 429 430 431 432 433 434 435 436 437 438 439
<xq>{xqescape}  	{ 
				check_escape_warning();
				addlit(yytext, yyleng);
			}
<xq>{xqoctesc}		{ 
				check_escape_warning();
				addlit(yytext, yyleng);
			}
<xq>{xqhexesc}		{ 
				check_escape_warning();
				addlit(yytext, yyleng);
			}
<xq>{quotecontinue}	{ /* ignore */ }
440 441 442 443
<xq>.		{
			   /* This is only needed for \ just before EOF */
			   addlitchar(yytext[0]);
			}
444
<xq><<EOF>>		{ mmerror(PARSE_ERROR, ET_FATAL, "Unterminated quoted string"); }
445 446 447 448 449 450
<SQL>{dolqfailed}	{
				/* throw back all but the initial "$" */
				yyless(1);
				/* and treat it as {other} */
				return yytext[0];	
			}
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
<SQL>{dolqdelim}        {
				token_start = yytext;
				dolqstart = mm_strdup(yytext);
				BEGIN(xdolq);
				startlit();
			}
<xdolq>{dolqdelim}      {
				if (strcmp(yytext, dolqstart) == 0)
				{
					free(dolqstart);
					BEGIN(SQL);
					yylval.str = mm_strdup(literalbuf);
					return SCONST;
				}
				else
				{
467 468 469 470 471 472 473
			        /*
			         * When we fail to match $...$ to dolqstart, transfer
			         * the $... part to the output, but put back the final
			         * $ for rescanning.  Consider $delim$...$junk$delim$
			         */
			        addlit(yytext, yyleng-1);
			        yyless(yyleng-1);
474 475
				}
			}
476 477
<xdolq>{dolqinside} 	{ addlit(yytext, yyleng); }
<xdolq>{dolqfailed}	{ addlit(yytext, yyleng); }
478
<xdolq>.	{
479 480 481 482
				/* $$ is implemented as a single-quoted string, so double it? */
				if (yytext[0] == '\'')
					addlitchar(yytext[0]);
				/* single quote or dollar sign */
483 484 485
				addlitchar(yytext[0]);
			}
<xdolq><<EOF>> { yyerror("unterminated dollar-quoted string"); }
486 487 488 489 490 491

<SQL>{xdstart}		{
						state_before = YYSTATE;
						BEGIN(xd);
						startlit();
					}
M
Michael Meskes 已提交
492
<xd>{xdstop}		{
493
						BEGIN(state_before);
494 495
						if (literallen == 0)
							mmerror(PARSE_ERROR, ET_ERROR, "zero-length delimited identifier");
496
						/* The backend will truncate the idnetifier here. We do not as it does not change the result. */
497 498 499 500 501 502 503 504
						yylval.str = mm_strdup(literalbuf);
						return CSTRING;
					}
<xdc>{xdstop}		{
						BEGIN(state_before);
						yylval.str = mm_strdup(literalbuf);
						return CSTRING;
					}
505
<xd>{xddouble}		{ addlitchar('"'); }
506
<xd>{xdinside}		{ addlit(yytext, yyleng); }
507
<xd,xdc><<EOF>>		{ mmerror(PARSE_ERROR, ET_FATAL, "Unterminated quoted identifier"); }
508 509 510 511
<C,SQL>{xdstart}	{
						state_before = YYSTATE;
						BEGIN(xdc);
						startlit();
M
Michael Meskes 已提交
512
					}
513 514
<xdc>{xdcinside}	{ addlit(yytext, yyleng); }
<SQL>{typecast}		{ return TYPECAST; }
515 516
<SQL>{informix_special}	{
			  /* are we simulating Informix? */
517 518 519 520 521 522 523
				if (INFORMIX_MODE)
				{
					unput(':');
				}
				else
					return yytext[0];
				}
524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
<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;
541 542
						char   *slashstar = strstr(yytext, "/*");
						char   *dashdash = strstr(yytext, "--");
543 544

						if (slashstar && dashdash)
545
						{
546 547 548
							/* if both appear, take the first one */
							if (slashstar > dashdash)
								slashstar = dashdash;
549
						}
550 551 552
						else if (!slashstar)
							slashstar = dashdash;
						if (slashstar)
553
							nchars = slashstar - yytext;
554 555

						/*
556
						 * For SQL compatibility, '+' and '-' cannot be the
557
						 * last char of a multi-char operator unless the operator
558
						 * contains chars that are not in SQL operators.
559 560
						 * The idea is to lex '=-' as two operators, but not
						 * to forbid operator names like '?-' that could not be
561
						 * sequences of SQL operators.
M
Michael Meskes 已提交
562
						 */
563 564 565 566 567 568 569 570
						while (nchars > 1 &&
							   (yytext[nchars-1] == '+' ||
								yytext[nchars-1] == '-'))
						{
							int		ic;

							for (ic = nchars-2; ic >= 0; ic--)
							{
M
Michael Meskes 已提交
571
								if (strchr("~!@#^&|`?%", yytext[ic]))
572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589
									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 &&
M
Michael Meskes 已提交
590
								strchr(",()[].;:+-*/%^<>=", yytext[0]))
591 592 593 594
								return yytext[0];
						}

						/* Convert "!=" operator to "<>" for compatibility */
595
						if (strcmp(yytext, "!=") == 0)
596 597
							yylval.str = mm_strdup("<>");
						else
598
							yylval.str = mm_strdup(yytext);
599
						return Op;
M
Michael Meskes 已提交
600
					}
601
<SQL>{param}		{
602
						yylval.ival = atol(yytext+1);
603 604 605 606 607
						return PARAM;
					}
<C,SQL>{integer}	{
						long val;
						char* endptr;
M
Michael Meskes 已提交
608

M
Marc G. Fournier 已提交
609
						errno = 0;
610 611 612 613 614 615 616 617 618
						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;
619
							yylval.str = mm_strdup(yytext);
620 621 622 623 624 625
							return FCONST;
						}
						yylval.ival = val;
						return ICONST;
					}
<SQL>{ip}			{
626
						yylval.str = mm_strdup(yytext);
627 628 629
						return IP;
					}
{decimal}			{
630
						yylval.str = mm_strdup(yytext);
631
						return FCONST;
632
			}
633
<C,SQL>{real}		{
634
						yylval.str = mm_strdup(yytext);
M
Michael Meskes 已提交
635
						return FCONST;
636 637
			}
<SQL>{realfail1}	{
638 639 640 641
						yyless(yyleng-1);
						yylval.str = mm_strdup(yytext);
						return FCONST;
					}
642
<SQL>{realfail2}	{
643 644 645 646
						yyless(yyleng-2);
						yylval.str = mm_strdup(yytext);
						return FCONST;
					}
647
<SQL>:{identifier}((("->"|\.){identifier})|(\[{array}\]))*	{
648
						yylval.str = mm_strdup(yytext+1);
649 650
						return(CVARIABLE);
					}
M
Marc G. Fournier 已提交
651
<SQL>{identifier}	{
652 653
						ScanKeyword    *keyword;
						struct _defines *ptr;
M
Michael Meskes 已提交
654
						
655 656
						/* How about a DEFINE? */
						for (ptr = defines; ptr; ptr = ptr->next)
M
Marc G. Fournier 已提交
657
						{
M
Michael Meskes 已提交
658
							if (strcmp(yytext, ptr->old) == 0 && ptr->used == NULL)
659 660
							{
								struct _yy_buffer *yb;
M
 
Marc G. Fournier 已提交
661

662 663 664 665 666
								yb = mm_alloc(sizeof(struct _yy_buffer));

								yb->buffer =  YY_CURRENT_BUFFER;
								yb->lineno = yylineno;
								yb->filename = mm_strdup(input_filename);
667
								yb->next = yy_buffer;
M
Michael Meskes 已提交
668
								
669
								ptr->used = yy_buffer = yb;
M
 
Marc G. Fournier 已提交
670

671 672 673 674
								yy_scan_string(ptr->new);
								break;
							}
						}
675 676 677 678 679 680
						if (ptr == NULL)
						{
							/* Is it an SQL keyword? */
							keyword = ScanKeywordLookup(yytext);
							if (keyword != NULL)
								return keyword->value;
681

682 683 684 685
							/* Is it an ECPG keyword? */
							keyword = ScanECPGKeywordLookup( yytext);
							if (keyword != NULL)
								return keyword->value;
686

687 688 689 690
							/* Is it a C keyword? */
							keyword = ScanCKeywordLookup(yytext);
							if (keyword != NULL)
								return keyword->value;
691

692 693 694
							/*
							 * None of the above.  Return it as an identifier.
							 *
M
Michael Meskes 已提交
695
							 * The backend will attempt to truncate and case-fold
696 697 698 699
							 * 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.
							 */
M
Michael Meskes 已提交
700 701
							yylval.str = mm_strdup(yytext);
							return IDENT;
M
Marc G. Fournier 已提交
702 703
						}
					}
704 705
<SQL>{other}		{ return yytext[0]; }
<C>{exec_sql}		{ BEGIN SQL; return SQL_START; }
706
<C>{informix_special}	{ 
707 708 709 710 711 712 713 714 715 716
						/* are we simulating Informix? */
						if (INFORMIX_MODE)
						{
							BEGIN SQL;
							return SQL_START;
						}
						else
							return S_ANYTHING;
					 }
<C>{ccomment}		{ ECHO; }
M
Michael Meskes 已提交
717
<C>{xch}			{
718
						char* endptr;
M
Michael Meskes 已提交
719 720

						errno = 0;
M
Michael Meskes 已提交
721
						yylval.ival = strtoul((char *)yytext,&endptr,16);
722 723 724
						if (*endptr != '\0' || errno == ERANGE)
						{
							errno = 0;
725
							yylval.str = mm_strdup(yytext);
726 727 728 729
							return SCONST;
						}
						return ICONST;
					}
730
<C>{cppinclude}		{
731 732 733 734 735 736 737 738 739 740 741
						if (system_includes)
						{
							BEGIN(incl);
						}
						else
					 	{
							yylval.str = mm_strdup(yytext);
							return(CPP_LINE);
					  	}
					}
<C,SQL>{cppline}	{
742
						yylval.str = mm_strdup(yytext);
743
						return(CPP_LINE);
M
Michael Meskes 已提交
744
					}
745 746
<C>{identifier} 	{
						ScanKeyword		*keyword;
747
						struct _defines *ptr;
M
 
Marc G. Fournier 已提交
748

749
						if (INFORMIX_MODE)
M
 
Marc G. Fournier 已提交
750
						{
751 752 753 754 755 756 757
							/* Informix uses SQL defines only in SQL space */
							ptr = NULL;
						}
						else
						{
							/* is it a define? */
							for (ptr = defines; ptr; ptr = ptr->next)
M
 
Marc G. Fournier 已提交
758
							{
759 760 761
								if (strcmp(yytext, ptr->old) == 0 && ptr->used == NULL)
								{
									struct _yy_buffer *yb;
M
 
Marc G. Fournier 已提交
762

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

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

770
									ptr->used = yy_buffer = yb;
M
 
Marc G. Fournier 已提交
771

772 773 774
									yy_scan_string(ptr->new);
									break;
								}
775
							}
776 777 778 779 780 781 782
						}

						if (ptr == NULL)
						{
							keyword = ScanCKeywordLookup(yytext);
							if (keyword != NULL)
								return keyword->value;
783 784
							else
							{
785
								yylval.str = mm_strdup(yytext);
786
								return IDENT;
M
 
Marc G. Fournier 已提交
787 788
							}
						}
M
Marc G. Fournier 已提交
789
					}
790
<C>":"				{ return(':'); }
791 792 793 794 795 796 797 798 799
<C>";"				{ return(';'); }
<C>","				{ return(','); }
<C>"*"				{ return('*'); }
<C>"%"				{ return('%'); }
<C>"/"				{ return('/'); }
<C>"+"				{ return('+'); }
<C>"-"				{ return('-'); }
<C>"("				{ return('('); }
<C>")"				{ return(')'); }
800
<C,xskip>{space}	{ ECHO; }
801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822
<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; }
823

824
<C>{exec_sql}{define}{space}*	{ BEGIN(def_ident); }
825 826
<C>{informix_special}{define}{space}*	{
						/* are we simulating Informix? */
827
						if (INFORMIX_MODE)
828 829 830 831 832
						{
							BEGIN(def_ident);
						}
						else
						{
833
							yyless(1);
834 835 836
							return (S_ANYTHING);
						}
					}
837
<C>{exec_sql}{include}{space}*	{ BEGIN(incl); }
838 839
<C>{informix_special}{include}{space}* { 
					  /* are we simulating Informix? */
840
					  if (INFORMIX_MODE)
841
					  {
842
						  BEGIN(incl);
843 844 845
					  }
					  else
					  {
846 847
						  yyless(1);
						  return (S_ANYTHING);
848 849
					  }
					}
850
<C,xskip>{exec_sql}{ifdef}{space}*	{ ifcond = TRUE; BEGIN(xcond); }
851 852
<C,xskip>{informix_special}{ifdef}{space}* { 
					  /* are we simulating Informix? */
853
					  if (INFORMIX_MODE)
854
					  {
855 856
						  ifcond = TRUE;
						  BEGIN(xcond);
857 858 859
					  }
					  else
					  {
860 861
						  yyless(1);
						  return (S_ANYTHING);
862 863
					  }
					}
864
<C,xskip>{exec_sql}{ifndef}{space}* { ifcond = FALSE; BEGIN(xcond); }
865 866
<C,xskip>{informix_special}{ifndef}{space}* { 
					  /* are we simulating Informix? */
867
					  if (INFORMIX_MODE)
868
					  {
869 870
						  ifcond = FALSE;
						  BEGIN(xcond);
871 872 873
					  }
					  else
					  {
874 875
						  yyless(1);
						  return (S_ANYTHING);
876 877
					  }
					}
878
<C,xskip>{exec_sql}{elif}{space}*	{	/* pop stack */
879
						if ( preproc_tos == 0 ) {
880
							mmerror(PARSE_ERROR, ET_FATAL, "Missing matching 'EXEC SQL IFDEF / EXEC SQL IFNDEF'");
881
						}
882 883 884 885
						else if ( stacked_if_value[preproc_tos].else_branch )
							mmerror(PARSE_ERROR, ET_FATAL, "Missing 'EXEC SQL ENDIF;'");
						else
							preproc_tos--;
886 887 888

						ifcond = TRUE; BEGIN(xcond);
					}
889
<C,xskip>{informix_special}{elif}{space}* { 
890 891 892 893
					/* are we simulating Informix? */
					if (INFORMIX_MODE)
					{
						if (preproc_tos == 0)
894
							mmerror(PARSE_ERROR, ET_FATAL, "Missing matching 'EXEC SQL IFDEF / EXEC SQL IFNDEF'");
895
						else if (stacked_if_value[preproc_tos].else_branch)
896 897 898 899
							mmerror(PARSE_ERROR, ET_FATAL, "Missing 'EXEC SQL ENDIF;'");
						else
							preproc_tos--;

900 901
						ifcond = TRUE;
						BEGIN(xcond);
902
					}
903 904 905 906 907 908
					else
					{
						yyless(1);
						return (S_ANYTHING);
					}
				}
909

910
<C,xskip>{exec_sql}{else}{space}*";" {	/* only exec sql endif pops the stack, so take care of duplicated 'else' */
911 912 913 914 915 916
					if (stacked_if_value[preproc_tos].else_branch)
						mmerror(PARSE_ERROR, ET_FATAL, "Duplicated 'EXEC SQL ELSE;'");
					else
					{
						stacked_if_value[preproc_tos].else_branch = TRUE;
						stacked_if_value[preproc_tos].condition =
917
							(stacked_if_value[preproc_tos-1].condition &&
918
							 !stacked_if_value[preproc_tos].condition);
919

920 921 922 923
						if (stacked_if_value[preproc_tos].condition)
							BEGIN(C);
						else
							BEGIN(xskip);
924
					}
925
				}
926
<C,xskip>{informix_special}{else}{space}*	{
927 928 929 930
					/* are we simulating Informix? */
					if (INFORMIX_MODE)
					{
						if (stacked_if_value[preproc_tos].else_branch)
931
							mmerror(PARSE_ERROR, ET_FATAL, "Duplicated 'EXEC SQL ELSE;'");
932 933
						else
						{
934 935 936
							stacked_if_value[preproc_tos].else_branch = TRUE;
							stacked_if_value[preproc_tos].condition =
							(stacked_if_value[preproc_tos-1].condition &&
937
							 !stacked_if_value[preproc_tos].condition);
938

939
							if (stacked_if_value[preproc_tos].condition)
940 941 942 943 944
								BEGIN(C);
							else
								BEGIN(xskip);
						}
					}
945 946 947 948
					else
					{
						yyless(1);
						return (S_ANYTHING);
949
					}
950 951 952 953 954 955 956 957 958 959 960 961
				}
<C,xskip>{exec_sql}{endif}{space}*";" {
					if (preproc_tos == 0)
						mmerror(PARSE_ERROR, ET_FATAL, "Unmatched 'EXEC SQL ENDIF;'");
					else
						preproc_tos--;

					if (stacked_if_value[preproc_tos].condition)
					   BEGIN(C);
					else
					   BEGIN(xskip);
				}
M
Michael Meskes 已提交
962
<C,xskip>{informix_special}{endif}{space}*";"	{
963 964 965 966
					/* are we simulating Informix? */
					if (INFORMIX_MODE)
					{
						if (preproc_tos == 0)
967 968 969 970
							mmerror(PARSE_ERROR, ET_FATAL, "Unmatched 'EXEC SQL ENDIF;'");
						else
							preproc_tos--;

971 972
						if (stacked_if_value[preproc_tos].condition)
							BEGIN(C);
973
						else
974 975 976 977 978 979
							BEGIN(xskip);
					}
					else
					{
						yyless(1);
						return (S_ANYTHING);
980
					}
981
				}
982

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

985
<xcond>{identifier}{space}*";" {
986 987 988 989 990 991
					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;
992

993 994 995 996 997 998 999 1000 1001 1002 1003 1004
						/*
						 *	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 && strcmp(yytext, defptr->old) != 0;
1005
							 defptr = defptr->next);
1006 1007 1008 1009 1010

						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;
1011 1012
					}

1013 1014 1015 1016 1017 1018
					if (stacked_if_value[preproc_tos].condition)
						BEGIN C;
					else
						BEGIN(xskip);
				}

1019 1020 1021 1022
<xcond>{other}	{
			mmerror(PARSE_ERROR, ET_FATAL, "Missing identifier in 'EXEC SQL IFDEF' command");
			yyterminate();
		}
1023
<def_ident>{identifier} {
M
 
Marc G. Fournier 已提交
1024
				old = mm_strdup(yytext);
M
 
Marc G. Fournier 已提交
1025
				BEGIN(def);
1026
				startlit();
M
 
Marc G. Fournier 已提交
1027
			}
1028 1029 1030 1031
<def_ident>{other}	{
			mmerror(PARSE_ERROR, ET_FATAL, "Missing identifier in 'EXEC SQL DEFINE' command");
			yyterminate();
		}
1032
<def>{space}*";"	{
1033
						struct _defines *ptr, *this;
1034

1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045
						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)
						{
M
Michael Meskes 已提交
1046
							this = (struct _defines *) mm_alloc(sizeof(struct _defines));
1047

M
Michael Meskes 已提交
1048 1049 1050
							/* initial definition */
							this->old = old;
							this->new = mm_strdup(literalbuf);
1051
							this->next = defines;
M
Michael Meskes 已提交
1052
							this->used = NULL;
1053 1054
							defines = this;
						}
1055

1056 1057 1058
						BEGIN(C);
					}
<def>[^;]			{ addlit(yytext, yyleng); }
1059 1060
<incl>\<[^\>]+\>{space}*";"?		{	parse_include(); }
<incl>{dquote}{xdinside}{dquote}{space}*";"?	{	parse_include(); }
1061
<incl>[^;\<\>\"]+";"		{ parse_include(); }
1062 1063 1064 1065
<incl>{other}	{
			mmerror(PARSE_ERROR, ET_FATAL, "Incorrect 'EXEC SQL INCLUDE' command");
			yyterminate();
		}
1066 1067

<<EOF>>				{
1068 1069
			  		if (yy_buffer == NULL)
					{
1070 1071 1072 1073 1074
				  		if ( preproc_tos > 0 ) 
						{
					  		preproc_tos = 0;
							mmerror(PARSE_ERROR, ET_FATAL, "Missing 'EXEC SQL ENDIF;'");
				  		}
1075 1076 1077 1078 1079 1080 1081
						yyterminate();
					}
			  		else
			  		{
						struct _yy_buffer *yb = yy_buffer;
						int i;
						struct _defines *ptr;
1082

1083 1084 1085 1086 1087 1088 1089 1090 1091
						for (ptr = defines; ptr; ptr = ptr->next)
							if (ptr->used == yy_buffer)
							{
								ptr->used = NULL;
								break;
							}
								
						if (yyin != NULL)
							fclose(yyin);
1092

1093 1094
						yy_delete_buffer( YY_CURRENT_BUFFER );
						yy_switch_to_buffer(yy_buffer->buffer);
1095

1096
						yylineno = yy_buffer->lineno;
1097

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

1101 1102
						free(input_filename);
						input_filename = yy_buffer->filename;
1103

1104 1105
						yy_buffer = yy_buffer->next;
						free(yb);
1106

1107 1108 1109 1110 1111
						if (i != 0)
							output_line_number();
						
			  		}
				}
1112 1113
%%
void
1114
lex_init(void)
1115
{
1116 1117 1118
	braces_open = 0;

	preproc_tos = 0;
M
Michael Meskes 已提交
1119
	yylineno = 1;
1120 1121 1122
	ifcond = TRUE;
	stacked_if_value[preproc_tos].condition = ifcond;
	stacked_if_value[preproc_tos].else_branch = FALSE;
1123 1124 1125 1126 1127 1128 1129 1130 1131

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

1132
	BEGIN C;
1133 1134
}

1135 1136 1137 1138 1139 1140
static void
addlit(char *ytext, int yleng)
{
	/* enlarge buffer if needed */
	if ((literallen+yleng) >= literalalloc)
	{
1141
		do 
1142
			literalalloc *= 2;
1143
		while ((literallen+yleng) >= literalalloc);
1144 1145
		literalbuf = (char *) realloc(literalbuf, literalalloc);
	}
1146 1147
	/* append new data, add trailing null */
	memcpy(literalbuf+literallen, ytext, yleng);
1148
	literallen += yleng;
1149
	literalbuf[literallen] = '\0';
1150 1151
}

1152 1153
static void
addlitchar(unsigned char ychar)
1154
{
1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165
	/* 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';
}
1166

1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188
static void
parse_include(void)
{
	/* got the include file name */
	struct _yy_buffer *yb;
  	struct _include_path *ip;
  	char inc_file[MAXPGPATH];
  	unsigned int i;

  	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;

  	/*
	 * skip the ";" if there is one and trailing whitespace. Note that
	 * yytext contains at least one non-space character plus the ";" 
	 */
1189 1190 1191 1192
  	for (i = strlen(yytext)-2;
		 i > 0 && isspace((unsigned char) yytext[i]);
		 i--)
		;
1193 1194 1195 1196 1197 1198 1199 1200 1201 1202

	if (yytext[i] == ';')
		i--;

	yytext[i+1] = '\0';
	
	yyin = NULL;

	/* If file name is enclosed in '"' remove these and look only in '.' */
	/* Informix does look into all include paths though, except filename starts with '/' */
1203
	if (yytext[0] == '"' && yytext[i] == '"' &&
1204
	    ((compat != ECPG_COMPAT_INFORMIX && compat != ECPG_COMPAT_INFORMIX_SE) || yytext[1] == '/'))
1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248
	{
		yytext[i] = '\0';
		memmove(yytext, yytext+1, strlen(yytext));
	
		strncpy(inc_file, yytext, sizeof(inc_file));
		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");
			}
		}
		
	}
	else
	{
		if ((yytext[0] == '"' && yytext[i] == '"') || (yytext[0] == '<' && yytext[i] == '>'))
		{
			yytext[i] = '\0';
			memmove(yytext, yytext+1, strlen(yytext));
		}
		
	  	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;
			}
			snprintf (inc_file, sizeof(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
Michael Meskes 已提交
1249
		mmerror(NO_INCLUDE_FILE, ET_FATAL, "Cannot open include file %s in line %d\n", yytext, yylineno);
1250 1251 1252 1253 1254 1255 1256 1257

	input_filename = mm_strdup(inc_file);
	yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE ));
	yylineno = 1;
	output_line_number();

  	BEGIN C;
}
1258 1259 1260 1261 1262 1263

static void
check_escape_warning(void)
{
	if (warn_on_first_escape && escape_string_warning)
	       	mmerror (PARSE_ERROR, ET_WARNING, "nonstandard use of escape in a string literal");
1264
	warn_on_first_escape = false;   /* warn only once per string */
1265
}