summaryrefslogtreecommitdiff
path: root/src/interfaces/ecpg/preproc/pgc.l
diff options
context:
space:
mode:
Diffstat (limited to 'src/interfaces/ecpg/preproc/pgc.l')
-rw-r--r--src/interfaces/ecpg/preproc/pgc.l172
1 files changed, 145 insertions, 27 deletions
diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/preproc/pgc.l
index d84144262ea..53f65843439 100644
--- a/src/interfaces/ecpg/preproc/pgc.l
+++ b/src/interfaces/ecpg/preproc/pgc.l
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/pgc.l,v 1.46 1999/10/25 03:07:59 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/pgc.l,v 1.47 1999/12/21 17:42:16 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -59,9 +59,16 @@ struct _yy_buffer { YY_BUFFER_STATE buffer;
struct _yy_buffer * next;
} *yy_buffer = NULL;
-struct _defines *defines = NULL;
static char *old;
+#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];
+
%}
%option yylineno
%s C SQL incl def def_ident
@@ -94,6 +101,9 @@ static char *old;
%x xdc
%x xh
%x xq
+%x xpre
+%x xcond
+%x xskip
/* Binary number
*/
@@ -142,15 +152,15 @@ xdcinside ({xdcqq}|{xdcqdq}|{xdcother})
/* Comments
* Ignored by the scanner and parser.
*/
-xcline [\/][\*].*[\*][\/]{space}*\n*
+xcline [\/][\*].*[\*][\/]{line_end}+
xcstart [\/][\*]{op_and_self}*
-xcstop {op_and_self}*[\*][\/]({space}*|\n)
+xcstop {op_and_self}*[\*][\/]{space_or_nl}*
xcinside [^*]*
xcstar [^/]
digit [0-9]
letter [\200-\377_A-Za-z]
-letter_or_digit [\200-\377_A-Za-z0-9]
+letter_or_digit [\200-\377_A-Za-z0-9]
identifier {letter}{letter_or_digit}*
@@ -167,23 +177,34 @@ operator {op_and_self}+
integer {digit}+
decimal (({digit}*\.{digit}+)|({digit}+\.{digit}*))
-real ((({digit}*\.{digit}+)|({digit}+\.{digit}*)|({digit}+))([Ee][-+]?{digit}+))
+real ((({digit}*\.{digit}+)|({digit}+\.{digit}*)|({digit}+))([Ee][-+]?{digit}+))
param \${integer}
comment ("--"|"//").*
ccomment "//".*\n
-space [ \t\n\r\f]
+space [ \t\r\f]
+space_or_nl [ \t\r\f\n]
+line_end {space}*\n
other .
/* some stuff needed for ecpg */
exec [eE][xX][eE][cC]
+sql [sS][qQ][lL]
define [dD][eE][fF][iI][nN][eE]
include [iI][nN][cC][lL][uU][dD][eE]
-sql [sS][qQ][lL]
-cppline {space}*#.*(\\{space}*\n)*\n*
+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}*
+
+/* Take care of cpp continuation lines */
+cppline {space}*#(.*\\{line_end})*.*
/* DO NOT PUT ANY COMMENTS IN THE FOLLOWING SECTION.
* AT&T lex does not properly handle C-style comments in this second lex block.
@@ -268,7 +289,6 @@ cppline {space}*#.*(\\{space}*\n)*\n*
<xq>{xqcat} {
}
-
<SQL>{xdstart} {
BEGIN(xd);
startlit();
@@ -406,9 +426,9 @@ cppline {space}*#.*(\\{space}*\n)*\n*
}
}
}
-<SQL>{space} { /* ignore */ }
+<SQL>{space_or_nl} { /* ignore */ }
<SQL>{other} { return yytext[0]; }
-<C>{exec}{space}*{sql} { BEGIN SQL; return SQL_START; }
+<C>{exec_sql} { BEGIN SQL; return SQL_START; }
<C>{ccomment} { /* ignore */ }
<C>{xch} {
char* endptr;
@@ -473,22 +493,106 @@ cppline {space}*#.*(\\{space}*\n)*\n*
<C>"-" { return('-'); }
<C>"(" { return('('); }
<C>")" { return(')'); }
-<C>{space} { ECHO; }
+<C>{space_or_nl} { ECHO; }
<C>\{ { return('{'); }
<C>\} { return('}'); }
<C>\[ { return('['); }
<C>\] { return(']'); }
<C>\= { return('='); }
<C>{other} { return S_ANYTHING; }
-<C>{exec}{space}{sql}{space}{define} {BEGIN(def_ident);}
-<def_ident>{space} {}
+
+<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 ) {
+ yyerror("ERROR: missing matching 'EXEC SQL IFDEF / EXEC SQL IFNDEF'");
+ }
+ else if ( stacked_if_value[preproc_tos].else_branch ) {
+ yyerror("ERROR: missing 'EXEC SQL ENDIF;'");
+ }
+ 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 ) {
+ yyerror("ERROR: duplicated 'EXEC SQL ELSE;'");
+ }
+ 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 ) {
+ yyerror("ERROR: unmatched 'EXEC SQL ENDIF;'");
+ }
+ 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 ) {
+ yyerror("ERROR: 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(yytext[i]); i-- ) {}
+ 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);
+ }
+ }
+
<def_ident>{identifier} {
old = mm_strdup(yytext);
BEGIN(def);
startlit();
}
-<def>{space} /* eat the whitespace */
-<def>";" {
+<def>{space_or_nl}*";" {
struct _defines *ptr, *this;
for (ptr = defines; ptr != NULL; ptr = ptr->next)
@@ -517,12 +621,12 @@ cppline {space}*#.*(\\{space}*\n)*\n*
<def>[^";"] {
addlit(yytext, yyleng);
}
-<C>{exec}{space}{sql}{space}{include} { BEGIN(incl); }
-<incl>{space} /* eat the whitespace */
-<incl>[^ \t\n]+ { /* got the include file name */
+
+<incl>[^";"]+";" { /* 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));
@@ -533,8 +637,10 @@ cppline {space}*#.*(\\{space}*\n)*\n*
yy_buffer = yb;
- if (yytext[strlen(yytext) - 1] == ';')
- yytext[strlen(yytext) - 1] = '\0';
+ /* 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(yytext[i]); i-- ) {}
+ yytext[i+1] = '\0';
yyin = NULL;
for (ip = include_paths; yyin == NULL && ip != NULL; ip = ip->next)
@@ -564,13 +670,20 @@ cppline {space}*#.*(\\{space}*\n)*\n*
input_filename = mm_strdup(inc_file);
yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE ));
- yylineno = 0;
+ yylineno = 1;
output_line_number();
BEGIN C;
}
-<incl>";" { BEGIN C; }
-<<EOF>> { if (yy_buffer == NULL)
+
+<<EOF>> {
+ if ( preproc_tos > 0 ) {
+ preproc_tos = 0;
+
+ yyerror("ERROR: missing 'EXEC SQL ENDIF;'");
+ }
+
+ if (yy_buffer == NULL)
yyterminate();
else
{
@@ -596,7 +709,12 @@ cppline {space}*#.*(\\{space}*\n)*\n*
void
lex_init(void)
{
- braces_open = 0;
+ braces_open = 0;
+
+ preproc_tos = 0;
+ ifcond = TRUE;
+ stacked_if_value[preproc_tos].condition = ifcond;
+ stacked_if_value[preproc_tos].else_branch = FALSE;
/* initialize literal buffer to a reasonable but expansible size */
if (literalbuf == NULL)
@@ -626,6 +744,6 @@ addlit(char *ytext, int yleng)
}
int yywrap(void)
-{
+{
return 1;
}