aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/interfaces/ecpg/preproc/ecpg.c55
-rw-r--r--src/interfaces/ecpg/preproc/pgc.l172
-rw-r--r--src/interfaces/ecpg/preproc/preproc.y71
-rw-r--r--src/interfaces/ecpg/preproc/type.h1
4 files changed, 238 insertions, 61 deletions
diff --git a/src/interfaces/ecpg/preproc/ecpg.c b/src/interfaces/ecpg/preproc/ecpg.c
index 938559670f3..a49cc6b60d5 100644
--- a/src/interfaces/ecpg/preproc/ecpg.c
+++ b/src/interfaces/ecpg/preproc/ecpg.c
@@ -12,7 +12,9 @@
#include "extern.h"
struct _include_path *include_paths;
-int ret_value = OK, autocommit = 0;
+struct _defines *defines = NULL;
+int autocommit = 0;
+int ret_value = OK;
struct cursor *cur = NULL;
struct typedefs *types = NULL;
@@ -20,7 +22,7 @@ static void
usage(char *progname)
{
fprintf(stderr, "ecpg - the postgresql preprocessor, version: %d.%d.%d\n", MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL);
- fprintf(stderr, "Usage: %s: [-v] [-t] [-I include path] [ -o output file name] file1 [file2] ...\n", progname);
+ fprintf(stderr, "Usage: %s: [-v] [-t] [-I include path] [ -o output file name] [-D define name] file1 [file2] ...\n", progname);
}
static void
@@ -33,6 +35,18 @@ add_include_path(char *path)
include_paths->next = ip;
}
+static void
+add_preprocessor_define(char *define)
+{
+ struct _defines *pd = defines;
+
+ defines = mm_alloc(sizeof(struct _defines));
+ defines->old = strdup(define);
+ defines->new = strdup("");
+ defines->pertinent = true;
+ defines->next = pd;
+}
+
int
main(int argc, char *const argv[])
{
@@ -46,7 +60,7 @@ main(int argc, char *const argv[])
add_include_path("/usr/local/include");
add_include_path(".");
- while ((c = getopt(argc, argv, "vo:I:t")) != EOF)
+ while ((c = getopt(argc, argv, "vo:I:tD:")) != EOF)
{
switch (c)
{
@@ -74,6 +88,9 @@ main(int argc, char *const argv[])
fprintf(stderr, " %s\n", ip->path);
fprintf(stderr, "End of search list.\n");
return OK;
+ case 'D':
+ add_preprocessor_define(optarg);
+ break;
default:
usage(argv[0]);
return ILLEGAL_OPTION;
@@ -97,7 +114,9 @@ main(int argc, char *const argv[])
strcpy(input_filename, argv[fnr]);
- ptr2ext = strrchr(input_filename, '.');
+ /* take care of relative paths */
+ ptr2ext = strrchr(input_filename, '/');
+ ptr2ext = (ptr2ext ? strrchr(ptr2ext, '.') : strrchr(input_filename, '.'));
/* no extension? */
if (ptr2ext == NULL)
{
@@ -170,16 +189,29 @@ main(int argc, char *const argv[])
ptr = ptr->next;
free(this);
}
+ cur = NULL;
+
+ /* remove non-pertinent old defines as well */
+ while ( defines && !defines->pertinent ) {
+ defptr = defines;
+ defines = defines->next;
+
+ free(defptr->new);
+ free(defptr->old);
+ free(defptr);
+ }
- /* remove old defines as well */
- for (defptr = defines; defptr != NULL;)
+ for (defptr = defines; defptr != NULL; defptr = defptr->next )
{
- struct _defines *this = defptr;
+ struct _defines *this = defptr->next;
+
+ if ( this && !this->pertinent ) {
+ defptr->next = this->next;
- free(defptr->new);
- free(defptr->old);
- defptr = defptr->next;
+ free(this->new);
+ free(this->old);
free(this);
+ }
}
/* and old typedefs */
@@ -193,12 +225,13 @@ main(int argc, char *const argv[])
typeptr = typeptr->next;
free(this);
}
+ types = NULL;
/* initialize lex */
lex_init();
/* we need two includes */
- fprintf(yyout, "/* Processed by ecpg (%d.%d.%d) */\n/* These two include files are added by the preprocessor */\n#include <ecpgtype.h>\n#include <ecpglib.h>\n\n", MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL);
+ fprintf(yyout, "/* Processed by ecpg (%d.%d.%d) */\n/* These two include files are added by the preprocessor */\n#include <ecpgtype.h>\n#include <ecpglib.h>\n#line 1 \"%s\"\n", MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL, input_filename);
/* and parse the source */
yyparse();
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;
}
diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y
index 2ba33e05d0e..999ae050c9a 100644
--- a/src/interfaces/ecpg/preproc/preproc.y
+++ b/src/interfaces/ecpg/preproc/preproc.y
@@ -27,6 +27,7 @@ static char *connection = NULL;
static int QueryIsRule = 0, ForUpdateNotAllowed = 0, FoundInto = 0;
static struct this_type actual_type[STRUCT_DEPTH];
static char *actual_storage[STRUCT_DEPTH];
+static char *actual_startline[STRUCT_DEPTH];
/* temporarily store struct members while creating the data structure */
struct ECPGstruct_member *struct_member_list[STRUCT_DEPTH] = { NULL };
@@ -69,7 +70,7 @@ void
output_line_number()
{
if (input_filename)
- fprintf(yyout, "\n#line %d \"%s\"\n", yylineno + 1, input_filename);
+ fprintf(yyout, "\n#line %d \"%s\"\n", yylineno, input_filename);
}
static void
@@ -479,6 +480,20 @@ make_name(void)
return(name);
}
+static char *
+hashline_number()
+{
+ if (input_filename)
+ {
+ char* line = mm_alloc(strlen("\n#line %d \"%s\"\n") + 21 + strlen(input_filename));
+ sprintf(line, "\n#line %d \"%s\"\n", yylineno, input_filename);
+
+ return line;
+ }
+
+ return EMPTY;
+}
+
static void
output_statement(char * stmt, int mode)
{
@@ -757,7 +772,7 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim
%type <str> columnList DeleteStmt LockStmt UpdateStmt CursorStmt
%type <str> NotifyStmt columnElem copy_dirn UnlistenStmt copy_null
%type <str> copy_delimiter ListenStmt CopyStmt copy_file_name opt_binary
-%type <str> opt_with_copy FetchStmt opt_direction fetch_how_many opt_portal_name
+%type <str> opt_with_copy FetchStmt direction fetch_how_many portal_name
%type <str> ClosePortalStmt DropStmt VacuumStmt opt_verbose
%type <str> opt_analyze opt_va_list va_list ExplainStmt index_params
%type <str> index_list func_index index_elem opt_type opt_class access_method_clause
@@ -807,7 +822,7 @@ adjust_array(enum ECPGttype type_enum, int *dimension, int *length, int type_dim
%type <str> enum_type civariableonly ECPGCursorStmt ECPGDeallocate
%type <str> ECPGFree ECPGDeclare ECPGVar sql_variable_declarations
%type <str> sql_declaration sql_variable_list sql_variable opt_at
-%type <str> struct_type s_struct declaration variable_declarations
+%type <str> struct_type s_struct declaration declarations variable_declarations
%type <str> s_struct s_union union_type ECPGSetAutocommit on_off
%type <type_enum> simple_type varchar_type
@@ -1870,20 +1885,36 @@ TruncateStmt: TRUNCATE TABLE relation_name
*
*****************************************************************************/
-FetchStmt: FETCH opt_direction fetch_how_many opt_portal_name INTO into_list
+FetchStmt: FETCH direction fetch_how_many portal_name INTO into_list
{
if (strcmp($2, "relative") == 0 && atol($3) == 0L)
mmerror(ET_ERROR, "FETCH/RELATIVE at current position is not supported");
$$ = cat_str(4, make_str("fetch"), $2, $3, $4);
}
- | MOVE opt_direction fetch_how_many opt_portal_name
+ | FETCH fetch_how_many portal_name INTO into_list
+ {
+ $$ = cat_str(3, make_str("fetch"), $2, $3);
+ }
+ | FETCH portal_name INTO into_list
{
- $$ = cat_str(4, make_str("fetch"), $2, $3, $4);
+ $$ = cat_str(2, make_str("fetch"), $2);
+ }
+ | MOVE direction fetch_how_many portal_name
+ {
+ $$ = cat_str(4, make_str("move"), $2, $3, $4);
+ }
+ | MOVE fetch_how_many portal_name
+ {
+ $$ = cat_str(3, make_str("move"), $2, $3);
+ }
+ | MOVE portal_name
+ {
+ $$ = cat_str(2, make_str("move"), $2);
}
;
-opt_direction: FORWARD { $$ = make_str("forward"); }
+direction: FORWARD { $$ = make_str("forward"); }
| BACKWARD { $$ = make_str("backward"); }
| RELATIVE { $$ = make_str("relative"); }
| ABSOLUTE
@@ -1891,7 +1922,6 @@ opt_direction: FORWARD { $$ = make_str("forward"); }
mmerror(ET_WARN, "FETCH/ABSOLUTE not supported, backend will use RELATIVE");
$$ = make_str("absolute");
}
- | /*EMPTY*/ { $$ = EMPTY; /* default */ }
;
fetch_how_many: Iconst { $$ = $1; }
@@ -1899,13 +1929,11 @@ fetch_how_many: Iconst { $$ = $1; }
| ALL { $$ = make_str("all"); }
| NEXT { $$ = make_str("next"); }
| PRIOR { $$ = make_str("prior"); }
- | /*EMPTY*/ { $$ = EMPTY; /*default*/ }
;
-opt_portal_name: IN name { $$ = cat2_str(make_str("in"), $2); }
+portal_name: IN name { $$ = cat2_str(make_str("in"), $2); }
| FROM name { $$ = cat2_str(make_str("from"), $2); }
-/* | name { $$ = cat2_str(make_str("in"), $1); */
- | /*EMPTY*/ { $$ = EMPTY; }
+ | name { $$ = cat2_str(make_str("in"), $1); }
;
/*****************************************************************************
@@ -4475,7 +4503,6 @@ ECPGDeallocate: SQL_DEALLOCATE SQL_PREPARE ident { $$ = cat_str(3, make_str("ECP
ECPGDeclaration: sql_startdeclare
{
fputs("/* exec sql begin declare section */", yyout);
- output_line_number();
}
variable_declarations sql_enddeclare
{
@@ -4488,18 +4515,16 @@ sql_startdeclare : ecpgstart BEGIN_TRANS DECLARE SQL_SECTION ';' {}
sql_enddeclare: ecpgstart END_TRANS DECLARE SQL_SECTION ';' {}
-variable_declarations: /* empty */
- {
- $$ = EMPTY;
- }
- | declaration variable_declarations
- {
- $$ = cat2_str($1, $2);
- }
+variable_declarations: /* empty */ { $$ = EMPTY; }
+ | declarations { $$ = $1; }
+
+declarations: declaration { $$ = $1; }
+ | declarations declaration { $$ = cat2_str($1, $2); }
declaration: storage_clause
{
actual_storage[struct_level] = mm_strdup($1);
+ actual_startline[struct_level] = hashline_number();
}
type
{
@@ -4509,7 +4534,7 @@ declaration: storage_clause
}
variable_list ';'
{
- $$ = cat_str(4, $1, $3.type_str, $5, make_str(";\n"));
+ $$ = cat_str(5, actual_startline[struct_level], $1, $3.type_str, $5, make_str(";\n"));
}
storage_clause : S_EXTERN { $$ = make_str("extern"); }
@@ -5416,7 +5441,7 @@ c_stuff: c_anything { $$ = $1; }
}
c_list: c_term { $$ = $1; }
- | c_term ',' c_list { $$ = cat_str(3, $1, make_str(","), $3); }
+ | c_list ',' c_term { $$ = cat_str(3, $1, make_str(","), $3); }
c_term: c_stuff { $$ = $1; }
| '{' c_list '}' { $$ = cat_str(3, make_str("{"), $2, make_str("}")); }
diff --git a/src/interfaces/ecpg/preproc/type.h b/src/interfaces/ecpg/preproc/type.h
index 7cdc476e83d..1af1e63344f 100644
--- a/src/interfaces/ecpg/preproc/type.h
+++ b/src/interfaces/ecpg/preproc/type.h
@@ -119,6 +119,7 @@ struct _defines
{
char *old;
char *new;
+ int pertinent;
struct _defines *next;
};