Re: ECPG cleanup and fix for clang compile-time problem - Mailing list pgsql-hackers
From | Tom Lane |
---|---|
Subject | Re: ECPG cleanup and fix for clang compile-time problem |
Date | |
Msg-id | 228286.1720195015@sss.pgh.pa.us Whole thread Raw |
In response to | Re: ECPG cleanup and fix for clang compile-time problem (Tom Lane <tgl@sss.pgh.pa.us>) |
Responses |
Re: ECPG cleanup and fix for clang compile-time problem
|
List | pgsql-hackers |
The cfbot noticed that this patchset had a conflict with d35cd0619, so here's a rebase. It's just a rebase of v1, no other changes. regards, tom lane From b6bdf1b2029a2edac1cc7e101e4a48e3f95662fd Mon Sep 17 00:00:00 2001 From: Tom Lane <tgl@sss.pgh.pa.us> Date: Fri, 5 Jul 2024 11:31:26 -0400 Subject: [PATCH v2 1/6] Clean up indentation and whitespace inconsistencies in ecpg. ecpg's lexer and parser files aren't normally processed by pgindent, and unsurprisingly there's a lot of code in there that doesn't really match project style. I spent some time running pgindent over the fragments of these files that are C code, and this is the result. This is in the same spirit as commit 30ed71e42, though apparently Peter used a different method for that one, since it didn't find these problems. --- src/interfaces/ecpg/preproc/ecpg.addons | 231 +- src/interfaces/ecpg/preproc/ecpg.header | 180 +- src/interfaces/ecpg/preproc/ecpg.trailer | 3566 ++++++++++++---------- src/interfaces/ecpg/preproc/pgc.l | 642 ++-- 4 files changed, 2608 insertions(+), 2011 deletions(-) diff --git a/src/interfaces/ecpg/preproc/ecpg.addons b/src/interfaces/ecpg/preproc/ecpg.addons index e94da2a3f8..e7dce4e404 100644 --- a/src/interfaces/ecpg/preproc/ecpg.addons +++ b/src/interfaces/ecpg/preproc/ecpg.addons @@ -3,7 +3,7 @@ ECPG: stmtClosePortalStmt block { if (INFORMIX_MODE) { - if (pg_strcasecmp($1+strlen("close "), "database") == 0) + if (pg_strcasecmp($1 + strlen("close "), "database") == 0) { if (connection) mmerror(PARSE_ERROR, ET_ERROR, "AT option not allowed in CLOSE DATABASE statement"); @@ -22,7 +22,9 @@ ECPG: stmtDeallocateStmt block output_deallocate_prepare_statement($1); } ECPG: stmtDeclareCursorStmt block - { output_simple_statement($1, (strncmp($1, "ECPGset_var", strlen("ECPGset_var")) == 0) ? 4 : 0); } + { + output_simple_statement($1, (strncmp($1, "ECPGset_var", strlen("ECPGset_var")) == 0) ? 4 : 0); + } ECPG: stmtDiscardStmt block ECPG: stmtFetchStmt block { output_statement($1, 1, ECPGst_normal); } @@ -44,10 +46,13 @@ ECPG: stmtExecuteStmt block else { /* case of ecpg_ident or CSTRING */ - char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); - char *str = mm_strdup($1.name + 1); + char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); + char *str = mm_strdup($1.name + 1); - /* It must be cut off double quotation because new_variable() double-quotes. */ + /* + * It must be cut off double quotation because new_variable() + * double-quotes. + */ str[strlen(str) - 1] = '\0'; sprintf(length, "%zu", strlen(str)); add_variable_to_tail(&argsinsert, new_variable(str, ECPGmake_simple_type(ECPGt_const, length, 0), 0), &no_indicator); @@ -62,7 +67,8 @@ ECPG: stmtPrepareStmt block output_prepare_statement($1.name, $1.stmt); else if (strlen($1.type) == 0) { - char *stmt = cat_str(3, mm_strdup("\""), $1.stmt, mm_strdup("\"")); + char *stmt = cat_str(3, mm_strdup("\""), $1.stmt, mm_strdup("\"")); + output_prepare_statement($1.name, stmt); } else @@ -72,10 +78,13 @@ ECPG: stmtPrepareStmt block add_variable_to_tail(&argsinsert, find_variable($1.name), &no_indicator); else { - char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); - char *str = mm_strdup($1.name + 1); + char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); + char *str = mm_strdup($1.name + 1); - /* It must be cut off double quotation because new_variable() double-quotes. */ + /* + * It must be cut off double quotation because new_variable() + * double-quotes. + */ str[strlen(str) - 1] = '\0'; sprintf(length, "%zu", strlen(str)); add_variable_to_tail(&argsinsert, new_variable(str, ECPGmake_simple_type(ECPGt_const, length, 0), 0), &no_indicator); @@ -98,7 +107,7 @@ ECPG: toplevel_stmtTransactionStmtLegacy block ECPG: stmtViewStmt rule | ECPGAllocateDescr { - fprintf(base_yyout,"ECPGallocate_desc(__LINE__, %s);",$1); + fprintf(base_yyout, "ECPGallocate_desc(__LINE__, %s);", $1); whenever_action(0); free($1); } @@ -118,11 +127,11 @@ ECPG: stmtViewStmt rule } | ECPGCursorStmt { - output_simple_statement($1, (strncmp($1, "ECPGset_var", strlen("ECPGset_var")) == 0) ? 4 : 0); + output_simple_statement($1, (strncmp($1, "ECPGset_var", strlen("ECPGset_var")) == 0) ? 4 : 0); } | ECPGDeallocateDescr { - fprintf(base_yyout,"ECPGdeallocate_desc(__LINE__, %s);",$1); + fprintf(base_yyout, "ECPGdeallocate_desc(__LINE__, %s);", $1); whenever_action(0); free($1); } @@ -152,7 +161,10 @@ ECPG: stmtViewStmt rule whenever_action(2); free($1); } - | ECPGExecuteImmediateStmt { output_statement($1, 0, ECPGst_exec_immediate); } + | ECPGExecuteImmediateStmt + { + output_statement($1, 0, ECPGst_exec_immediate); + } | ECPGFree { const char *con = connection ? connection : "NULL"; @@ -160,7 +172,7 @@ ECPG: stmtViewStmt rule if (strcmp($1, "all") == 0) fprintf(base_yyout, "{ ECPGdeallocate_all(__LINE__, %d, %s);", compat, con); else if ($1[0] == ':') - fprintf(base_yyout, "{ ECPGdeallocate(__LINE__, %d, %s, %s);", compat, con, $1+1); + fprintf(base_yyout, "{ ECPGdeallocate(__LINE__, %d, %s, %s);", compat, con, $1 + 1); else fprintf(base_yyout, "{ ECPGdeallocate(__LINE__, %d, %s, \"%s\");", compat, con, $1); @@ -244,13 +256,14 @@ ECPG: stmtViewStmt rule } ECPG: where_or_current_clauseWHERECURRENT_POFcursor_name block { - char *cursor_marker = $4[0] == ':' ? mm_strdup("$0") : $4; - $$ = cat_str(2,mm_strdup("where current of"), cursor_marker); + char *cursor_marker = $4[0] == ':' ? mm_strdup("$0") : $4; + + $$ = cat_str(2, mm_strdup("where current of"), cursor_marker); } ECPG: CopyStmtCOPYopt_binaryqualified_nameopt_column_listcopy_fromopt_programcopy_file_namecopy_delimiteropt_withcopy_optionswhere_clause addon - if (strcmp($6, "from") == 0 && - (strcmp($7, "stdin") == 0 || strcmp($7, "stdout") == 0)) - mmerror(PARSE_ERROR, ET_WARNING, "COPY FROM STDIN is not implemented"); + if (strcmp($6, "from") == 0 && + (strcmp($7, "stdin") == 0 || strcmp($7, "stdout") == 0)) + mmerror(PARSE_ERROR, ET_WARNING, "COPY FROM STDIN is not implemented"); ECPG: var_valueNumericOnly addon if ($1[0] == '$') { @@ -259,9 +272,9 @@ ECPG: var_valueNumericOnly addon } ECPG: fetch_argscursor_name addon struct cursor *ptr = add_additional_variables($1, false); - if (ptr -> connection) - connection = mm_strdup(ptr -> connection); + if (ptr->connection) + connection = mm_strdup(ptr->connection); if ($1[0] == ':') { free($1); @@ -269,9 +282,9 @@ ECPG: fetch_argscursor_name addon } ECPG: fetch_argsfrom_incursor_name addon struct cursor *ptr = add_additional_variables($2, false); - if (ptr -> connection) - connection = mm_strdup(ptr -> connection); + if (ptr->connection) + connection = mm_strdup(ptr->connection); if ($2[0] == ':') { free($2); @@ -283,9 +296,9 @@ ECPG: fetch_argsFIRST_Popt_from_incursor_name addon ECPG: fetch_argsLAST_Popt_from_incursor_name addon ECPG: fetch_argsALLopt_from_incursor_name addon struct cursor *ptr = add_additional_variables($3, false); - if (ptr -> connection) - connection = mm_strdup(ptr -> connection); + if (ptr->connection) + connection = mm_strdup(ptr->connection); if ($3[0] == ':') { free($3); @@ -293,9 +306,9 @@ ECPG: fetch_argsALLopt_from_incursor_name addon } ECPG: fetch_argsSignedIconstopt_from_incursor_name addon struct cursor *ptr = add_additional_variables($3, false); - if (ptr -> connection) - connection = mm_strdup(ptr -> connection); + if (ptr->connection) + connection = mm_strdup(ptr->connection); if ($3[0] == ':') { free($3); @@ -309,9 +322,9 @@ ECPG: fetch_argsSignedIconstopt_from_incursor_name addon ECPG: fetch_argsFORWARDALLopt_from_incursor_name addon ECPG: fetch_argsBACKWARDALLopt_from_incursor_name addon struct cursor *ptr = add_additional_variables($4, false); - if (ptr -> connection) - connection = mm_strdup(ptr -> connection); + if (ptr->connection) + connection = mm_strdup(ptr->connection); if ($4[0] == ':') { free($4); @@ -322,9 +335,9 @@ ECPG: fetch_argsRELATIVE_PSignedIconstopt_from_incursor_name addon ECPG: fetch_argsFORWARDSignedIconstopt_from_incursor_name addon ECPG: fetch_argsBACKWARDSignedIconstopt_from_incursor_name addon struct cursor *ptr = add_additional_variables($4, false); - if (ptr -> connection) - connection = mm_strdup(ptr -> connection); + if (ptr->connection) + connection = mm_strdup(ptr->connection); if ($4[0] == ':') { free($4); @@ -337,13 +350,14 @@ ECPG: fetch_argsBACKWARDSignedIconstopt_from_incursor_name addon } ECPG: cursor_namename rule | char_civar - { - char *curname = mm_alloc(strlen($1) + 2); - sprintf(curname, ":%s", $1); - free($1); - $1 = curname; - $$ = $1; - } + { + char *curname = mm_alloc(strlen($1) + 2); + + sprintf(curname, ":%s", $1); + free($1); + $1 = curname; + $$ = $1; + } ECPG: ExplainableStmtExecuteStmt block { $$ = $1.name; @@ -367,28 +381,31 @@ ECPG: ExecuteStmtEXECUTEprepared_nameexecute_param_clauseexecute_rest block } ECPG: ExecuteStmtCREATEOptTempTABLEcreate_as_targetASEXECUTEprepared_nameexecute_param_clauseopt_with_dataexecute_rest block { - $$.name = cat_str(8,mm_strdup("create"),$2,mm_strdup("table"),$4,mm_strdup("as execute"),$7,$8,$9); + $$.name = cat_str(8, mm_strdup("create"), $2, mm_strdup("table"), $4, mm_strdup("as execute"), $7, $8, $9); } ECPG: ExecuteStmtCREATEOptTempTABLEIF_PNOTEXISTScreate_as_targetASEXECUTEprepared_nameexecute_param_clauseopt_with_dataexecute_rest block { - $$.name = cat_str(8,mm_strdup("create"),$2,mm_strdup("table if not exists"),$7,mm_strdup("as execute"),$10,$11,$12); + $$.name = cat_str(8, mm_strdup("create"), $2, mm_strdup("table if not exists"), $7, mm_strdup("as execute"), $10,$11, $12); } ECPG: DeclareCursorStmtDECLAREcursor_namecursor_optionsCURSORopt_holdFORSelectStmt block { - struct cursor *ptr, *this; - char *cursor_marker = $2[0] == ':' ? mm_strdup("$0") : mm_strdup($2); - char *comment, *c1, *c2; - int (* strcmp_fn)(const char *, const char *) = (($2[0] == ':' || $2[0] == '"') ? strcmp : pg_strcasecmp); + struct cursor *ptr, + *this; + char *cursor_marker = $2[0] == ':' ? mm_strdup("$0") : mm_strdup($2); + char *comment, + *c1, + *c2; + int (*strcmp_fn) (const char *, const char *) = (($2[0] == ':' || $2[0] == '"') ? strcmp : pg_strcasecmp); - if (INFORMIX_MODE && pg_strcasecmp($2, "database") == 0) - mmfatal(PARSE_ERROR, "\"database\" cannot be used as cursor name in INFORMIX mode"); + if (INFORMIX_MODE && pg_strcasecmp($2, "database") == 0) + mmfatal(PARSE_ERROR, "\"database\" cannot be used as cursor name in INFORMIX mode"); for (ptr = cur; ptr != NULL; ptr = ptr->next) { if (strcmp_fn($2, ptr->name) == 0) { if ($2[0] == ':') - mmerror(PARSE_ERROR, ET_ERROR, "using variable \"%s\" in different declare statements is not supported",$2+1); + mmerror(PARSE_ERROR, ET_ERROR, "using variable \"%s\" in different declare statements is not supported",$2 + 1); else mmerror(PARSE_ERROR, ET_ERROR, "cursor \"%s\" is already defined", $2); } @@ -401,7 +418,7 @@ ECPG: DeclareCursorStmtDECLAREcursor_namecursor_optionsCURSORopt_holdFORSelectSt this->function = (current_function ? mm_strdup(current_function) : NULL); this->connection = connection ? mm_strdup(connection) : NULL; this->opened = false; - this->command = cat_str(7, mm_strdup("declare"), cursor_marker, $3, mm_strdup("cursor"), $5, mm_strdup("for"),$7); + this->command = cat_str(7, mm_strdup("declare"), cursor_marker, $3, mm_strdup("cursor"), $5, mm_strdup("for"), $7); this->argsinsert = argsinsert; this->argsinsert_oos = NULL; this->argsresult = argsresult; @@ -422,15 +439,15 @@ ECPG: DeclareCursorStmtDECLAREcursor_namecursor_optionsCURSORopt_holdFORSelectSt } ECPG: ClosePortalStmtCLOSEcursor_name block { - char *cursor_marker = $2[0] == ':' ? mm_strdup("$0") : $2; + char *cursor_marker = $2[0] == ':' ? mm_strdup("$0") : $2; struct cursor *ptr = NULL; - for (ptr = cur; ptr != NULL; ptr = ptr -> next) + + for (ptr = cur; ptr != NULL; ptr = ptr->next) { - if (strcmp($2, ptr -> name) == 0) + if (strcmp($2, ptr->name) == 0) { - if (ptr -> connection) - connection = mm_strdup(ptr -> connection); - + if (ptr->connection) + connection = mm_strdup(ptr->connection); break; } } @@ -444,15 +461,22 @@ ECPG: opt_hold block $$ = EMPTY; } ECPG: into_clauseINTOOptTempTableName block - { - FoundInto = 1; - $$= cat2_str(mm_strdup("into"), $2); - } - | ecpg_into { $$ = EMPTY; } + { + FoundInto = 1; + $$ = cat2_str(mm_strdup("into"), $2); + } + | ecpg_into + { + $$ = EMPTY; + } ECPG: TypenameSimpleTypenameopt_array_bounds block - { $$ = cat2_str($1, $2.str); } + { + $$ = cat2_str($1, $2.str); + } ECPG: TypenameSETOFSimpleTypenameopt_array_bounds block - { $$ = cat_str(3, mm_strdup("setof"), $2, $3.str); } + { + $$ = cat_str(3, mm_strdup("setof"), $2, $3.str); + } ECPG: opt_array_boundsopt_array_bounds'['']' block { $$.index1 = $1.index1; @@ -477,22 +501,24 @@ ECPG: opt_array_bounds { $$.index1 = mm_strdup("-1"); $$.index2 = mm_strdup("-1"); - $$.str= EMPTY; + $$.str = EMPTY; } ECPG: IconstICONST block - { $$ = make_name(); } + { + $$ = make_name(); + } ECPG: AexprConstNULL_P rule - | civar { $$ = $1; } - | civarind { $$ = $1; } + | civar { $$ = $1; } + | civarind { $$ = $1; } ECPG: ColIdcol_name_keyword rule - | ECPGKeywords { $$ = $1; } - | ECPGCKeywords { $$ = $1; } - | CHAR_P { $$ = mm_strdup("char"); } - | VALUES { $$ = mm_strdup("values"); } + | ECPGKeywords { $$ = $1; } + | ECPGCKeywords { $$ = $1; } + | CHAR_P { $$ = mm_strdup("char"); } + | VALUES { $$ = mm_strdup("values"); } ECPG: type_function_nametype_func_name_keyword rule - | ECPGKeywords { $$ = $1; } - | ECPGTypeName { $$ = $1; } - | ECPGCKeywords { $$ = $1; } + | ECPGKeywords { $$ = $1; } + | ECPGTypeName { $$ = $1; } + | ECPGCKeywords { $$ = $1; } ECPG: VariableShowStmtSHOWALL block { mmerror(PARSE_ERROR, ET_ERROR, "SHOW ALL is not implemented"); @@ -505,73 +531,81 @@ ECPG: FetchStmtMOVEfetch_args rule } | FETCH FORWARD cursor_name opt_ecpg_fetch_into { - char *cursor_marker = $3[0] == ':' ? mm_strdup("$0") : $3; + char *cursor_marker = $3[0] == ':' ? mm_strdup("$0") : $3; struct cursor *ptr = add_additional_variables($3, false); - if (ptr -> connection) - connection = mm_strdup(ptr -> connection); + + if (ptr->connection) + connection = mm_strdup(ptr->connection); $$ = cat_str(2, mm_strdup("fetch forward"), cursor_marker); } | FETCH FORWARD from_in cursor_name opt_ecpg_fetch_into { - char *cursor_marker = $4[0] == ':' ? mm_strdup("$0") : $4; + char *cursor_marker = $4[0] == ':' ? mm_strdup("$0") : $4; struct cursor *ptr = add_additional_variables($4, false); - if (ptr -> connection) - connection = mm_strdup(ptr -> connection); + + if (ptr->connection) + connection = mm_strdup(ptr->connection); $$ = cat_str(2, mm_strdup("fetch forward from"), cursor_marker); } | FETCH BACKWARD cursor_name opt_ecpg_fetch_into { - char *cursor_marker = $3[0] == ':' ? mm_strdup("$0") : $3; + char *cursor_marker = $3[0] == ':' ? mm_strdup("$0") : $3; struct cursor *ptr = add_additional_variables($3, false); - if (ptr -> connection) - connection = mm_strdup(ptr -> connection); + + if (ptr->connection) + connection = mm_strdup(ptr->connection); $$ = cat_str(2, mm_strdup("fetch backward"), cursor_marker); } | FETCH BACKWARD from_in cursor_name opt_ecpg_fetch_into { - char *cursor_marker = $4[0] == ':' ? mm_strdup("$0") : $4; + char *cursor_marker = $4[0] == ':' ? mm_strdup("$0") : $4; struct cursor *ptr = add_additional_variables($4, false); - if (ptr -> connection) - connection = mm_strdup(ptr -> connection); + + if (ptr->connection) + connection = mm_strdup(ptr->connection); $$ = cat_str(2, mm_strdup("fetch backward from"), cursor_marker); } | MOVE FORWARD cursor_name { - char *cursor_marker = $3[0] == ':' ? mm_strdup("$0") : $3; + char *cursor_marker = $3[0] == ':' ? mm_strdup("$0") : $3; struct cursor *ptr = add_additional_variables($3, false); - if (ptr -> connection) - connection = mm_strdup(ptr -> connection); + + if (ptr->connection) + connection = mm_strdup(ptr->connection); $$ = cat_str(2, mm_strdup("move forward"), cursor_marker); } | MOVE FORWARD from_in cursor_name { - char *cursor_marker = $4[0] == ':' ? mm_strdup("$0") : $4; + char *cursor_marker = $4[0] == ':' ? mm_strdup("$0") : $4; struct cursor *ptr = add_additional_variables($4, false); - if (ptr -> connection) - connection = mm_strdup(ptr -> connection); + + if (ptr->connection) + connection = mm_strdup(ptr->connection); $$ = cat_str(2, mm_strdup("move forward from"), cursor_marker); } | MOVE BACKWARD cursor_name { - char *cursor_marker = $3[0] == ':' ? mm_strdup("$0") : $3; + char *cursor_marker = $3[0] == ':' ? mm_strdup("$0") : $3; struct cursor *ptr = add_additional_variables($3, false); - if (ptr -> connection) - connection = mm_strdup(ptr -> connection); + + if (ptr->connection) + connection = mm_strdup(ptr->connection); $$ = cat_str(2, mm_strdup("move backward"), cursor_marker); } | MOVE BACKWARD from_in cursor_name { - char *cursor_marker = $4[0] == ':' ? mm_strdup("$0") : $4; + char *cursor_marker = $4[0] == ':' ? mm_strdup("$0") : $4; struct cursor *ptr = add_additional_variables($4, false); - if (ptr -> connection) - connection = mm_strdup(ptr -> connection); + + if (ptr->connection) + connection = mm_strdup(ptr->connection); $$ = cat_str(2, mm_strdup("move backward from"), cursor_marker); } @@ -581,4 +615,7 @@ ECPG: limit_clauseLIMITselect_limit_value','select_offset_value block $$ = cat_str(4, mm_strdup("limit"), $2, mm_strdup(","), $4); } ECPG: SignedIconstIconst rule - | civar { $$ = $1; } + | civar + { + $$ = $1; + } diff --git a/src/interfaces/ecpg/preproc/ecpg.header b/src/interfaces/ecpg/preproc/ecpg.header index 5950289425..3ed39b5c77 100644 --- a/src/interfaces/ecpg/preproc/ecpg.header +++ b/src/interfaces/ecpg/preproc/ecpg.header @@ -32,24 +32,25 @@ /* * Variables containing simple states. */ -int struct_level = 0; -int braces_open; /* brace level counter */ -char *current_function; -int ecpg_internal_var = 0; -char *connection = NULL; -char *input_filename = NULL; +int struct_level = 0; +int braces_open; /* brace level counter */ +char *current_function; +int ecpg_internal_var = 0; +char *connection = NULL; +char *input_filename = NULL; static int FoundInto = 0; static int initializer = 0; static int pacounter = 1; -static char pacounter_buffer[sizeof(int) * CHAR_BIT * 10 / 3]; /* a rough guess at the size we need */ +static char pacounter_buffer[sizeof(int) * CHAR_BIT * 10 / 3]; /* a rough guess at the + * size we need */ static struct this_type actual_type[STRUCT_DEPTH]; static char *actual_startline[STRUCT_DEPTH]; static int varchar_counter = 1; static int bytea_counter = 1; /* temporarily store struct members while creating the data structure */ -struct ECPGstruct_member *struct_member_list[STRUCT_DEPTH] = { NULL }; +struct ECPGstruct_member *struct_member_list[STRUCT_DEPTH] = {NULL}; /* also store struct type so we can do a sizeof() later */ static char *ECPGstruct_sizeof = NULL; @@ -77,7 +78,7 @@ vmmerror(int error_code, enum errortype type, const char *error, va_list ap) fprintf(stderr, "%s:%d: ", input_filename, base_yylineno); - switch(type) + switch (type) { case ET_WARNING: fprintf(stderr, _("WARNING: ")); @@ -91,7 +92,7 @@ vmmerror(int error_code, enum errortype type, const char *error, va_list ap) fprintf(stderr, "\n"); - switch(type) + switch (type) { case ET_WARNING: break; @@ -102,7 +103,7 @@ vmmerror(int error_code, enum errortype type, const char *error, va_list ap) } void -mmerror(int error_code, enum errortype type, const char *error, ...) +mmerror(int error_code, enum errortype type, const char *error,...) { va_list ap; @@ -112,7 +113,7 @@ mmerror(int error_code, enum errortype type, const char *error, ...) } void -mmfatal(int error_code, const char *error, ...) +mmfatal(int error_code, const char *error,...) { va_list ap; @@ -137,7 +138,7 @@ mmfatal(int error_code, const char *error, ...) static char * cat2_str(char *str1, char *str2) { - char * res_str = (char *)mm_alloc(strlen(str1) + strlen(str2) + 2); + char *res_str = (char *) mm_alloc(strlen(str1) + strlen(str2) + 2); strcpy(res_str, str1); if (strlen(str1) != 0 && strlen(str2) != 0) @@ -149,11 +150,11 @@ cat2_str(char *str1, char *str2) } static char * -cat_str(int count, ...) +cat_str(int count,...) { va_list args; int i; - char *res_str; + char *res_str; va_start(args, count); @@ -171,7 +172,7 @@ cat_str(int count, ...) static char * make2_str(char *str1, char *str2) { - char * res_str = (char *)mm_alloc(strlen(str1) + strlen(str2) + 1); + char *res_str = (char *) mm_alloc(strlen(str1) + strlen(str2) + 1); strcpy(res_str, str1); strcat(res_str, str2); @@ -183,7 +184,7 @@ make2_str(char *str1, char *str2) static char * make3_str(char *str1, char *str2, char *str3) { - char * res_str = (char *)mm_alloc(strlen(str1) + strlen(str2) +strlen(str3) + 1); + char *res_str = (char *) mm_alloc(strlen(str1) + strlen(str2) + strlen(str3) + 1); strcpy(res_str, str1); strcat(res_str, str2); @@ -205,13 +206,18 @@ static char * create_questionmarks(char *name, bool array) { struct variable *p = find_variable(name); - int count; - char *result = EMPTY; + int count; + char *result = EMPTY; - /* In case we have a struct, we have to print as many "?" as there are attributes in the struct + /* + * In case we have a struct, we have to print as many "?" as there are + * attributes in the struct + * * An array is only allowed together with an element argument - * This is essentially only used for inserts, but using a struct as input parameter is an error anywhere else - * so we don't have to worry here. */ + * + * This is essentially only used for inserts, but using a struct as input + * parameter is an error anywhere else so we don't have to worry here. + */ if (p->type->type == ECPGt_struct || (array && p->type->type == ECPGt_array && p->type->u.element->type == ECPGt_struct)) { @@ -222,12 +228,12 @@ create_questionmarks(char *name, bool array) else m = p->type->u.element->u.members; - for (count = 0; m != NULL; m=m->next, count++); + for (count = 0; m != NULL; m = m->next, count++); } else count = 1; - for (; count > 0; count --) + for (; count > 0; count--) { sprintf(pacounter_buffer, "$%d", pacounter++); result = cat_str(3, result, mm_strdup(pacounter_buffer), mm_strdup(" , ")); @@ -235,42 +241,45 @@ create_questionmarks(char *name, bool array) /* removed the trailing " ," */ - result[strlen(result)-3] = '\0'; + result[strlen(result) - 3] = '\0'; return result; } static char * adjust_outofscope_cursor_vars(struct cursor *cur) { - /* Informix accepts DECLARE with variables that are out of scope when OPEN is called. - * For instance you can DECLARE a cursor in one function, and OPEN/FETCH/CLOSE - * it in another functions. This is very useful for e.g. event-driver programming, - * but may also lead to dangerous programming. The limitation when this is allowed - * and doesn't cause problems have to be documented, like the allocated variables - * must not be realloc()'ed. + /* + * Informix accepts DECLARE with variables that are out of scope when OPEN + * is called. For instance you can DECLARE a cursor in one function, and + * OPEN/FETCH/CLOSE it in another functions. This is very useful for e.g. + * event-driver programming, but may also lead to dangerous programming. + * The limitation when this is allowed and doesn't cause problems have to + * be documented, like the allocated variables must not be realloc()'ed. * - * We have to change the variables to our own struct and just store the pointer - * instead of the variable. Do it only for local variables, not for globals. + * We have to change the variables to our own struct and just store the + * pointer instead of the variable. Do it only for local variables, not + * for globals. */ - char *result = EMPTY; - int insert; + char *result = EMPTY; + int insert; for (insert = 1; insert >= 0; insert--) { struct arguments *list; struct arguments *ptr; struct arguments *newlist = NULL; - struct variable *newvar, *newind; + struct variable *newvar, + *newind; list = (insert ? cur->argsinsert : cur->argsresult); for (ptr = list; ptr != NULL; ptr = ptr->next) { - char var_text[20]; - char *original_var; - bool skip_set_var = false; - bool var_ptr = false; + char var_text[20]; + char *original_var; + bool skip_set_var = false; + bool var_ptr = false; /* change variable name to "ECPGget_var(<counter>)" */ original_var = ptr->variable->name; @@ -345,10 +354,10 @@ adjust_outofscope_cursor_vars(struct cursor *cur) || ptr->variable->type->u.element->type == ECPGt_union) { newvar = new_variable(cat_str(5, mm_strdup("(*("), - mm_strdup(ptr->variable->type->u.element->type_name), - mm_strdup(" *)(ECPGget_var("), - mm_strdup(var_text), - mm_strdup(")")), + mm_strdup(ptr->variable->type->u.element->type_name), + mm_strdup(" *)(ECPGget_var("), + mm_strdup(var_text), + mm_strdup(")")), ECPGmake_struct_type(ptr->variable->type->u.element->u.members, ptr->variable->type->u.element->type, ptr->variable->type->u.element->type_name, @@ -382,7 +391,10 @@ adjust_outofscope_cursor_vars(struct cursor *cur) var_ptr = true; } - /* create call to "ECPGset_var(<counter>, <connection>, <pointer>. <line number>)" */ + /* + * create call to "ECPGset_var(<counter>, <connection>, <pointer>. + * <line number>)" + */ if (!skip_set_var) { sprintf(var_text, "%d, %s", ecpg_internal_var++, var_ptr ? "&(" : "("); @@ -391,7 +403,10 @@ adjust_outofscope_cursor_vars(struct cursor *cur) mm_strdup("), __LINE__);\n")); } - /* now the indicator if there is one and it's not a global variable */ + /* + * now the indicator if there is one and it's not a global + * variable + */ if ((ptr->indicator->type->type == ECPGt_NO_INDICATOR) || (ptr->indicator->brace_level == 0)) { newind = ptr->indicator; @@ -407,10 +422,10 @@ adjust_outofscope_cursor_vars(struct cursor *cur) || ptr->indicator->type->type == ECPGt_union) { newind = new_variable(cat_str(5, mm_strdup("(*("), - mm_strdup(ptr->indicator->type->type_name), - mm_strdup(" *)(ECPGget_var("), - mm_strdup(var_text), - mm_strdup(")")), + mm_strdup(ptr->indicator->type->type_name), + mm_strdup(" *)(ECPGget_var("), + mm_strdup(var_text), + mm_strdup(")")), ECPGmake_struct_type(ptr->indicator->type->u.members, ptr->indicator->type->type, ptr->indicator->type->type_name, @@ -424,10 +439,10 @@ adjust_outofscope_cursor_vars(struct cursor *cur) || ptr->indicator->type->u.element->type == ECPGt_union) { newind = new_variable(cat_str(5, mm_strdup("(*("), - mm_strdup(ptr->indicator->type->u.element->type_name), - mm_strdup(" *)(ECPGget_var("), - mm_strdup(var_text), - mm_strdup(")")), + mm_strdup(ptr->indicator->type->u.element->type_name), + mm_strdup(" *)(ECPGget_var("), + mm_strdup(var_text), + mm_strdup(")")), ECPGmake_struct_type(ptr->indicator->type->u.element->u.members, ptr->indicator->type->u.element->type, ptr->indicator->type->u.element->type_name, @@ -471,7 +486,10 @@ adjust_outofscope_cursor_vars(struct cursor *cur) var_ptr = true; } - /* create call to "ECPGset_var(<counter>, <pointer>. <line number>)" */ + /* + * create call to "ECPGset_var(<counter>, <pointer>. <line + * number>)" + */ sprintf(var_text, "%d, %s", ecpg_internal_var++, var_ptr ? "&(" : "("); result = cat_str(5, result, mm_strdup("ECPGset_var("), mm_strdup(var_text), mm_strdup(original_var), @@ -500,9 +518,9 @@ add_additional_variables(char *name, bool insert) { struct cursor *ptr; struct arguments *p; - int (* strcmp_fn)(const char *, const char *) = ((name[0] == ':' || name[0] == '"') ? strcmp : pg_strcasecmp); + int (*strcmp_fn) (const char *, const char *) = ((name[0] == ':' || name[0] == '"') ? strcmp : pg_strcasecmp); - for (ptr = cur; ptr != NULL; ptr=ptr->next) + for (ptr = cur; ptr != NULL; ptr = ptr->next) { if (strcmp_fn(ptr->name, name) == 0) break; @@ -516,8 +534,12 @@ add_additional_variables(char *name, bool insert) if (insert) { - /* add all those input variables that were given earlier - * note that we have to append here but have to keep the existing order */ + /* + * add all those input variables that were given earlier + * + * note that we have to append here but have to keep the existing + * order + */ for (p = (SAMEFUNC(ptr) ? ptr->argsinsert : ptr->argsinsert_oos); p; p = p->next) add_variable_to_tail(&argsinsert, p->variable, p->indicator); } @@ -534,7 +556,8 @@ add_typedef(char *name, char *dimension, char *length, enum ECPGttype type_enum, char *type_dimension, char *type_index, int initializer, int array) { /* add entry to list */ - struct typedefs *ptr, *this; + struct typedefs *ptr, + *this; if ((type_enum == ECPGt_struct || type_enum == ECPGt_union) && @@ -565,7 +588,7 @@ add_typedef(char *name, char *dimension, char *length, enum ECPGttype type_enum, this->type->type_index = length; /* length of string */ this->type->type_sizeof = ECPGstruct_sizeof; this->struct_member_list = (type_enum == ECPGt_struct || type_enum == ECPGt_union) ? - ECPGstruct_member_dup(struct_member_list[struct_level]) : NULL; + ECPGstruct_member_dup(struct_member_list[struct_level]) : NULL; if (type_enum != ECPGt_varchar && type_enum != ECPGt_bytea && @@ -588,15 +611,16 @@ static bool check_declared_list(const char *name) { struct declared_list *ptr = NULL; - for (ptr = g_declared_list; ptr != NULL; ptr = ptr -> next) + + for (ptr = g_declared_list; ptr != NULL; ptr = ptr->next) { if (!ptr->connection) continue; - if (strcmp(name, ptr -> name) == 0) + if (strcmp(name, ptr->name) == 0) { if (connection && strcmp(ptr->connection, connection) != 0) mmerror(PARSE_ERROR, ET_WARNING, "connection %s is overwritten with %s by DECLARE statement %s", connection,ptr->connection, name); - connection = mm_strdup(ptr -> connection); + connection = mm_strdup(ptr->connection); return true; } } @@ -609,18 +633,18 @@ check_declared_list(const char *name) %locations %union { - double dval; - char *str; - int ival; - struct when action; - struct index index; - int tagname; - struct this_type type; - enum ECPGttype type_enum; - enum ECPGdtype dtype_enum; - struct fetch_desc descriptor; - struct su_symbol struct_union; - struct prep prep; - struct exec exec; - struct describe describe; + double dval; + char *str; + int ival; + struct when action; + struct index index; + int tagname; + struct this_type type; + enum ECPGttype type_enum; + enum ECPGdtype dtype_enum; + struct fetch_desc descriptor; + struct su_symbol struct_union; + struct prep prep; + struct exec exec; + struct describe describe; } diff --git a/src/interfaces/ecpg/preproc/ecpg.trailer b/src/interfaces/ecpg/preproc/ecpg.trailer index b2aa44f36d..b6233e5e53 100644 --- a/src/interfaces/ecpg/preproc/ecpg.trailer +++ b/src/interfaces/ecpg/preproc/ecpg.trailer @@ -1,465 +1,610 @@ /* src/interfaces/ecpg/preproc/ecpg.trailer */ -statements: /*EMPTY*/ - | statements statement - ; +statements: /* EMPTY */ + | statements statement + ; statement: ecpgstart at toplevel_stmt ';' - { - if (connection) - free(connection); - connection = NULL; - } - | ecpgstart toplevel_stmt ';' - { - if (connection) - free(connection); - connection = NULL; - } - | ecpgstart ECPGVarDeclaration - { - fprintf(base_yyout, "%s", $2); - free($2); - output_line_number(); - } - | ECPGDeclaration - | c_thing { fprintf(base_yyout, "%s", $1); free($1); } - | CPP_LINE { fprintf(base_yyout, "%s", $1); free($1); } - | '{' { braces_open++; fputs("{", base_yyout); } - | '}' + { + if (connection) + free(connection); + connection = NULL; + } + | ecpgstart toplevel_stmt ';' + { + if (connection) + free(connection); + connection = NULL; + } + | ecpgstart ECPGVarDeclaration + { + fprintf(base_yyout, "%s", $2); + free($2); + output_line_number(); + } + | ECPGDeclaration + | c_thing + { + fprintf(base_yyout, "%s", $1); + free($1); + } + | CPP_LINE + { + fprintf(base_yyout, "%s", $1); + free($1); + } + | '{' + { + braces_open++; + fputs("{", base_yyout); + } + | '}' + { + remove_typedefs(braces_open); + remove_variables(braces_open--); + if (braces_open == 0) { - remove_typedefs(braces_open); - remove_variables(braces_open--); - if (braces_open == 0) - { - free(current_function); - current_function = NULL; - } - fputs("}", base_yyout); + free(current_function); + current_function = NULL; } - ; + fputs("}", base_yyout); + } + ; -CreateAsStmt: CREATE OptTemp TABLE create_as_target AS {FoundInto = 0;} SelectStmt opt_with_data - { - if (FoundInto == 1) - mmerror(PARSE_ERROR, ET_ERROR, "CREATE TABLE AS cannot specify INTO"); +CreateAsStmt: CREATE OptTemp TABLE create_as_target AS + { + FoundInto = 0; + } SelectStmt opt_with_data + { + if (FoundInto == 1) + mmerror(PARSE_ERROR, ET_ERROR, "CREATE TABLE AS cannot specify INTO"); - $$ = cat_str(7, mm_strdup("create"), $2, mm_strdup("table"), $4, mm_strdup("as"), $7, $8); - } - | CREATE OptTemp TABLE IF_P NOT EXISTS create_as_target AS {FoundInto = 0;} SelectStmt opt_with_data - { - if (FoundInto == 1) - mmerror(PARSE_ERROR, ET_ERROR, "CREATE TABLE AS cannot specify INTO"); + $$ = cat_str(7, mm_strdup("create"), $2, mm_strdup("table"), $4, mm_strdup("as"), $7, $8); + } + | CREATE OptTemp TABLE IF_P NOT EXISTS create_as_target AS + { + FoundInto = 0; + } SelectStmt opt_with_data + { + if (FoundInto == 1) + mmerror(PARSE_ERROR, ET_ERROR, "CREATE TABLE AS cannot specify INTO"); - $$ = cat_str(7, mm_strdup("create"), $2, mm_strdup("table if not exists"), $7, mm_strdup("as"), $10, $11); - } - ; + $$ = cat_str(7, mm_strdup("create"), $2, mm_strdup("table if not exists"), $7, mm_strdup("as"), $10, $11); + } + ; at: AT connection_object - { - connection = $2; - /* - * Do we have a variable as connection target? Remove the variable - * from the variable list or else it will be used twice. - */ - if (argsinsert != NULL) - argsinsert = NULL; - } - ; + { + connection = $2; + + /* + * Do we have a variable as connection target? Remove the variable + * from the variable list or else it will be used twice. + */ + if (argsinsert != NULL) + argsinsert = NULL; + } + ; /* * the exec sql connect statement: connect to the given database */ ECPGConnect: SQL_CONNECT TO connection_target opt_connection_name opt_user - { $$ = cat_str(5, $3, mm_strdup(","), $5, mm_strdup(","), $4); } - | SQL_CONNECT TO DEFAULT - { $$ = mm_strdup("NULL, NULL, NULL, \"DEFAULT\""); } - /* also allow ORACLE syntax */ - | SQL_CONNECT ora_user - { $$ = cat_str(3, mm_strdup("NULL,"), $2, mm_strdup(", NULL")); } - | DATABASE connection_target - { $$ = cat2_str($2, mm_strdup(", NULL, NULL, NULL")); } - ; + { + $$ = cat_str(5, $3, mm_strdup(","), $5, mm_strdup(","), $4); + } + | SQL_CONNECT TO DEFAULT + { + $$ = mm_strdup("NULL, NULL, NULL, \"DEFAULT\""); + } + /* also allow ORACLE syntax */ + | SQL_CONNECT ora_user + { + $$ = cat_str(3, mm_strdup("NULL,"), $2, mm_strdup(", NULL")); + } + | DATABASE connection_target + { + $$ = cat2_str($2, mm_strdup(", NULL, NULL, NULL")); + } + ; connection_target: opt_database_name opt_server opt_port - { - /* old style: dbname[@server][:port] */ - if (strlen($2) > 0 && *($2) != '@') - mmerror(PARSE_ERROR, ET_ERROR, "expected \"@\", found \"%s\"", $2); + { + /* old style: dbname[@server][:port] */ + if (strlen($2) > 0 && *($2) != '@') + mmerror(PARSE_ERROR, ET_ERROR, "expected \"@\", found \"%s\"", $2); - /* C strings need to be handled differently */ - if ($1[0] == '\"') - $$ = $1; - else - $$ = make3_str(mm_strdup("\""), make3_str($1, $2, $3), mm_strdup("\"")); - } - | db_prefix ':' server opt_port '/' opt_database_name opt_options - { - /* new style: <tcp|unix>:postgresql://server[:port][/dbname] */ - if (strncmp($1, "unix:postgresql", strlen("unix:postgresql")) != 0 && strncmp($1, "tcp:postgresql", strlen("tcp:postgresql"))!= 0) - mmerror(PARSE_ERROR, ET_ERROR, "only protocols \"tcp\" and \"unix\" and database type \"postgresql\" aresupported"); + /* C strings need to be handled differently */ + if ($1[0] == '\"') + $$ = $1; + else + $$ = make3_str(mm_strdup("\""), make3_str($1, $2, $3), mm_strdup("\"")); + } + | db_prefix ':' server opt_port '/' opt_database_name opt_options + { + /* new style: <tcp|unix>:postgresql://server[:port][/dbname] */ + if (strncmp($1, "unix:postgresql", strlen("unix:postgresql")) != 0 && strncmp($1, "tcp:postgresql", strlen("tcp:postgresql"))!= 0) + mmerror(PARSE_ERROR, ET_ERROR, "only protocols \"tcp\" and \"unix\" and database type \"postgresql\" are supported"); - if (strncmp($3, "//", strlen("//")) != 0) - mmerror(PARSE_ERROR, ET_ERROR, "expected \"://\", found \"%s\"", $3); + if (strncmp($3, "//", strlen("//")) != 0) + mmerror(PARSE_ERROR, ET_ERROR, "expected \"://\", found \"%s\"", $3); - if (strncmp($1, "unix", strlen("unix")) == 0 && - strncmp($3 + strlen("//"), "localhost", strlen("localhost")) != 0 && - strncmp($3 + strlen("//"), "127.0.0.1", strlen("127.0.0.1")) != 0) - mmerror(PARSE_ERROR, ET_ERROR, "Unix-domain sockets only work on \"localhost\" but not on \"%s\"", $3 +strlen("//")); + if (strncmp($1, "unix", strlen("unix")) == 0 && + strncmp($3 + strlen("//"), "localhost", strlen("localhost")) != 0 && + strncmp($3 + strlen("//"), "127.0.0.1", strlen("127.0.0.1")) != 0) + mmerror(PARSE_ERROR, ET_ERROR, "Unix-domain sockets only work on \"localhost\" but not on \"%s\"", $3 + strlen("//")); - $$ = make3_str(make3_str(mm_strdup("\""), $1, mm_strdup(":")), $3, make3_str(make3_str($4, mm_strdup("/"), $6),$7, mm_strdup("\""))); - } - | char_variable - { - $$ = $1; - } - | ecpg_sconst - { - /* We can only process double quoted strings not single quotes ones, - * so we change the quotes. - * Note, that the rule for ecpg_sconst adds these single quotes. */ - $1[0] = '\"'; - $1[strlen($1)-1] = '\"'; - $$ = $1; - } - ; + $$ = make3_str(make3_str(mm_strdup("\""), $1, mm_strdup(":")), $3, make3_str(make3_str($4, mm_strdup("/"), $6),$7, mm_strdup("\""))); + } + | char_variable + { + $$ = $1; + } + | ecpg_sconst + { + /* + * We can only process double quoted strings not single quotes ones, + * so we change the quotes. Note, that the rule for ecpg_sconst adds + * these single quotes. + */ + $1[0] = '\"'; + $1[strlen($1) - 1] = '\"'; + $$ = $1; + } + ; -opt_database_name: name { $$ = $1; } - | /*EMPTY*/ { $$ = EMPTY; } - ; +opt_database_name: name + { + $$ = $1; + } + | /* EMPTY */ + { + $$ = EMPTY; + } + ; db_prefix: ecpg_ident cvariable - { - if (strcmp($2, "postgresql") != 0 && strcmp($2, "postgres") != 0) - mmerror(PARSE_ERROR, ET_ERROR, "expected \"postgresql\", found \"%s\"", $2); + { + if (strcmp($2, "postgresql") != 0 && strcmp($2, "postgres") != 0) + mmerror(PARSE_ERROR, ET_ERROR, "expected \"postgresql\", found \"%s\"", $2); - if (strcmp($1, "tcp") != 0 && strcmp($1, "unix") != 0) - mmerror(PARSE_ERROR, ET_ERROR, "invalid connection type: %s", $1); + if (strcmp($1, "tcp") != 0 && strcmp($1, "unix") != 0) + mmerror(PARSE_ERROR, ET_ERROR, "invalid connection type: %s", $1); - $$ = make3_str($1, mm_strdup(":"), $2); - } - ; + $$ = make3_str($1, mm_strdup(":"), $2); + } + ; server: Op server_name - { - if (strcmp($1, "@") != 0 && strcmp($1, "//") != 0) - mmerror(PARSE_ERROR, ET_ERROR, "expected \"@\" or \"://\", found \"%s\"", $1); + { + if (strcmp($1, "@") != 0 && strcmp($1, "//") != 0) + mmerror(PARSE_ERROR, ET_ERROR, "expected \"@\" or \"://\", found \"%s\"", $1); - $$ = make2_str($1, $2); - } - ; + $$ = make2_str($1, $2); + } + ; -opt_server: server { $$ = $1; } - | /*EMPTY*/ { $$ = EMPTY; } - ; +opt_server: server + { + $$ = $1; + } + | /* EMPTY */ + { + $$ = EMPTY; + } + ; -server_name: ColId { $$ = $1; } - | ColId '.' server_name { $$ = make3_str($1, mm_strdup("."), $3); } - | IP { $$ = make_name(); } - ; +server_name: ColId + { + $$ = $1; + } + | ColId '.' server_name + { + $$ = make3_str($1, mm_strdup("."), $3); + } + | IP + { + $$ = make_name(); + } + ; -opt_port: ':' Iconst { $$ = make2_str(mm_strdup(":"), $2); } - | /*EMPTY*/ { $$ = EMPTY; } - ; +opt_port: ':' Iconst + { + $$ = make2_str(mm_strdup(":"), $2); + } + | /* EMPTY */ + { + $$ = EMPTY; + } + ; -opt_connection_name: AS connection_object { $$ = $2; } - | /*EMPTY*/ { $$ = mm_strdup("NULL"); } - ; +opt_connection_name: AS connection_object + { + $$ = $2; + } + | /* EMPTY */ + { + $$ = mm_strdup("NULL"); + } + ; -opt_user: USER ora_user { $$ = $2; } - | /*EMPTY*/ { $$ = mm_strdup("NULL, NULL"); } - ; +opt_user: USER ora_user + { + $$ = $2; + } + | /* EMPTY */ + { + $$ = mm_strdup("NULL, NULL"); + } + ; ora_user: user_name - { $$ = cat2_str($1, mm_strdup(", NULL")); } - | user_name '/' user_name - { $$ = cat_str(3, $1, mm_strdup(","), $3); } - | user_name SQL_IDENTIFIED BY user_name - { $$ = cat_str(3, $1, mm_strdup(","), $4); } - | user_name USING user_name - { $$ = cat_str(3, $1, mm_strdup(","), $3); } - ; + { + $$ = cat2_str($1, mm_strdup(", NULL")); + } + | user_name '/' user_name + { + $$ = cat_str(3, $1, mm_strdup(","), $3); + } + | user_name SQL_IDENTIFIED BY user_name + { + $$ = cat_str(3, $1, mm_strdup(","), $4); + } + | user_name USING user_name + { + $$ = cat_str(3, $1, mm_strdup(","), $3); + } + ; user_name: RoleId - { - if ($1[0] == '\"') - $$ = $1; - else - $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); - } - | ecpg_sconst - { - if ($1[0] == '\"') - $$ = $1; - else - $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); - } - | civar - { - enum ECPGttype type = argsinsert->variable->type->type; + { + if ($1[0] == '\"') + $$ = $1; + else + $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); + } + | ecpg_sconst + { + if ($1[0] == '\"') + $$ = $1; + else + $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); + } + | civar + { + enum ECPGttype type = argsinsert->variable->type->type; - /* if array see what's inside */ - if (type == ECPGt_array) - type = argsinsert->variable->type->u.element->type; + /* if array see what's inside */ + if (type == ECPGt_array) + type = argsinsert->variable->type->u.element->type; - /* handle varchars */ - if (type == ECPGt_varchar) - $$ = make2_str(mm_strdup(argsinsert->variable->name), mm_strdup(".arr")); - else - $$ = mm_strdup(argsinsert->variable->name); - } - ; + /* handle varchars */ + if (type == ECPGt_varchar) + $$ = make2_str(mm_strdup(argsinsert->variable->name), mm_strdup(".arr")); + else + $$ = mm_strdup(argsinsert->variable->name); + } + ; char_variable: cvariable + { + /* check if we have a string variable */ + struct variable *p = find_variable($1); + enum ECPGttype type = p->type->type; + + /* If we have just one character this is not a string */ + if (atol(p->type->size) == 1) + mmerror(PARSE_ERROR, ET_ERROR, "invalid data type"); + else { - /* check if we have a string variable */ - struct variable *p = find_variable($1); - enum ECPGttype type = p->type->type; + /* if array see what's inside */ + if (type == ECPGt_array) + type = p->type->u.element->type; - /* If we have just one character this is not a string */ - if (atol(p->type->size) == 1) - mmerror(PARSE_ERROR, ET_ERROR, "invalid data type"); - else + switch (type) { - /* if array see what's inside */ - if (type == ECPGt_array) - type = p->type->u.element->type; - - switch (type) - { - case ECPGt_char: - case ECPGt_unsigned_char: - case ECPGt_string: - $$ = $1; - break; - case ECPGt_varchar: - $$ = make2_str($1, mm_strdup(".arr")); - break; - default: - mmerror(PARSE_ERROR, ET_ERROR, "invalid data type"); - $$ = $1; - break; - } + case ECPGt_char: + case ECPGt_unsigned_char: + case ECPGt_string: + $$ = $1; + break; + case ECPGt_varchar: + $$ = make2_str($1, mm_strdup(".arr")); + break; + default: + mmerror(PARSE_ERROR, ET_ERROR, "invalid data type"); + $$ = $1; + break; } } - ; + } + ; opt_options: Op connect_options - { - if (strlen($1) == 0) - mmerror(PARSE_ERROR, ET_ERROR, "incomplete statement"); + { + if (strlen($1) == 0) + mmerror(PARSE_ERROR, ET_ERROR, "incomplete statement"); - if (strcmp($1, "?") != 0) - mmerror(PARSE_ERROR, ET_ERROR, "unrecognized token \"%s\"", $1); + if (strcmp($1, "?") != 0) + mmerror(PARSE_ERROR, ET_ERROR, "unrecognized token \"%s\"", $1); - $$ = make2_str(mm_strdup("?"), $2); - } - | /*EMPTY*/ { $$ = EMPTY; } - ; + $$ = make2_str(mm_strdup("?"), $2); + } + | /* EMPTY */ + { + $$ = EMPTY; + } + ; -connect_options: ColId opt_opt_value - { - $$ = make2_str($1, $2); - } - | ColId opt_opt_value Op connect_options - { - if (strlen($3) == 0) - mmerror(PARSE_ERROR, ET_ERROR, "incomplete statement"); +connect_options: ColId opt_opt_value + { + $$ = make2_str($1, $2); + } + | ColId opt_opt_value Op connect_options + { + if (strlen($3) == 0) + mmerror(PARSE_ERROR, ET_ERROR, "incomplete statement"); - if (strcmp($3, "&") != 0) - mmerror(PARSE_ERROR, ET_ERROR, "unrecognized token \"%s\"", $3); + if (strcmp($3, "&") != 0) + mmerror(PARSE_ERROR, ET_ERROR, "unrecognized token \"%s\"", $3); - $$ = cat_str(3, make2_str($1, $2), $3, $4); - } - ; - -opt_opt_value: /*EMPTY*/ - { $$ = EMPTY; } - | '=' Iconst - { $$ = make2_str(mm_strdup("="), $2); } - | '=' ecpg_ident - { $$ = make2_str(mm_strdup("="), $2); } - | '=' civar - { $$ = make2_str(mm_strdup("="), $2); } - ; + $$ = cat_str(3, make2_str($1, $2), $3, $4); + } + ; + +opt_opt_value: /* EMPTY */ + { + $$ = EMPTY; + } + | '=' Iconst + { + $$ = make2_str(mm_strdup("="), $2); + } + | '=' ecpg_ident + { + $$ = make2_str(mm_strdup("="), $2); + } + | '=' civar + { + $$ = make2_str(mm_strdup("="), $2); + } + ; prepared_name: name + { + if ($1[0] == '\"' && $1[strlen($1) - 1] == '\"') /* already quoted? */ + $$ = $1; + else /* not quoted => convert to lowercase */ { - if ($1[0] == '\"' && $1[strlen($1)-1] == '\"') /* already quoted? */ - $$ = $1; - else /* not quoted => convert to lowercase */ - { - size_t i; + size_t i; - for (i = 0; i< strlen($1); i++) - $1[i] = tolower((unsigned char) $1[i]); + for (i = 0; i < strlen($1); i++) + $1[i] = tolower((unsigned char) $1[i]); - $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); - } + $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); } - | char_variable { $$ = $1; } - ; + } + | char_variable + { + $$ = $1; + } + ; /* * Declare Statement */ ECPGDeclareStmt: DECLARE prepared_name STATEMENT + { + struct declared_list *ptr = NULL; + + /* Check whether the declared name has been defined or not */ + for (ptr = g_declared_list; ptr != NULL; ptr = ptr->next) { - struct declared_list *ptr = NULL; - /* Check whether the declared name has been defined or not */ - for (ptr = g_declared_list; ptr != NULL; ptr = ptr->next) + if (strcmp($2, ptr->name) == 0) { - if (strcmp($2, ptr->name) == 0) - { - /* re-definition is not allowed */ - mmerror(PARSE_ERROR, ET_ERROR, "name \"%s\" is already declared", ptr->name); - } + /* re-definition is not allowed */ + mmerror(PARSE_ERROR, ET_ERROR, "name \"%s\" is already declared", ptr->name); } + } - /* Add a new declared name into the g_declared_list */ - ptr = NULL; - ptr = (struct declared_list *)mm_alloc(sizeof(struct declared_list)); - if (ptr) - { - /* initial definition */ - ptr -> name = $2; - if (connection) - ptr -> connection = mm_strdup(connection); - else - ptr -> connection = NULL; - - ptr -> next = g_declared_list; - g_declared_list = ptr; - } + /* Add a new declared name into the g_declared_list */ + ptr = NULL; + ptr = (struct declared_list *) mm_alloc(sizeof(struct declared_list)); + if (ptr) + { + /* initial definition */ + ptr->name = $2; + if (connection) + ptr->connection = mm_strdup(connection); + else + ptr->connection = NULL; - $$ = cat_str(3 , mm_strdup("/* declare "), mm_strdup($2), mm_strdup(" as an SQL identifier */")); + ptr->next = g_declared_list; + g_declared_list = ptr; } -; + + $$ = cat_str(3, mm_strdup("/* declare "), mm_strdup($2), mm_strdup(" as an SQL identifier */")); + } + ; /* * Declare a prepared cursor. The syntax is different from the standard * declare statement, so we create a new rule. */ -ECPGCursorStmt: DECLARE cursor_name cursor_options CURSOR opt_hold FOR prepared_name - { - struct cursor *ptr, *this; - char *cursor_marker = $2[0] == ':' ? mm_strdup("$0") : mm_strdup($2); - int (* strcmp_fn)(const char *, const char *) = (($2[0] == ':' || $2[0] == '"') ? strcmp : pg_strcasecmp); - struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable)); - char *comment; - char *con; - - if (INFORMIX_MODE && pg_strcasecmp($2, "database") == 0) - mmfatal(PARSE_ERROR, "\"database\" cannot be used as cursor name in INFORMIX mode"); - - check_declared_list($7); - con = connection ? connection : "NULL"; - for (ptr = cur; ptr != NULL; ptr = ptr->next) +ECPGCursorStmt: DECLARE cursor_name cursor_options CURSOR opt_hold FOR prepared_name + { + struct cursor *ptr, + *this; + char *cursor_marker = $2[0] == ':' ? mm_strdup("$0") : mm_strdup($2); + int (*strcmp_fn) (const char *, const char *) = (($2[0] == ':' || $2[0] == '"') ? strcmp : pg_strcasecmp); + struct variable *thisquery = (struct variable *) mm_alloc(sizeof(struct variable)); + char *comment; + char *con; + + if (INFORMIX_MODE && pg_strcasecmp($2, "database") == 0) + mmfatal(PARSE_ERROR, "\"database\" cannot be used as cursor name in INFORMIX mode"); + + check_declared_list($7); + con = connection ? connection : "NULL"; + for (ptr = cur; ptr != NULL; ptr = ptr->next) + { + if (strcmp_fn($2, ptr->name) == 0) { - if (strcmp_fn($2, ptr->name) == 0) - { - /* re-definition is a bug */ - if ($2[0] == ':') - mmerror(PARSE_ERROR, ET_ERROR, "using variable \"%s\" in different declare statements is not supported",$2+1); - else - mmerror(PARSE_ERROR, ET_ERROR, "cursor \"%s\" is already defined", $2); - } + /* re-definition is a bug */ + if ($2[0] == ':') + mmerror(PARSE_ERROR, ET_ERROR, "using variable \"%s\" in different declare statements is not supported",$2 + 1); + else + mmerror(PARSE_ERROR, ET_ERROR, "cursor \"%s\" is already defined", $2); } + } - this = (struct cursor *) mm_alloc(sizeof(struct cursor)); + this = (struct cursor *) mm_alloc(sizeof(struct cursor)); - /* initial definition */ - this->next = cur; - this->name = $2; - this->function = (current_function ? mm_strdup(current_function) : NULL); - this->connection = connection ? mm_strdup(connection) : NULL; - this->command = cat_str(6, mm_strdup("declare"), cursor_marker, $3, mm_strdup("cursor"), $5, mm_strdup("for$1")); - this->argsresult = NULL; - this->argsresult_oos = NULL; - - thisquery->type = &ecpg_query; - thisquery->brace_level = 0; - thisquery->next = NULL; - thisquery->name = (char *) mm_alloc(sizeof("ECPGprepared_statement(, , __LINE__)") + strlen(con) + strlen($7)); - sprintf(thisquery->name, "ECPGprepared_statement(%s, %s, __LINE__)", con, $7); - - this->argsinsert = NULL; - this->argsinsert_oos = NULL; - if ($2[0] == ':') - { - struct variable *var = find_variable($2 + 1); - remove_variable_from_list(&argsinsert, var); - add_variable_to_head(&(this->argsinsert), var, &no_indicator); - } - add_variable_to_head(&(this->argsinsert), thisquery, &no_indicator); + /* initial definition */ + this->next = cur; + this->name = $2; + this->function = (current_function ? mm_strdup(current_function) : NULL); + this->connection = connection ? mm_strdup(connection) : NULL; + this->command = cat_str(6, mm_strdup("declare"), cursor_marker, $3, mm_strdup("cursor"), $5, mm_strdup("for $1")); + this->argsresult = NULL; + this->argsresult_oos = NULL; - cur = this; + thisquery->type = &ecpg_query; + thisquery->brace_level = 0; + thisquery->next = NULL; + thisquery->name = (char *) mm_alloc(sizeof("ECPGprepared_statement(, , __LINE__)") + strlen(con) + strlen($7)); + sprintf(thisquery->name, "ECPGprepared_statement(%s, %s, __LINE__)", con, $7); - comment = cat_str(3, mm_strdup("/*"), mm_strdup(this->command), mm_strdup("*/")); + this->argsinsert = NULL; + this->argsinsert_oos = NULL; + if ($2[0] == ':') + { + struct variable *var = find_variable($2 + 1); - $$ = cat_str(2, adjust_outofscope_cursor_vars(this), - comment); + remove_variable_from_list(&argsinsert, var); + add_variable_to_head(&(this->argsinsert), var, &no_indicator); } - ; + add_variable_to_head(&(this->argsinsert), thisquery, &no_indicator); + + cur = this; + + comment = cat_str(3, mm_strdup("/*"), mm_strdup(this->command), mm_strdup("*/")); + + $$ = cat_str(2, adjust_outofscope_cursor_vars(this), + comment); + } + ; ECPGExecuteImmediateStmt: EXECUTE IMMEDIATE execstring - { - /* execute immediate means prepare the statement and - * immediately execute it */ - $$ = $3; - }; + { + /* + * execute immediate means prepare the statement and immediately + * execute it + */ + $$ = $3; + } + ; + /* * variable declaration outside exec sql declare block */ ECPGVarDeclaration: single_vt_declaration; -single_vt_declaration: type_declaration { $$ = $1; } - | var_declaration { $$ = $1; } - ; - -precision: NumericOnly { $$ = $1; }; - -opt_scale: ',' NumericOnly { $$ = $2; } - | /* EMPTY */ { $$ = EMPTY; } - ; +single_vt_declaration: type_declaration + { + $$ = $1; + } + | var_declaration + { + $$ = $1; + } + ; -ecpg_interval: opt_interval { $$ = $1; } - | YEAR_P TO MINUTE_P { $$ = mm_strdup("year to minute"); } - | YEAR_P TO SECOND_P { $$ = mm_strdup("year to second"); } - | DAY_P TO DAY_P { $$ = mm_strdup("day to day"); } - | MONTH_P TO MONTH_P { $$ = mm_strdup("month to month"); } - ; +precision: NumericOnly + { + $$ = $1; + } + ; + +opt_scale: ',' NumericOnly + { + $$ = $2; + } + | /* EMPTY */ + { + $$ = EMPTY; + } + ; + +ecpg_interval: opt_interval { $$ = $1; } + | YEAR_P TO MINUTE_P { $$ = mm_strdup("year to minute"); } + | YEAR_P TO SECOND_P { $$ = mm_strdup("year to second"); } + | DAY_P TO DAY_P { $$ = mm_strdup("day to day"); } + | MONTH_P TO MONTH_P { $$ = mm_strdup("month to month"); } + ; /* * variable declaration inside exec sql declare block */ ECPGDeclaration: sql_startdeclare - { fputs("/* exec sql begin declare section */", base_yyout); } - var_type_declarations sql_enddeclare - { - fprintf(base_yyout, "%s/* exec sql end declare section */", $3); - free($3); - output_line_number(); - } - ; + { + fputs("/* exec sql begin declare section */", base_yyout); + } + var_type_declarations sql_enddeclare + { + fprintf(base_yyout, "%s/* exec sql end declare section */", $3); + free($3); + output_line_number(); + } + ; -sql_startdeclare: ecpgstart BEGIN_P DECLARE SQL_SECTION ';' {}; +sql_startdeclare: ecpgstart BEGIN_P DECLARE SQL_SECTION ';' + { + } + ; -sql_enddeclare: ecpgstart END_P DECLARE SQL_SECTION ';' {}; +sql_enddeclare: ecpgstart END_P DECLARE SQL_SECTION ';' + { + } + ; -var_type_declarations: /*EMPTY*/ { $$ = EMPTY; } - | vt_declarations { $$ = $1; } - ; +var_type_declarations: /* EMPTY */ + { + $$ = EMPTY; + } + | vt_declarations + { + $$ = $1; + } + ; -vt_declarations: single_vt_declaration { $$ = $1; } - | CPP_LINE { $$ = $1; } - | vt_declarations single_vt_declaration { $$ = cat2_str($1, $2); } - | vt_declarations CPP_LINE { $$ = cat2_str($1, $2); } - ; +vt_declarations: single_vt_declaration + { + $$ = $1; + } + | CPP_LINE + { + $$ = $1; + } + | vt_declarations single_vt_declaration + { + $$ = cat2_str($1, $2); + } + | vt_declarations CPP_LINE + { + $$ = cat2_str($1, $2); + } + ; -variable_declarations: var_declaration { $$ = $1; } - | variable_declarations var_declaration { $$ = cat2_str($1, $2); } - ; +variable_declarations: var_declaration + { + $$ = $1; + } + | variable_declarations var_declaration + { + $$ = cat2_str($1, $2); + } + ; type_declaration: S_TYPEDEF { @@ -467,750 +612,885 @@ type_declaration: S_TYPEDEF /* an initializer specified */ initializer = 0; } - var_type opt_pointer ECPGColLabel opt_array_bounds ';' + var_type opt_pointer ECPGColLabel opt_array_bounds ';' { add_typedef($5, $6.index1, $6.index2, $3.type_enum, $3.type_dimension, $3.type_index, initializer, *$4 ? 1 : 0); fprintf(base_yyout, "typedef %s %s %s %s;\n", $3.type_str, *$4 ? "*" : "", $5, $6.str); output_line_number(); $$ = mm_strdup(""); - }; + } + ; var_declaration: - storage_declaration var_type + storage_declaration var_type + { + actual_type[struct_level].type_storage = $1; + actual_type[struct_level].type_enum = $2.type_enum; + actual_type[struct_level].type_str = $2.type_str; + actual_type[struct_level].type_dimension = $2.type_dimension; + actual_type[struct_level].type_index = $2.type_index; + actual_type[struct_level].type_sizeof = $2.type_sizeof; + + actual_startline[struct_level] = hashline_number(); + } + variable_list ';' + { + $$ = cat_str(5, actual_startline[struct_level], $1, $2.type_str, $4, mm_strdup(";\n")); + } + | var_type + { + actual_type[struct_level].type_storage = EMPTY; + actual_type[struct_level].type_enum = $1.type_enum; + actual_type[struct_level].type_str = $1.type_str; + actual_type[struct_level].type_dimension = $1.type_dimension; + actual_type[struct_level].type_index = $1.type_index; + actual_type[struct_level].type_sizeof = $1.type_sizeof; + + actual_startline[struct_level] = hashline_number(); + } + variable_list ';' + { + $$ = cat_str(4, actual_startline[struct_level], $1.type_str, $3, mm_strdup(";\n")); + } + | struct_union_type_with_symbol ';' + { + $$ = cat2_str($1, mm_strdup(";")); + } + ; + +opt_bit_field: ':' Iconst + { + $$ = cat2_str(mm_strdup(":"), $2); + } + | /* EMPTY */ + { + $$ = EMPTY; + } + ; + +storage_declaration: storage_clause storage_modifier + { + $$ = cat2_str($1, $2); + } + | storage_clause + { + $$ = $1; + } + | storage_modifier + { + $$ = $1; + } + ; + +storage_clause: S_EXTERN { $$ = mm_strdup("extern"); } + | S_STATIC { $$ = mm_strdup("static"); } + | S_REGISTER { $$ = mm_strdup("register"); } + | S_AUTO { $$ = mm_strdup("auto"); } + ; + +storage_modifier: S_CONST { $$ = mm_strdup("const"); } + | S_VOLATILE { $$ = mm_strdup("volatile"); } + ; + +var_type: simple_type + { + $$.type_enum = $1; + $$.type_str = mm_strdup(ecpg_type_name($1)); + $$.type_dimension = mm_strdup("-1"); + $$.type_index = mm_strdup("-1"); + $$.type_sizeof = NULL; + } + | struct_union_type + { + $$.type_str = $1; + $$.type_dimension = mm_strdup("-1"); + $$.type_index = mm_strdup("-1"); + + if (strncmp($1, "struct", sizeof("struct") - 1) == 0) { - actual_type[struct_level].type_storage = $1; - actual_type[struct_level].type_enum = $2.type_enum; - actual_type[struct_level].type_str = $2.type_str; - actual_type[struct_level].type_dimension = $2.type_dimension; - actual_type[struct_level].type_index = $2.type_index; - actual_type[struct_level].type_sizeof = $2.type_sizeof; - - actual_startline[struct_level] = hashline_number(); + $$.type_enum = ECPGt_struct; + $$.type_sizeof = ECPGstruct_sizeof; } - variable_list ';' + else { - $$ = cat_str(5, actual_startline[struct_level], $1, $2.type_str, $4, mm_strdup(";\n")); + $$.type_enum = ECPGt_union; + $$.type_sizeof = NULL; } - | var_type + } + | enum_type + { + $$.type_str = $1; + $$.type_enum = ECPGt_int; + $$.type_dimension = mm_strdup("-1"); + $$.type_index = mm_strdup("-1"); + $$.type_sizeof = NULL; + } + | NUMERIC '(' precision opt_scale ')' + { + $$.type_enum = ECPGt_numeric; + $$.type_str = mm_strdup("numeric"); + $$.type_dimension = mm_strdup("-1"); + $$.type_index = mm_strdup("-1"); + $$.type_sizeof = NULL; + } + | DECIMAL_P '(' precision opt_scale ')' + { + $$.type_enum = ECPGt_decimal; + $$.type_str = mm_strdup("decimal"); + $$.type_dimension = mm_strdup("-1"); + $$.type_index = mm_strdup("-1"); + $$.type_sizeof = NULL; + } + | IDENT '(' precision opt_scale ')' + { + /* + * In C parsing mode, NUMERIC and DECIMAL are not keywords, so they + * will show up here as a plain identifier, and we need this duplicate + * code to recognize them. + */ + if (strcmp($1, "numeric") == 0) { - actual_type[struct_level].type_storage = EMPTY; - actual_type[struct_level].type_enum = $1.type_enum; - actual_type[struct_level].type_str = $1.type_str; - actual_type[struct_level].type_dimension = $1.type_dimension; - actual_type[struct_level].type_index = $1.type_index; - actual_type[struct_level].type_sizeof = $1.type_sizeof; - - actual_startline[struct_level] = hashline_number(); + $$.type_enum = ECPGt_numeric; + $$.type_str = mm_strdup("numeric"); } - variable_list ';' + else if (strcmp($1, "decimal") == 0) { - $$ = cat_str(4, actual_startline[struct_level], $1.type_str, $3, mm_strdup(";\n")); + $$.type_enum = ECPGt_decimal; + $$.type_str = mm_strdup("decimal"); } - | struct_union_type_with_symbol ';' + else { - $$ = cat2_str($1, mm_strdup(";")); + mmerror(PARSE_ERROR, ET_ERROR, "only data types numeric and decimal have precision/scale argument"); + $$.type_enum = ECPGt_numeric; + $$.type_str = mm_strdup("numeric"); } - ; - -opt_bit_field: ':' Iconst { $$ =cat2_str(mm_strdup(":"), $2); } - | /* EMPTY */ { $$ = EMPTY; } - ; -storage_declaration: storage_clause storage_modifier - {$$ = cat2_str ($1, $2); } - | storage_clause {$$ = $1; } - | storage_modifier {$$ = $1; } - ; - -storage_clause : S_EXTERN { $$ = mm_strdup("extern"); } - | S_STATIC { $$ = mm_strdup("static"); } - | S_REGISTER { $$ = mm_strdup("register"); } - | S_AUTO { $$ = mm_strdup("auto"); } - ; - -storage_modifier : S_CONST { $$ = mm_strdup("const"); } - | S_VOLATILE { $$ = mm_strdup("volatile"); } - ; - -var_type: simple_type + $$.type_dimension = mm_strdup("-1"); + $$.type_index = mm_strdup("-1"); + $$.type_sizeof = NULL; + } + | VARCHAR + { + $$.type_enum = ECPGt_varchar; + $$.type_str = EMPTY; /* mm_strdup("varchar"); */ + $$.type_dimension = mm_strdup("-1"); + $$.type_index = mm_strdup("-1"); + $$.type_sizeof = NULL; + } + | FLOAT_P + { + /* Note: DOUBLE is handled in simple_type */ + $$.type_enum = ECPGt_float; + $$.type_str = mm_strdup("float"); + $$.type_dimension = mm_strdup("-1"); + $$.type_index = mm_strdup("-1"); + $$.type_sizeof = NULL; + } + | NUMERIC + { + $$.type_enum = ECPGt_numeric; + $$.type_str = mm_strdup("numeric"); + $$.type_dimension = mm_strdup("-1"); + $$.type_index = mm_strdup("-1"); + $$.type_sizeof = NULL; + } + | DECIMAL_P + { + $$.type_enum = ECPGt_decimal; + $$.type_str = mm_strdup("decimal"); + $$.type_dimension = mm_strdup("-1"); + $$.type_index = mm_strdup("-1"); + $$.type_sizeof = NULL; + } + | TIMESTAMP + { + $$.type_enum = ECPGt_timestamp; + $$.type_str = mm_strdup("timestamp"); + $$.type_dimension = mm_strdup("-1"); + $$.type_index = mm_strdup("-1"); + $$.type_sizeof = NULL; + } + | STRING_P + { + if (INFORMIX_MODE) { - $$.type_enum = $1; - $$.type_str = mm_strdup(ecpg_type_name($1)); + /* In Informix mode, "string" is automatically a typedef */ + $$.type_enum = ECPGt_string; + $$.type_str = mm_strdup("char"); $$.type_dimension = mm_strdup("-1"); $$.type_index = mm_strdup("-1"); $$.type_sizeof = NULL; } - | struct_union_type + else { - $$.type_str = $1; - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); + /* Otherwise, legal only if user typedef'ed it */ + struct typedefs *this = get_typedef("string", false); - if (strncmp($1, "struct", sizeof("struct")-1) == 0) - { - $$.type_enum = ECPGt_struct; - $$.type_sizeof = ECPGstruct_sizeof; - } + $$.type_str = (this->type->type_enum == ECPGt_varchar || this->type->type_enum == ECPGt_bytea) ? EMPTY : mm_strdup(this->name); + $$.type_enum = this->type->type_enum; + $$.type_dimension = this->type->type_dimension; + $$.type_index = this->type->type_index; + if (this->type->type_sizeof && strlen(this->type->type_sizeof) != 0) + $$.type_sizeof = this->type->type_sizeof; else - { - $$.type_enum = ECPGt_union; - $$.type_sizeof = NULL; - } + $$.type_sizeof = cat_str(3, mm_strdup("sizeof("), mm_strdup(this->name), mm_strdup(")")); + + struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list); } - | enum_type + } + | INTERVAL ecpg_interval + { + $$.type_enum = ECPGt_interval; + $$.type_str = mm_strdup("interval"); + $$.type_dimension = mm_strdup("-1"); + $$.type_index = mm_strdup("-1"); + $$.type_sizeof = NULL; + } + | IDENT ecpg_interval + { + /* + * In C parsing mode, the above SQL type names are not keywords, so + * they will show up here as a plain identifier, and we need this + * duplicate code to recognize them. + * + * Note that we also handle the type names bytea, date, and datetime + * here, but not above because those are not currently SQL keywords. + * If they ever become so, they must gain duplicate productions above. + */ + if (strlen($2) != 0 && strcmp($1, "datetime") != 0 && strcmp($1, "interval") != 0) + mmerror(PARSE_ERROR, ET_ERROR, "interval specification not allowed here"); + + if (strcmp($1, "varchar") == 0) { - $$.type_str = $1; - $$.type_enum = ECPGt_int; + $$.type_enum = ECPGt_varchar; + $$.type_str = EMPTY; /* mm_strdup("varchar"); */ $$.type_dimension = mm_strdup("-1"); $$.type_index = mm_strdup("-1"); $$.type_sizeof = NULL; } - | NUMERIC '(' precision opt_scale ')' + else if (strcmp($1, "bytea") == 0) { - $$.type_enum = ECPGt_numeric; - $$.type_str = mm_strdup("numeric"); + $$.type_enum = ECPGt_bytea; + $$.type_str = EMPTY; $$.type_dimension = mm_strdup("-1"); $$.type_index = mm_strdup("-1"); $$.type_sizeof = NULL; } - | DECIMAL_P '(' precision opt_scale ')' + else if (strcmp($1, "float") == 0) { - $$.type_enum = ECPGt_decimal; - $$.type_str = mm_strdup("decimal"); + $$.type_enum = ECPGt_float; + $$.type_str = mm_strdup("float"); $$.type_dimension = mm_strdup("-1"); $$.type_index = mm_strdup("-1"); $$.type_sizeof = NULL; } - | IDENT '(' precision opt_scale ')' + else if (strcmp($1, "double") == 0) { - /* - * In C parsing mode, NUMERIC and DECIMAL are not keywords, so - * they will show up here as a plain identifier, and we need - * this duplicate code to recognize them. - */ - if (strcmp($1, "numeric") == 0) - { - $$.type_enum = ECPGt_numeric; - $$.type_str = mm_strdup("numeric"); - } - else if (strcmp($1, "decimal") == 0) - { - $$.type_enum = ECPGt_decimal; - $$.type_str = mm_strdup("decimal"); - } - else - { - mmerror(PARSE_ERROR, ET_ERROR, "only data types numeric and decimal have precision/scale argument"); - $$.type_enum = ECPGt_numeric; - $$.type_str = mm_strdup("numeric"); - } - + $$.type_enum = ECPGt_double; + $$.type_str = mm_strdup("double"); $$.type_dimension = mm_strdup("-1"); $$.type_index = mm_strdup("-1"); $$.type_sizeof = NULL; } - | VARCHAR + else if (strcmp($1, "numeric") == 0) { - $$.type_enum = ECPGt_varchar; - $$.type_str = EMPTY; /*mm_strdup("varchar");*/ + $$.type_enum = ECPGt_numeric; + $$.type_str = mm_strdup("numeric"); $$.type_dimension = mm_strdup("-1"); $$.type_index = mm_strdup("-1"); $$.type_sizeof = NULL; } - | FLOAT_P + else if (strcmp($1, "decimal") == 0) { - /* Note: DOUBLE is handled in simple_type */ - $$.type_enum = ECPGt_float; - $$.type_str = mm_strdup("float"); + $$.type_enum = ECPGt_decimal; + $$.type_str = mm_strdup("decimal"); $$.type_dimension = mm_strdup("-1"); $$.type_index = mm_strdup("-1"); $$.type_sizeof = NULL; } - | NUMERIC + else if (strcmp($1, "date") == 0) { - $$.type_enum = ECPGt_numeric; - $$.type_str = mm_strdup("numeric"); + $$.type_enum = ECPGt_date; + $$.type_str = mm_strdup("date"); $$.type_dimension = mm_strdup("-1"); $$.type_index = mm_strdup("-1"); $$.type_sizeof = NULL; } - | DECIMAL_P + else if (strcmp($1, "timestamp") == 0) { - $$.type_enum = ECPGt_decimal; - $$.type_str = mm_strdup("decimal"); + $$.type_enum = ECPGt_timestamp; + $$.type_str = mm_strdup("timestamp"); $$.type_dimension = mm_strdup("-1"); $$.type_index = mm_strdup("-1"); $$.type_sizeof = NULL; } - | TIMESTAMP + else if (strcmp($1, "interval") == 0) { - $$.type_enum = ECPGt_timestamp; - $$.type_str = mm_strdup("timestamp"); + $$.type_enum = ECPGt_interval; + $$.type_str = mm_strdup("interval"); $$.type_dimension = mm_strdup("-1"); $$.type_index = mm_strdup("-1"); $$.type_sizeof = NULL; } - | STRING_P - { - if (INFORMIX_MODE) - { - /* In Informix mode, "string" is automatically a typedef */ - $$.type_enum = ECPGt_string; - $$.type_str = mm_strdup("char"); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); - $$.type_sizeof = NULL; - } - else - { - /* Otherwise, legal only if user typedef'ed it */ - struct typedefs *this = get_typedef("string", false); - - $$.type_str = (this->type->type_enum == ECPGt_varchar || this->type->type_enum == ECPGt_bytea) ? EMPTY :mm_strdup(this->name); - $$.type_enum = this->type->type_enum; - $$.type_dimension = this->type->type_dimension; - $$.type_index = this->type->type_index; - if (this->type->type_sizeof && strlen(this->type->type_sizeof) != 0) - $$.type_sizeof = this->type->type_sizeof; - else - $$.type_sizeof = cat_str(3, mm_strdup("sizeof("), mm_strdup(this->name), mm_strdup(")")); - - struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list); - } - } - | INTERVAL ecpg_interval + else if (strcmp($1, "datetime") == 0) { - $$.type_enum = ECPGt_interval; - $$.type_str = mm_strdup("interval"); + $$.type_enum = ECPGt_timestamp; + $$.type_str = mm_strdup("timestamp"); $$.type_dimension = mm_strdup("-1"); $$.type_index = mm_strdup("-1"); $$.type_sizeof = NULL; } - | IDENT ecpg_interval + else if ((strcmp($1, "string") == 0) && INFORMIX_MODE) { - /* - * In C parsing mode, the above SQL type names are not keywords, - * so they will show up here as a plain identifier, and we need - * this duplicate code to recognize them. - * - * Note that we also handle the type names bytea, date, and - * datetime here, but not above because those are not currently - * SQL keywords. If they ever become so, they must gain duplicate - * productions above. - */ - if (strlen($2) != 0 && strcmp ($1, "datetime") != 0 && strcmp ($1, "interval") != 0) - mmerror (PARSE_ERROR, ET_ERROR, "interval specification not allowed here"); - - if (strcmp($1, "varchar") == 0) - { - $$.type_enum = ECPGt_varchar; - $$.type_str = EMPTY; /*mm_strdup("varchar");*/ - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); - $$.type_sizeof = NULL; - } - else if (strcmp($1, "bytea") == 0) - { - $$.type_enum = ECPGt_bytea; - $$.type_str = EMPTY; - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); - $$.type_sizeof = NULL; - } - else if (strcmp($1, "float") == 0) - { - $$.type_enum = ECPGt_float; - $$.type_str = mm_strdup("float"); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); - $$.type_sizeof = NULL; - } - else if (strcmp($1, "double") == 0) - { - $$.type_enum = ECPGt_double; - $$.type_str = mm_strdup("double"); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); - $$.type_sizeof = NULL; - } - else if (strcmp($1, "numeric") == 0) - { - $$.type_enum = ECPGt_numeric; - $$.type_str = mm_strdup("numeric"); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); - $$.type_sizeof = NULL; - } - else if (strcmp($1, "decimal") == 0) - { - $$.type_enum = ECPGt_decimal; - $$.type_str = mm_strdup("decimal"); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); - $$.type_sizeof = NULL; - } - else if (strcmp($1, "date") == 0) - { - $$.type_enum = ECPGt_date; - $$.type_str = mm_strdup("date"); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); - $$.type_sizeof = NULL; - } - else if (strcmp($1, "timestamp") == 0) - { - $$.type_enum = ECPGt_timestamp; - $$.type_str = mm_strdup("timestamp"); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); - $$.type_sizeof = NULL; - } - else if (strcmp($1, "interval") == 0) - { - $$.type_enum = ECPGt_interval; - $$.type_str = mm_strdup("interval"); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); - $$.type_sizeof = NULL; - } - else if (strcmp($1, "datetime") == 0) - { - $$.type_enum = ECPGt_timestamp; - $$.type_str = mm_strdup("timestamp"); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); - $$.type_sizeof = NULL; - } - else if ((strcmp($1, "string") == 0) && INFORMIX_MODE) - { - $$.type_enum = ECPGt_string; - $$.type_str = mm_strdup("char"); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); - $$.type_sizeof = NULL; - } - else - { - /* Otherwise, it must be a user-defined typedef name */ - struct typedefs *this = get_typedef($1, false); - - $$.type_str = (this->type->type_enum == ECPGt_varchar || this->type->type_enum == ECPGt_bytea) ? EMPTY :mm_strdup(this->name); - $$.type_enum = this->type->type_enum; - $$.type_dimension = this->type->type_dimension; - $$.type_index = this->type->type_index; - if (this->type->type_sizeof && strlen(this->type->type_sizeof) != 0) - $$.type_sizeof = this->type->type_sizeof; - else - $$.type_sizeof = cat_str(3, mm_strdup("sizeof("), mm_strdup(this->name), mm_strdup(")")); - - struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list); - } + $$.type_enum = ECPGt_string; + $$.type_str = mm_strdup("char"); + $$.type_dimension = mm_strdup("-1"); + $$.type_index = mm_strdup("-1"); + $$.type_sizeof = NULL; } - | s_struct_union_symbol + else { - /* this is for named structs/unions */ - char *name; - struct typedefs *this; - bool forward = (forward_name != NULL && strcmp($1.symbol, forward_name) == 0 && strcmp($1.su, "struct") == 0); - - name = cat2_str($1.su, $1.symbol); - /* Do we have a forward definition? */ - if (!forward) - { - /* No */ + /* Otherwise, it must be a user-defined typedef name */ + struct typedefs *this = get_typedef($1, false); - this = get_typedef(name, false); - $$.type_str = mm_strdup(this->name); - $$.type_enum = this->type->type_enum; - $$.type_dimension = this->type->type_dimension; - $$.type_index = this->type->type_index; + $$.type_str = (this->type->type_enum == ECPGt_varchar || this->type->type_enum == ECPGt_bytea) ? EMPTY : mm_strdup(this->name); + $$.type_enum = this->type->type_enum; + $$.type_dimension = this->type->type_dimension; + $$.type_index = this->type->type_index; + if (this->type->type_sizeof && strlen(this->type->type_sizeof) != 0) $$.type_sizeof = this->type->type_sizeof; - struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list); - free(name); - } else - { - $$.type_str = name; - $$.type_enum = ECPGt_long; - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); - $$.type_sizeof = mm_strdup(""); - struct_member_list[struct_level] = NULL; - } + $$.type_sizeof = cat_str(3, mm_strdup("sizeof("), mm_strdup(this->name), mm_strdup(")")); + + struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list); + } + } + | s_struct_union_symbol + { + /* this is for named structs/unions */ + char *name; + struct typedefs *this; + bool forward = (forward_name != NULL && strcmp($1.symbol, forward_name) == 0 && strcmp($1.su, "struct") ==0); + + name = cat2_str($1.su, $1.symbol); + /* Do we have a forward definition? */ + if (!forward) + { + /* No */ + + this = get_typedef(name, false); + $$.type_str = mm_strdup(this->name); + $$.type_enum = this->type->type_enum; + $$.type_dimension = this->type->type_dimension; + $$.type_index = this->type->type_index; + $$.type_sizeof = this->type->type_sizeof; + struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list); + free(name); + } + else + { + $$.type_str = name; + $$.type_enum = ECPGt_long; + $$.type_dimension = mm_strdup("-1"); + $$.type_index = mm_strdup("-1"); + $$.type_sizeof = mm_strdup(""); + struct_member_list[struct_level] = NULL; } - ; + } + ; enum_type: ENUM_P symbol enum_definition - { $$ = cat_str(3, mm_strdup("enum"), $2, $3); } - | ENUM_P enum_definition - { $$ = cat2_str(mm_strdup("enum"), $2); } - | ENUM_P symbol - { $$ = cat2_str(mm_strdup("enum"), $2); } - ; + { + $$ = cat_str(3, mm_strdup("enum"), $2, $3); + } + | ENUM_P enum_definition + { + $$ = cat2_str(mm_strdup("enum"), $2); + } + | ENUM_P symbol + { + $$ = cat2_str(mm_strdup("enum"), $2); + } + ; enum_definition: '{' c_list '}' - { $$ = cat_str(3, mm_strdup("{"), $2, mm_strdup("}")); }; + { + $$ = cat_str(3, mm_strdup("{"), $2, mm_strdup("}")); + } + ; struct_union_type_with_symbol: s_struct_union_symbol - { - struct_member_list[struct_level++] = NULL; - if (struct_level >= STRUCT_DEPTH) - mmerror(PARSE_ERROR, ET_ERROR, "too many levels in nested structure/union definition"); - forward_name = mm_strdup($1.symbol); - } - '{' variable_declarations '}' - { - struct typedefs *ptr, *this; - struct this_type su_type; - - ECPGfree_struct_member(struct_member_list[struct_level]); - struct_member_list[struct_level] = NULL; - struct_level--; - if (strncmp($1.su, "struct", sizeof("struct")-1) == 0) - su_type.type_enum = ECPGt_struct; - else - su_type.type_enum = ECPGt_union; - su_type.type_str = cat2_str($1.su, $1.symbol); - free(forward_name); - forward_name = NULL; - - /* This is essentially a typedef but needs the keyword struct/union as well. - * So we create the typedef for each struct definition with symbol */ - for (ptr = types; ptr != NULL; ptr = ptr->next) - { - if (strcmp(su_type.type_str, ptr->name) == 0) - /* re-definition is a bug */ - mmerror(PARSE_ERROR, ET_ERROR, "type \"%s\" is already defined", su_type.type_str); - } - - this = (struct typedefs *) mm_alloc(sizeof(struct typedefs)); - - /* initial definition */ - this->next = types; - this->name = mm_strdup(su_type.type_str); - this->brace_level = braces_open; - this->type = (struct this_type *) mm_alloc(sizeof(struct this_type)); - this->type->type_enum = su_type.type_enum; - this->type->type_str = mm_strdup(su_type.type_str); - this->type->type_dimension = mm_strdup("-1"); /* dimension of array */ - this->type->type_index = mm_strdup("-1"); /* length of string */ - this->type->type_sizeof = ECPGstruct_sizeof; - this->struct_member_list = struct_member_list[struct_level]; - - types = this; - $$ = cat_str(4, su_type.type_str, mm_strdup("{"), $4, mm_strdup("}")); - } - ; + { + struct_member_list[struct_level++] = NULL; + if (struct_level >= STRUCT_DEPTH) + mmerror(PARSE_ERROR, ET_ERROR, "too many levels in nested structure/union definition"); + forward_name = mm_strdup($1.symbol); + } + '{' variable_declarations '}' + { + struct typedefs *ptr, + *this; + struct this_type su_type; + + ECPGfree_struct_member(struct_member_list[struct_level]); + struct_member_list[struct_level] = NULL; + struct_level--; + if (strncmp($1.su, "struct", sizeof("struct") - 1) == 0) + su_type.type_enum = ECPGt_struct; + else + su_type.type_enum = ECPGt_union; + su_type.type_str = cat2_str($1.su, $1.symbol); + free(forward_name); + forward_name = NULL; + + /* + * This is essentially a typedef but needs the keyword struct/union as + * well. So we create the typedef for each struct definition with + * symbol + */ + for (ptr = types; ptr != NULL; ptr = ptr->next) + { + if (strcmp(su_type.type_str, ptr->name) == 0) + /* re-definition is a bug */ + mmerror(PARSE_ERROR, ET_ERROR, "type \"%s\" is already defined", su_type.type_str); + } + + this = (struct typedefs *) mm_alloc(sizeof(struct typedefs)); + + /* initial definition */ + this->next = types; + this->name = mm_strdup(su_type.type_str); + this->brace_level = braces_open; + this->type = (struct this_type *) mm_alloc(sizeof(struct this_type)); + this->type->type_enum = su_type.type_enum; + this->type->type_str = mm_strdup(su_type.type_str); + this->type->type_dimension = mm_strdup("-1"); /* dimension of array */ + this->type->type_index = mm_strdup("-1"); /* length of string */ + this->type->type_sizeof = ECPGstruct_sizeof; + this->struct_member_list = struct_member_list[struct_level]; + + types = this; + $$ = cat_str(4, su_type.type_str, mm_strdup("{"), $4, mm_strdup("}")); + } + ; -struct_union_type: struct_union_type_with_symbol { $$ = $1; } - | s_struct_union - { - struct_member_list[struct_level++] = NULL; - if (struct_level >= STRUCT_DEPTH) - mmerror(PARSE_ERROR, ET_ERROR, "too many levels in nested structure/union definition"); - } - '{' variable_declarations '}' - { - ECPGfree_struct_member(struct_member_list[struct_level]); - struct_member_list[struct_level] = NULL; - struct_level--; - $$ = cat_str(4, $1, mm_strdup("{"), $4, mm_strdup("}")); - } - ; +struct_union_type: struct_union_type_with_symbol + { + $$ = $1; + } + | s_struct_union + { + struct_member_list[struct_level++] = NULL; + if (struct_level >= STRUCT_DEPTH) + mmerror(PARSE_ERROR, ET_ERROR, "too many levels in nested structure/union definition"); + } + '{' variable_declarations '}' + { + ECPGfree_struct_member(struct_member_list[struct_level]); + struct_member_list[struct_level] = NULL; + struct_level--; + $$ = cat_str(4, $1, mm_strdup("{"), $4, mm_strdup("}")); + } + ; s_struct_union_symbol: SQL_STRUCT symbol - { - $$.su = mm_strdup("struct"); - $$.symbol = $2; - ECPGstruct_sizeof = cat_str(3, mm_strdup("sizeof("), cat2_str(mm_strdup($$.su), mm_strdup($$.symbol)), mm_strdup(")")); - } - | UNION symbol - { - $$.su = mm_strdup("union"); - $$.symbol = $2; - } - ; + { + $$.su = mm_strdup("struct"); + $$.symbol = $2; + ECPGstruct_sizeof = cat_str(3, mm_strdup("sizeof("), cat2_str(mm_strdup($$.su), mm_strdup($$.symbol)), mm_strdup(")")); + } + | UNION symbol + { + $$.su = mm_strdup("union"); + $$.symbol = $2; + } + ; s_struct_union: SQL_STRUCT - { - ECPGstruct_sizeof = mm_strdup(""); /* This must not be NULL to distinguish from simple types. */ - $$ = mm_strdup("struct"); - } - | UNION - { - $$ = mm_strdup("union"); - } - ; - -simple_type: unsigned_type { $$=$1; } - | opt_signed signed_type { $$=$2; } - ; - -unsigned_type: SQL_UNSIGNED SQL_SHORT { $$ = ECPGt_unsigned_short; } - | SQL_UNSIGNED SQL_SHORT INT_P { $$ = ECPGt_unsigned_short; } - | SQL_UNSIGNED { $$ = ECPGt_unsigned_int; } - | SQL_UNSIGNED INT_P { $$ = ECPGt_unsigned_int; } - | SQL_UNSIGNED SQL_LONG { $$ = ECPGt_unsigned_long; } - | SQL_UNSIGNED SQL_LONG INT_P { $$ = ECPGt_unsigned_long; } - | SQL_UNSIGNED SQL_LONG SQL_LONG { $$ = ECPGt_unsigned_long_long; } - | SQL_UNSIGNED SQL_LONG SQL_LONG INT_P { $$ = ECPGt_unsigned_long_long; } - | SQL_UNSIGNED CHAR_P { $$ = ECPGt_unsigned_char; } - ; - -signed_type: SQL_SHORT { $$ = ECPGt_short; } - | SQL_SHORT INT_P { $$ = ECPGt_short; } - | INT_P { $$ = ECPGt_int; } - | SQL_LONG { $$ = ECPGt_long; } - | SQL_LONG INT_P { $$ = ECPGt_long; } - | SQL_LONG SQL_LONG { $$ = ECPGt_long_long; } - | SQL_LONG SQL_LONG INT_P { $$ = ECPGt_long_long; } - | SQL_BOOL { $$ = ECPGt_bool; } - | CHAR_P { $$ = ECPGt_char; } - | DOUBLE_P { $$ = ECPGt_double; } - ; + { + ECPGstruct_sizeof = mm_strdup(""); /* This must not be NULL to + * distinguish from simple types. */ + $$ = mm_strdup("struct"); + } + | UNION + { + $$ = mm_strdup("union"); + } + ; + +simple_type: unsigned_type { $$ = $1; } + | opt_signed signed_type { $$ = $2; } + ; + +unsigned_type: SQL_UNSIGNED SQL_SHORT { $$ = ECPGt_unsigned_short; } + | SQL_UNSIGNED SQL_SHORT INT_P { $$ = ECPGt_unsigned_short; } + | SQL_UNSIGNED { $$ = ECPGt_unsigned_int; } + | SQL_UNSIGNED INT_P { $$ = ECPGt_unsigned_int; } + | SQL_UNSIGNED SQL_LONG { $$ = ECPGt_unsigned_long; } + | SQL_UNSIGNED SQL_LONG INT_P { $$ = ECPGt_unsigned_long; } + | SQL_UNSIGNED SQL_LONG SQL_LONG { $$ = ECPGt_unsigned_long_long; } + | SQL_UNSIGNED SQL_LONG SQL_LONG INT_P { $$ = ECPGt_unsigned_long_long; } + | SQL_UNSIGNED CHAR_P { $$ = ECPGt_unsigned_char; } + ; + +signed_type: SQL_SHORT { $$ = ECPGt_short; } + | SQL_SHORT INT_P { $$ = ECPGt_short; } + | INT_P { $$ = ECPGt_int; } + | SQL_LONG { $$ = ECPGt_long; } + | SQL_LONG INT_P { $$ = ECPGt_long; } + | SQL_LONG SQL_LONG { $$ = ECPGt_long_long; } + | SQL_LONG SQL_LONG INT_P { $$ = ECPGt_long_long; } + | SQL_BOOL { $$ = ECPGt_bool; } + | CHAR_P { $$ = ECPGt_char; } + | DOUBLE_P { $$ = ECPGt_double; } + ; opt_signed: SQL_SIGNED - | /* EMPTY */ - ; + | /* EMPTY */ + ; variable_list: variable - { $$ = $1; } - | variable_list ',' variable - { - if (actual_type[struct_level].type_enum == ECPGt_varchar || actual_type[struct_level].type_enum == ECPGt_bytea) - $$ = cat_str(4, $1, mm_strdup(";"), mm_strdup(actual_type[struct_level].type_storage), $3); - else - $$ = cat_str(3, $1, mm_strdup(","), $3); - } - ; + { + $$ = $1; + } + | variable_list ',' variable + { + if (actual_type[struct_level].type_enum == ECPGt_varchar || actual_type[struct_level].type_enum == ECPGt_bytea) + $$ = cat_str(4, $1, mm_strdup(";"), mm_strdup(actual_type[struct_level].type_storage), $3); + else + $$ = cat_str(3, $1, mm_strdup(","), $3); + } + ; variable: opt_pointer ECPGColLabel opt_array_bounds opt_bit_field opt_initializer - { - struct ECPGtype * type; - char *dimension = $3.index1; /* dimension of array */ - char *length = $3.index2; /* length of string */ - char *dim_str; - char *vcn; - int *varlen_type_counter; - char *struct_name; - - adjust_array(actual_type[struct_level].type_enum, &dimension, &length, actual_type[struct_level].type_dimension,actual_type[struct_level].type_index, strlen($1), false); - switch (actual_type[struct_level].type_enum) - { - case ECPGt_struct: - case ECPGt_union: - if (atoi(dimension) < 0) - type = ECPGmake_struct_type(struct_member_list[struct_level], actual_type[struct_level].type_enum,actual_type[struct_level].type_str, actual_type[struct_level].type_sizeof); - else - type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level], actual_type[struct_level].type_enum,actual_type[struct_level].type_str, actual_type[struct_level].type_sizeof), dimension); + { + struct ECPGtype *type; + char *dimension = $3.index1; /* dimension of array */ + char *length = $3.index2; /* length of string */ + char *dim_str; + char *vcn; + int *varlen_type_counter; + char *struct_name; + + adjust_array(actual_type[struct_level].type_enum, &dimension, &length, actual_type[struct_level].type_dimension,actual_type[struct_level].type_index, strlen($1), false); + switch (actual_type[struct_level].type_enum) + { + case ECPGt_struct: + case ECPGt_union: + if (atoi(dimension) < 0) + type = ECPGmake_struct_type(struct_member_list[struct_level], actual_type[struct_level].type_enum, actual_type[struct_level].type_str,actual_type[struct_level].type_sizeof); + else + type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level], actual_type[struct_level].type_enum,actual_type[struct_level].type_str, actual_type[struct_level].type_sizeof), dimension); - $$ = cat_str(5, $1, mm_strdup($2), $3.str, $4, $5); - break; + $$ = cat_str(5, $1, mm_strdup($2), $3.str, $4, $5); + break; - case ECPGt_varchar: - case ECPGt_bytea: - if (actual_type[struct_level].type_enum == ECPGt_varchar) - { - varlen_type_counter = &varchar_counter; - struct_name = " struct varchar_"; - } - else - { - varlen_type_counter = &bytea_counter; - struct_name = " struct bytea_"; - } - if (atoi(dimension) < 0) - type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length, *varlen_type_counter); - else - type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length, *varlen_type_counter),dimension); + case ECPGt_varchar: + case ECPGt_bytea: + if (actual_type[struct_level].type_enum == ECPGt_varchar) + { + varlen_type_counter = &varchar_counter; + struct_name = " struct varchar_"; + } + else + { + varlen_type_counter = &bytea_counter; + struct_name = " struct bytea_"; + } + if (atoi(dimension) < 0) + type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length, *varlen_type_counter); + else + type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length, *varlen_type_counter),dimension); - if (strcmp(dimension, "0") == 0 || abs(atoi(dimension)) == 1) - dim_str=mm_strdup(""); - else - dim_str=cat_str(3, mm_strdup("["), mm_strdup(dimension), mm_strdup("]")); - /* cannot check for atoi <= 0 because a defined constant will yield 0 here as well */ - if (atoi(length) < 0 || strcmp(length, "0") == 0) - mmerror(PARSE_ERROR, ET_ERROR, "pointers to varchar are not implemented"); - - /* make sure varchar struct name is unique by adding a unique counter to its definition */ - vcn = (char *) mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); - sprintf(vcn, "%d", *varlen_type_counter); - if (strcmp(dimension, "0") == 0) - $$ = cat_str(7, make2_str(mm_strdup(struct_name), vcn), mm_strdup(" { int len; char arr["), mm_strdup(length),mm_strdup("]; } *"), mm_strdup($2), $4, $5); - else - $$ = cat_str(8, make2_str(mm_strdup(struct_name), vcn), mm_strdup(" { int len; char arr["), mm_strdup(length),mm_strdup("]; } "), mm_strdup($2), dim_str, $4, $5); - (*varlen_type_counter)++; - break; + if (strcmp(dimension, "0") == 0 || abs(atoi(dimension)) == 1) + dim_str = mm_strdup(""); + else + dim_str = cat_str(3, mm_strdup("["), mm_strdup(dimension), mm_strdup("]")); + + /* + * cannot check for atoi <= 0 because a defined constant will + * yield 0 here as well + */ + if (atoi(length) < 0 || strcmp(length, "0") == 0) + mmerror(PARSE_ERROR, ET_ERROR, "pointers to varchar are not implemented"); + + /* + * make sure varchar struct name is unique by adding a unique + * counter to its definition + */ + vcn = (char *) mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); + sprintf(vcn, "%d", *varlen_type_counter); + if (strcmp(dimension, "0") == 0) + $$ = cat_str(7, make2_str(mm_strdup(struct_name), vcn), mm_strdup(" { int len; char arr["), mm_strdup(length),mm_strdup("]; } *"), mm_strdup($2), $4, $5); + else + $$ = cat_str(8, make2_str(mm_strdup(struct_name), vcn), mm_strdup(" { int len; char arr["), mm_strdup(length),mm_strdup("]; } "), mm_strdup($2), dim_str, $4, $5); + (*varlen_type_counter)++; + break; + + case ECPGt_char: + case ECPGt_unsigned_char: + case ECPGt_string: + if (atoi(dimension) == -1) + { + int i = strlen($5); - case ECPGt_char: - case ECPGt_unsigned_char: - case ECPGt_string: - if (atoi(dimension) == -1) + if (atoi(length) == -1 && i > 0) /* char <var>[] = + * "string" */ { - int i = strlen($5); - - if (atoi(length) == -1 && i > 0) /* char <var>[] = "string" */ - { - /* if we have an initializer but no string size set, let's use the initializer's length */ - free(length); - length = mm_alloc(i+sizeof("sizeof()")); - sprintf(length, "sizeof(%s)", $5+2); - } - type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length, 0); + /* + * if we have an initializer but no string size set, + * let's use the initializer's length + */ + free(length); + length = mm_alloc(i + sizeof("sizeof()")); + sprintf(length, "sizeof(%s)", $5 + 2); } - else - type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length, 0),dimension); + type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length, 0); + } + else + type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length, 0), dimension); - $$ = cat_str(5, $1, mm_strdup($2), $3.str, $4, $5); - break; + $$ = cat_str(5, $1, mm_strdup($2), $3.str, $4, $5); + break; - default: - if (atoi(dimension) < 0) - type = ECPGmake_simple_type(actual_type[struct_level].type_enum, mm_strdup("1"), 0); - else - type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, mm_strdup("1"),0), dimension); + default: + if (atoi(dimension) < 0) + type = ECPGmake_simple_type(actual_type[struct_level].type_enum, mm_strdup("1"), 0); + else + type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, mm_strdup("1"),0), dimension); - $$ = cat_str(5, $1, mm_strdup($2), $3.str, $4, $5); - break; - } + $$ = cat_str(5, $1, mm_strdup($2), $3.str, $4, $5); + break; + } - if (struct_level == 0) - new_variable($2, type, braces_open); - else - ECPGmake_struct_member($2, type, &(struct_member_list[struct_level - 1])); + if (struct_level == 0) + new_variable($2, type, braces_open); + else + ECPGmake_struct_member($2, type, &(struct_member_list[struct_level - 1])); - free($2); - } - ; + free($2); + } + ; -opt_initializer: /*EMPTY*/ - { $$ = EMPTY; } - | '=' c_term - { - initializer = 1; - $$ = cat2_str(mm_strdup("="), $2); - } - ; +opt_initializer: /* EMPTY */ + { + $$ = EMPTY; + } + | '=' c_term + { + initializer = 1; + $$ = cat2_str(mm_strdup("="), $2); + } + ; -opt_pointer: /*EMPTY*/ { $$ = EMPTY; } - | '*' { $$ = mm_strdup("*"); } - | '*' '*' { $$ = mm_strdup("**"); } - ; +opt_pointer: /* EMPTY */ + { + $$ = EMPTY; + } + | '*' + { + $$ = mm_strdup("*"); + } + | '*' '*' + { + $$ = mm_strdup("**"); + } + ; /* * We try to simulate the correct DECLARE syntax here so we get dynamic SQL */ ECPGDeclare: DECLARE STATEMENT ecpg_ident - { - /* this is only supported for compatibility */ - $$ = cat_str(3, mm_strdup("/* declare statement"), $3, mm_strdup("*/")); - } - ; + { + /* this is only supported for compatibility */ + $$ = cat_str(3, mm_strdup("/* declare statement"), $3, mm_strdup("*/")); + } + ; /* * the exec sql disconnect statement: disconnect from the given database */ -ECPGDisconnect: SQL_DISCONNECT dis_name { $$ = $2; } - ; +ECPGDisconnect: SQL_DISCONNECT dis_name + { + $$ = $2; + } + ; -dis_name: connection_object { $$ = $1; } - | CURRENT_P { $$ = mm_strdup("\"CURRENT\""); } - | ALL { $$ = mm_strdup("\"ALL\""); } - | /* EMPTY */ { $$ = mm_strdup("\"CURRENT\""); } - ; +dis_name: connection_object + { + $$ = $1; + } + | CURRENT_P + { + $$ = mm_strdup("\"CURRENT\""); + } + | ALL + { + $$ = mm_strdup("\"ALL\""); + } + | /* EMPTY */ + { + $$ = mm_strdup("\"CURRENT\""); + } + ; -connection_object: name { $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); } - | DEFAULT { $$ = mm_strdup("\"DEFAULT\""); } - | char_variable { $$ = $1; } - ; +connection_object: name + { + $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); + } + | DEFAULT + { + $$ = mm_strdup("\"DEFAULT\""); + } + | char_variable + { + $$ = $1; + } + ; execstring: char_variable - { $$ = $1; } - | CSTRING - { $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); } - ; + { + $$ = $1; + } + | CSTRING + { + $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); + } + ; /* * the exec sql free command to deallocate a previously * prepared statement */ -ECPGFree: SQL_FREE cursor_name { $$ = $2; } - | SQL_FREE ALL { $$ = mm_strdup("all"); } - ; +ECPGFree: SQL_FREE cursor_name + { + $$ = $2; + } + | SQL_FREE ALL + { + $$ = mm_strdup("all"); + } + ; /* * open is an open cursor, at the moment this has to be removed */ ECPGOpen: SQL_OPEN cursor_name opt_ecpg_using - { - if ($2[0] == ':') - remove_variable_from_list(&argsinsert, find_variable($2 + 1)); - $$ = $2; - } - ; + { + if ($2[0] == ':') + remove_variable_from_list(&argsinsert, find_variable($2 + 1)); + $$ = $2; + } + ; -opt_ecpg_using: /*EMPTY*/ { $$ = EMPTY; } - | ecpg_using { $$ = $1; } - ; +opt_ecpg_using: /* EMPTY */ + { + $$ = EMPTY; + } + | ecpg_using + { + $$ = $1; + } + ; -ecpg_using: USING using_list { $$ = EMPTY; } - | using_descriptor { $$ = $1; } - ; +ecpg_using: USING using_list + { + $$ = EMPTY; + } + | using_descriptor + { + $$ = $1; + } + ; using_descriptor: USING SQL_P SQL_DESCRIPTOR quoted_ident_stringvar - { - add_variable_to_head(&argsinsert, descriptor_variable($4,0), &no_indicator); - $$ = EMPTY; - } - | USING SQL_DESCRIPTOR name - { - add_variable_to_head(&argsinsert, sqlda_variable($3), &no_indicator); - $$ = EMPTY; - } - ; + { + add_variable_to_head(&argsinsert, descriptor_variable($4, 0), &no_indicator); + $$ = EMPTY; + } + | USING SQL_DESCRIPTOR name + { + add_variable_to_head(&argsinsert, sqlda_variable($3), &no_indicator); + $$ = EMPTY; + } + ; into_descriptor: INTO SQL_P SQL_DESCRIPTOR quoted_ident_stringvar - { - add_variable_to_head(&argsresult, descriptor_variable($4,1), &no_indicator); - $$ = EMPTY; - } - | INTO SQL_DESCRIPTOR name - { - add_variable_to_head(&argsresult, sqlda_variable($3), &no_indicator); - $$ = EMPTY; - } - ; + { + add_variable_to_head(&argsresult, descriptor_variable($4, 1), &no_indicator); + $$ = EMPTY; + } + | INTO SQL_DESCRIPTOR name + { + add_variable_to_head(&argsresult, sqlda_variable($3), &no_indicator); + $$ = EMPTY; + } + ; into_sqlda: INTO name - { - add_variable_to_head(&argsresult, sqlda_variable($2), &no_indicator); - $$ = EMPTY; - } - ; + { + add_variable_to_head(&argsresult, sqlda_variable($2), &no_indicator); + $$ = EMPTY; + } + ; -using_list: UsingValue | UsingValue ',' using_list; +using_list: UsingValue | UsingValue ',' using_list + ; UsingValue: UsingConst - { - char *length = mm_alloc(32); + { + char *length = mm_alloc(32); - sprintf(length, "%zu", strlen($1)); - add_variable_to_head(&argsinsert, new_variable($1, ECPGmake_simple_type(ECPGt_const, length, 0), 0), &no_indicator); - } - | civar { $$ = EMPTY; } - | civarind { $$ = EMPTY; } - ; - -UsingConst: Iconst { $$ = $1; } - | '+' Iconst { $$ = cat_str(2, mm_strdup("+"), $2); } - | '-' Iconst { $$ = cat_str(2, mm_strdup("-"), $2); } - | ecpg_fconst { $$ = $1; } - | '+' ecpg_fconst { $$ = cat_str(2, mm_strdup("+"), $2); } - | '-' ecpg_fconst { $$ = cat_str(2, mm_strdup("-"), $2); } - | ecpg_sconst { $$ = $1; } - | ecpg_bconst { $$ = $1; } - | ecpg_xconst { $$ = $1; } - ; + sprintf(length, "%zu", strlen($1)); + add_variable_to_head(&argsinsert, new_variable($1, ECPGmake_simple_type(ECPGt_const, length, 0), 0), &no_indicator); + } + | civar + { + $$ = EMPTY; + } + | civarind + { + $$ = EMPTY; + } + ; + +UsingConst: Iconst + { + $$ = $1; + } + | '+' Iconst + { + $$ = cat_str(2, mm_strdup("+"), $2); + } + | '-' Iconst + { + $$ = cat_str(2, mm_strdup("-"), $2); + } + | ecpg_fconst + { + $$ = $1; + } + | '+' ecpg_fconst + { + $$ = cat_str(2, mm_strdup("+"), $2); + } + | '-' ecpg_fconst + { + $$ = cat_str(2, mm_strdup("-"), $2); + } + | ecpg_sconst + { + $$ = $1; + } + | ecpg_bconst + { + $$ = $1; + } + | ecpg_xconst + { + $$ = $1; + } + ; /* * We accept DESCRIBE [OUTPUT] but do nothing with DESCRIBE INPUT so far. @@ -1223,6 +1503,7 @@ ECPGDescribe: SQL_DESCRIBE INPUT_P prepared_name using_descriptor | SQL_DESCRIBE opt_output prepared_name using_descriptor { struct variable *var; + var = argsinsert->variable; remove_variable_from_list(&argsinsert, var); add_variable_to_head(&argsresult, var, &no_indicator); @@ -1247,8 +1528,14 @@ ECPGDescribe: SQL_DESCRIBE INPUT_P prepared_name using_descriptor } ; -opt_output: SQL_OUTPUT { $$ = mm_strdup("output"); } - | /* EMPTY */ { $$ = EMPTY; } +opt_output: SQL_OUTPUT + { + $$ = mm_strdup("output"); + } + | /* EMPTY */ + { + $$ = EMPTY; + } ; /* @@ -1261,425 +1548,465 @@ opt_output: SQL_OUTPUT { $$ = mm_strdup("output"); } * allocate a descriptor */ ECPGAllocateDescr: SQL_ALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar - { - add_descriptor($3,connection); - $$ = $3; - } - ; + { + add_descriptor($3, connection); + $$ = $3; + } + ; /* * deallocate a descriptor */ -ECPGDeallocateDescr: DEALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar - { - drop_descriptor($3,connection); - $$ = $3; - } - ; +ECPGDeallocateDescr: DEALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar + { + drop_descriptor($3, connection); + $$ = $3; + } + ; /* * manipulate a descriptor header */ ECPGGetDescriptorHeader: SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar ECPGGetDescHeaderItems - { $$ = $3; } - ; + { + $$ = $3; + } + ; ECPGGetDescHeaderItems: ECPGGetDescHeaderItem - | ECPGGetDescHeaderItems ',' ECPGGetDescHeaderItem - ; + | ECPGGetDescHeaderItems ',' ECPGGetDescHeaderItem + ; ECPGGetDescHeaderItem: cvariable '=' desc_header_item - { push_assignment($1, $3); } - ; - + { + push_assignment($1, $3); + } + ; ECPGSetDescriptorHeader: SET SQL_DESCRIPTOR quoted_ident_stringvar ECPGSetDescHeaderItems - { $$ = $3; } - ; + { + $$ = $3; + } + ; ECPGSetDescHeaderItems: ECPGSetDescHeaderItem - | ECPGSetDescHeaderItems ',' ECPGSetDescHeaderItem - ; + | ECPGSetDescHeaderItems ',' ECPGSetDescHeaderItem + ; ECPGSetDescHeaderItem: desc_header_item '=' IntConstVar - { - push_assignment($3, $1); - } - ; + { + push_assignment($3, $1); + } + ; IntConstVar: Iconst - { - char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); + { + char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); - sprintf(length, "%zu", strlen($1)); - new_variable($1, ECPGmake_simple_type(ECPGt_const, length, 0), 0); - $$ = $1; - } - | cvariable - { - $$ = $1; - } - ; + sprintf(length, "%zu", strlen($1)); + new_variable($1, ECPGmake_simple_type(ECPGt_const, length, 0), 0); + $$ = $1; + } + | cvariable + { + $$ = $1; + } + ; -desc_header_item: SQL_COUNT { $$ = ECPGd_count; } - ; +desc_header_item: SQL_COUNT + { + $$ = ECPGd_count; + } + ; /* * manipulate a descriptor */ -ECPGGetDescriptor: SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar VALUE_P IntConstVar ECPGGetDescItems - { $$.str = $5; $$.name = $3; } - ; +ECPGGetDescriptor: SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar VALUE_P IntConstVar ECPGGetDescItems + { + $$.str = $5; + $$.name = $3; + } + ; ECPGGetDescItems: ECPGGetDescItem - | ECPGGetDescItems ',' ECPGGetDescItem - ; - -ECPGGetDescItem: cvariable '=' descriptor_item { push_assignment($1, $3); }; + | ECPGGetDescItems ',' ECPGGetDescItem + ; +ECPGGetDescItem: cvariable '=' descriptor_item + { + push_assignment($1, $3); + } + ; -ECPGSetDescriptor: SET SQL_DESCRIPTOR quoted_ident_stringvar VALUE_P IntConstVar ECPGSetDescItems - { $$.str = $5; $$.name = $3; } - ; +ECPGSetDescriptor: SET SQL_DESCRIPTOR quoted_ident_stringvar VALUE_P IntConstVar ECPGSetDescItems + { + $$.str = $5; + $$.name = $3; + } + ; ECPGSetDescItems: ECPGSetDescItem - | ECPGSetDescItems ',' ECPGSetDescItem - ; + | ECPGSetDescItems ',' ECPGSetDescItem + ; ECPGSetDescItem: descriptor_item '=' AllConstVar - { - push_assignment($3, $1); - } - ; + { + push_assignment($3, $1); + } + ; AllConstVar: ecpg_fconst - { - char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); - - sprintf(length, "%zu", strlen($1)); - new_variable($1, ECPGmake_simple_type(ECPGt_const, length, 0), 0); - $$ = $1; - } - - | IntConstVar - { - $$ = $1; - } - - | '-' ecpg_fconst - { - char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); - char *var = cat2_str(mm_strdup("-"), $2); + { + char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); - sprintf(length, "%zu", strlen(var)); - new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0); - $$ = var; - } + sprintf(length, "%zu", strlen($1)); + new_variable($1, ECPGmake_simple_type(ECPGt_const, length, 0), 0); + $$ = $1; + } + | IntConstVar + { + $$ = $1; + } + | '-' ecpg_fconst + { + char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); + char *var = cat2_str(mm_strdup("-"), $2); - | '-' Iconst - { - char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); - char *var = cat2_str(mm_strdup("-"), $2); + sprintf(length, "%zu", strlen(var)); + new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0); + $$ = var; + } + | '-' Iconst + { + char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); + char *var = cat2_str(mm_strdup("-"), $2); - sprintf(length, "%zu", strlen(var)); - new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0); - $$ = var; - } + sprintf(length, "%zu", strlen(var)); + new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0); + $$ = var; + } + | ecpg_sconst + { + char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); + char *var = $1 + 1; - | ecpg_sconst - { - char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); - char *var = $1 + 1; + var[strlen(var) - 1] = '\0'; + sprintf(length, "%zu", strlen(var)); + new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0); + $$ = var; + } + ; - var[strlen(var) - 1] = '\0'; - sprintf(length, "%zu", strlen(var)); - new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0); - $$ = var; - } - ; - -descriptor_item: SQL_CARDINALITY { $$ = ECPGd_cardinality; } - | DATA_P { $$ = ECPGd_data; } - | SQL_DATETIME_INTERVAL_CODE { $$ = ECPGd_di_code; } - | SQL_DATETIME_INTERVAL_PRECISION { $$ = ECPGd_di_precision; } - | SQL_INDICATOR { $$ = ECPGd_indicator; } - | SQL_KEY_MEMBER { $$ = ECPGd_key_member; } - | SQL_LENGTH { $$ = ECPGd_length; } - | NAME_P { $$ = ECPGd_name; } - | SQL_NULLABLE { $$ = ECPGd_nullable; } - | SQL_OCTET_LENGTH { $$ = ECPGd_octet; } - | PRECISION { $$ = ECPGd_precision; } - | SQL_RETURNED_LENGTH { $$ = ECPGd_length; } - | SQL_RETURNED_OCTET_LENGTH { $$ = ECPGd_ret_octet; } - | SQL_SCALE { $$ = ECPGd_scale; } - | TYPE_P { $$ = ECPGd_type; } - ; +descriptor_item: SQL_CARDINALITY { $$ = ECPGd_cardinality; } + | DATA_P { $$ = ECPGd_data; } + | SQL_DATETIME_INTERVAL_CODE { $$ = ECPGd_di_code; } + | SQL_DATETIME_INTERVAL_PRECISION { $$ = ECPGd_di_precision; } + | SQL_INDICATOR { $$ = ECPGd_indicator; } + | SQL_KEY_MEMBER { $$ = ECPGd_key_member; } + | SQL_LENGTH { $$ = ECPGd_length; } + | NAME_P { $$ = ECPGd_name; } + | SQL_NULLABLE { $$ = ECPGd_nullable; } + | SQL_OCTET_LENGTH { $$ = ECPGd_octet; } + | PRECISION { $$ = ECPGd_precision; } + | SQL_RETURNED_LENGTH { $$ = ECPGd_length; } + | SQL_RETURNED_OCTET_LENGTH { $$ = ECPGd_ret_octet; } + | SQL_SCALE { $$ = ECPGd_scale; } + | TYPE_P { $$ = ECPGd_type; } + ; /* * set/reset the automatic transaction mode, this needs a different handling * as the other set commands */ -ECPGSetAutocommit: SET SQL_AUTOCOMMIT '=' on_off { $$ = $4; } - | SET SQL_AUTOCOMMIT TO on_off { $$ = $4; } - ; +ECPGSetAutocommit: SET SQL_AUTOCOMMIT '=' on_off + { + $$ = $4; + } + | SET SQL_AUTOCOMMIT TO on_off + { + $$ = $4; + } + ; -on_off: ON { $$ = mm_strdup("on"); } - | OFF { $$ = mm_strdup("off"); } - ; +on_off: ON + { + $$ = mm_strdup("on"); + } + | OFF + { + $$ = mm_strdup("off"); + } + ; /* * set the actual connection, this needs a different handling as the other * set commands */ -ECPGSetConnection: SET CONNECTION TO connection_object { $$ = $4; } - | SET CONNECTION '=' connection_object { $$ = $4; } - | SET CONNECTION connection_object { $$ = $3; } - ; +ECPGSetConnection: SET CONNECTION TO connection_object + { + $$ = $4; + } + | SET CONNECTION '=' connection_object + { + $$ = $4; + } + | SET CONNECTION connection_object + { + $$ = $3; + } + ; /* * define a new type for embedded SQL */ ECPGTypedef: TYPE_P - { - /* reset this variable so we see if there was */ - /* an initializer specified */ - initializer = 0; - } - ECPGColLabel IS var_type opt_array_bounds opt_reference - { - add_typedef($3, $6.index1, $6.index2, $5.type_enum, $5.type_dimension, $5.type_index, initializer, *$7 ? 1 :0); + { + /* reset this variable so we see if there was */ + /* an initializer specified */ + initializer = 0; + } + ECPGColLabel IS var_type opt_array_bounds opt_reference + { + add_typedef($3, $6.index1, $6.index2, $5.type_enum, $5.type_dimension, $5.type_index, initializer, *$7 ? 1 : 0); - if (auto_create_c == false) - $$ = cat_str(7, mm_strdup("/* exec sql type"), mm_strdup($3), mm_strdup("is"), mm_strdup($5.type_str), mm_strdup($6.str),$7, mm_strdup("*/")); - else - $$ = cat_str(6, mm_strdup("typedef "), mm_strdup($5.type_str), *$7?mm_strdup("*"):mm_strdup(""), mm_strdup($3),mm_strdup($6.str), mm_strdup(";")); - } - ; + if (auto_create_c == false) + $$ = cat_str(7, mm_strdup("/* exec sql type"), mm_strdup($3), mm_strdup("is"), mm_strdup($5.type_str), mm_strdup($6.str),$7, mm_strdup("*/")); + else + $$ = cat_str(6, mm_strdup("typedef "), mm_strdup($5.type_str), *$7 ? mm_strdup("*") : mm_strdup(""), mm_strdup($3),mm_strdup($6.str), mm_strdup(";")); + } + ; -opt_reference: SQL_REFERENCE { $$ = mm_strdup("reference"); } - | /*EMPTY*/ { $$ = EMPTY; } - ; +opt_reference: SQL_REFERENCE + { + $$ = mm_strdup("reference"); + } + | /* EMPTY */ + { + $$ = EMPTY; + } + ; /* * define the type of one variable for embedded SQL */ ECPGVar: SQL_VAR + { + /* reset this variable so we see if there was */ + /* an initializer specified */ + initializer = 0; + } + ColLabel IS var_type opt_array_bounds opt_reference + { + struct variable *p = find_variable($3); + char *dimension = $6.index1; + char *length = $6.index2; + struct ECPGtype *type; + + if (($5.type_enum == ECPGt_struct || + $5.type_enum == ECPGt_union) && + initializer == 1) + mmerror(PARSE_ERROR, ET_ERROR, "initializer not allowed in EXEC SQL VAR command"); + else { - /* reset this variable so we see if there was */ - /* an initializer specified */ - initializer = 0; - } - ColLabel IS var_type opt_array_bounds opt_reference - { - struct variable *p = find_variable($3); - char *dimension = $6.index1; - char *length = $6.index2; - struct ECPGtype * type; - - if (($5.type_enum == ECPGt_struct || - $5.type_enum == ECPGt_union) && - initializer == 1) - mmerror(PARSE_ERROR, ET_ERROR, "initializer not allowed in EXEC SQL VAR command"); - else - { - adjust_array($5.type_enum, &dimension, &length, $5.type_dimension, $5.type_index, *$7?1:0, false); + adjust_array($5.type_enum, &dimension, &length, $5.type_dimension, $5.type_index, *$7 ? 1 : 0, false); - switch ($5.type_enum) - { + switch ($5.type_enum) + { case ECPGt_struct: case ECPGt_union: - if (atoi(dimension) < 0) - type = ECPGmake_struct_type(struct_member_list[struct_level], $5.type_enum, $5.type_str, $5.type_sizeof); - else - type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level], $5.type_enum,$5.type_str, $5.type_sizeof), dimension); - break; + if (atoi(dimension) < 0) + type = ECPGmake_struct_type(struct_member_list[struct_level], $5.type_enum, $5.type_str, $5.type_sizeof); + else + type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level], $5.type_enum,$5.type_str, $5.type_sizeof), dimension); + break; case ECPGt_varchar: case ECPGt_bytea: - if (atoi(dimension) == -1) - type = ECPGmake_simple_type($5.type_enum, length, 0); - else - type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, length, 0), dimension); - break; + if (atoi(dimension) == -1) + type = ECPGmake_simple_type($5.type_enum, length, 0); + else + type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, length, 0), dimension); + break; case ECPGt_char: case ECPGt_unsigned_char: case ECPGt_string: - if (atoi(dimension) == -1) - type = ECPGmake_simple_type($5.type_enum, length, 0); - else - type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, length, 0), dimension); - break; + if (atoi(dimension) == -1) + type = ECPGmake_simple_type($5.type_enum, length, 0); + else + type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, length, 0), dimension); + break; default: - if (atoi(length) >= 0) - mmerror(PARSE_ERROR, ET_ERROR, "multidimensional arrays for simple data types are not supported"); - - if (atoi(dimension) < 0) - type = ECPGmake_simple_type($5.type_enum, mm_strdup("1"), 0); - else - type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, mm_strdup("1"), 0), dimension); - break; - } + if (atoi(length) >= 0) + mmerror(PARSE_ERROR, ET_ERROR, "multidimensional arrays for simple data types are not supported"); - ECPGfree_type(p->type); - p->type = type; + if (atoi(dimension) < 0) + type = ECPGmake_simple_type($5.type_enum, mm_strdup("1"), 0); + else + type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, mm_strdup("1"), 0), dimension); + break; } - $$ = cat_str(7, mm_strdup("/* exec sql var"), mm_strdup($3), mm_strdup("is"), mm_strdup($5.type_str), mm_strdup($6.str),$7, mm_strdup("*/")); + ECPGfree_type(p->type); + p->type = type; } - ; + + $$ = cat_str(7, mm_strdup("/* exec sql var"), mm_strdup($3), mm_strdup("is"), mm_strdup($5.type_str),mm_strdup($6.str), $7, mm_strdup("*/")); + } + ; /* * whenever statement: decide what to do in case of error/no data found * according to SQL standards we lack: SQLSTATE, CONSTRAINT and SQLEXCEPTION */ ECPGWhenever: SQL_WHENEVER SQL_SQLERROR action - { - when_error.code = $<action>3.code; - when_error.command = $<action>3.command; - $$ = cat_str(3, mm_strdup("/* exec sql whenever sqlerror "), $3.str, mm_strdup("; */")); - } - | SQL_WHENEVER NOT SQL_FOUND action - { - when_nf.code = $<action>4.code; - when_nf.command = $<action>4.command; - $$ = cat_str(3, mm_strdup("/* exec sql whenever not found "), $4.str, mm_strdup("; */")); - } - | SQL_WHENEVER SQL_SQLWARNING action - { - when_warn.code = $<action>3.code; - when_warn.command = $<action>3.command; - $$ = cat_str(3, mm_strdup("/* exec sql whenever sql_warning "), $3.str, mm_strdup("; */")); - } - ; + { + when_error.code = $<action>3.code; + when_error.command = $<action>3.command; + $$ = cat_str(3, mm_strdup("/* exec sql whenever sqlerror "), $3.str, mm_strdup("; */")); + } + | SQL_WHENEVER NOT SQL_FOUND action + { + when_nf.code = $<action>4.code; + when_nf.command = $<action>4.command; + $$ = cat_str(3, mm_strdup("/* exec sql whenever not found "), $4.str, mm_strdup("; */")); + } + | SQL_WHENEVER SQL_SQLWARNING action + { + when_warn.code = $<action>3.code; + when_warn.command = $<action>3.command; + $$ = cat_str(3, mm_strdup("/* exec sql whenever sql_warning "), $3.str, mm_strdup("; */")); + } + ; -action : CONTINUE_P - { - $<action>$.code = W_NOTHING; - $<action>$.command = NULL; - $<action>$.str = mm_strdup("continue"); - } - | SQL_SQLPRINT - { - $<action>$.code = W_SQLPRINT; - $<action>$.command = NULL; - $<action>$.str = mm_strdup("sqlprint"); - } - | SQL_STOP - { - $<action>$.code = W_STOP; - $<action>$.command = NULL; - $<action>$.str = mm_strdup("stop"); - } - | SQL_GOTO name - { - $<action>$.code = W_GOTO; - $<action>$.command = mm_strdup($2); - $<action>$.str = cat2_str(mm_strdup("goto "), $2); - } - | SQL_GO TO name - { - $<action>$.code = W_GOTO; - $<action>$.command = mm_strdup($3); - $<action>$.str = cat2_str(mm_strdup("goto "), $3); - } - | DO name '(' c_args ')' - { - $<action>$.code = W_DO; - $<action>$.command = cat_str(4, $2, mm_strdup("("), $4, mm_strdup(")")); - $<action>$.str = cat2_str(mm_strdup("do"), mm_strdup($<action>$.command)); - } - | DO SQL_BREAK - { - $<action>$.code = W_BREAK; - $<action>$.command = NULL; - $<action>$.str = mm_strdup("break"); - } - | DO CONTINUE_P - { - $<action>$.code = W_CONTINUE; - $<action>$.command = NULL; - $<action>$.str = mm_strdup("continue"); - } - | CALL name '(' c_args ')' - { - $<action>$.code = W_DO; - $<action>$.command = cat_str(4, $2, mm_strdup("("), $4, mm_strdup(")")); - $<action>$.str = cat2_str(mm_strdup("call"), mm_strdup($<action>$.command)); - } - | CALL name - { - $<action>$.code = W_DO; - $<action>$.command = cat2_str($2, mm_strdup("()")); - $<action>$.str = cat2_str(mm_strdup("call"), mm_strdup($<action>$.command)); - } - ; +action: CONTINUE_P + { + $<action>$.code = W_NOTHING; + $<action>$.command = NULL; + $<action>$.str = mm_strdup("continue"); + } + | SQL_SQLPRINT + { + $<action>$.code = W_SQLPRINT; + $<action>$.command = NULL; + $<action>$.str = mm_strdup("sqlprint"); + } + | SQL_STOP + { + $<action>$.code = W_STOP; + $<action>$.command = NULL; + $<action>$.str = mm_strdup("stop"); + } + | SQL_GOTO name + { + $<action>$.code = W_GOTO; + $<action>$.command = mm_strdup($2); + $<action>$.str = cat2_str(mm_strdup("goto "), $2); + } + | SQL_GO TO name + { + $<action>$.code = W_GOTO; + $<action>$.command = mm_strdup($3); + $<action>$.str = cat2_str(mm_strdup("goto "), $3); + } + | DO name '(' c_args ')' + { + $<action>$.code = W_DO; + $<action>$.command = cat_str(4, $2, mm_strdup("("), $4, mm_strdup(")")); + $<action>$.str = cat2_str(mm_strdup("do"), mm_strdup($<action>$.command)); + } + | DO SQL_BREAK + { + $<action>$.code = W_BREAK; + $<action>$.command = NULL; + $<action>$.str = mm_strdup("break"); + } + | DO CONTINUE_P + { + $<action>$.code = W_CONTINUE; + $<action>$.command = NULL; + $<action>$.str = mm_strdup("continue"); + } + | CALL name '(' c_args ')' + { + $<action>$.code = W_DO; + $<action>$.command = cat_str(4, $2, mm_strdup("("), $4, mm_strdup(")")); + $<action>$.str = cat2_str(mm_strdup("call"), mm_strdup($<action>$.command)); + } + | CALL name + { + $<action>$.code = W_DO; + $<action>$.command = cat2_str($2, mm_strdup("()")); + $<action>$.str = cat2_str(mm_strdup("call"), mm_strdup($<action>$.command)); + } + ; /* some other stuff for ecpg */ /* additional unreserved keywords */ -ECPGKeywords: ECPGKeywords_vanames { $$ = $1; } - | ECPGKeywords_rest { $$ = $1; } - ; - -ECPGKeywords_vanames: SQL_BREAK { $$ = mm_strdup("break"); } - | SQL_CARDINALITY { $$ = mm_strdup("cardinality"); } - | SQL_COUNT { $$ = mm_strdup("count"); } - | SQL_DATETIME_INTERVAL_CODE { $$ = mm_strdup("datetime_interval_code"); } - | SQL_DATETIME_INTERVAL_PRECISION { $$ = mm_strdup("datetime_interval_precision"); } - | SQL_FOUND { $$ = mm_strdup("found"); } - | SQL_GO { $$ = mm_strdup("go"); } - | SQL_GOTO { $$ = mm_strdup("goto"); } - | SQL_IDENTIFIED { $$ = mm_strdup("identified"); } - | SQL_INDICATOR { $$ = mm_strdup("indicator"); } - | SQL_KEY_MEMBER { $$ = mm_strdup("key_member"); } - | SQL_LENGTH { $$ = mm_strdup("length"); } - | SQL_NULLABLE { $$ = mm_strdup("nullable"); } - | SQL_OCTET_LENGTH { $$ = mm_strdup("octet_length"); } - | SQL_RETURNED_LENGTH { $$ = mm_strdup("returned_length"); } - | SQL_RETURNED_OCTET_LENGTH { $$ = mm_strdup("returned_octet_length"); } - | SQL_SCALE { $$ = mm_strdup("scale"); } - | SQL_SECTION { $$ = mm_strdup("section"); } - | SQL_SQLERROR { $$ = mm_strdup("sqlerror"); } - | SQL_SQLPRINT { $$ = mm_strdup("sqlprint"); } - | SQL_SQLWARNING { $$ = mm_strdup("sqlwarning"); } - | SQL_STOP { $$ = mm_strdup("stop"); } - ; - -ECPGKeywords_rest: SQL_CONNECT { $$ = mm_strdup("connect"); } - | SQL_DESCRIBE { $$ = mm_strdup("describe"); } - | SQL_DISCONNECT { $$ = mm_strdup("disconnect"); } - | SQL_OPEN { $$ = mm_strdup("open"); } - | SQL_VAR { $$ = mm_strdup("var"); } - | SQL_WHENEVER { $$ = mm_strdup("whenever"); } - ; +ECPGKeywords: ECPGKeywords_vanames { $$ = $1; } + | ECPGKeywords_rest { $$ = $1; } + ; + +ECPGKeywords_vanames: SQL_BREAK { $$ = mm_strdup("break"); } + | SQL_CARDINALITY { $$ = mm_strdup("cardinality"); } + | SQL_COUNT { $$ = mm_strdup("count"); } + | SQL_DATETIME_INTERVAL_CODE { $$ = mm_strdup("datetime_interval_code"); } + | SQL_DATETIME_INTERVAL_PRECISION { $$ = mm_strdup("datetime_interval_precision"); } + | SQL_FOUND { $$ = mm_strdup("found"); } + | SQL_GO { $$ = mm_strdup("go"); } + | SQL_GOTO { $$ = mm_strdup("goto"); } + | SQL_IDENTIFIED { $$ = mm_strdup("identified"); } + | SQL_INDICATOR { $$ = mm_strdup("indicator"); } + | SQL_KEY_MEMBER { $$ = mm_strdup("key_member"); } + | SQL_LENGTH { $$ = mm_strdup("length"); } + | SQL_NULLABLE { $$ = mm_strdup("nullable"); } + | SQL_OCTET_LENGTH { $$ = mm_strdup("octet_length"); } + | SQL_RETURNED_LENGTH { $$ = mm_strdup("returned_length"); } + | SQL_RETURNED_OCTET_LENGTH { $$ = mm_strdup("returned_octet_length"); } + | SQL_SCALE { $$ = mm_strdup("scale"); } + | SQL_SECTION { $$ = mm_strdup("section"); } + | SQL_SQLERROR { $$ = mm_strdup("sqlerror"); } + | SQL_SQLPRINT { $$ = mm_strdup("sqlprint"); } + | SQL_SQLWARNING { $$ = mm_strdup("sqlwarning"); } + | SQL_STOP { $$ = mm_strdup("stop"); } + ; + +ECPGKeywords_rest: SQL_CONNECT { $$ = mm_strdup("connect"); } + | SQL_DESCRIBE { $$ = mm_strdup("describe"); } + | SQL_DISCONNECT { $$ = mm_strdup("disconnect"); } + | SQL_OPEN { $$ = mm_strdup("open"); } + | SQL_VAR { $$ = mm_strdup("var"); } + | SQL_WHENEVER { $$ = mm_strdup("whenever"); } + ; /* additional keywords that can be SQL type names (but not ECPGColLabels) */ -ECPGTypeName: SQL_BOOL { $$ = mm_strdup("bool"); } - | SQL_LONG { $$ = mm_strdup("long"); } - | SQL_OUTPUT { $$ = mm_strdup("output"); } - | SQL_SHORT { $$ = mm_strdup("short"); } - | SQL_STRUCT { $$ = mm_strdup("struct"); } - | SQL_SIGNED { $$ = mm_strdup("signed"); } - | SQL_UNSIGNED { $$ = mm_strdup("unsigned"); } - ; - -symbol: ColLabel { $$ = $1; } - ; - -ECPGColId: ecpg_ident { $$ = $1; } - | unreserved_keyword { $$ = $1; } - | col_name_keyword { $$ = $1; } - | ECPGunreserved_interval { $$ = $1; } - | ECPGKeywords { $$ = $1; } - | ECPGCKeywords { $$ = $1; } - | CHAR_P { $$ = mm_strdup("char"); } - | VALUES { $$ = mm_strdup("values"); } - ; +ECPGTypeName: SQL_BOOL { $$ = mm_strdup("bool"); } + | SQL_LONG { $$ = mm_strdup("long"); } + | SQL_OUTPUT { $$ = mm_strdup("output"); } + | SQL_SHORT { $$ = mm_strdup("short"); } + | SQL_STRUCT { $$ = mm_strdup("struct"); } + | SQL_SIGNED { $$ = mm_strdup("signed"); } + | SQL_UNSIGNED { $$ = mm_strdup("unsigned"); } + ; + +symbol: ColLabel { $$ = $1; } + ; + +ECPGColId: ecpg_ident { $$ = $1; } + | unreserved_keyword { $$ = $1; } + | col_name_keyword { $$ = $1; } + | ECPGunreserved_interval { $$ = $1; } + | ECPGKeywords { $$ = $1; } + | ECPGCKeywords { $$ = $1; } + | CHAR_P { $$ = mm_strdup("char"); } + | VALUES { $$ = mm_strdup("values"); } + ; /* * Name classification hierarchy. @@ -1691,59 +2018,59 @@ ECPGColId: ecpg_ident { $$ = $1; } /* Column identifier --- names that can be column, table, etc names. */ -ColId: ecpg_ident { $$ = $1; } - | all_unreserved_keyword { $$ = $1; } - | col_name_keyword { $$ = $1; } - | ECPGKeywords { $$ = $1; } - | ECPGCKeywords { $$ = $1; } - | CHAR_P { $$ = mm_strdup("char"); } - | VALUES { $$ = mm_strdup("values"); } - ; +ColId: ecpg_ident { $$ = $1; } + | all_unreserved_keyword { $$ = $1; } + | col_name_keyword { $$ = $1; } + | ECPGKeywords { $$ = $1; } + | ECPGCKeywords { $$ = $1; } + | CHAR_P { $$ = mm_strdup("char"); } + | VALUES { $$ = mm_strdup("values"); } + ; /* Type/function identifier --- names that can be type or function names. */ -type_function_name: ecpg_ident { $$ = $1; } - | all_unreserved_keyword { $$ = $1; } - | type_func_name_keyword { $$ = $1; } - | ECPGKeywords { $$ = $1; } - | ECPGCKeywords { $$ = $1; } - | ECPGTypeName { $$ = $1; } - ; +type_function_name: ecpg_ident { $$ = $1; } + | all_unreserved_keyword { $$ = $1; } + | type_func_name_keyword { $$ = $1; } + | ECPGKeywords { $$ = $1; } + | ECPGCKeywords { $$ = $1; } + | ECPGTypeName { $$ = $1; } + ; /* Column label --- allowed labels in "AS" clauses. * This presently includes *all* Postgres keywords. */ -ColLabel: ECPGColLabel { $$ = $1; } - | ECPGTypeName { $$ = $1; } - | CHAR_P { $$ = mm_strdup("char"); } - | CURRENT_P { $$ = mm_strdup("current"); } - | INPUT_P { $$ = mm_strdup("input"); } - | INT_P { $$ = mm_strdup("int"); } - | TO { $$ = mm_strdup("to"); } - | UNION { $$ = mm_strdup("union"); } - | VALUES { $$ = mm_strdup("values"); } - | ECPGCKeywords { $$ = $1; } - | ECPGunreserved_interval { $$ = $1; } - ; - -ECPGColLabel: ecpg_ident { $$ = $1; } - | unreserved_keyword { $$ = $1; } - | col_name_keyword { $$ = $1; } - | type_func_name_keyword { $$ = $1; } - | reserved_keyword { $$ = $1; } - | ECPGKeywords_vanames { $$ = $1; } - | ECPGKeywords_rest { $$ = $1; } - | CONNECTION { $$ = mm_strdup("connection"); } - ; - -ECPGCKeywords: S_AUTO { $$ = mm_strdup("auto"); } - | S_CONST { $$ = mm_strdup("const"); } - | S_EXTERN { $$ = mm_strdup("extern"); } - | S_REGISTER { $$ = mm_strdup("register"); } - | S_STATIC { $$ = mm_strdup("static"); } - | S_TYPEDEF { $$ = mm_strdup("typedef"); } - | S_VOLATILE { $$ = mm_strdup("volatile"); } - ; +ColLabel: ECPGColLabel { $$ = $1; } + | ECPGTypeName { $$ = $1; } + | CHAR_P { $$ = mm_strdup("char"); } + | CURRENT_P { $$ = mm_strdup("current"); } + | INPUT_P { $$ = mm_strdup("input"); } + | INT_P { $$ = mm_strdup("int"); } + | TO { $$ = mm_strdup("to"); } + | UNION { $$ = mm_strdup("union"); } + | VALUES { $$ = mm_strdup("values"); } + | ECPGCKeywords { $$ = $1; } + | ECPGunreserved_interval { $$ = $1; } + ; + +ECPGColLabel: ecpg_ident { $$ = $1; } + | unreserved_keyword { $$ = $1; } + | col_name_keyword { $$ = $1; } + | type_func_name_keyword { $$ = $1; } + | reserved_keyword { $$ = $1; } + | ECPGKeywords_vanames { $$ = $1; } + | ECPGKeywords_rest { $$ = $1; } + | CONNECTION { $$ = mm_strdup("connection"); } + ; + +ECPGCKeywords: S_AUTO { $$ = mm_strdup("auto"); } + | S_CONST { $$ = mm_strdup("const"); } + | S_EXTERN { $$ = mm_strdup("extern"); } + | S_REGISTER { $$ = mm_strdup("register"); } + | S_STATIC { $$ = mm_strdup("static"); } + | S_TYPEDEF { $$ = mm_strdup("typedef"); } + | S_VOLATILE { $$ = mm_strdup("volatile"); } + ; /* "Unreserved" keywords --- available for use as any kind of name. */ @@ -1760,250 +2087,402 @@ ECPGCKeywords: S_AUTO { $$ = mm_strdup("auto"); } * The mentioned exclusions are done by $replace_line settings in parse.pl. */ all_unreserved_keyword: unreserved_keyword { $$ = $1; } - | ECPGunreserved_interval { $$ = $1; } - | CONNECTION { $$ = mm_strdup("connection"); } - ; - -ECPGunreserved_interval: DAY_P { $$ = mm_strdup("day"); } - | HOUR_P { $$ = mm_strdup("hour"); } - | MINUTE_P { $$ = mm_strdup("minute"); } - | MONTH_P { $$ = mm_strdup("month"); } - | SECOND_P { $$ = mm_strdup("second"); } - | YEAR_P { $$ = mm_strdup("year"); } - ; + | ECPGunreserved_interval { $$ = $1; } + | CONNECTION { $$ = mm_strdup("connection"); } + ; +ECPGunreserved_interval: DAY_P { $$ = mm_strdup("day"); } + | HOUR_P { $$ = mm_strdup("hour"); } + | MINUTE_P { $$ = mm_strdup("minute"); } + | MONTH_P { $$ = mm_strdup("month"); } + | SECOND_P { $$ = mm_strdup("second"); } + | YEAR_P { $$ = mm_strdup("year"); } + ; -into_list : coutputvariable | into_list ',' coutputvariable - ; +into_list: coutputvariable | into_list ',' coutputvariable + ; -ecpgstart: SQL_START { - reset_variables(); - pacounter = 1; - } - ; +ecpgstart: SQL_START + { + reset_variables(); + pacounter = 1; + } + ; -c_args: /*EMPTY*/ { $$ = EMPTY; } - | c_list { $$ = $1; } - ; +c_args: /* EMPTY */ + { + $$ = EMPTY; + } + | c_list + { + $$ = $1; + } + ; coutputvariable: cvariable indicator - { add_variable_to_head(&argsresult, find_variable($1), find_variable($2)); } - | cvariable - { add_variable_to_head(&argsresult, find_variable($1), &no_indicator); } - ; + { + add_variable_to_head(&argsresult, find_variable($1), find_variable($2)); + } + | cvariable + { + add_variable_to_head(&argsresult, find_variable($1), &no_indicator); + } + ; civarind: cvariable indicator - { - if (find_variable($2)->type->type == ECPGt_array) - mmerror(PARSE_ERROR, ET_ERROR, "arrays of indicators are not allowed on input"); + { + if (find_variable($2)->type->type == ECPGt_array) + mmerror(PARSE_ERROR, ET_ERROR, "arrays of indicators are not allowed on input"); - add_variable_to_head(&argsinsert, find_variable($1), find_variable($2)); - $$ = create_questionmarks($1, false); - } - ; + add_variable_to_head(&argsinsert, find_variable($1), find_variable($2)); + $$ = create_questionmarks($1, false); + } + ; char_civar: char_variable - { - char *ptr = strstr($1, ".arr"); + { + char *ptr = strstr($1, ".arr"); - if (ptr) /* varchar, we need the struct name here, not the struct element */ - *ptr = '\0'; - add_variable_to_head(&argsinsert, find_variable($1), &no_indicator); - $$ = $1; - } - ; + if (ptr) /* varchar, we need the struct name here, not + * the struct element */ + *ptr = '\0'; + add_variable_to_head(&argsinsert, find_variable($1), &no_indicator); + $$ = $1; + } + ; civar: cvariable - { - add_variable_to_head(&argsinsert, find_variable($1), &no_indicator); - $$ = create_questionmarks($1, false); - } - ; + { + add_variable_to_head(&argsinsert, find_variable($1), &no_indicator); + $$ = create_questionmarks($1, false); + } + ; -indicator: cvariable { check_indicator((find_variable($1))->type); $$ = $1; } - | SQL_INDICATOR cvariable { check_indicator((find_variable($2))->type); $$ = $2; } - | SQL_INDICATOR name { check_indicator((find_variable($2))->type); $$ = $2; } - ; +indicator: cvariable + { + check_indicator((find_variable($1))->type); + $$ = $1; + } + | SQL_INDICATOR cvariable + { + check_indicator((find_variable($2))->type); + $$ = $2; + } + | SQL_INDICATOR name + { + check_indicator((find_variable($2))->type); + $$ = $2; + } + ; -cvariable: CVARIABLE - { - /* As long as multidimensional arrays are not implemented we have to check for those here */ - char *ptr = $1; - int brace_open=0, brace = false; +cvariable: CVARIABLE + { + /* + * As long as multidimensional arrays are not implemented we have to + * check for those here + */ + char *ptr = $1; + int brace_open = 0, + brace = false; - for (; *ptr; ptr++) + for (; *ptr; ptr++) + { + switch (*ptr) { - switch (*ptr) - { - case '[': - if (brace) - mmfatal(PARSE_ERROR, "multidimensional arrays for simple data types are not supported"); - brace_open++; - break; - case ']': - brace_open--; - if (brace_open == 0) - brace = true; - break; - case '\t': - case ' ': - break; - default: - if (brace_open == 0) - brace = false; - break; - } + case '[': + if (brace) + mmfatal(PARSE_ERROR, "multidimensional arrays for simple data types are not supported"); + brace_open++; + break; + case ']': + brace_open--; + if (brace_open == 0) + brace = true; + break; + case '\t': + case ' ': + break; + default: + if (brace_open == 0) + brace = false; + break; } - $$ = $1; } - ; + $$ = $1; + } + ; -ecpg_param: PARAM { $$ = make_name(); } ; +ecpg_param: PARAM + { + $$ = make_name(); + } + ; -ecpg_bconst: BCONST { $$ = $1; } ; +ecpg_bconst: BCONST + { + $$ = $1; + } + ; -ecpg_fconst: FCONST { $$ = make_name(); } ; +ecpg_fconst: FCONST + { + $$ = make_name(); + } + ; -ecpg_sconst: SCONST { $$ = $1; } ; +ecpg_sconst: SCONST + { + $$ = $1; + } + ; -ecpg_xconst: XCONST { $$ = $1; } ; +ecpg_xconst: XCONST + { + $$ = $1; + } + ; -ecpg_ident: IDENT { $$ = $1; } - | CSTRING { $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); } - ; +ecpg_ident: IDENT + { + $$ = $1; + } + | CSTRING + { + $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); + } + ; quoted_ident_stringvar: name - { $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); } - | char_variable - { $$ = make3_str(mm_strdup("("), $1, mm_strdup(")")); } - ; + { + $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); + } + | char_variable + { + $$ = make3_str(mm_strdup("("), $1, mm_strdup(")")); + } + ; /* * C stuff */ -c_stuff_item: c_anything { $$ = $1; } - | '(' ')' { $$ = mm_strdup("()"); } - | '(' c_stuff ')' - { $$ = cat_str(3, mm_strdup("("), $2, mm_strdup(")")); } - ; - -c_stuff: c_stuff_item { $$ = $1; } - | c_stuff c_stuff_item - { $$ = cat2_str($1, $2); } - ; - -c_list: c_term { $$ = $1; } - | c_list ',' c_term { $$ = cat_str(3, $1, mm_strdup(","), $3); } - ; - -c_term: c_stuff { $$ = $1; } - | '{' c_list '}' { $$ = cat_str(3, mm_strdup("{"), $2, mm_strdup("}")); } - ; - -c_thing: c_anything { $$ = $1; } - | '(' { $$ = mm_strdup("("); } - | ')' { $$ = mm_strdup(")"); } - | ',' { $$ = mm_strdup(","); } - | ';' { $$ = mm_strdup(";"); } - ; - -c_anything: ecpg_ident { $$ = $1; } - | Iconst { $$ = $1; } - | ecpg_fconst { $$ = $1; } - | ecpg_sconst { $$ = $1; } - | '*' { $$ = mm_strdup("*"); } - | '+' { $$ = mm_strdup("+"); } - | '-' { $$ = mm_strdup("-"); } - | '/' { $$ = mm_strdup("/"); } - | '%' { $$ = mm_strdup("%"); } - | NULL_P { $$ = mm_strdup("NULL"); } - | S_ADD { $$ = mm_strdup("+="); } - | S_AND { $$ = mm_strdup("&&"); } - | S_ANYTHING { $$ = make_name(); } - | S_AUTO { $$ = mm_strdup("auto"); } - | S_CONST { $$ = mm_strdup("const"); } - | S_DEC { $$ = mm_strdup("--"); } - | S_DIV { $$ = mm_strdup("/="); } - | S_DOTPOINT { $$ = mm_strdup(".*"); } - | S_EQUAL { $$ = mm_strdup("=="); } - | S_EXTERN { $$ = mm_strdup("extern"); } - | S_INC { $$ = mm_strdup("++"); } - | S_LSHIFT { $$ = mm_strdup("<<"); } - | S_MEMBER { $$ = mm_strdup("->"); } - | S_MEMPOINT { $$ = mm_strdup("->*"); } - | S_MOD { $$ = mm_strdup("%="); } - | S_MUL { $$ = mm_strdup("*="); } - | S_NEQUAL { $$ = mm_strdup("!="); } - | S_OR { $$ = mm_strdup("||"); } - | S_REGISTER { $$ = mm_strdup("register"); } - | S_RSHIFT { $$ = mm_strdup(">>"); } - | S_STATIC { $$ = mm_strdup("static"); } - | S_SUB { $$ = mm_strdup("-="); } - | S_TYPEDEF { $$ = mm_strdup("typedef"); } - | S_VOLATILE { $$ = mm_strdup("volatile"); } - | SQL_BOOL { $$ = mm_strdup("bool"); } - | ENUM_P { $$ = mm_strdup("enum"); } - | HOUR_P { $$ = mm_strdup("hour"); } - | INT_P { $$ = mm_strdup("int"); } - | SQL_LONG { $$ = mm_strdup("long"); } - | MINUTE_P { $$ = mm_strdup("minute"); } - | MONTH_P { $$ = mm_strdup("month"); } - | SECOND_P { $$ = mm_strdup("second"); } - | SQL_SHORT { $$ = mm_strdup("short"); } - | SQL_SIGNED { $$ = mm_strdup("signed"); } - | SQL_STRUCT { $$ = mm_strdup("struct"); } - | SQL_UNSIGNED { $$ = mm_strdup("unsigned"); } - | YEAR_P { $$ = mm_strdup("year"); } - | CHAR_P { $$ = mm_strdup("char"); } - | FLOAT_P { $$ = mm_strdup("float"); } - | TO { $$ = mm_strdup("to"); } - | UNION { $$ = mm_strdup("union"); } - | VARCHAR { $$ = mm_strdup("varchar"); } - | '[' { $$ = mm_strdup("["); } - | ']' { $$ = mm_strdup("]"); } - | '=' { $$ = mm_strdup("="); } - | ':' { $$ = mm_strdup(":"); } - ; - -DeallocateStmt: DEALLOCATE prepared_name { check_declared_list($2); $$ = $2; } - | DEALLOCATE PREPARE prepared_name { check_declared_list($3); $$ = $3; } - | DEALLOCATE ALL { $$ = mm_strdup("all"); } - | DEALLOCATE PREPARE ALL { $$ = mm_strdup("all"); } - ; - -Iresult: Iconst { $$ = $1; } - | '(' Iresult ')' { $$ = cat_str(3, mm_strdup("("), $2, mm_strdup(")")); } - | Iresult '+' Iresult { $$ = cat_str(3, $1, mm_strdup("+"), $3); } - | Iresult '-' Iresult { $$ = cat_str(3, $1, mm_strdup("-"), $3); } - | Iresult '*' Iresult { $$ = cat_str(3, $1, mm_strdup("*"), $3); } - | Iresult '/' Iresult { $$ = cat_str(3, $1, mm_strdup("/"), $3); } - | Iresult '%' Iresult { $$ = cat_str(3, $1, mm_strdup("%"), $3); } - | ecpg_sconst { $$ = $1; } - | ColId { $$ = $1; } - | ColId '(' var_type ')' { if (pg_strcasecmp($1, "sizeof") != 0) - mmerror(PARSE_ERROR, ET_ERROR, "operator not allowed in variable definition"); - else - $$ = cat_str(4, $1, mm_strdup("("), $3.type_str, mm_strdup(")")); - } - ; - -execute_rest: /* EMPTY */ { $$ = EMPTY; } - | ecpg_using opt_ecpg_into { $$ = EMPTY; } - | ecpg_into ecpg_using { $$ = EMPTY; } - | ecpg_into { $$ = EMPTY; } - ; - -ecpg_into: INTO into_list { $$ = EMPTY; } - | into_descriptor { $$ = $1; } - ; - -opt_ecpg_into: /* EMPTY */ { $$ = EMPTY; } - | ecpg_into { $$ = $1; } - ; - -ecpg_fetch_into: ecpg_into { $$ = $1; } +c_stuff_item: c_anything + { + $$ = $1; + } + | '(' ')' + { + $$ = mm_strdup("()"); + } + | '(' c_stuff ')' + { + $$ = cat_str(3, mm_strdup("("), $2, mm_strdup(")")); + } + ; + +c_stuff: c_stuff_item + { + $$ = $1; + } + | c_stuff c_stuff_item + { + $$ = cat2_str($1, $2); + } + ; + +c_list: c_term + { + $$ = $1; + } + | c_list ',' c_term + { + $$ = cat_str(3, $1, mm_strdup(","), $3); + } + ; + +c_term: c_stuff + { + $$ = $1; + } + | '{' c_list '}' + { + $$ = cat_str(3, mm_strdup("{"), $2, mm_strdup("}")); + } + ; + +c_thing: c_anything { $$ = $1; } + | '(' { $$ = mm_strdup("("); } + | ')' { $$ = mm_strdup(")"); } + | ',' { $$ = mm_strdup(","); } + | ';' { $$ = mm_strdup(";"); } + ; + +c_anything: ecpg_ident { $$ = $1; } + | Iconst { $$ = $1; } + | ecpg_fconst { $$ = $1; } + | ecpg_sconst { $$ = $1; } + | '*' { $$ = mm_strdup("*"); } + | '+' { $$ = mm_strdup("+"); } + | '-' { $$ = mm_strdup("-"); } + | '/' { $$ = mm_strdup("/"); } + | '%' { $$ = mm_strdup("%"); } + | NULL_P { $$ = mm_strdup("NULL"); } + | S_ADD { $$ = mm_strdup("+="); } + | S_AND { $$ = mm_strdup("&&"); } + | S_ANYTHING { $$ = make_name(); } + | S_AUTO { $$ = mm_strdup("auto"); } + | S_CONST { $$ = mm_strdup("const"); } + | S_DEC { $$ = mm_strdup("--"); } + | S_DIV { $$ = mm_strdup("/="); } + | S_DOTPOINT { $$ = mm_strdup(".*"); } + | S_EQUAL { $$ = mm_strdup("=="); } + | S_EXTERN { $$ = mm_strdup("extern"); } + | S_INC { $$ = mm_strdup("++"); } + | S_LSHIFT { $$ = mm_strdup("<<"); } + | S_MEMBER { $$ = mm_strdup("->"); } + | S_MEMPOINT { $$ = mm_strdup("->*"); } + | S_MOD { $$ = mm_strdup("%="); } + | S_MUL { $$ = mm_strdup("*="); } + | S_NEQUAL { $$ = mm_strdup("!="); } + | S_OR { $$ = mm_strdup("||"); } + | S_REGISTER { $$ = mm_strdup("register"); } + | S_RSHIFT { $$ = mm_strdup(">>"); } + | S_STATIC { $$ = mm_strdup("static"); } + | S_SUB { $$ = mm_strdup("-="); } + | S_TYPEDEF { $$ = mm_strdup("typedef"); } + | S_VOLATILE { $$ = mm_strdup("volatile"); } + | SQL_BOOL { $$ = mm_strdup("bool"); } + | ENUM_P { $$ = mm_strdup("enum"); } + | HOUR_P { $$ = mm_strdup("hour"); } + | INT_P { $$ = mm_strdup("int"); } + | SQL_LONG { $$ = mm_strdup("long"); } + | MINUTE_P { $$ = mm_strdup("minute"); } + | MONTH_P { $$ = mm_strdup("month"); } + | SECOND_P { $$ = mm_strdup("second"); } + | SQL_SHORT { $$ = mm_strdup("short"); } + | SQL_SIGNED { $$ = mm_strdup("signed"); } + | SQL_STRUCT { $$ = mm_strdup("struct"); } + | SQL_UNSIGNED { $$ = mm_strdup("unsigned"); } + | YEAR_P { $$ = mm_strdup("year"); } + | CHAR_P { $$ = mm_strdup("char"); } + | FLOAT_P { $$ = mm_strdup("float"); } + | TO { $$ = mm_strdup("to"); } + | UNION { $$ = mm_strdup("union"); } + | VARCHAR { $$ = mm_strdup("varchar"); } + | '[' { $$ = mm_strdup("["); } + | ']' { $$ = mm_strdup("]"); } + | '=' { $$ = mm_strdup("="); } + | ':' { $$ = mm_strdup(":"); } + ; + +DeallocateStmt: DEALLOCATE prepared_name + { + check_declared_list($2); + $$ = $2; + } + | DEALLOCATE PREPARE prepared_name + { + check_declared_list($3); + $$ = $3; + } + | DEALLOCATE ALL + { + $$ = mm_strdup("all"); + } + | DEALLOCATE PREPARE ALL + { + $$ = mm_strdup("all"); + } + ; + +Iresult: Iconst + { + $$ = $1; + } + | '(' Iresult ')' + { + $$ = cat_str(3, mm_strdup("("), $2, mm_strdup(")")); + } + | Iresult '+' Iresult + { + $$ = cat_str(3, $1, mm_strdup("+"), $3); + } + | Iresult '-' Iresult + { + $$ = cat_str(3, $1, mm_strdup("-"), $3); + } + | Iresult '*' Iresult + { + $$ = cat_str(3, $1, mm_strdup("*"), $3); + } + | Iresult '/' Iresult + { + $$ = cat_str(3, $1, mm_strdup("/"), $3); + } + | Iresult '%' Iresult + { + $$ = cat_str(3, $1, mm_strdup("%"), $3); + } + | ecpg_sconst + { + $$ = $1; + } + | ColId + { + $$ = $1; + } + | ColId '(' var_type ')' + { + if (pg_strcasecmp($1, "sizeof") != 0) + mmerror(PARSE_ERROR, ET_ERROR, "operator not allowed in variable definition"); + else + $$ = cat_str(4, $1, mm_strdup("("), $3.type_str, mm_strdup(")")); + } + ; + +execute_rest: /* EMPTY */ + { + $$ = EMPTY; + } + | ecpg_using opt_ecpg_into + { + $$ = EMPTY; + } + | ecpg_into ecpg_using + { + $$ = EMPTY; + } + | ecpg_into + { + $$ = EMPTY; + } + ; + +ecpg_into: INTO into_list + { + $$ = EMPTY; + } + | into_descriptor + { + $$ = $1; + } + ; + +opt_ecpg_into: /* EMPTY */ + { + $$ = EMPTY; + } + | ecpg_into + { + $$ = $1; + } + ; + +ecpg_fetch_into: ecpg_into + { + $$ = $1; + } | using_descriptor { struct variable *var; @@ -2015,20 +2494,31 @@ ecpg_fetch_into: ecpg_into { $$ = $1; } } ; -opt_ecpg_fetch_into: /* EMPTY */ { $$ = EMPTY; } - | ecpg_fetch_into { $$ = $1; } +opt_ecpg_fetch_into: /* EMPTY */ + { + $$ = EMPTY; + } + | ecpg_fetch_into + { + $$ = $1; + } ; %% -void base_yyerror(const char *error) +void +base_yyerror(const char *error) { /* translator: %s is typically the translation of "syntax error" */ mmerror(PARSE_ERROR, ET_ERROR, "%s at or near \"%s\"", _(error), token_start ? token_start : base_yytext); } -void parser_init(void) +void +parser_init(void) { - /* This function is empty. It only exists for compatibility with the backend parser right now. */ + /* + * This function is empty. It only exists for compatibility with the + * backend parser right now. + */ } diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/preproc/pgc.l index 27261f42d8..f363a34659 100644 --- a/src/interfaces/ecpg/preproc/pgc.l +++ b/src/interfaces/ecpg/preproc/pgc.l @@ -35,8 +35,8 @@ extern YYSTYPE base_yylval; -static int xcdepth = 0; /* depth of nesting in slash-star comments */ -static char *dolqstart = NULL; /* current $foo$ quote start string */ +static int xcdepth = 0; /* depth of nesting in slash-star comments */ +static char *dolqstart = NULL; /* current $foo$ quote start string */ /* * literalbuf is used to accumulate literal values when multiple rules @@ -44,15 +44,15 @@ static char *dolqstart = NULL; /* current $foo$ quote start string */ * 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 */ +static char *literalbuf = NULL; /* expandable buffer */ +static int literallen; /* actual current length */ +static int literalalloc; /* current allocated buffer size */ /* Used for detecting global state together with braces_open */ -static int parenths_open; +static int parenths_open; /* Used to tell parse_include() whether the command was #include or #include_next */ -static bool include_next; +static bool include_next; #define startlit() (literalbuf[0] = '\0', literallen = 0) static void addlit(char *ytext, int yleng); @@ -63,11 +63,11 @@ static bool ecpg_isspace(char ch); static bool isdefine(void); static bool isinformixdefine(void); -char *token_start; +char *token_start; /* vars to keep track of start conditions when scanning literals */ -static int state_before_str_start; -static int state_before_str_stop; +static int state_before_str_start; +static int state_before_str_stop; /* * State for handling include files and macro expansion. We use a new @@ -78,10 +78,10 @@ static int state_before_str_stop; */ static struct _yy_buffer { - YY_BUFFER_STATE buffer; - long lineno; - char *filename; - struct _yy_buffer *next; + YY_BUFFER_STATE buffer; + long lineno; + char *filename; + struct _yy_buffer *next; } *yy_buffer = NULL; /* @@ -541,7 +541,9 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ <xb>{xbinside} { addlit(yytext, yyleng); } -<xb><<EOF>> { mmfatal(PARSE_ERROR, "unterminated bit string literal"); } +<xb><<EOF>> { + mmfatal(PARSE_ERROR, "unterminated bit string literal"); + } <SQL>{xhstart} { token_start = yytext; @@ -549,7 +551,9 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ BEGIN(xh); startlit(); } -<xh><<EOF>> { mmfatal(PARSE_ERROR, "unterminated hexadecimal string literal"); } +<xh><<EOF>> { + mmfatal(PARSE_ERROR, "unterminated hexadecimal string literal"); + } <C>{xqstart} { token_start = yytext; @@ -560,9 +564,7 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ <SQL>{ {xnstart} { - /* National character. - * Transfer it as-is to the backend. - */ + /* National character. Transfer it as-is to the backend. */ token_start = yytext; state_before_str_start = YYSTATE; BEGIN(xn); @@ -651,29 +653,37 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ } } -<xq,xe,xn,xus>{xqdouble} { addlit(yytext, yyleng); } -<xqc>{xqcquote} { addlit(yytext, yyleng); } -<xq,xqc,xn,xus>{xqinside} { addlit(yytext, yyleng); } -<xe>{xeinside} { +<xq,xe,xn,xus>{xqdouble} { + addlit(yytext, yyleng); + } +<xqc>{xqcquote} { + addlit(yytext, yyleng); + } +<xq,xqc,xn,xus>{xqinside} { addlit(yytext, yyleng); } -<xe>{xeunicode} { +<xe>{xeinside} { addlit(yytext, yyleng); } -<xe>{xeescape} { +<xe>{xeunicode} { addlit(yytext, yyleng); } -<xe>{xeoctesc} { +<xe>{xeescape} { addlit(yytext, yyleng); } -<xe>{xehexesc} { +<xe>{xeoctesc} { + addlit(yytext, yyleng); + } +<xe>{xehexesc} { addlit(yytext, yyleng); } <xe>. { /* This is only needed for \ just before EOF */ addlitchar(yytext[0]); } -<xq,xqc,xe,xn,xus><<EOF>> { mmfatal(PARSE_ERROR, "unterminated quoted string"); } +<xq,xqc,xe,xn,xus><<EOF>> { + mmfatal(PARSE_ERROR, "unterminated quoted string"); + } <SQL>{ {dolqdelim} { @@ -693,7 +703,7 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ } } /* <SQL> */ -<xdolq>{dolqdelim} { +<xdolq>{dolqdelim} { if (strcmp(yytext, dolqstart) == 0) { addlit(yytext, yyleng); @@ -724,7 +734,9 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ /* single quote or dollar sign */ addlitchar(yytext[0]); } -<xdolq><<EOF>> { mmfatal(PARSE_ERROR, "unterminated dollar-quoted string"); } +<xdolq><<EOF>> { + mmfatal(PARSE_ERROR, "unterminated dollar-quoted string"); + } <SQL>{ {xdstart} { @@ -743,6 +755,7 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ BEGIN(state_before_str_start); if (literallen == 0) mmerror(PARSE_ERROR, ET_ERROR, "zero-length delimited identifier"); + /* * The server will truncate the identifier here. We do * not, as (1) it does not change the result; (2) we don't @@ -763,26 +776,34 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ BEGIN(state_before_str_start); if (literallen == 0) mmerror(PARSE_ERROR, ET_ERROR, "zero-length delimited identifier"); - /* The backend will truncate the identifier here. We do not as it does not change the result. */ + + /* + * The backend will truncate the identifier here. We do + * not as it does not change the result. + */ base_yylval.str = psprintf("U&\"%s\"", literalbuf); return UIDENT; } -<xd,xui>{xddouble} { +<xd,xui>{xddouble} { addlit(yytext, yyleng); } -<xd,xui>{xdinside} { +<xd,xui>{xdinside} { addlit(yytext, yyleng); } -<xd,xui><<EOF>> { mmfatal(PARSE_ERROR, "unterminated quoted identifier"); } +<xd,xui><<EOF>> { + mmfatal(PARSE_ERROR, "unterminated quoted identifier"); + } <C>{xdstart} { state_before_str_start = YYSTATE; BEGIN(xdc); startlit(); } -<xdc>{xdcinside} { +<xdc>{xdcinside} { addlit(yytext, yyleng); } -<xdc><<EOF>> { mmfatal(PARSE_ERROR, "unterminated quoted string"); } +<xdc><<EOF>> { + mmfatal(PARSE_ERROR, "unterminated quoted string"); + } <SQL>{ {typecast} { @@ -819,21 +840,20 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ return NOT_EQUALS; } -{informix_special} { - /* are we simulating Informix? */ - if (INFORMIX_MODE) - { - unput(':'); - } - else - return yytext[0]; +{informix_special} { + /* are we simulating Informix? */ + if (INFORMIX_MODE) + { + unput(':'); + } + else + return yytext[0]; } {self} { /* - * We may find a ';' inside a structure - * definition in a TYPE or VAR statement. - * This is not an EOL marker. + * 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); @@ -878,7 +898,8 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ for (ic = nchars - 2; ic >= 0; ic--) { - char c = yytext[ic]; + char c = yytext[ic]; + if (c == '~' || c == '!' || c == '@' || c == '#' || c == '^' || c == '&' || c == '|' || c == '`' || c == '?' || @@ -891,11 +912,12 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ * didn't find a qualifying character, so remove * all trailing [+-] */ - do { + do + { nchars--; } while (nchars > 1 && - (yytext[nchars - 1] == '+' || - yytext[nchars - 1] == '-')); + (yytext[nchars - 1] == '+' || + yytext[nchars - 1] == '-')); } } @@ -903,6 +925,7 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ { /* 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 @@ -912,6 +935,7 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ if (nchars == 1 && strchr(",()[].;:+-*/%^<>=", yytext[0])) return yytext[0]; + /* * Likewise, if what we have left is two chars, and * those match the tokens ">=", "<=", "=>", "<>" or @@ -999,16 +1023,16 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ * Note that some trailing junk is valid in C (such as 100LL), so we * contain this to SQL mode. */ -{decinteger_junk} { +{decinteger_junk} { mmfatal(PARSE_ERROR, "trailing junk after numeric literal"); } -{hexinteger_junk} { +{hexinteger_junk} { mmfatal(PARSE_ERROR, "trailing junk after numeric literal"); } -{octinteger_junk} { +{octinteger_junk} { mmfatal(PARSE_ERROR, "trailing junk after numeric literal"); } -{bininteger_junk} { +{bininteger_junk} { mmfatal(PARSE_ERROR, "trailing junk after numeric literal"); } {numeric_junk} { @@ -1019,7 +1043,7 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ } :{identifier}((("->"|\.){identifier})|(\[{array}\]))* { - base_yylval.str = mm_strdup(yytext+1); + base_yylval.str = mm_strdup(yytext + 1); return CVARIABLE; } @@ -1027,7 +1051,7 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ /* First check to see if it's a define symbol to expand */ if (!isdefine()) { - int kwvalue; + int kwvalue; /* * User-defined typedefs override SQL keywords, but @@ -1053,8 +1077,8 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ * * The backend will attempt to truncate and case-fold * the identifier, but I see no good reason for ecpg - * to do so; that's just another way that ecpg could get - * out of step with the backend. + * to do so; that's just another way that ecpg could + * get out of step with the backend. */ base_yylval.str = mm_strdup(yytext); return IDENT; @@ -1070,75 +1094,82 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ * Begin ECPG-specific rules */ -<C>{exec_sql} { BEGIN(SQL); return SQL_START; } +<C>{exec_sql} { + BEGIN(SQL); + return SQL_START; + } <C>{informix_special} { - /* are we simulating Informix? */ - if (INFORMIX_MODE) - { - BEGIN(SQL); - return SQL_START; - } - else - return S_ANYTHING; - } -<C>{ccomment} { ECHO; } -<C>{cppinclude} { - if (system_includes) - { - include_next = false; - BEGIN(incl); - } - else - { - base_yylval.str = mm_strdup(yytext); - return CPP_LINE; - } + /* are we simulating Informix? */ + if (INFORMIX_MODE) + { + BEGIN(SQL); + return SQL_START; } -<C>{cppinclude_next} { - if (system_includes) - { - include_next = true; - BEGIN(incl); - } - else - { - base_yylval.str = mm_strdup(yytext); - return CPP_LINE; - } + else + return S_ANYTHING; + } +<C>{ccomment} { + ECHO; + } +<C>{cppinclude} { + if (system_includes) + { + include_next = false; + BEGIN(incl); } -<C,SQL>{cppline} { + else + { base_yylval.str = mm_strdup(yytext); return CPP_LINE; } -<C>{identifier} { - /* - * Try to detect a function name: - * look for identifiers at the global scope - * keep the last identifier before the first '(' and '{' - */ - if (braces_open == 0 && parenths_open == 0) - { - if (current_function) - free(current_function); - current_function = mm_strdup(yytext); - } - /* Informix uses SQL defines only in SQL space */ - /* however, some defines have to be taken care of for compatibility */ - if ((!INFORMIX_MODE || !isinformixdefine()) && !isdefine()) - { - int kwvalue; + } +<C>{cppinclude_next} { + if (system_includes) + { + include_next = true; + BEGIN(incl); + } + else + { + base_yylval.str = mm_strdup(yytext); + return CPP_LINE; + } + } +<C,SQL>{cppline} { + base_yylval.str = mm_strdup(yytext); + return CPP_LINE; + } +<C>{identifier} { + /* + * Try to detect a function name: + * look for identifiers at the global scope + * keep the last identifier before the first '(' and '{' + */ + if (braces_open == 0 && parenths_open == 0) + { + if (current_function) + free(current_function); + current_function = mm_strdup(yytext); + } + /* Informix uses SQL defines only in SQL space */ + /* however, some defines have to be taken care of for compatibility */ + if ((!INFORMIX_MODE || !isinformixdefine()) && !isdefine()) + { + int kwvalue; - kwvalue = ScanCKeywordLookup(yytext); - if (kwvalue >= 0) - return kwvalue; - else - { - base_yylval.str = mm_strdup(yytext); - return IDENT; - } + kwvalue = ScanCKeywordLookup(yytext); + if (kwvalue >= 0) + return kwvalue; + else + { + base_yylval.str = mm_strdup(yytext); + return IDENT; } } -<C>{xcstop} { mmerror(PARSE_ERROR, ET_ERROR, "nested /* ... */ comments"); } + } +<C>{xcstop} { + mmerror(PARSE_ERROR, ET_ERROR, "nested /* ... */ comments"); + } <C>":" { return ':'; } <C>";" { return ';'; } <C>"," { return ','; } @@ -1174,44 +1205,46 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ <C>{other} { return S_ANYTHING; } <C>{exec_sql}{define}{space}* { BEGIN(def_ident); } <C>{informix_special}{define}{space}* { - /* are we simulating Informix? */ - if (INFORMIX_MODE) - { - BEGIN(def_ident); - } - else - { - yyless(1); - return S_ANYTHING; - } + /* are we simulating Informix? */ + if (INFORMIX_MODE) + { + BEGIN(def_ident); + } + else + { + yyless(1); + return S_ANYTHING; } -<C>{exec_sql}{undef}{space}* { BEGIN(undef); } + } +<C>{exec_sql}{undef}{space}* { + BEGIN(undef); + } <C>{informix_special}{undef}{space}* { - /* are we simulating Informix? */ - if (INFORMIX_MODE) - { - BEGIN(undef); - } - else - { - yyless(1); - return S_ANYTHING; - } + /* are we simulating Informix? */ + if (INFORMIX_MODE) + { + BEGIN(undef); } + else + { + yyless(1); + return S_ANYTHING; + } + } <undef>{identifier}{space}*";" { - struct _defines *ptr, *ptr2 = NULL; - int i; + struct _defines *ptr, + *ptr2 = NULL; + int i; /* - * Skip the ";" and trailing whitespace. Note that yytext - * contains at least one non-space character plus the ";" + * Skip the ";" and trailing whitespace. Note that yytext + * contains at least one non-space character plus the ";" */ - for (i = strlen(yytext)-2; + for (i = strlen(yytext) - 2; i > 0 && ecpg_isspace(yytext[i]); i--) ; - yytext[i+1] = '\0'; - + yytext[i + 1] = '\0'; /* Find and unset any matching define; should be only 1 */ for (ptr = defines; ptr; ptr2 = ptr, ptr = ptr->next) @@ -1237,88 +1270,90 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ BEGIN(C); } <undef>{other}|\n { - mmfatal(PARSE_ERROR, "missing identifier in EXEC SQL UNDEF command"); - yyterminate(); + mmfatal(PARSE_ERROR, "missing identifier in EXEC SQL UNDEF command"); + yyterminate(); + } +<C>{exec_sql}{include}{space}* { + BEGIN(incl); } -<C>{exec_sql}{include}{space}* { BEGIN(incl); } <C>{informix_special}{include}{space}* { - /* are we simulating Informix? */ - if (INFORMIX_MODE) - { - BEGIN(incl); - } - else - { - yyless(1); - return S_ANYTHING; - } + /* are we simulating Informix? */ + if (INFORMIX_MODE) + { + BEGIN(incl); } -<C,xskip>{exec_sql}{ifdef}{space}* { - if (preproc_tos >= MAX_NESTED_IF-1) - mmfatal(PARSE_ERROR, "too many nested EXEC SQL IFDEF conditions"); - preproc_tos++; - stacked_if_value[preproc_tos].active = false; - stacked_if_value[preproc_tos].saw_active = false; - stacked_if_value[preproc_tos].else_branch = false; - ifcond = true; - BEGIN(xcond); + else + { + yyless(1); + return S_ANYTHING; } + } +<C,xskip>{exec_sql}{ifdef}{space}* { + if (preproc_tos >= MAX_NESTED_IF - 1) + mmfatal(PARSE_ERROR, "too many nested EXEC SQL IFDEF conditions"); + preproc_tos++; + stacked_if_value[preproc_tos].active = false; + stacked_if_value[preproc_tos].saw_active = false; + stacked_if_value[preproc_tos].else_branch = false; + ifcond = true; + BEGIN(xcond); + } <C,xskip>{informix_special}{ifdef}{space}* { - /* are we simulating Informix? */ - if (INFORMIX_MODE) - { - if (preproc_tos >= MAX_NESTED_IF-1) - mmfatal(PARSE_ERROR, "too many nested EXEC SQL IFDEF conditions"); - preproc_tos++; - stacked_if_value[preproc_tos].active = false; - stacked_if_value[preproc_tos].saw_active = false; - stacked_if_value[preproc_tos].else_branch = false; - ifcond = true; - BEGIN(xcond); - } - else - { - yyless(1); - return S_ANYTHING; - } + /* are we simulating Informix? */ + if (INFORMIX_MODE) + { + if (preproc_tos >= MAX_NESTED_IF - 1) + mmfatal(PARSE_ERROR, "too many nested EXEC SQL IFDEF conditions"); + preproc_tos++; + stacked_if_value[preproc_tos].active = false; + stacked_if_value[preproc_tos].saw_active = false; + stacked_if_value[preproc_tos].else_branch = false; + ifcond = true; + BEGIN(xcond); } -<C,xskip>{exec_sql}{ifndef}{space}* { - if (preproc_tos >= MAX_NESTED_IF-1) - mmfatal(PARSE_ERROR, "too many nested EXEC SQL IFDEF conditions"); - preproc_tos++; - stacked_if_value[preproc_tos].active = false; - stacked_if_value[preproc_tos].saw_active = false; - stacked_if_value[preproc_tos].else_branch = false; - ifcond = false; - BEGIN(xcond); + else + { + yyless(1); + return S_ANYTHING; } + } +<C,xskip>{exec_sql}{ifndef}{space}* { + if (preproc_tos >= MAX_NESTED_IF - 1) + mmfatal(PARSE_ERROR, "too many nested EXEC SQL IFDEF conditions"); + preproc_tos++; + stacked_if_value[preproc_tos].active = false; + stacked_if_value[preproc_tos].saw_active = false; + stacked_if_value[preproc_tos].else_branch = false; + ifcond = false; + BEGIN(xcond); + } <C,xskip>{informix_special}{ifndef}{space}* { - /* are we simulating Informix? */ - if (INFORMIX_MODE) - { - if (preproc_tos >= MAX_NESTED_IF-1) - mmfatal(PARSE_ERROR, "too many nested EXEC SQL IFDEF conditions"); - preproc_tos++; - stacked_if_value[preproc_tos].active = false; - stacked_if_value[preproc_tos].saw_active = false; - stacked_if_value[preproc_tos].else_branch = false; - ifcond = false; - BEGIN(xcond); - } - else - { - yyless(1); - return S_ANYTHING; - } - } -<C,xskip>{exec_sql}{elif}{space}* { - if (preproc_tos == 0) - mmfatal(PARSE_ERROR, "missing matching \"EXEC SQL IFDEF\" / \"EXEC SQL IFNDEF\""); - if (stacked_if_value[preproc_tos].else_branch) - mmfatal(PARSE_ERROR, "missing \"EXEC SQL ENDIF;\""); - ifcond = true; + /* are we simulating Informix? */ + if (INFORMIX_MODE) + { + if (preproc_tos >= MAX_NESTED_IF - 1) + mmfatal(PARSE_ERROR, "too many nested EXEC SQL IFDEF conditions"); + preproc_tos++; + stacked_if_value[preproc_tos].active = false; + stacked_if_value[preproc_tos].saw_active = false; + stacked_if_value[preproc_tos].else_branch = false; + ifcond = false; BEGIN(xcond); } + else + { + yyless(1); + return S_ANYTHING; + } + } +<C,xskip>{exec_sql}{elif}{space}* { + if (preproc_tos == 0) + mmfatal(PARSE_ERROR, "missing matching \"EXEC SQL IFDEF\" / \"EXEC SQL IFNDEF\""); + if (stacked_if_value[preproc_tos].else_branch) + mmfatal(PARSE_ERROR, "missing \"EXEC SQL ENDIF;\""); + ifcond = true; + BEGIN(xcond); + } <C,xskip>{informix_special}{elif}{space}* { /* are we simulating Informix? */ if (INFORMIX_MODE) @@ -1337,7 +1372,8 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ } } -<C,xskip>{exec_sql}{else}{space}*";" { /* only exec sql endif pops the stack, so take care of duplicated 'else' */ +<C,xskip>{exec_sql}{else}{space}*";" { + /* only exec sql endif pops the stack, so take care of duplicated 'else' */ if (preproc_tos == 0) mmfatal(PARSE_ERROR, "missing matching \"EXEC SQL IFDEF\" / \"EXEC SQL IFNDEF\""); else if (stacked_if_value[preproc_tos].else_branch) @@ -1346,7 +1382,7 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ { stacked_if_value[preproc_tos].else_branch = true; stacked_if_value[preproc_tos].active = - (stacked_if_value[preproc_tos-1].active && + (stacked_if_value[preproc_tos - 1].active && !stacked_if_value[preproc_tos].saw_active); stacked_if_value[preproc_tos].saw_active = true; @@ -1356,7 +1392,7 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ BEGIN(xskip); } } -<C,xskip>{informix_special}{else}{space}*";" { +<C,xskip>{informix_special}{else}{space}*";" { /* are we simulating Informix? */ if (INFORMIX_MODE) { @@ -1368,7 +1404,7 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ { stacked_if_value[preproc_tos].else_branch = true; stacked_if_value[preproc_tos].active = - (stacked_if_value[preproc_tos-1].active && + (stacked_if_value[preproc_tos - 1].active && !stacked_if_value[preproc_tos].saw_active); stacked_if_value[preproc_tos].saw_active = true; @@ -1391,11 +1427,11 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ preproc_tos--; if (stacked_if_value[preproc_tos].active) - BEGIN(C); + BEGIN(C); else - BEGIN(xskip); + BEGIN(xskip); } -<C,xskip>{informix_special}{endif}{space}*";" { +<C,xskip>{informix_special}{endif}{space}*";" { /* are we simulating Informix? */ if (INFORMIX_MODE) { @@ -1416,23 +1452,24 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ } } -<xskip>{other} { /* ignore */ } +<xskip>{other} { /* ignore */ } <xcond>{identifier}{space}*";" { { struct _defines *defptr; unsigned int i; - bool this_active; + bool this_active; /* - * Skip the ";" and trailing whitespace. Note that yytext - * contains at least one non-space character plus the ";" + * Skip the ";" and trailing whitespace. Note that + * yytext contains at least one non-space character + * plus the ";" */ - for (i = strlen(yytext)-2; + for (i = strlen(yytext) - 2; i > 0 && ecpg_isspace(yytext[i]); i--) - ; - yytext[i+1] = '\0'; + /* skip */ ; + yytext[i + 1] = '\0'; /* Does a definition exist? */ for (defptr = defines; defptr; defptr = defptr->next) @@ -1448,7 +1485,7 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ this_active = (defptr ? ifcond : !ifcond); stacked_if_value[preproc_tos].active = - (stacked_if_value[preproc_tos-1].active && + (stacked_if_value[preproc_tos - 1].active && !stacked_if_value[preproc_tos].saw_active && this_active); stacked_if_value[preproc_tos].saw_active |= this_active; @@ -1460,59 +1497,59 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ BEGIN(xskip); } -<xcond>{other}|\n { - mmfatal(PARSE_ERROR, "missing identifier in EXEC SQL IFDEF command"); - yyterminate(); - } +<xcond>{other}|\n { + mmfatal(PARSE_ERROR, "missing identifier in EXEC SQL IFDEF command"); + yyterminate(); + } <def_ident>{identifier} { - newdefsymbol = mm_strdup(yytext); - BEGIN(def); - startlit(); - } -<def_ident>{other}|\n { - mmfatal(PARSE_ERROR, "missing identifier in EXEC SQL DEFINE command"); - yyterminate(); - } -<def>{space}*";" { - struct _defines *ptr; + newdefsymbol = mm_strdup(yytext); + BEGIN(def); + startlit(); + } +<def_ident>{other}|\n { + mmfatal(PARSE_ERROR, "missing identifier in EXEC SQL DEFINE command"); + yyterminate(); + } +<def>{space}*";" { + struct _defines *ptr; - /* Does it already exist? */ - for (ptr = defines; ptr != NULL; ptr = ptr->next) - { - if (strcmp(newdefsymbol, ptr->name) == 0) - { - free(ptr->value); - ptr->value = mm_strdup(literalbuf); - /* Don't leak newdefsymbol */ - free(newdefsymbol); - break; - } - } - if (ptr == NULL) + /* Does it already exist? */ + for (ptr = defines; ptr != NULL; ptr = ptr->next) + { + if (strcmp(newdefsymbol, ptr->name) == 0) { - /* Not present, make a new entry */ - ptr = (struct _defines *) mm_alloc(sizeof(struct _defines)); - - ptr->name = newdefsymbol; + free(ptr->value); ptr->value = mm_strdup(literalbuf); - ptr->cmdvalue = NULL; - ptr->used = NULL; - ptr->next = defines; - defines = ptr; + /* Don't leak newdefsymbol */ + free(newdefsymbol); + break; } - - BEGIN(C); } -<def>[^;] { addlit(yytext, yyleng); } -<incl>\<[^\>]+\>{space}*";"? { parse_include(); } + if (ptr == NULL) + { + /* Not present, make a new entry */ + ptr = (struct _defines *) mm_alloc(sizeof(struct _defines)); + + ptr->name = newdefsymbol; + ptr->value = mm_strdup(literalbuf); + ptr->cmdvalue = NULL; + ptr->used = NULL; + ptr->next = defines; + defines = ptr; + } + + BEGIN(C); + } +<def>[^;] { addlit(yytext, yyleng); } +<incl>\<[^\>]+\>{space}*";"? { parse_include(); } <incl>{dquote}{xdinside}{dquote}{space}*";"? { parse_include(); } -<incl>[^;\<\>\"]+";" { parse_include(); } -<incl>{other}|\n { +<incl>[^;\<\>\"]+";" { parse_include(); } +<incl>{other}|\n { mmfatal(PARSE_ERROR, "syntax error in EXEC SQL INCLUDE command"); yyterminate(); } -<<EOF>> { +<<EOF>> { if (yy_buffer == NULL) { /* No more input */ @@ -1527,7 +1564,7 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ { /* Revert to previous input source */ struct _yy_buffer *yb = yy_buffer; - int i; + int i; struct _defines *ptr; /* Check to see if we are exiting a macro value */ @@ -1559,11 +1596,12 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ if (i != 0) output_line_number(); - } } -<INITIAL>{other}|\n { mmfatal(PARSE_ERROR, "internal error: unreachable state; please report this to <%s>", PACKAGE_BUGREPORT);} +<INITIAL>{other}|\n { + mmfatal(PARSE_ERROR, "internal error: unreachable state; please report this to <%s>", PACKAGE_BUGREPORT); + } %% @@ -1599,15 +1637,15 @@ static void addlit(char *ytext, int yleng) { /* enlarge buffer if needed */ - if ((literallen+yleng) >= literalalloc) + if ((literallen + yleng) >= literalalloc) { do literalalloc *= 2; - while ((literallen+yleng) >= literalalloc); + while ((literallen + yleng) >= literalalloc); literalbuf = (char *) realloc(literalbuf, literalalloc); } /* append new data, add trailing null */ - memcpy(literalbuf+literallen, ytext, yleng); + memcpy(literalbuf + literallen, ytext, yleng); literallen += yleng; literalbuf[literallen] = '\0'; } @@ -1616,7 +1654,7 @@ static void addlitchar(unsigned char ychar) { /* enlarge buffer if needed */ - if ((literallen+1) >= literalalloc) + if ((literallen + 1) >= literalalloc) { literalalloc *= 2; literalbuf = (char *) realloc(literalbuf, literalalloc); @@ -1655,12 +1693,12 @@ parse_include(void) /* got the include file name */ struct _yy_buffer *yb; struct _include_path *ip; - char inc_file[MAXPGPATH]; + char inc_file[MAXPGPATH]; unsigned int i; yb = mm_alloc(sizeof(struct _yy_buffer)); - yb->buffer = YY_CURRENT_BUFFER; + yb->buffer = YY_CURRENT_BUFFER; yb->lineno = yylineno; yb->filename = input_filename; yb->next = yy_buffer; @@ -1668,10 +1706,10 @@ parse_include(void) yy_buffer = yb; /* - * skip the ";" if there is one and trailing whitespace. Note that - * yytext contains at least one non-space character plus the ";" + * skip the ";" if there is one and trailing whitespace. Note that yytext + * contains at least one non-space character plus the ";" */ - for (i = strlen(yytext)-2; + for (i = strlen(yytext) - 2; i > 0 && ecpg_isspace(yytext[i]); i--) ; @@ -1679,17 +1717,21 @@ parse_include(void) if (yytext[i] == ';') i--; - yytext[i+1] = '\0'; + 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 '/' */ + + /* + * Informix does look into all include paths though, except filename + * starts with '/' + */ if (yytext[0] == '"' && yytext[i] == '"' && ((compat != ECPG_COMPAT_INFORMIX && compat != ECPG_COMPAT_INFORMIX_SE) || yytext[1] == '/')) { yytext[i] = '\0'; - memmove(yytext, yytext+1, strlen(yytext)); + memmove(yytext, yytext + 1, strlen(yytext)); strlcpy(inc_file, yytext, sizeof(inc_file)); yyin = fopen(inc_file, "r"); @@ -1708,7 +1750,7 @@ parse_include(void) if ((yytext[0] == '"' && yytext[i] == '"') || (yytext[0] == '<' && yytext[i] == '>')) { yytext[i] = '\0'; - memmove(yytext, yytext+1, strlen(yytext)); + memmove(yytext, yytext + 1, strlen(yytext)); } for (ip = include_paths; yyin == NULL && ip != NULL; ip = ip->next) @@ -1718,7 +1760,7 @@ parse_include(void) fprintf(stderr, _("Error: include path \"%s/%s\" is too long on line %d, skipping\n"), ip->path, yytext,yylineno); continue; } - snprintf (inc_file, sizeof(inc_file), "%s/%s", ip->path, yytext); + snprintf(inc_file, sizeof(inc_file), "%s/%s", ip->path, yytext); yyin = fopen(inc_file, "r"); if (!yyin) { @@ -1728,10 +1770,14 @@ parse_include(void) yyin = fopen(inc_file, "r"); } } - /* if the command was "include_next" we have to disregard the first hit */ + + /* + * if the command was "include_next" we have to disregard the + * first hit + */ if (yyin && include_next) { - fclose (yyin); + fclose(yyin); yyin = NULL; include_next = false; } @@ -1741,7 +1787,7 @@ parse_include(void) mmfatal(NO_INCLUDE_FILE, "could not open include file \"%s\" on line %d", yytext, yylineno); input_filename = mm_strdup(inc_file); - yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE)); + yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); yylineno = 1; output_line_number(); @@ -1786,7 +1832,7 @@ isdefine(void) yb = mm_alloc(sizeof(struct _yy_buffer)); - yb->buffer = YY_CURRENT_BUFFER; + yb->buffer = YY_CURRENT_BUFFER; yb->lineno = yylineno; yb->filename = mm_strdup(input_filename); yb->next = yy_buffer; @@ -1830,7 +1876,7 @@ isinformixdefine(void) yb = mm_alloc(sizeof(struct _yy_buffer)); - yb->buffer = YY_CURRENT_BUFFER; + yb->buffer = YY_CURRENT_BUFFER; yb->lineno = yylineno; yb->filename = mm_strdup(input_filename); yb->next = yy_buffer; -- 2.43.5 From 7ecc8297b93695a26bcaae962ea8ebae8c02b0d4 Mon Sep 17 00:00:00 2001 From: Tom Lane <tgl@sss.pgh.pa.us> Date: Fri, 5 Jul 2024 11:35:09 -0400 Subject: [PATCH v2 2/6] Clean up documentation of parse.pl, and add more input checking. README.parser is the user's manual, such as it is, for parse.pl. It's rather poorly written if you ask me; so try to improve it. (More could be written here, but this at least covers the same info in a more organized fashion.) Also, the single solitary line of usage info in parse.pl itself was a lie. Replace. Add some error checks that the ecpg.addons entries meet the syntax rules set forth in README.parser. One of them didn't, but accidentally worked anyway because the logic in include_addon is such that 'block' is the default behavior. Also add a cross-check that each ecpg.addons entry is matched exactly once in the backend grammar. This exposed that there are two dead entries there --- they are dead because the %replace_types table in parse.pl causes their nonterminals to be ignored altogether. Removing them doesn't change the generated preproc.y file. (This implies that check_rules.pl is completely worthless and should be nuked: it adds build cycles and maintenance effort while failing to reliably accomplish its one job of detecting dead rules. I've not done that here, though.) --- src/interfaces/ecpg/preproc/README.parser | 119 ++++++++++++++-------- src/interfaces/ecpg/preproc/ecpg.addons | 11 +- src/interfaces/ecpg/preproc/parse.pl | 53 ++++++++-- 3 files changed, 120 insertions(+), 63 deletions(-) diff --git a/src/interfaces/ecpg/preproc/README.parser b/src/interfaces/ecpg/preproc/README.parser index ddc3061d48..7f7b0d5381 100644 --- a/src/interfaces/ecpg/preproc/README.parser +++ b/src/interfaces/ecpg/preproc/README.parser @@ -1,42 +1,77 @@ -ECPG modifies and extends the core grammar in a way that -1) every token in ECPG is <str> type. New tokens are - defined in ecpg.tokens, types are defined in ecpg.type -2) most tokens from the core grammar are simply converted - to literals concatenated together to form the SQL string - passed to the server, this is done by parse.pl. -3) some rules need side-effects, actions are either added - or completely overridden (compared to the basic token - concatenation) for them, these are defined in ecpg.addons, - the rules for ecpg.addons are explained below. -4) new grammar rules are needed for ECPG metacommands. - These are in ecpg.trailer. -5) ecpg.header contains common functions, etc. used by - actions for grammar rules. - -In "ecpg.addons", every modified rule follows this pattern: - ECPG: dumpedtokens postfix -where "dumpedtokens" is simply tokens from core gram.y's -rules concatenated together. e.g. if gram.y has this: - ruleA: tokenA tokenB tokenC {...} -then "dumpedtokens" is "ruleAtokenAtokenBtokenC". -"postfix" above can be: -a) "block" - the automatic rule created by parse.pl is completely - overridden, the code block has to be written completely as - it were in a plain bison grammar -b) "rule" - the automatic rule is extended on, so new syntaxes - are accepted for "ruleA". E.g.: - ECPG: ruleAtokenAtokenBtokenC rule - | tokenD tokenE { action_code; } - ... - It will be substituted with: - ruleA: <original syntax forms and actions up to and including - "tokenA tokenB tokenC"> - | tokenD tokenE { action_code; } - ... -c) "addon" - the automatic action for the rule (SQL syntax constructed - from the tokens concatenated together) is prepended with a new - action code part. This code part is written as is's already inside - the { ... } - -Multiple "addon" or "block" lines may appear together with the -new code block if the code block is common for those rules. +ECPG's grammar (preproc.y) is built by parse.pl from the +backend's grammar (gram.y) plus various add-on rules. +Some notes: + +1) Most input matching core grammar productions is simply converted + to strings and concatenated together to form the SQL string + passed to the server. parse.pl can automatically build the + grammar actions needed to do this. +2) Some grammar rules need special actions that are added to or + completely override the default token-concatenation behavior. + This is controlled by ecpg.addons as explained below. +3) Additional grammar rules are needed for ECPG's own commands. + These are in ecpg.trailer, as is the "epilogue" part of preproc.y. +4) ecpg.header contains the "prologue" part of preproc.y, including + support functions, Bison options, etc. +5) Additional terminals added by ECPG must be defined in ecpg.tokens. + Additional nonterminals added by ECPG must be defined in ecpg.type. + +ecpg.header, ecpg.tokens, ecpg.type, and ecpg.trailer are just +copied verbatim into preproc.y at appropriate points. + +ecpg.addons contains entries that begin with a line like + ECPG: concattokens ruletype +and typically have one or more following lines that are the code +for a grammar action. Any line not starting with ECPG: is taken +to be part of the code block for the preceding ECPG: line. + +"concattokens" identifies which gram.y production this entry affects. +It is simply the target nonterminal and the tokens from the gram.y rule +concatenated together. For example, to modify the action for a gram.y +rule like this: + target: tokenA tokenB tokenC {...} +"concattokens" would be "targettokenAtokenBtokenC". If we want to +modify a non-first alternative for a nonterminal, we still write the +nonterminal. For example, "concattokens" should be "targettokenDtokenE" +to affect the second alternative in: + target: tokenA tokenB tokenC {...} + | tokenD tokenE {...} + +"ruletype" is one of: + +a) "block" - the automatic action that parse.pl would create is + completely overridden. Instead the entry's code block is emitted. + The code block must include the braces ({}) needed for a Bison action. + +b) "addon" - the entry's code block is inserted into the generated + action, ahead of the automatic token-concatenation code. + In this case the code block need not contain braces, since + it will be inserted within braces. + +c) "rule" - the automatic action is emitted, but then the entry's + code block is added verbatim afterwards. This typically is + used to add new alternatives to a nonterminal of the core grammar. + For example, given the entry: + ECPG: targettokenAtokenBtokenC rule + | tokenD tokenE { custom_action; } + what will be emitted is + target: tokenA tokenB tokenC { automatic_action; } + | tokenD tokenE { custom_action; } + +Multiple ECPG: entries can share the same code block, if the +same action is needed for all. When an ECPG: line is immediately +followed by another one, it is not assigned an empty code block; +rather the next nonempty code block is assumed to apply to all +preceding ECPG: entries. + +In addition to the modifications specified by ecpg.addons, +parse.pl contains some tables that list backend grammar +productions to be ignored or modified. + +Nonterminals that construct strings (as described above) should be +given <str> type, which is parse.pl's default assumption for +nonterminals found in gram.y. That can be overridden at need by +making an entry in parse.pl's %replace_types table. %replace_types +can also be used to suppress output of a nonterminal's rules +altogether (in which case ecpg.trailer had better provide replacement +rules, since the nonterminal will still be referred to elsewhere). diff --git a/src/interfaces/ecpg/preproc/ecpg.addons b/src/interfaces/ecpg/preproc/ecpg.addons index e7dce4e404..6a1893553b 100644 --- a/src/interfaces/ecpg/preproc/ecpg.addons +++ b/src/interfaces/ecpg/preproc/ecpg.addons @@ -497,7 +497,7 @@ ECPG: opt_array_boundsopt_array_bounds'['']' block $$.index2 = mm_strdup($3); $$.str = cat_str(4, $1.str, mm_strdup("["), $3, mm_strdup("]")); } -ECPG: opt_array_bounds +ECPG: opt_array_bounds block { $$.index1 = mm_strdup("-1"); $$.index2 = mm_strdup("-1"); @@ -510,15 +510,6 @@ ECPG: IconstICONST block ECPG: AexprConstNULL_P rule | civar { $$ = $1; } | civarind { $$ = $1; } -ECPG: ColIdcol_name_keyword rule - | ECPGKeywords { $$ = $1; } - | ECPGCKeywords { $$ = $1; } - | CHAR_P { $$ = mm_strdup("char"); } - | VALUES { $$ = mm_strdup("values"); } -ECPG: type_function_nametype_func_name_keyword rule - | ECPGKeywords { $$ = $1; } - | ECPGTypeName { $$ = $1; } - | ECPGCKeywords { $$ = $1; } ECPG: VariableShowStmtSHOWALL block { mmerror(PARSE_ERROR, ET_ERROR, "SHOW ALL is not implemented"); diff --git a/src/interfaces/ecpg/preproc/parse.pl b/src/interfaces/ecpg/preproc/parse.pl index fe8d3e5178..edb6630e09 100644 --- a/src/interfaces/ecpg/preproc/parse.pl +++ b/src/interfaces/ecpg/preproc/parse.pl @@ -1,7 +1,13 @@ #!/usr/bin/perl # src/interfaces/ecpg/preproc/parse.pl # parser generator for ecpg version 2 -# call with backend parser as stdin +# +# See README.parser for some explanation of what this does. +# +# Command-line options: +# --srcdir: where to find ecpg-provided input files (default ".") +# --parser: the backend gram.y file to read (required, no default) +# --output: where to write preproc.y (required, no default) # # Copyright (c) 2007-2024, PostgreSQL Global Development Group # @@ -148,6 +154,14 @@ dump_buffer('trailer'); close($parserfh); +# Cross-check that we don't have dead or ambiguous addon rules. +foreach (keys %addons) +{ + die "addon rule $_ was never used\n" if $addons{$_}{used} == 0; + die "addon rule $_ was matched multiple times\n" if $addons{$_}{used} > 1; +} + + sub main { line: while (<$parserfh>) @@ -487,7 +501,10 @@ sub include_addon my $rec = $addons{$block}; return 0 unless $rec; - my $rectype = (defined $rec->{type}) ? $rec->{type} : ''; + # Track usage for later cross-check + $rec->{used}++; + + my $rectype = $rec->{type}; if ($rectype eq 'rule') { dump_fields($stmt_mode, $fields, ' { '); @@ -668,10 +685,10 @@ sub dump_line } =top - load addons into cache + load ecpg.addons into %addons hash. The result is something like %addons = { - stmtClosePortalStmt => { 'type' => 'block', 'lines' => [ "{", "if (INFORMIX_MODE)" ..., "}" ] }, - stmtViewStmt => { 'type' => 'rule', 'lines' => [ "| ECPGAllocateDescr", ... ] } + stmtClosePortalStmt => { 'type' => 'block', 'lines' => [ "{", "if (INFORMIX_MODE)" ..., "}" ], 'used' => 0 }, + stmtViewStmt => { 'type' => 'rule', 'lines' => [ "| ECPGAllocateDescr", ... ], 'used' => 0 } } =cut @@ -681,17 +698,24 @@ sub preload_addons my $filename = $srcdir . "/ecpg.addons"; open(my $fh, '<', $filename) or die; - # there may be multiple lines starting ECPG: and then multiple lines of code. - # the code need to be add to all prior ECPG records. - my (@needsRules, @code, $record); + # There may be multiple ECPG: lines and then multiple lines of code. + # Each block of code needs to be added to all prior ECPG records. + my (@needsRules, @code); # there may be comments before the first ECPG line, skip them my $skip = 1; while (<$fh>) { - if (/^ECPG:\s(\S+)\s?(\w+)?/) + if (/^ECPG:\s+(\S+)\s+(\w+)\s*$/) { + # Found an ECPG: line, so we're done skipping the header $skip = 0; + # Validate record type and target + die "invalid record type $2 in addon rule for $1\n" + unless ($2 eq 'block' or $2 eq 'addon' or $2 eq 'rule'); + die "duplicate addon rule for $1\n" if (exists $addons{$1}); + # If we had some preceding code lines, attach them to all + # as-yet-unfinished records. if (@code) { for my $x (@needsRules) @@ -701,20 +725,27 @@ sub preload_addons @code = (); @needsRules = (); } - $record = {}; + my $record = {}; $record->{type} = $2; $record->{lines} = []; - if (exists $addons{$1}) { die "Ga! there are dups!\n"; } + $record->{used} = 0; $addons{$1} = $record; push(@needsRules, $record); } + elsif (/^ECPG:/) + { + # Complain if preceding regex failed to match + die "incorrect syntax in ECPG line: $_\n"; + } else { + # Non-ECPG line: add to @code unless we're still skipping next if $skip; push(@code, $_); } } close($fh); + # Deal with final code block if (@code) { for my $x (@needsRules) -- 2.43.5 From 01da0a091a47dc3791fe0ff92f9132f12fe5d434 Mon Sep 17 00:00:00 2001 From: Tom Lane <tgl@sss.pgh.pa.us> Date: Fri, 5 Jul 2024 11:37:30 -0400 Subject: [PATCH v2 3/6] Major cleanup, simplification, and documentation of parse.pl. Remove a lot of cruft, clean up and document what's left. This produces the same output as before, except for fewer blank lines. (It's not like we're making any attempt to match the layout of gram.y, so I removed the one bit of logic that seemed to have that in mind.) --- src/interfaces/ecpg/preproc/parse.pl | 486 ++++++++++++++++----------- 1 file changed, 292 insertions(+), 194 deletions(-) diff --git a/src/interfaces/ecpg/preproc/parse.pl b/src/interfaces/ecpg/preproc/parse.pl index edb6630e09..7e53401dd9 100644 --- a/src/interfaces/ecpg/preproc/parse.pl +++ b/src/interfaces/ecpg/preproc/parse.pl @@ -31,27 +31,11 @@ GetOptions( 'output=s' => \$outfile, 'parser=s' => \$parser,) or die "wrong arguments"; -# open parser / output file early, to raise errors early -open(my $parserfh, '<', $parser) or die "could not open parser file $parser"; -open(my $outfh, '>', $outfile) or die "could not open output file $outfile"; - -my $copymode = 0; -my $brace_indent = 0; -my $yaccmode = 0; -my $in_rule = 0; -my $header_included = 0; -my $has_feature_not_supported = 0; -my $has_if_command = 0; -my $tokenmode = 0; - -my (%buff, $infield, $comment, %tokens, %addons); -my ($stmt_mode, @fields); -my $line = ''; -my $non_term_id; +# These hash tables define additional transformations to apply to +# grammar rules. -# some token have to be replaced by other symbols -# either in the rule +# Substitutions to apply to tokens whenever they are seen in a rule. my %replace_token = ( 'BCONST' => 'ecpg_bconst', 'FCONST' => 'ecpg_fconst', @@ -60,7 +44,9 @@ my %replace_token = ( 'IDENT' => 'ecpg_ident', 'PARAM' => 'ecpg_param',); -# or in the block +# Substitutions to apply to terminal token names to reconstruct the +# literal form of the token. (There is also a hard-wired substitution +# rule that strips trailing '_P'.) my %replace_string = ( 'FORMAT_LA' => 'format', 'NOT_LA' => 'not', @@ -75,14 +61,16 @@ my %replace_string = ( 'GREATER_EQUALS' => '>=', 'NOT_EQUALS' => '<>',); -# specific replace_types for specific non-terminals - never include the ':' -# ECPG-only replace_types are defined in ecpg-replace_types +# This hash can provide a result type to override '<str>' for nonterminals +# that need that, or it can specify 'ignore' to cause us to skip the rule +# for that nonterminal. (In that case, ecpg.trailer had better provide +# a substitute rule.) my %replace_types = ( 'PrepareStmt' => '<prep>', 'ExecuteStmt' => '<exec>', 'opt_array_bounds' => '<index>', - # "ignore" means: do not create type and rules for this non-term-id + # "ignore" means: do not create type and rules for this nonterminal 'parse_toplevel' => 'ignore', 'stmtmulti' => 'ignore', 'CreateAsStmt' => 'ignore', @@ -97,9 +85,12 @@ my %replace_types = ( 'plassign_target' => 'ignore', 'plassign_equals' => 'ignore',); -# these replace_line commands excise certain keywords from the core keyword -# lists. Be sure to account for these in ColLabel and related productions. +# This hash provides an "ignore" option or substitute expansion for any +# rule or rule alternative. The hash key is the same "concattokens" tag +# used for lookup in ecpg.addons. my %replace_line = ( + # These entries excise certain keywords from the core keyword lists. + # Be sure to account for these in ColLabel and related productions. 'unreserved_keywordCONNECTION' => 'ignore', 'unreserved_keywordCURRENT_P' => 'ignore', 'unreserved_keywordDAY_P' => 'ignore', @@ -137,10 +128,77 @@ my %replace_line = ( 'PREPARE prepared_name prep_type_clause AS PreparableStmt', 'var_nameColId' => 'ECPGColId'); + +# Declare assorted state variables. + +# yaccmode counts the '%%' separator lines we have seen, so that we can +# distinguish prologue, rules, and epilogue sections of gram.y. +my $yaccmode = 0; +# in /* ... */ comment? +my $comment = 0; +# in { ... } braced text? +my $brace_indent = 0; +# within a rule (production)? +my $in_rule = 0; +# count of alternatives processed within the current rule. +my $alt_count = 0; +# copymode = 1 when we want to emit the current rule to preproc.y. +# If it's 0, we have decided to ignore the current rule, and should +# skip all output until we get to the ending semicolon. +my $copymode = 0; +# tokenmode = 1 indicates we are processing %token and following declarations. +my $tokenmode = 0; +# stmt_mode = 1 indicates that we are processing the 'stmt:' rule. +my $stmt_mode = 0; +# Hacky state for emitting feature-not-supported warnings. +my $has_feature_not_supported = 0; +my $has_if_command = 0; + +# %addons holds the rules loaded from ecpg.addons. +my %addons; + +# %buff holds various named "buffers", which are just strings that accumulate +# the output destined for different sections of the preproc.y file. This +# allows us to process the input in one pass even though the resulting output +# needs to appear in various places. See dump_buffer calls below for the +# set of buffer names and the order in which they'll be dumped. +my %buff; + +# %tokens contains an entry for every name we have discovered to be a token. +my %tokens; + +# $non_term_id is the name of the nonterminal that is the target of the +# current rule. +my $non_term_id; + +# $line holds the reconstructed rule text (that is, RHS token list) that +# we plan to emit for the current rule. +my $line = ''; + +# @fields holds the items to be emitted in the token-concatenation action +# for the current rule (assuming we emit one). "$N" refers to the N'th +# input token of the rule; anything else is a string to emit literally. +# (We assume no such string can need to start with '$'.) +my @fields; + + +# Open parser / output file early, to raise errors early. +open(my $parserfh, '<', $parser) or die "could not open parser file $parser"; +open(my $outfh, '>', $outfile) or die "could not open output file $outfile"; + +# Read the various ecpg-supplied input files. +# ecpg.addons is loaded into the %addons hash, while the other files +# are just copied into buffers for verbatim output later. preload_addons(); +include_file('header', 'ecpg.header'); +include_file('tokens', 'ecpg.tokens'); +include_file('ecpgtype', 'ecpg.type'); +include_file('trailer', 'ecpg.trailer'); +# Read gram.y, and do the bulk of the processing. main(); +# Emit data from the various buffers we filled. dump_buffer('header'); dump_buffer('tokens'); dump_buffer('types'); @@ -149,7 +207,6 @@ dump_buffer('orig_tokens'); print $outfh '%%', "\n"; print $outfh 'prog: statements;', "\n"; dump_buffer('rules'); -include_file('trailer', 'ecpg.trailer'); dump_buffer('trailer'); close($parserfh); @@ -162,83 +219,67 @@ foreach (keys %addons) } +# Read the backend grammar. sub main { line: while (<$parserfh>) { chomp; - # comment out the line below to make the result file match (blank line wise) - # the prior version. - #next if ($_ eq ''); - - # Dump the action for a rule - - # stmt_mode indicates if we are processing the 'stmt:' - # rule (mode==0 means normal, mode==1 means stmt:) - # flds are the fields to use. These may start with a '$' - in - # which case they are the result of a previous non-terminal - # - # if they don't start with a '$' then they are token name - # - # len is the number of fields in flds... - # leadin is the padding to apply at the beginning (just use for formatting) - if (/^%%/) { - $tokenmode = 2; - $copymode = 1; + # New file section, so advance yaccmode. $yaccmode++; - $infield = 0; + # We are no longer examining %token and related commands. + $tokenmode = 0; + # Shouldn't be anything else on the line. + next line; } + # Hacky check for rules that throw FEATURE_NOT_SUPPORTED + # (do this before $_ has a chance to get clobbered) if ($yaccmode == 1) { - # Check for rules that throw FEATURE_NOT_SUPPORTED $has_feature_not_supported = 1 if /ERRCODE_FEATURE_NOT_SUPPORTED/; $has_if_command = 1 if /^\s*if/; } + # We track %prec per-line, not per-rule, which is not quite right + # but there are no counterexamples in gram.y at present. my $prec = 0; - # Make sure any braces are split + # Make sure any braces are split into separate fields s/{/ { /g; s/}/ } /g; - # Any comments are split + # Likewise for comment start/end markers s|\/\*| /* |g; s|\*\/| */ |g; # Now split the line into individual fields my @arr = split(' '); + # Ignore empty lines if (!@arr) { - # empty line: in tokenmode 1, emit an empty line, else ignore - if ($tokenmode == 1) - { - add_to_buffer('orig_tokens', ''); - } next line; } - if ($arr[0] eq '%token' && $tokenmode == 0) + # Once we have seen %token in the prologue, we assume all that follows + # up to the '%%' separator is %token and associativity declarations. + # Collect and process that as necessary. + if ($arr[0] eq '%token' && $yaccmode == 0) { $tokenmode = 1; - include_file('tokens', 'ecpg.tokens'); - } - elsif ($arr[0] eq '%type' && $header_included == 0) - { - include_file('header', 'ecpg.header'); - include_file('ecpgtype', 'ecpg.type'); - $header_included = 1; } if ($tokenmode == 1) { + # Collect everything of interest on this line into $str. my $str = ''; - my $prior = ''; for my $a (@arr) { + # Skip comments. if ($a eq '/*') { $comment++; @@ -253,40 +294,50 @@ sub main { next; } + + # If it's "<something>", it's a type in a %token declaration, + # which we can just drop. if (substr($a, 0, 1) eq '<') { next; - - # its a type } + + # Remember that this is a token. This will also make entries + # for "%token" and the associativity keywords such as "%left", + # which should be harmless so it's not worth the trouble to + # avoid it. If a token appears both in %token and in an + # associativity declaration, we'll redundantly re-set its + # entry, which is also OK. $tokens{$a} = 1; + # Accumulate the line in $str. $str = $str . ' ' . $a; - if ($a eq 'IDENT' && $prior eq '%nonassoc') - { - # add more tokens to the list + # HACK: insert our own %nonassoc line after IDENT. + # XXX: this seems pretty wrong, IDENT is not last on its line! + if ($a eq 'IDENT' && $arr[0] eq '%nonassoc') + { $str = $str . "\n%nonassoc CSTRING"; } - $prior = $a; } + # Save the lightly-processed line in orig_tokens. add_to_buffer('orig_tokens', $str); next line; } - # Don't worry about anything if we're not in the right section of gram.y + # The rest is only appropriate if we're in the rules section of gram.y if ($yaccmode != 1) { next line; } - - # Go through each field in turn + # Go through each word of the rule in turn for ( my $fieldIndexer = 0; $fieldIndexer < scalar(@arr); $fieldIndexer++) { + # Detect and ignore comments and braced action text if ($arr[$fieldIndexer] eq '*/' && $comment) { $comment = 0; @@ -298,15 +349,10 @@ sub main } elsif ($arr[$fieldIndexer] eq '/*') { - - # start of a multiline comment + # start of a possibly-multiline comment $comment = 1; next; } - elsif ($arr[$fieldIndexer] eq '//') - { - next line; - } elsif ($arr[$fieldIndexer] eq '}') { $brace_indent--; @@ -317,29 +363,35 @@ sub main $brace_indent++; next; } - if ($brace_indent > 0) { next; } + + # OK, it's not a comment or part of an action. + # Check for ';' ending the current rule, or '|' ending the + # current alternative. if ($arr[$fieldIndexer] eq ';') { if ($copymode) { - if ($infield) - { - dump_line($stmt_mode, \@fields); - } + # Print the accumulated rule. + emit_rule(\@fields); add_to_buffer('rules', ";\n\n"); } else { + # End of an ignored rule; revert to copymode = 1. $copymode = 1; } + + # Reset for the next rule. @fields = (); - $infield = 0; $line = ''; $in_rule = 0; + $alt_count = 0; + $has_feature_not_supported = 0; + $has_if_command = 0; next; } @@ -347,56 +399,68 @@ sub main { if ($copymode) { - if ($infield) - { - $infield = $infield + dump_line($stmt_mode, \@fields); - } - if ($infield > 1) - { - $line = '| '; - } + # Print the accumulated alternative. + # Increment $alt_count for each non-ignored alternative. + $alt_count += emit_rule(\@fields); } + + # Reset for the next alternative. @fields = (); + # Start the next line with '|' if we've printed at least one + # alternative. + if ($alt_count > 1) + { + $line = '| '; + } + else + { + $line = ''; + } + $has_feature_not_supported = 0; + $has_if_command = 0; next; } + # Apply replace_token substitution if we have one. if (exists $replace_token{ $arr[$fieldIndexer] }) { $arr[$fieldIndexer] = $replace_token{ $arr[$fieldIndexer] }; } - # Are we looking at a declaration of a non-terminal ? - if (($arr[$fieldIndexer] =~ /[A-Za-z0-9]+:/) + # Are we looking at a declaration of a non-terminal? + # We detect that by seeing ':' on the end of the token or + # as the next token. + if (($arr[$fieldIndexer] =~ /[A-Za-z0-9]+:$/) || ( $fieldIndexer + 1 < scalar(@arr) && $arr[ $fieldIndexer + 1 ] eq ':')) { + # Extract the non-terminal, sans : if any $non_term_id = $arr[$fieldIndexer]; $non_term_id =~ tr/://d; + # Consume the ':' if it's separate + if (!($arr[$fieldIndexer] =~ /[A-Za-z0-9]+:$/)) + { + $fieldIndexer++; + } + + # Check for %replace_types override of nonterminal's type if (not defined $replace_types{$non_term_id}) { + # By default, the type is <str> $replace_types{$non_term_id} = '<str>'; - $copymode = 1; } elsif ($replace_types{$non_term_id} eq 'ignore') { + # We'll ignore this nonterminal and rule altogether. $copymode = 0; - $line = ''; next line; } - $line = $line . ' ' . $arr[$fieldIndexer]; - # Do we have the : attached already ? - # If yes, we'll have already printed the ':' - if (!($arr[$fieldIndexer] =~ '[A-Za-z0-9]+:')) - { + # OK, we want this rule. + $copymode = 1; - # Consume the ':' which is next... - $line = $line . ':'; - $fieldIndexer++; - } - - # Special mode? + # Set special mode for the "stmt:" rule. if ($non_term_id eq 'stmt') { $stmt_mode = 1; @@ -405,69 +469,73 @@ sub main { $stmt_mode = 0; } + + # Emit appropriate %type declaration for this nonterminal. my $tstr = '%type ' . $replace_types{$non_term_id} . ' ' . $non_term_id; add_to_buffer('types', $tstr); - if ($copymode) - { - add_to_buffer('rules', $line); - } + # Emit the target part of the rule. + # Note: the leading space is just to match + # the old, rather weird output logic. + $tstr = ' ' . $non_term_id . ':'; + add_to_buffer('rules', $tstr); + + # Prepare for reading the fields (tokens) of the rule. $line = ''; @fields = (); - $infield = 1; die "unterminated rule at grammar line $.\n" if $in_rule; $in_rule = 1; + $alt_count = 1; next; } elsif ($copymode) { + # Not a nonterminal declaration, so just add it to $line. $line = $line . ' ' . $arr[$fieldIndexer]; } + + # %prec and whatever follows it should get added to $line, + # but not to @fields. if ($arr[$fieldIndexer] eq '%prec') { $prec = 1; next; } + # Emit transformed version of token to @fields if appropriate. if ( $copymode && !$prec && !$comment - && $fieldIndexer < scalar(@arr) - && length($arr[$fieldIndexer]) - && $infield) + && $in_rule) { - if ($arr[$fieldIndexer] ne 'Op' - && (( defined $tokens{ $arr[$fieldIndexer] } - && $tokens{ $arr[$fieldIndexer] } > 0) - || $arr[$fieldIndexer] =~ /'.+'/) - || $stmt_mode == 1) + my $S = $arr[$fieldIndexer]; + + # If it's a known terminal token (other than Op) or a literal + # character, we need to emit the equivalent string, which'll + # later get wrapped into a C string literal, perhaps after + # merging with adjacent strings. + if ($S ne 'Op' + && (defined $tokens{$S} + || $S =~ /^'.+'$/)) { - my $S; - if (exists $replace_string{ $arr[$fieldIndexer] }) - { - $S = $replace_string{ $arr[$fieldIndexer] }; - } - else - { - $S = $arr[$fieldIndexer]; - } - $S =~ s/_P//g; + # Apply replace_string substitution if any. + $S = $replace_string{$S} if (exists $replace_string{$S}); + # Automatically strip _P if present. + $S =~ s/_P$//; + # And get rid of quotes if it's a literal character. $S =~ tr/'//d; - if ($stmt_mode == 1) - { - push(@fields, $S); - } - else - { - push(@fields, lc($S)); - } + # Finally, downcase and push into @fields. + push(@fields, lc($S)); } else { + # Otherwise, push a $N reference to this input token. + # (We assume this cannot be confused with anything the + # above code would produce.) push(@fields, '$' . (scalar(@fields) + 1)); } } @@ -495,94 +563,108 @@ sub include_file return; } -sub include_addon +# Emit the semantic action for the current rule. +# This function mainly accounts for any modifications specified +# by an ecpg.addons entry. +sub emit_rule_action { - my ($buffer, $block, $fields, $stmt_mode) = @_; - my $rec = $addons{$block}; - return 0 unless $rec; + my ($tag, $fields) = @_; - # Track usage for later cross-check + # See if we have an addons entry; if not, just emit default action + my $rec = $addons{$tag}; + if (!$rec) + { + emit_default_action($fields, 0); + return; + } + + # Track addons entry usage for later cross-check $rec->{used}++; my $rectype = $rec->{type}; if ($rectype eq 'rule') { - dump_fields($stmt_mode, $fields, ' { '); + # Emit default action and then the code block. + emit_default_action($fields, 0); } elsif ($rectype eq 'addon') { + # Emit the code block wrapped in the same braces as the default action. add_to_buffer('rules', ' { '); } - #add_to_buffer( $stream, $_ ); - #We have an array to add to the buffer, we'll add it ourself instead of - #calling add_to_buffer, which does not know about arrays - - push(@{ $buff{$buffer} }, @{ $rec->{lines} }); + # Emit the addons entry's code block. + # We have an array to add to the buffer, we'll add it directly instead of + # calling add_to_buffer, which does not know about arrays. + push(@{ $buff{'rules'} }, @{ $rec->{lines} }); if ($rectype eq 'addon') { - dump_fields($stmt_mode, $fields, ''); + emit_default_action($fields, 1); } - - - # if we added something (ie there are lines in our array), return 1 - return 1 if (scalar(@{ $rec->{lines} }) > 0); - return 0; + return; } - -# include_addon does this same thing, but does not call this -# sub... so if you change this, you need to fix include_addon too +# Add the given line to the specified buffer. # Pass: buffer_name, string_to_append +# Note we add a newline automatically. sub add_to_buffer { push(@{ $buff{ $_[0] } }, "$_[1]\n"); return; } +# Dump the specified buffer to the output file. sub dump_buffer { my ($buffer) = @_; + # Label the output for debugging purposes. print $outfh '/* ', $buffer, ' */', "\n"; my $ref = $buff{$buffer}; print $outfh @$ref; return; } -sub dump_fields +# Emit the default action (usually token concatenation) for the current rule. +# Pass: fields array, brace_printed boolean +# brace_printed should be true if caller already printed action's open brace. +sub emit_default_action { - my ($mode, $flds, $ln) = @_; + my ($flds, $brace_printed) = @_; my $len = scalar(@$flds); - if ($mode == 0) + if ($stmt_mode == 0) { - - #Normal - add_to_buffer('rules', $ln); + # Normal rule if ($has_feature_not_supported and not $has_if_command) { # The backend unconditionally reports # FEATURE_NOT_SUPPORTED in this rule, so let's emit # a warning on the ecpg side. + if (!$brace_printed) + { + add_to_buffer('rules', ' { '); + $brace_printed = 1; + } add_to_buffer('rules', 'mmerror(PARSE_ERROR, ET_WARNING, "unsupported feature will be passed to server");' ); } - $has_feature_not_supported = 0; - $has_if_command = 0; if ($len == 0) { - - # We have no fields ? + # Empty rule + if (!$brace_printed) + { + add_to_buffer('rules', ' { '); + $brace_printed = 1; + } add_to_buffer('rules', ' $$=EMPTY; }'); } else { - - # Go through each field and try to 'aggregate' the tokens - # into a single 'mm_strdup' where possible + # Go through each field and aggregate consecutive literal tokens + # into a single 'mm_strdup' call. my @flds_new; my $str; for (my $z = 0; $z < $len; $z++) @@ -600,8 +682,10 @@ sub dump_fields if ($z >= $len - 1 || substr($flds->[ $z + 1 ], 0, 1) eq '$') { - - # We're at the end... + # Can't combine any more literals; push to @flds_new. + # This code would need work if any literals contain + # backslash or double quote, but right now that never + # happens. push(@flds_new, "mm_strdup(\"$str\")"); last; } @@ -614,49 +698,62 @@ sub dump_fields $len = scalar(@flds_new); if ($len == 1) { - - # Straight assignment + # Single field can be handled by straight assignment + if (!$brace_printed) + { + add_to_buffer('rules', ' { '); + $brace_printed = 1; + } $str = ' $$ = ' . $flds_new[0] . ';'; add_to_buffer('rules', $str); } else { - - # Need to concatenate the results to form - # our final string + # Need to concatenate the results to form our final string + if (!$brace_printed) + { + add_to_buffer('rules', ' { '); + $brace_printed = 1; + } $str = ' $$ = cat_str(' . $len . ',' . join(',', @flds_new) . ');'; add_to_buffer('rules', $str); } - add_to_buffer('rules', '}'); + add_to_buffer('rules', '}') if ($brace_printed); } } else { - - # we're in the stmt: rule + # We're in the "stmt:" rule, where we need to output special actions. + # This code assumes that no ecpg.addons entry applies. if ($len) { - - # or just the statement ... + # Any regular kind of statement calls output_statement add_to_buffer('rules', ' { output_statement($1, 0, ECPGst_normal); }'); } else { + # The empty production for stmt: do nothing add_to_buffer('rules', ' { $$ = NULL; }'); } } return; } - -sub dump_line +# Print the accumulated rule text (in $line) and the appropriate action. +# Ordinarily return 1. However, if the rule matches an "ignore" +# entry in %replace_line, then do nothing and return 0. +sub emit_rule { - my ($stmt_mode, $fields) = @_; - my $block = $non_term_id . $line; - $block =~ tr/ |//d; - my $rep = $replace_line{$block}; + my ($fields) = @_; + + # compute tag to be used as lookup key in %replace_line and %addons + my $tag = $non_term_id . $line; + $tag =~ tr/ |//d; + + # apply replace_line substitution if any + my $rep = $replace_line{$tag}; if ($rep) { if ($rep eq 'ignore') @@ -664,6 +761,7 @@ sub dump_line return 0; } + # non-ignore entries replace the line, but we'd better keep any '|' if (index($line, '|') != -1) { $line = '| ' . $rep; @@ -672,15 +770,15 @@ sub dump_line { $line = $rep; } - $block = $non_term_id . $line; - $block =~ tr/ |//d; + + # recompute tag for use in emit_rule_action + $tag = $non_term_id . $line; + $tag =~ tr/ |//d; } + + # Emit $line, then print the appropriate action. add_to_buffer('rules', $line); - my $i = include_addon('rules', $block, $fields, $stmt_mode); - if ($i == 0) - { - dump_fields($stmt_mode, $fields, ' { '); - } + emit_rule_action($tag, $fields); return 1; } -- 2.43.5 From 52b6867e25de043822889e540e023588dc178846 Mon Sep 17 00:00:00 2001 From: Tom Lane <tgl@sss.pgh.pa.us> Date: Fri, 5 Jul 2024 11:39:54 -0400 Subject: [PATCH v2 4/6] Re-implement ecpg preprocessor's string management. Most productions in the preprocessor grammar construct strings representing SQL or C statements or fragments thereof. Instead of returning these as <str> results of the productions, return them as "location" values, taking advantage of Bison's flexibility about what a location is. We aren't really giving up anything thereby, since ecpg's error reports have always just given line numbers, and that's tracked separately. The advantage of this is that a single instance of the YYLLOC_DEFAULT macro can perform all the work needed by the vast majority of productions, including all the ones made automatically by parse.pl. This avoids having large numbers of effectively-identical productions, which tickles an optimization inefficiency in recent versions of clang. (This patch reduces the compilation time for preproc.o by more than 100-fold with clang 16.) The compiled parser is noticeably smaller as well. A disadvantage of this approach is that YYLLOC_DEFAULT is applied before running the production's semantic action (if any). This means it cannot use the method favored by cat_str() of free'ing all the input strings; if the action needs to look at the input strings, it'd be looking at dangling storage. As this stands, therefore, it leaks memory like a sieve. This is already a big patch though, and fixing the memory management seems like a separable problem, so let's leave that for the next step. (This does remove some free() calls that I'd have had to touch anyway, in the expectation that the next step will manage memory reclamation quite differently.) --- src/interfaces/ecpg/preproc/README.parser | 32 +- src/interfaces/ecpg/preproc/ecpg.addons | 294 ++--- src/interfaces/ecpg/preproc/ecpg.header | 63 +- src/interfaces/ecpg/preproc/ecpg.trailer | 1148 +++++++----------- src/interfaces/ecpg/preproc/ecpg.type | 127 -- src/interfaces/ecpg/preproc/output.c | 16 +- src/interfaces/ecpg/preproc/parse.pl | 215 +--- src/interfaces/ecpg/preproc/parser.c | 58 +- src/interfaces/ecpg/preproc/preproc_extern.h | 15 +- 9 files changed, 752 insertions(+), 1216 deletions(-) diff --git a/src/interfaces/ecpg/preproc/README.parser b/src/interfaces/ecpg/preproc/README.parser index 7f7b0d5381..412465c79b 100644 --- a/src/interfaces/ecpg/preproc/README.parser +++ b/src/interfaces/ecpg/preproc/README.parser @@ -4,8 +4,8 @@ Some notes: 1) Most input matching core grammar productions is simply converted to strings and concatenated together to form the SQL string - passed to the server. parse.pl can automatically build the - grammar actions needed to do this. + passed to the server. This is handled mostly automatically, + as described below. 2) Some grammar rules need special actions that are added to or completely override the default token-concatenation behavior. This is controlled by ecpg.addons as explained below. @@ -14,11 +14,31 @@ Some notes: 4) ecpg.header contains the "prologue" part of preproc.y, including support functions, Bison options, etc. 5) Additional terminals added by ECPG must be defined in ecpg.tokens. - Additional nonterminals added by ECPG must be defined in ecpg.type. + Additional nonterminals added by ECPG must be defined in ecpg.type, + but only if they have non-void result type, which most don't. ecpg.header, ecpg.tokens, ecpg.type, and ecpg.trailer are just copied verbatim into preproc.y at appropriate points. + +In the original implementation of ecpg, the strings constructed +by grammar rules were returned as the Bison result of each rule. +This led to a large number of effectively-identical rule actions, +which caused compilation-time problems with some versions of clang. +Now, rules that need to return a string are declared as having +void type (which in Bison means leaving out any %type declaration +for them). Instead, we abuse Bison's "location tracking" mechanism +to carry the string results, which allows a single YYLLOC_DEFAULT +call to handle the standard token-concatenation behavior for the +vast majority of the rules. Rules that don't need to do anything +else can omit a semantic action altogether. Rules that need to +construct an output string specially can do so, but they should +assign it to "@$" rather than the usual "$$"; also, to reference +the string value of the N'th input token, write "@N" not "$N". +(But rules that return something other than a simple string +continue to use the normal Bison notations.) + + ecpg.addons contains entries that begin with a line like ECPG: concattokens ruletype and typically have one or more following lines that are the code @@ -69,9 +89,9 @@ parse.pl contains some tables that list backend grammar productions to be ignored or modified. Nonterminals that construct strings (as described above) should be -given <str> type, which is parse.pl's default assumption for -nonterminals found in gram.y. That can be overridden at need by -making an entry in parse.pl's %replace_types table. %replace_types +given void type, which is parse.pl's default assumption for +nonterminals found in gram.y. If the result should be of some other +type, make an entry in parse.pl's %replace_types table. %replace_types can also be used to suppress output of a nonterminal's rules altogether (in which case ecpg.trailer had better provide replacement rules, since the nonterminal will still be referred to elsewhere). diff --git a/src/interfaces/ecpg/preproc/ecpg.addons b/src/interfaces/ecpg/preproc/ecpg.addons index 6a1893553b..24ee54554e 100644 --- a/src/interfaces/ecpg/preproc/ecpg.addons +++ b/src/interfaces/ecpg/preproc/ecpg.addons @@ -3,36 +3,35 @@ ECPG: stmtClosePortalStmt block { if (INFORMIX_MODE) { - if (pg_strcasecmp($1 + strlen("close "), "database") == 0) + if (pg_strcasecmp(@1 + strlen("close "), "database") == 0) { if (connection) mmerror(PARSE_ERROR, ET_ERROR, "AT option not allowed in CLOSE DATABASE statement"); fprintf(base_yyout, "{ ECPGdisconnect(__LINE__, \"CURRENT\");"); whenever_action(2); - free($1); break; } } - output_statement($1, 0, ECPGst_normal); + output_statement(@1, 0, ECPGst_normal); } ECPG: stmtDeallocateStmt block { - output_deallocate_prepare_statement($1); + output_deallocate_prepare_statement(@1); } ECPG: stmtDeclareCursorStmt block { - output_simple_statement($1, (strncmp($1, "ECPGset_var", strlen("ECPGset_var")) == 0) ? 4 : 0); + output_simple_statement(@1, (strncmp(@1, "ECPGset_var", strlen("ECPGset_var")) == 0) ? 4 : 0); } ECPG: stmtDiscardStmt block ECPG: stmtFetchStmt block - { output_statement($1, 1, ECPGst_normal); } + { output_statement(@1, 1, ECPGst_normal); } ECPG: stmtDeleteStmt block ECPG: stmtInsertStmt block ECPG: stmtSelectStmt block ECPG: stmtUpdateStmt block - { output_statement($1, 1, ECPGst_prepnormal); } + { output_statement(@1, 1, ECPGst_prepnormal); } ECPG: stmtExecuteStmt block { check_declared_list($1.name); @@ -94,50 +93,45 @@ ECPG: stmtPrepareStmt block } ECPG: stmtTransactionStmt block { - fprintf(base_yyout, "{ ECPGtrans(__LINE__, %s, \"%s\");", connection ? connection : "NULL", $1); + fprintf(base_yyout, "{ ECPGtrans(__LINE__, %s, \"%s\");", connection ? connection : "NULL", @1); whenever_action(2); - free($1); } ECPG: toplevel_stmtTransactionStmtLegacy block { - fprintf(base_yyout, "{ ECPGtrans(__LINE__, %s, \"%s\");", connection ? connection : "NULL", $1); + fprintf(base_yyout, "{ ECPGtrans(__LINE__, %s, \"%s\");", connection ? connection : "NULL", @1); whenever_action(2); - free($1); } ECPG: stmtViewStmt rule | ECPGAllocateDescr { - fprintf(base_yyout, "ECPGallocate_desc(__LINE__, %s);", $1); + fprintf(base_yyout, "ECPGallocate_desc(__LINE__, %s);", @1); whenever_action(0); - free($1); } | ECPGConnect { if (connection) mmerror(PARSE_ERROR, ET_ERROR, "AT option not allowed in CONNECT statement"); - fprintf(base_yyout, "{ ECPGconnect(__LINE__, %d, %s, %d); ", compat, $1, autocommit); + fprintf(base_yyout, "{ ECPGconnect(__LINE__, %d, %s, %d); ", compat, @1, autocommit); reset_variables(); whenever_action(2); - free($1); } | ECPGDeclareStmt { - output_simple_statement($1, 0); + output_simple_statement(@1, 0); } | ECPGCursorStmt { - output_simple_statement($1, (strncmp($1, "ECPGset_var", strlen("ECPGset_var")) == 0) ? 4 : 0); + output_simple_statement(@1, (strncmp(@1, "ECPGset_var", strlen("ECPGset_var")) == 0) ? 4 : 0); } | ECPGDeallocateDescr { - fprintf(base_yyout, "ECPGdeallocate_desc(__LINE__, %s);", $1); + fprintf(base_yyout, "ECPGdeallocate_desc(__LINE__, %s);", @1); whenever_action(0); - free($1); } | ECPGDeclare { - output_simple_statement($1, 0); + output_simple_statement(@1, 0); } | ECPGDescribe { @@ -157,27 +151,25 @@ ECPG: stmtViewStmt rule mmerror(PARSE_ERROR, ET_ERROR, "AT option not allowed in DISCONNECT statement"); fprintf(base_yyout, "{ ECPGdisconnect(__LINE__, %s);", - $1 ? $1 : "\"CURRENT\""); + @1 ? @1 : "\"CURRENT\""); whenever_action(2); - free($1); } | ECPGExecuteImmediateStmt { - output_statement($1, 0, ECPGst_exec_immediate); + output_statement(@1, 0, ECPGst_exec_immediate); } | ECPGFree { const char *con = connection ? connection : "NULL"; - if (strcmp($1, "all") == 0) + if (strcmp(@1, "all") == 0) fprintf(base_yyout, "{ ECPGdeallocate_all(__LINE__, %d, %s);", compat, con); - else if ($1[0] == ':') - fprintf(base_yyout, "{ ECPGdeallocate(__LINE__, %d, %s, %s);", compat, con, $1 + 1); + else if (@1[0] == ':') + fprintf(base_yyout, "{ ECPGdeallocate(__LINE__, %d, %s, %s);", compat, con, @1 + 1); else - fprintf(base_yyout, "{ ECPGdeallocate(__LINE__, %d, %s, \"%s\");", compat, con, $1); + fprintf(base_yyout, "{ ECPGdeallocate(__LINE__, %d, %s, \"%s\");", compat, con, @1); whenever_action(2); - free($1); } | ECPGGetDescriptor { @@ -188,15 +180,14 @@ ECPG: stmtViewStmt rule } | ECPGGetDescriptorHeader { - lookup_descriptor($1, connection); - output_get_descr_header($1); - free($1); + lookup_descriptor(@1, connection); + output_get_descr_header(@1); } | ECPGOpen { struct cursor *ptr; - if ((ptr = add_additional_variables($1, true)) != NULL) + if ((ptr = add_additional_variables(@1, true)) != NULL) { connection = ptr->connection ? mm_strdup(ptr->connection) : NULL; output_statement(mm_strdup(ptr->command), 0, ECPGst_normal); @@ -205,18 +196,16 @@ ECPG: stmtViewStmt rule } | ECPGSetAutocommit { - fprintf(base_yyout, "{ ECPGsetcommit(__LINE__, \"%s\", %s);", $1, connection ? connection : "NULL"); + fprintf(base_yyout, "{ ECPGsetcommit(__LINE__, \"%s\", %s);", @1, connection ? connection : "NULL"); whenever_action(2); - free($1); } | ECPGSetConnection { if (connection) mmerror(PARSE_ERROR, ET_ERROR, "AT option not allowed in SET CONNECTION statement"); - fprintf(base_yyout, "{ ECPGsetconn(__LINE__, %s);", $1); + fprintf(base_yyout, "{ ECPGsetconn(__LINE__, %s);", @1); whenever_action(2); - free($1); } | ECPGSetDescriptor { @@ -227,17 +216,15 @@ ECPG: stmtViewStmt rule } | ECPGSetDescriptorHeader { - lookup_descriptor($1, connection); - output_set_descr_header($1); - free($1); + lookup_descriptor(@1, connection); + output_set_descr_header(@1); } | ECPGTypedef { if (connection) mmerror(PARSE_ERROR, ET_ERROR, "AT option not allowed in TYPE statement"); - fprintf(base_yyout, "%s", $1); - free($1); + fprintf(base_yyout, "%s", @1); output_line_number(); } | ECPGVar @@ -245,180 +232,169 @@ ECPG: stmtViewStmt rule if (connection) mmerror(PARSE_ERROR, ET_ERROR, "AT option not allowed in VAR statement"); - output_simple_statement($1, 0); + output_simple_statement(@1, 0); } | ECPGWhenever { if (connection) mmerror(PARSE_ERROR, ET_ERROR, "AT option not allowed in WHENEVER statement"); - output_simple_statement($1, 0); + output_simple_statement(@1, 0); } ECPG: where_or_current_clauseWHERECURRENT_POFcursor_name block { - char *cursor_marker = $4[0] == ':' ? mm_strdup("$0") : $4; + char *cursor_marker = @4[0] == ':' ? mm_strdup("$0") : @4; - $$ = cat_str(2, mm_strdup("where current of"), cursor_marker); + @$ = cat_str(2, mm_strdup("where current of"), cursor_marker); } ECPG: CopyStmtCOPYopt_binaryqualified_nameopt_column_listcopy_fromopt_programcopy_file_namecopy_delimiteropt_withcopy_optionswhere_clause addon - if (strcmp($6, "from") == 0 && - (strcmp($7, "stdin") == 0 || strcmp($7, "stdout") == 0)) + if (strcmp(@6, "from") == 0 && + (strcmp(@7, "stdin") == 0 || strcmp(@7, "stdout") == 0)) mmerror(PARSE_ERROR, ET_WARNING, "COPY FROM STDIN is not implemented"); ECPG: var_valueNumericOnly addon - if ($1[0] == '$') - { - free($1); - $1 = mm_strdup("$0"); - } + if (@1[0] == '$') + @$ = mm_strdup("$0"); ECPG: fetch_argscursor_name addon - struct cursor *ptr = add_additional_variables($1, false); + struct cursor *ptr = add_additional_variables(@1, false); if (ptr->connection) connection = mm_strdup(ptr->connection); - if ($1[0] == ':') - { - free($1); - $1 = mm_strdup("$0"); - } + if (@1[0] == ':') + @$ = mm_strdup("$0"); ECPG: fetch_argsfrom_incursor_name addon - struct cursor *ptr = add_additional_variables($2, false); + struct cursor *ptr = add_additional_variables(@2, false); if (ptr->connection) connection = mm_strdup(ptr->connection); - if ($2[0] == ':') - { - free($2); - $2 = mm_strdup("$0"); - } + if (@2[0] == ':') + @$ = cat2_str(mm_strdup(@1), mm_strdup("$0")); ECPG: fetch_argsNEXTopt_from_incursor_name addon ECPG: fetch_argsPRIORopt_from_incursor_name addon ECPG: fetch_argsFIRST_Popt_from_incursor_name addon ECPG: fetch_argsLAST_Popt_from_incursor_name addon ECPG: fetch_argsALLopt_from_incursor_name addon - struct cursor *ptr = add_additional_variables($3, false); + struct cursor *ptr = add_additional_variables(@3, false); if (ptr->connection) connection = mm_strdup(ptr->connection); - if ($3[0] == ':') - { - free($3); - $3 = mm_strdup("$0"); - } + if (@3[0] == ':') + @$ = cat_str(3, mm_strdup(@1), mm_strdup(@2), mm_strdup("$0")); ECPG: fetch_argsSignedIconstopt_from_incursor_name addon - struct cursor *ptr = add_additional_variables($3, false); + struct cursor *ptr = add_additional_variables(@3, false); + bool replace = false; if (ptr->connection) connection = mm_strdup(ptr->connection); - if ($3[0] == ':') + if (@3[0] == ':') { - free($3); - $3 = mm_strdup("$0"); + @3 = mm_strdup("$0"); + replace = true; } - if ($1[0] == '$') + if (@1[0] == '$') { - free($1); - $1 = mm_strdup("$0"); + @1 = mm_strdup("$0"); + replace = true; } + if (replace) + @$ = cat_str(3, mm_strdup(@1), mm_strdup(@2), mm_strdup(@3)); ECPG: fetch_argsFORWARDALLopt_from_incursor_name addon ECPG: fetch_argsBACKWARDALLopt_from_incursor_name addon - struct cursor *ptr = add_additional_variables($4, false); + struct cursor *ptr = add_additional_variables(@4, false); if (ptr->connection) connection = mm_strdup(ptr->connection); - if ($4[0] == ':') - { - free($4); - $4 = mm_strdup("$0"); - } + if (@4[0] == ':') + @$ = cat_str(4, mm_strdup(@1), mm_strdup(@2), mm_strdup(@3), mm_strdup("$0")); ECPG: fetch_argsABSOLUTE_PSignedIconstopt_from_incursor_name addon ECPG: fetch_argsRELATIVE_PSignedIconstopt_from_incursor_name addon ECPG: fetch_argsFORWARDSignedIconstopt_from_incursor_name addon ECPG: fetch_argsBACKWARDSignedIconstopt_from_incursor_name addon - struct cursor *ptr = add_additional_variables($4, false); + struct cursor *ptr = add_additional_variables(@4, false); + bool replace = false; if (ptr->connection) connection = mm_strdup(ptr->connection); - if ($4[0] == ':') + if (@4[0] == ':') { - free($4); - $4 = mm_strdup("$0"); + @4 = mm_strdup("$0"); + replace = true; } - if ($2[0] == '$') + if (@2[0] == '$') { - free($2); - $2 = mm_strdup("$0"); + @2 = mm_strdup("$0"); + replace = true; } -ECPG: cursor_namename rule + if (replace) + @$ = cat_str(4, mm_strdup(@1), mm_strdup(@2), mm_strdup(@3), mm_strdup(@4)); +ECPG: cursor_namename block | char_civar { - char *curname = mm_alloc(strlen($1) + 2); + char *curname = mm_alloc(strlen(@1) + 2); - sprintf(curname, ":%s", $1); - free($1); - $1 = curname; - $$ = $1; + sprintf(curname, ":%s", @1); + @$ = curname; } ECPG: ExplainableStmtExecuteStmt block { - $$ = $1.name; + @$ = $1.name; } ECPG: PrepareStmtPREPAREprepared_nameprep_type_clauseASPreparableStmt block { - $$.name = $2; - $$.type = $3; - $$.stmt = $5; + $$.name = @2; + $$.type = @3; + $$.stmt = @5; } | PREPARE prepared_name FROM execstring { - $$.name = $2; + $$.name = @2; $$.type = NULL; - $$.stmt = $4; + $$.stmt = @4; } ECPG: ExecuteStmtEXECUTEprepared_nameexecute_param_clauseexecute_rest block { - $$.name = $2; - $$.type = $3; + $$.name = @2; + $$.type = @3; } ECPG: ExecuteStmtCREATEOptTempTABLEcreate_as_targetASEXECUTEprepared_nameexecute_param_clauseopt_with_dataexecute_rest block { - $$.name = cat_str(8, mm_strdup("create"), $2, mm_strdup("table"), $4, mm_strdup("as execute"), $7, $8, $9); + $$.name = @$; } ECPG: ExecuteStmtCREATEOptTempTABLEIF_PNOTEXISTScreate_as_targetASEXECUTEprepared_nameexecute_param_clauseopt_with_dataexecute_rest block { - $$.name = cat_str(8, mm_strdup("create"), $2, mm_strdup("table if not exists"), $7, mm_strdup("as execute"), $10,$11, $12); + $$.name = @$; } ECPG: DeclareCursorStmtDECLAREcursor_namecursor_optionsCURSORopt_holdFORSelectStmt block { struct cursor *ptr, *this; - char *cursor_marker = $2[0] == ':' ? mm_strdup("$0") : mm_strdup($2); + char *cursor_marker = @2[0] == ':' ? mm_strdup("$0") : mm_strdup(@2); char *comment, *c1, *c2; - int (*strcmp_fn) (const char *, const char *) = (($2[0] == ':' || $2[0] == '"') ? strcmp : pg_strcasecmp); + int (*strcmp_fn) (const char *, const char *) = ((@2[0] == ':' || @2[0] == '"') ? strcmp : pg_strcasecmp); - if (INFORMIX_MODE && pg_strcasecmp($2, "database") == 0) + if (INFORMIX_MODE && pg_strcasecmp(@2, "database") == 0) mmfatal(PARSE_ERROR, "\"database\" cannot be used as cursor name in INFORMIX mode"); for (ptr = cur; ptr != NULL; ptr = ptr->next) { - if (strcmp_fn($2, ptr->name) == 0) + if (strcmp_fn(@2, ptr->name) == 0) { - if ($2[0] == ':') - mmerror(PARSE_ERROR, ET_ERROR, "using variable \"%s\" in different declare statements is not supported",$2 + 1); + if (@2[0] == ':') + mmerror(PARSE_ERROR, ET_ERROR, "using variable \"%s\" in different declare statements is not supported",@2 + 1); else - mmerror(PARSE_ERROR, ET_ERROR, "cursor \"%s\" is already defined", $2); + mmerror(PARSE_ERROR, ET_ERROR, "cursor \"%s\" is already defined", @2); } } this = (struct cursor *) mm_alloc(sizeof(struct cursor)); this->next = cur; - this->name = $2; + this->name = mm_strdup(@2); this->function = (current_function ? mm_strdup(current_function) : NULL); this->connection = connection ? mm_strdup(connection) : NULL; this->opened = false; - this->command = cat_str(7, mm_strdup("declare"), cursor_marker, $3, mm_strdup("cursor"), $5, mm_strdup("for"), $7); + this->command = cat_str(7, mm_strdup("declare"), cursor_marker, @3, mm_strdup("cursor"), @5, mm_strdup("for"), @7); this->argsinsert = argsinsert; this->argsinsert_oos = NULL; this->argsresult = argsresult; @@ -435,47 +411,47 @@ ECPG: DeclareCursorStmtDECLAREcursor_namecursor_optionsCURSORopt_holdFORSelectSt } comment = cat_str(3, mm_strdup("/*"), c1, mm_strdup("*/")); - $$ = cat2_str(adjust_outofscope_cursor_vars(this), comment); + @$ = cat2_str(adjust_outofscope_cursor_vars(this), comment); } ECPG: ClosePortalStmtCLOSEcursor_name block { - char *cursor_marker = $2[0] == ':' ? mm_strdup("$0") : $2; + char *cursor_marker = @2[0] == ':' ? mm_strdup("$0") : @2; struct cursor *ptr = NULL; for (ptr = cur; ptr != NULL; ptr = ptr->next) { - if (strcmp($2, ptr->name) == 0) + if (strcmp(@2, ptr->name) == 0) { if (ptr->connection) connection = mm_strdup(ptr->connection); break; } } - $$ = cat2_str(mm_strdup("close"), cursor_marker); + @$ = cat2_str(mm_strdup("close"), cursor_marker); } ECPG: opt_hold block { if (compat == ECPG_COMPAT_INFORMIX_SE && autocommit) - $$ = mm_strdup("with hold"); + @$ = mm_strdup("with hold"); else - $$ = EMPTY; + @$ = EMPTY; } ECPG: into_clauseINTOOptTempTableName block { FoundInto = 1; - $$ = cat2_str(mm_strdup("into"), $2); + @$ = cat2_str(mm_strdup("into"), @2); } | ecpg_into { - $$ = EMPTY; + @$ = EMPTY; } ECPG: TypenameSimpleTypenameopt_array_bounds block { - $$ = cat2_str($1, $2.str); + @$ = cat2_str(@1, $2.str); } ECPG: TypenameSETOFSimpleTypenameopt_array_bounds block { - $$ = cat_str(3, mm_strdup("setof"), $2, $3.str); + @$ = cat_str(3, mm_strdup("setof"), @2, $3.str); } ECPG: opt_array_boundsopt_array_bounds'['']' block { @@ -492,10 +468,10 @@ ECPG: opt_array_boundsopt_array_bounds'['']' block $$.index1 = $1.index1; $$.index2 = $1.index2; if (strcmp($1.index1, "-1") == 0) - $$.index1 = mm_strdup($3); + $$.index1 = mm_strdup(@3); else if (strcmp($1.index2, "-1") == 0) - $$.index2 = mm_strdup($3); - $$.str = cat_str(4, $1.str, mm_strdup("["), $3, mm_strdup("]")); + $$.index2 = mm_strdup(@3); + $$.str = cat_str(4, $1.str, mm_strdup("["), @3, mm_strdup("]")); } ECPG: opt_array_bounds block { @@ -505,108 +481,100 @@ ECPG: opt_array_bounds block } ECPG: IconstICONST block { - $$ = make_name(); + @$ = make_name(); } ECPG: AexprConstNULL_P rule - | civar { $$ = $1; } - | civarind { $$ = $1; } + | civar + | civarind ECPG: VariableShowStmtSHOWALL block { mmerror(PARSE_ERROR, ET_ERROR, "SHOW ALL is not implemented"); - $$ = EMPTY; } ECPG: FetchStmtMOVEfetch_args rule | FETCH fetch_args ecpg_fetch_into - { - $$ = cat2_str(mm_strdup("fetch"), $2); - } | FETCH FORWARD cursor_name opt_ecpg_fetch_into { - char *cursor_marker = $3[0] == ':' ? mm_strdup("$0") : $3; - struct cursor *ptr = add_additional_variables($3, false); + char *cursor_marker = @3[0] == ':' ? mm_strdup("$0") : @3; + struct cursor *ptr = add_additional_variables(@3, false); if (ptr->connection) connection = mm_strdup(ptr->connection); - $$ = cat_str(2, mm_strdup("fetch forward"), cursor_marker); + @$ = cat_str(2, mm_strdup("fetch forward"), cursor_marker); } | FETCH FORWARD from_in cursor_name opt_ecpg_fetch_into { - char *cursor_marker = $4[0] == ':' ? mm_strdup("$0") : $4; - struct cursor *ptr = add_additional_variables($4, false); + char *cursor_marker = @4[0] == ':' ? mm_strdup("$0") : @4; + struct cursor *ptr = add_additional_variables(@4, false); if (ptr->connection) connection = mm_strdup(ptr->connection); - $$ = cat_str(2, mm_strdup("fetch forward from"), cursor_marker); + @$ = cat_str(2, mm_strdup("fetch forward from"), cursor_marker); } | FETCH BACKWARD cursor_name opt_ecpg_fetch_into { - char *cursor_marker = $3[0] == ':' ? mm_strdup("$0") : $3; - struct cursor *ptr = add_additional_variables($3, false); + char *cursor_marker = @3[0] == ':' ? mm_strdup("$0") : @3; + struct cursor *ptr = add_additional_variables(@3, false); if (ptr->connection) connection = mm_strdup(ptr->connection); - $$ = cat_str(2, mm_strdup("fetch backward"), cursor_marker); + @$ = cat_str(2, mm_strdup("fetch backward"), cursor_marker); } | FETCH BACKWARD from_in cursor_name opt_ecpg_fetch_into { - char *cursor_marker = $4[0] == ':' ? mm_strdup("$0") : $4; - struct cursor *ptr = add_additional_variables($4, false); + char *cursor_marker = @4[0] == ':' ? mm_strdup("$0") : @4; + struct cursor *ptr = add_additional_variables(@4, false); if (ptr->connection) connection = mm_strdup(ptr->connection); - $$ = cat_str(2, mm_strdup("fetch backward from"), cursor_marker); + @$ = cat_str(2, mm_strdup("fetch backward from"), cursor_marker); } | MOVE FORWARD cursor_name { - char *cursor_marker = $3[0] == ':' ? mm_strdup("$0") : $3; - struct cursor *ptr = add_additional_variables($3, false); + char *cursor_marker = @3[0] == ':' ? mm_strdup("$0") : @3; + struct cursor *ptr = add_additional_variables(@3, false); if (ptr->connection) connection = mm_strdup(ptr->connection); - $$ = cat_str(2, mm_strdup("move forward"), cursor_marker); + @$ = cat_str(2, mm_strdup("move forward"), cursor_marker); } | MOVE FORWARD from_in cursor_name { - char *cursor_marker = $4[0] == ':' ? mm_strdup("$0") : $4; - struct cursor *ptr = add_additional_variables($4, false); + char *cursor_marker = @4[0] == ':' ? mm_strdup("$0") : @4; + struct cursor *ptr = add_additional_variables(@4, false); if (ptr->connection) connection = mm_strdup(ptr->connection); - $$ = cat_str(2, mm_strdup("move forward from"), cursor_marker); + @$ = cat_str(2, mm_strdup("move forward from"), cursor_marker); } | MOVE BACKWARD cursor_name { - char *cursor_marker = $3[0] == ':' ? mm_strdup("$0") : $3; - struct cursor *ptr = add_additional_variables($3, false); + char *cursor_marker = @3[0] == ':' ? mm_strdup("$0") : @3; + struct cursor *ptr = add_additional_variables(@3, false); if (ptr->connection) connection = mm_strdup(ptr->connection); - $$ = cat_str(2, mm_strdup("move backward"), cursor_marker); + @$ = cat_str(2, mm_strdup("move backward"), cursor_marker); } | MOVE BACKWARD from_in cursor_name { - char *cursor_marker = $4[0] == ':' ? mm_strdup("$0") : $4; - struct cursor *ptr = add_additional_variables($4, false); + char *cursor_marker = @4[0] == ':' ? mm_strdup("$0") : @4; + struct cursor *ptr = add_additional_variables(@4, false); if (ptr->connection) connection = mm_strdup(ptr->connection); - $$ = cat_str(2, mm_strdup("move backward from"), cursor_marker); + @$ = cat_str(2, mm_strdup("move backward from"), cursor_marker); } ECPG: limit_clauseLIMITselect_limit_value','select_offset_value block { mmerror(PARSE_ERROR, ET_WARNING, "no longer supported LIMIT #,# syntax passed to server"); - $$ = cat_str(4, mm_strdup("limit"), $2, mm_strdup(","), $4); } ECPG: SignedIconstIconst rule | civar - { - $$ = $1; - } diff --git a/src/interfaces/ecpg/preproc/ecpg.header b/src/interfaces/ecpg/preproc/ecpg.header index 3ed39b5c77..46023a0106 100644 --- a/src/interfaces/ecpg/preproc/ecpg.header +++ b/src/interfaces/ecpg/preproc/ecpg.header @@ -8,14 +8,6 @@ #include "ecpg_config.h" #include <unistd.h> -/* Location tracking support --- simpler than bison's default */ -#define YYLLOC_DEFAULT(Current, Rhs, N) \ - do { \ - if (N) \ - (Current) = (Rhs)[1]; \ - else \ - (Current) = (Rhs)[0]; \ - } while (0) /* * The %name-prefix option below will make bison call base_yylex, but we @@ -195,6 +187,61 @@ make3_str(char *str1, char *str2, char *str3) return res_str; } +/* + * "Location tracking" support. We commandeer Bison's location tracking + * mechanism to manage the output string for productions that ordinarily would + * return a <str> result. This allows the majority of those productions to + * have default semantic actions, reducing the size of the parser, and also + * greatly reducing its compilation time on some versions of clang. + * + * To do this, we make YYLTYPE be a pointer to a malloc'd string, and then + * merge the location strings of the input tokens in the default YYLLOC + * computation. Productions that are okay with the standard merge need not + * do anything more; otherwise, they can override it by assigning to @$. + */ +#define YYLLOC_DEFAULT(Current, Rhs, N) yylloc_default(&(Current), Rhs, N) + +static void +yylloc_default(YYLTYPE *target, YYLTYPE *rhs, int N) +{ + if (N > 1) + { + /* Concatenate non-empty inputs with one space between them */ + char *result, + *ptr; + size_t needed = 0; + + for (int i = 1; i <= N; i++) + { + size_t thislen = strlen(rhs[i]); + + if (needed > 0 && thislen > 0) + needed++; + needed += thislen; + } + result = (char *) mm_alloc(needed + 1); + ptr = result; + for (int i = 1; i <= N; i++) + { + size_t thislen = strlen(rhs[i]); + + if (ptr > result && thislen > 0) + *ptr++ = ' '; + memcpy(ptr, rhs[i], thislen); + ptr += thislen; + } + *ptr = '\0'; + *target = result; + } + else if (N == 1) + { + /* Just re-use the single input */ + *target = rhs[1]; + } + else + *target = EMPTY; +} + /* and the rest */ static char * make_name(void) diff --git a/src/interfaces/ecpg/preproc/ecpg.trailer b/src/interfaces/ecpg/preproc/ecpg.trailer index b6233e5e53..e6475e170d 100644 --- a/src/interfaces/ecpg/preproc/ecpg.trailer +++ b/src/interfaces/ecpg/preproc/ecpg.trailer @@ -18,20 +18,17 @@ statement: ecpgstart at toplevel_stmt ';' } | ecpgstart ECPGVarDeclaration { - fprintf(base_yyout, "%s", $2); - free($2); + fprintf(base_yyout, "%s", @$); output_line_number(); } | ECPGDeclaration | c_thing { - fprintf(base_yyout, "%s", $1); - free($1); + fprintf(base_yyout, "%s", @$); } | CPP_LINE { - fprintf(base_yyout, "%s", $1); - free($1); + fprintf(base_yyout, "%s", @$); } | '{' { @@ -58,8 +55,6 @@ CreateAsStmt: CREATE OptTemp TABLE create_as_target AS { if (FoundInto == 1) mmerror(PARSE_ERROR, ET_ERROR, "CREATE TABLE AS cannot specify INTO"); - - $$ = cat_str(7, mm_strdup("create"), $2, mm_strdup("table"), $4, mm_strdup("as"), $7, $8); } | CREATE OptTemp TABLE IF_P NOT EXISTS create_as_target AS { @@ -68,14 +63,12 @@ CreateAsStmt: CREATE OptTemp TABLE create_as_target AS { if (FoundInto == 1) mmerror(PARSE_ERROR, ET_ERROR, "CREATE TABLE AS cannot specify INTO"); - - $$ = cat_str(7, mm_strdup("create"), $2, mm_strdup("table if not exists"), $7, mm_strdup("as"), $10, $11); } ; at: AT connection_object { - connection = $2; + connection = @2; /* * Do we have a variable as connection target? Remove the variable @@ -91,55 +84,52 @@ at: AT connection_object */ ECPGConnect: SQL_CONNECT TO connection_target opt_connection_name opt_user { - $$ = cat_str(5, $3, mm_strdup(","), $5, mm_strdup(","), $4); + @$ = cat_str(5, @3, mm_strdup(","), @5, mm_strdup(","), @4); } | SQL_CONNECT TO DEFAULT { - $$ = mm_strdup("NULL, NULL, NULL, \"DEFAULT\""); + @$ = mm_strdup("NULL, NULL, NULL, \"DEFAULT\""); } /* also allow ORACLE syntax */ | SQL_CONNECT ora_user { - $$ = cat_str(3, mm_strdup("NULL,"), $2, mm_strdup(", NULL")); + @$ = cat_str(3, mm_strdup("NULL,"), @2, mm_strdup(", NULL")); } | DATABASE connection_target { - $$ = cat2_str($2, mm_strdup(", NULL, NULL, NULL")); + @$ = cat2_str(@2, mm_strdup(", NULL, NULL, NULL")); } ; connection_target: opt_database_name opt_server opt_port { /* old style: dbname[@server][:port] */ - if (strlen($2) > 0 && *($2) != '@') - mmerror(PARSE_ERROR, ET_ERROR, "expected \"@\", found \"%s\"", $2); + if (strlen(@2) > 0 && *(@2) != '@') + mmerror(PARSE_ERROR, ET_ERROR, "expected \"@\", found \"%s\"", @2); /* C strings need to be handled differently */ - if ($1[0] == '\"') - $$ = $1; + if (@1[0] == '\"') + @$ = @1; else - $$ = make3_str(mm_strdup("\""), make3_str($1, $2, $3), mm_strdup("\"")); + @$ = make3_str(mm_strdup("\""), make3_str(@1, @2, @3), mm_strdup("\"")); } | db_prefix ':' server opt_port '/' opt_database_name opt_options { /* new style: <tcp|unix>:postgresql://server[:port][/dbname] */ - if (strncmp($1, "unix:postgresql", strlen("unix:postgresql")) != 0 && strncmp($1, "tcp:postgresql", strlen("tcp:postgresql"))!= 0) + if (strncmp(@1, "unix:postgresql", strlen("unix:postgresql")) != 0 && strncmp(@1, "tcp:postgresql", strlen("tcp:postgresql"))!= 0) mmerror(PARSE_ERROR, ET_ERROR, "only protocols \"tcp\" and \"unix\" and database type \"postgresql\" are supported"); - if (strncmp($3, "//", strlen("//")) != 0) - mmerror(PARSE_ERROR, ET_ERROR, "expected \"://\", found \"%s\"", $3); + if (strncmp(@3, "//", strlen("//")) != 0) + mmerror(PARSE_ERROR, ET_ERROR, "expected \"://\", found \"%s\"", @3); - if (strncmp($1, "unix", strlen("unix")) == 0 && - strncmp($3 + strlen("//"), "localhost", strlen("localhost")) != 0 && - strncmp($3 + strlen("//"), "127.0.0.1", strlen("127.0.0.1")) != 0) - mmerror(PARSE_ERROR, ET_ERROR, "Unix-domain sockets only work on \"localhost\" but not on \"%s\"", $3 + strlen("//")); + if (strncmp(@1, "unix", strlen("unix")) == 0 && + strncmp(@3 + strlen("//"), "localhost", strlen("localhost")) != 0 && + strncmp(@3 + strlen("//"), "127.0.0.1", strlen("127.0.0.1")) != 0) + mmerror(PARSE_ERROR, ET_ERROR, "Unix-domain sockets only work on \"localhost\" but not on \"%s\"", @3 + strlen("//")); - $$ = make3_str(make3_str(mm_strdup("\""), $1, mm_strdup(":")), $3, make3_str(make3_str($4, mm_strdup("/"), $6),$7, mm_strdup("\""))); + @$ = make3_str(make3_str(mm_strdup("\""), @1, mm_strdup(":")), @3, make3_str(make3_str(@4, mm_strdup("/"), @6),@7, mm_strdup("\""))); } | char_variable - { - $$ = $1; - } | ecpg_sconst { /* @@ -147,128 +137,107 @@ connection_target: opt_database_name opt_server opt_port * so we change the quotes. Note, that the rule for ecpg_sconst adds * these single quotes. */ - $1[0] = '\"'; - $1[strlen($1) - 1] = '\"'; - $$ = $1; + @1[0] = '\"'; + @1[strlen(@1) - 1] = '\"'; + @$ = @1; } ; opt_database_name: name - { - $$ = $1; - } | /* EMPTY */ - { - $$ = EMPTY; - } ; db_prefix: ecpg_ident cvariable { - if (strcmp($2, "postgresql") != 0 && strcmp($2, "postgres") != 0) - mmerror(PARSE_ERROR, ET_ERROR, "expected \"postgresql\", found \"%s\"", $2); + if (strcmp(@2, "postgresql") != 0 && strcmp(@2, "postgres") != 0) + mmerror(PARSE_ERROR, ET_ERROR, "expected \"postgresql\", found \"%s\"", @2); - if (strcmp($1, "tcp") != 0 && strcmp($1, "unix") != 0) - mmerror(PARSE_ERROR, ET_ERROR, "invalid connection type: %s", $1); + if (strcmp(@1, "tcp") != 0 && strcmp(@1, "unix") != 0) + mmerror(PARSE_ERROR, ET_ERROR, "invalid connection type: %s", @1); - $$ = make3_str($1, mm_strdup(":"), $2); + @$ = make3_str(@1, mm_strdup(":"), @2); } ; server: Op server_name { - if (strcmp($1, "@") != 0 && strcmp($1, "//") != 0) - mmerror(PARSE_ERROR, ET_ERROR, "expected \"@\" or \"://\", found \"%s\"", $1); + if (strcmp(@1, "@") != 0 && strcmp(@1, "//") != 0) + mmerror(PARSE_ERROR, ET_ERROR, "expected \"@\" or \"://\", found \"%s\"", @1); - $$ = make2_str($1, $2); + @$ = make2_str(@1, @2); } ; opt_server: server - { - $$ = $1; - } | /* EMPTY */ - { - $$ = EMPTY; - } ; server_name: ColId - { - $$ = $1; - } | ColId '.' server_name - { - $$ = make3_str($1, mm_strdup("."), $3); - } | IP { - $$ = make_name(); + @$ = make_name(); } ; opt_port: ':' Iconst { - $$ = make2_str(mm_strdup(":"), $2); + @$ = make2_str(mm_strdup(":"), @2); } | /* EMPTY */ - { - $$ = EMPTY; - } ; opt_connection_name: AS connection_object { - $$ = $2; + @$ = @2; } | /* EMPTY */ { - $$ = mm_strdup("NULL"); + @$ = mm_strdup("NULL"); } ; opt_user: USER ora_user { - $$ = $2; + @$ = @2; } | /* EMPTY */ { - $$ = mm_strdup("NULL, NULL"); + @$ = mm_strdup("NULL, NULL"); } ; ora_user: user_name { - $$ = cat2_str($1, mm_strdup(", NULL")); + @$ = cat2_str(@1, mm_strdup(", NULL")); } | user_name '/' user_name { - $$ = cat_str(3, $1, mm_strdup(","), $3); + @$ = cat_str(3, @1, mm_strdup(","), @3); } | user_name SQL_IDENTIFIED BY user_name { - $$ = cat_str(3, $1, mm_strdup(","), $4); + @$ = cat_str(3, @1, mm_strdup(","), @4); } | user_name USING user_name { - $$ = cat_str(3, $1, mm_strdup(","), $3); + @$ = cat_str(3, @1, mm_strdup(","), @3); } ; user_name: RoleId { - if ($1[0] == '\"') - $$ = $1; + if (@1[0] == '\"') + @$ = @1; else - $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); + @$ = make3_str(mm_strdup("\""), @1, mm_strdup("\"")); } | ecpg_sconst { - if ($1[0] == '\"') - $$ = $1; + if (@1[0] == '\"') + @$ = @1; else - $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); + @$ = make3_str(mm_strdup("\""), @1, mm_strdup("\"")); } | civar { @@ -280,16 +249,16 @@ user_name: RoleId /* handle varchars */ if (type == ECPGt_varchar) - $$ = make2_str(mm_strdup(argsinsert->variable->name), mm_strdup(".arr")); + @$ = make2_str(mm_strdup(argsinsert->variable->name), mm_strdup(".arr")); else - $$ = mm_strdup(argsinsert->variable->name); + @$ = mm_strdup(argsinsert->variable->name); } ; char_variable: cvariable { /* check if we have a string variable */ - struct variable *p = find_variable($1); + struct variable *p = find_variable(@1); enum ECPGttype type = p->type->type; /* If we have just one character this is not a string */ @@ -306,14 +275,14 @@ char_variable: cvariable case ECPGt_char: case ECPGt_unsigned_char: case ECPGt_string: - $$ = $1; + @$ = @1; break; case ECPGt_varchar: - $$ = make2_str($1, mm_strdup(".arr")); + @$ = make2_str(@1, mm_strdup(".arr")); break; default: mmerror(PARSE_ERROR, ET_ERROR, "invalid data type"); - $$ = $1; + @$ = @1; break; } } @@ -322,72 +291,63 @@ char_variable: cvariable opt_options: Op connect_options { - if (strlen($1) == 0) + if (strlen(@1) == 0) mmerror(PARSE_ERROR, ET_ERROR, "incomplete statement"); - if (strcmp($1, "?") != 0) - mmerror(PARSE_ERROR, ET_ERROR, "unrecognized token \"%s\"", $1); + if (strcmp(@1, "?") != 0) + mmerror(PARSE_ERROR, ET_ERROR, "unrecognized token \"%s\"", @1); - $$ = make2_str(mm_strdup("?"), $2); + @$ = make2_str(mm_strdup("?"), @2); } | /* EMPTY */ - { - $$ = EMPTY; - } ; connect_options: ColId opt_opt_value { - $$ = make2_str($1, $2); + @$ = make2_str(@1, @2); } | ColId opt_opt_value Op connect_options { - if (strlen($3) == 0) + if (strlen(@3) == 0) mmerror(PARSE_ERROR, ET_ERROR, "incomplete statement"); - if (strcmp($3, "&") != 0) - mmerror(PARSE_ERROR, ET_ERROR, "unrecognized token \"%s\"", $3); + if (strcmp(@3, "&") != 0) + mmerror(PARSE_ERROR, ET_ERROR, "unrecognized token \"%s\"", @3); - $$ = cat_str(3, make2_str($1, $2), $3, $4); + @$ = cat_str(3, make2_str(@1, @2), @3, @4); } ; opt_opt_value: /* EMPTY */ - { - $$ = EMPTY; - } | '=' Iconst { - $$ = make2_str(mm_strdup("="), $2); + @$ = make2_str(mm_strdup("="), @2); } | '=' ecpg_ident { - $$ = make2_str(mm_strdup("="), $2); + @$ = make2_str(mm_strdup("="), @2); } | '=' civar { - $$ = make2_str(mm_strdup("="), $2); + @$ = make2_str(mm_strdup("="), @2); } ; prepared_name: name { - if ($1[0] == '\"' && $1[strlen($1) - 1] == '\"') /* already quoted? */ - $$ = $1; + if (@1[0] == '\"' && @1[strlen(@1) - 1] == '\"') /* already quoted? */ + @$ = @1; else /* not quoted => convert to lowercase */ { size_t i; - for (i = 0; i < strlen($1); i++) - $1[i] = tolower((unsigned char) $1[i]); + for (i = 0; i < strlen(@1); i++) + @1[i] = tolower((unsigned char) @1[i]); - $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); + @$ = make3_str(mm_strdup("\""), @1, mm_strdup("\"")); } } | char_variable - { - $$ = $1; - } ; /* @@ -400,7 +360,7 @@ ECPGDeclareStmt: DECLARE prepared_name STATEMENT /* Check whether the declared name has been defined or not */ for (ptr = g_declared_list; ptr != NULL; ptr = ptr->next) { - if (strcmp($2, ptr->name) == 0) + if (strcmp(@2, ptr->name) == 0) { /* re-definition is not allowed */ mmerror(PARSE_ERROR, ET_ERROR, "name \"%s\" is already declared", ptr->name); @@ -413,7 +373,7 @@ ECPGDeclareStmt: DECLARE prepared_name STATEMENT if (ptr) { /* initial definition */ - ptr->name = $2; + ptr->name = @2; if (connection) ptr->connection = mm_strdup(connection); else @@ -423,7 +383,7 @@ ECPGDeclareStmt: DECLARE prepared_name STATEMENT g_declared_list = ptr; } - $$ = cat_str(3, mm_strdup("/* declare "), mm_strdup($2), mm_strdup(" as an SQL identifier */")); + @$ = cat_str(3, mm_strdup("/* declare "), mm_strdup(@2), mm_strdup(" as an SQL identifier */")); } ; @@ -435,26 +395,26 @@ ECPGCursorStmt: DECLARE cursor_name cursor_options CURSOR opt_hold FOR prepared_ { struct cursor *ptr, *this; - char *cursor_marker = $2[0] == ':' ? mm_strdup("$0") : mm_strdup($2); - int (*strcmp_fn) (const char *, const char *) = (($2[0] == ':' || $2[0] == '"') ? strcmp : pg_strcasecmp); + char *cursor_marker = @2[0] == ':' ? mm_strdup("$0") : mm_strdup(@2); + int (*strcmp_fn) (const char *, const char *) = ((@2[0] == ':' || @2[0] == '"') ? strcmp : pg_strcasecmp); struct variable *thisquery = (struct variable *) mm_alloc(sizeof(struct variable)); char *comment; char *con; - if (INFORMIX_MODE && pg_strcasecmp($2, "database") == 0) + if (INFORMIX_MODE && pg_strcasecmp(@2, "database") == 0) mmfatal(PARSE_ERROR, "\"database\" cannot be used as cursor name in INFORMIX mode"); - check_declared_list($7); + check_declared_list(@7); con = connection ? connection : "NULL"; for (ptr = cur; ptr != NULL; ptr = ptr->next) { - if (strcmp_fn($2, ptr->name) == 0) + if (strcmp_fn(@2, ptr->name) == 0) { /* re-definition is a bug */ - if ($2[0] == ':') - mmerror(PARSE_ERROR, ET_ERROR, "using variable \"%s\" in different declare statements is not supported",$2 + 1); + if (@2[0] == ':') + mmerror(PARSE_ERROR, ET_ERROR, "using variable \"%s\" in different declare statements is not supported",@2 + 1); else - mmerror(PARSE_ERROR, ET_ERROR, "cursor \"%s\" is already defined", $2); + mmerror(PARSE_ERROR, ET_ERROR, "cursor \"%s\" is already defined", @2); } } @@ -462,24 +422,24 @@ ECPGCursorStmt: DECLARE cursor_name cursor_options CURSOR opt_hold FOR prepared_ /* initial definition */ this->next = cur; - this->name = $2; + this->name = @2; this->function = (current_function ? mm_strdup(current_function) : NULL); this->connection = connection ? mm_strdup(connection) : NULL; - this->command = cat_str(6, mm_strdup("declare"), cursor_marker, $3, mm_strdup("cursor"), $5, mm_strdup("for $1")); + this->command = cat_str(6, mm_strdup("declare"), cursor_marker, @3, mm_strdup("cursor"), @5, mm_strdup("for $1")); this->argsresult = NULL; this->argsresult_oos = NULL; thisquery->type = &ecpg_query; thisquery->brace_level = 0; thisquery->next = NULL; - thisquery->name = (char *) mm_alloc(sizeof("ECPGprepared_statement(, , __LINE__)") + strlen(con) + strlen($7)); - sprintf(thisquery->name, "ECPGprepared_statement(%s, %s, __LINE__)", con, $7); + thisquery->name = (char *) mm_alloc(sizeof("ECPGprepared_statement(, , __LINE__)") + strlen(con) + strlen(@7)); + sprintf(thisquery->name, "ECPGprepared_statement(%s, %s, __LINE__)", con, @7); this->argsinsert = NULL; this->argsinsert_oos = NULL; - if ($2[0] == ':') + if (@2[0] == ':') { - struct variable *var = find_variable($2 + 1); + struct variable *var = find_variable(@2 + 1); remove_variable_from_list(&argsinsert, var); add_variable_to_head(&(this->argsinsert), var, &no_indicator); @@ -490,7 +450,7 @@ ECPGCursorStmt: DECLARE cursor_name cursor_options CURSOR opt_hold FOR prepared_ comment = cat_str(3, mm_strdup("/*"), mm_strdup(this->command), mm_strdup("*/")); - $$ = cat_str(2, adjust_outofscope_cursor_vars(this), + @$ = cat_str(2, adjust_outofscope_cursor_vars(this), comment); } ; @@ -501,7 +461,7 @@ ECPGExecuteImmediateStmt: EXECUTE IMMEDIATE execstring * execute immediate means prepare the statement and immediately * execute it */ - $$ = $3; + @$ = @3; } ; @@ -511,36 +471,24 @@ ECPGExecuteImmediateStmt: EXECUTE IMMEDIATE execstring ECPGVarDeclaration: single_vt_declaration; single_vt_declaration: type_declaration - { - $$ = $1; - } | var_declaration - { - $$ = $1; - } ; precision: NumericOnly - { - $$ = $1; - } ; opt_scale: ',' NumericOnly { - $$ = $2; + @$ = @2; } | /* EMPTY */ - { - $$ = EMPTY; - } ; -ecpg_interval: opt_interval { $$ = $1; } - | YEAR_P TO MINUTE_P { $$ = mm_strdup("year to minute"); } - | YEAR_P TO SECOND_P { $$ = mm_strdup("year to second"); } - | DAY_P TO DAY_P { $$ = mm_strdup("day to day"); } - | MONTH_P TO MONTH_P { $$ = mm_strdup("month to month"); } +ecpg_interval: opt_interval + | YEAR_P TO MINUTE_P + | YEAR_P TO SECOND_P + | DAY_P TO DAY_P + | MONTH_P TO MONTH_P ; /* @@ -552,8 +500,7 @@ ECPGDeclaration: sql_startdeclare } var_type_declarations sql_enddeclare { - fprintf(base_yyout, "%s/* exec sql end declare section */", $3); - free($3); + fprintf(base_yyout, "%s/* exec sql end declare section */", @3); output_line_number(); } ; @@ -569,41 +516,17 @@ sql_enddeclare: ecpgstart END_P DECLARE SQL_SECTION ';' ; var_type_declarations: /* EMPTY */ - { - $$ = EMPTY; - } | vt_declarations - { - $$ = $1; - } ; vt_declarations: single_vt_declaration - { - $$ = $1; - } | CPP_LINE - { - $$ = $1; - } | vt_declarations single_vt_declaration - { - $$ = cat2_str($1, $2); - } | vt_declarations CPP_LINE - { - $$ = cat2_str($1, $2); - } ; variable_declarations: var_declaration - { - $$ = $1; - } | variable_declarations var_declaration - { - $$ = cat2_str($1, $2); - } ; type_declaration: S_TYPEDEF @@ -614,18 +537,18 @@ type_declaration: S_TYPEDEF } var_type opt_pointer ECPGColLabel opt_array_bounds ';' { - add_typedef($5, $6.index1, $6.index2, $3.type_enum, $3.type_dimension, $3.type_index, initializer, *$4 ? 1 : 0); + add_typedef(@5, $6.index1, $6.index2, $3.type_enum, $3.type_dimension, $3.type_index, initializer, *@4 ? 1 : 0); - fprintf(base_yyout, "typedef %s %s %s %s;\n", $3.type_str, *$4 ? "*" : "", $5, $6.str); + fprintf(base_yyout, "typedef %s %s %s %s;\n", $3.type_str, *@4 ? "*" : "", @5, $6.str); output_line_number(); - $$ = mm_strdup(""); + @$ = EMPTY; } ; var_declaration: storage_declaration var_type { - actual_type[struct_level].type_storage = $1; + actual_type[struct_level].type_storage = @1; actual_type[struct_level].type_enum = $2.type_enum; actual_type[struct_level].type_str = $2.type_str; actual_type[struct_level].type_dimension = $2.type_dimension; @@ -636,7 +559,7 @@ var_declaration: } variable_list ';' { - $$ = cat_str(5, actual_startline[struct_level], $1, $2.type_str, $4, mm_strdup(";\n")); + @$ = cat_str(5, actual_startline[struct_level], @1, $2.type_str, @4, mm_strdup(";\n")); } | var_type { @@ -651,46 +574,31 @@ var_declaration: } variable_list ';' { - $$ = cat_str(4, actual_startline[struct_level], $1.type_str, $3, mm_strdup(";\n")); + @$ = cat_str(4, actual_startline[struct_level], $1.type_str, @3, mm_strdup(";\n")); } | struct_union_type_with_symbol ';' { - $$ = cat2_str($1, mm_strdup(";")); + @$ = cat2_str(@1, mm_strdup(";")); } ; opt_bit_field: ':' Iconst - { - $$ = cat2_str(mm_strdup(":"), $2); - } | /* EMPTY */ - { - $$ = EMPTY; - } ; storage_declaration: storage_clause storage_modifier - { - $$ = cat2_str($1, $2); - } | storage_clause - { - $$ = $1; - } | storage_modifier - { - $$ = $1; - } ; -storage_clause: S_EXTERN { $$ = mm_strdup("extern"); } - | S_STATIC { $$ = mm_strdup("static"); } - | S_REGISTER { $$ = mm_strdup("register"); } - | S_AUTO { $$ = mm_strdup("auto"); } +storage_clause: S_EXTERN + | S_STATIC + | S_REGISTER + | S_AUTO ; -storage_modifier: S_CONST { $$ = mm_strdup("const"); } - | S_VOLATILE { $$ = mm_strdup("volatile"); } +storage_modifier: S_CONST + | S_VOLATILE ; var_type: simple_type @@ -703,11 +611,11 @@ var_type: simple_type } | struct_union_type { - $$.type_str = $1; + $$.type_str = @1; $$.type_dimension = mm_strdup("-1"); $$.type_index = mm_strdup("-1"); - if (strncmp($1, "struct", sizeof("struct") - 1) == 0) + if (strncmp(@1, "struct", sizeof("struct") - 1) == 0) { $$.type_enum = ECPGt_struct; $$.type_sizeof = ECPGstruct_sizeof; @@ -720,7 +628,7 @@ var_type: simple_type } | enum_type { - $$.type_str = $1; + $$.type_str = @1; $$.type_enum = ECPGt_int; $$.type_dimension = mm_strdup("-1"); $$.type_index = mm_strdup("-1"); @@ -749,12 +657,12 @@ var_type: simple_type * will show up here as a plain identifier, and we need this duplicate * code to recognize them. */ - if (strcmp($1, "numeric") == 0) + if (strcmp(@1, "numeric") == 0) { $$.type_enum = ECPGt_numeric; $$.type_str = mm_strdup("numeric"); } - else if (strcmp($1, "decimal") == 0) + else if (strcmp(@1, "decimal") == 0) { $$.type_enum = ECPGt_decimal; $$.type_str = mm_strdup("decimal"); @@ -858,10 +766,10 @@ var_type: simple_type * here, but not above because those are not currently SQL keywords. * If they ever become so, they must gain duplicate productions above. */ - if (strlen($2) != 0 && strcmp($1, "datetime") != 0 && strcmp($1, "interval") != 0) + if (strlen(@2) != 0 && strcmp(@1, "datetime") != 0 && strcmp(@1, "interval") != 0) mmerror(PARSE_ERROR, ET_ERROR, "interval specification not allowed here"); - if (strcmp($1, "varchar") == 0) + if (strcmp(@1, "varchar") == 0) { $$.type_enum = ECPGt_varchar; $$.type_str = EMPTY; /* mm_strdup("varchar"); */ @@ -869,7 +777,7 @@ var_type: simple_type $$.type_index = mm_strdup("-1"); $$.type_sizeof = NULL; } - else if (strcmp($1, "bytea") == 0) + else if (strcmp(@1, "bytea") == 0) { $$.type_enum = ECPGt_bytea; $$.type_str = EMPTY; @@ -877,7 +785,7 @@ var_type: simple_type $$.type_index = mm_strdup("-1"); $$.type_sizeof = NULL; } - else if (strcmp($1, "float") == 0) + else if (strcmp(@1, "float") == 0) { $$.type_enum = ECPGt_float; $$.type_str = mm_strdup("float"); @@ -885,7 +793,7 @@ var_type: simple_type $$.type_index = mm_strdup("-1"); $$.type_sizeof = NULL; } - else if (strcmp($1, "double") == 0) + else if (strcmp(@1, "double") == 0) { $$.type_enum = ECPGt_double; $$.type_str = mm_strdup("double"); @@ -893,7 +801,7 @@ var_type: simple_type $$.type_index = mm_strdup("-1"); $$.type_sizeof = NULL; } - else if (strcmp($1, "numeric") == 0) + else if (strcmp(@1, "numeric") == 0) { $$.type_enum = ECPGt_numeric; $$.type_str = mm_strdup("numeric"); @@ -901,7 +809,7 @@ var_type: simple_type $$.type_index = mm_strdup("-1"); $$.type_sizeof = NULL; } - else if (strcmp($1, "decimal") == 0) + else if (strcmp(@1, "decimal") == 0) { $$.type_enum = ECPGt_decimal; $$.type_str = mm_strdup("decimal"); @@ -909,7 +817,7 @@ var_type: simple_type $$.type_index = mm_strdup("-1"); $$.type_sizeof = NULL; } - else if (strcmp($1, "date") == 0) + else if (strcmp(@1, "date") == 0) { $$.type_enum = ECPGt_date; $$.type_str = mm_strdup("date"); @@ -917,7 +825,7 @@ var_type: simple_type $$.type_index = mm_strdup("-1"); $$.type_sizeof = NULL; } - else if (strcmp($1, "timestamp") == 0) + else if (strcmp(@1, "timestamp") == 0) { $$.type_enum = ECPGt_timestamp; $$.type_str = mm_strdup("timestamp"); @@ -925,7 +833,7 @@ var_type: simple_type $$.type_index = mm_strdup("-1"); $$.type_sizeof = NULL; } - else if (strcmp($1, "interval") == 0) + else if (strcmp(@1, "interval") == 0) { $$.type_enum = ECPGt_interval; $$.type_str = mm_strdup("interval"); @@ -933,7 +841,7 @@ var_type: simple_type $$.type_index = mm_strdup("-1"); $$.type_sizeof = NULL; } - else if (strcmp($1, "datetime") == 0) + else if (strcmp(@1, "datetime") == 0) { $$.type_enum = ECPGt_timestamp; $$.type_str = mm_strdup("timestamp"); @@ -941,7 +849,7 @@ var_type: simple_type $$.type_index = mm_strdup("-1"); $$.type_sizeof = NULL; } - else if ((strcmp($1, "string") == 0) && INFORMIX_MODE) + else if ((strcmp(@1, "string") == 0) && INFORMIX_MODE) { $$.type_enum = ECPGt_string; $$.type_str = mm_strdup("char"); @@ -952,7 +860,7 @@ var_type: simple_type else { /* Otherwise, it must be a user-defined typedef name */ - struct typedefs *this = get_typedef($1, false); + struct typedefs *this = get_typedef(@1, false); $$.type_str = (this->type->type_enum == ECPGt_varchar || this->type->type_enum == ECPGt_bytea) ? EMPTY : mm_strdup(this->name); $$.type_enum = this->type->type_enum; @@ -1001,23 +909,11 @@ var_type: simple_type ; enum_type: ENUM_P symbol enum_definition - { - $$ = cat_str(3, mm_strdup("enum"), $2, $3); - } | ENUM_P enum_definition - { - $$ = cat2_str(mm_strdup("enum"), $2); - } | ENUM_P symbol - { - $$ = cat2_str(mm_strdup("enum"), $2); - } ; enum_definition: '{' c_list '}' - { - $$ = cat_str(3, mm_strdup("{"), $2, mm_strdup("}")); - } ; struct_union_type_with_symbol: s_struct_union_symbol @@ -1071,14 +967,11 @@ struct_union_type_with_symbol: s_struct_union_symbol this->struct_member_list = struct_member_list[struct_level]; types = this; - $$ = cat_str(4, su_type.type_str, mm_strdup("{"), $4, mm_strdup("}")); + @$ = cat_str(4, su_type.type_str, mm_strdup("{"), @4, mm_strdup("}")); } ; struct_union_type: struct_union_type_with_symbol - { - $$ = $1; - } | s_struct_union { struct_member_list[struct_level++] = NULL; @@ -1090,20 +983,20 @@ struct_union_type: struct_union_type_with_symbol ECPGfree_struct_member(struct_member_list[struct_level]); struct_member_list[struct_level] = NULL; struct_level--; - $$ = cat_str(4, $1, mm_strdup("{"), $4, mm_strdup("}")); + @$ = cat_str(4, @1, mm_strdup("{"), @4, mm_strdup("}")); } ; s_struct_union_symbol: SQL_STRUCT symbol { $$.su = mm_strdup("struct"); - $$.symbol = $2; + $$.symbol = @2; ECPGstruct_sizeof = cat_str(3, mm_strdup("sizeof("), cat2_str(mm_strdup($$.su), mm_strdup($$.symbol)), mm_strdup(")")); } | UNION symbol { $$.su = mm_strdup("union"); - $$.symbol = $2; + $$.symbol = @2; } ; @@ -1111,15 +1004,15 @@ s_struct_union: SQL_STRUCT { ECPGstruct_sizeof = mm_strdup(""); /* This must not be NULL to * distinguish from simple types. */ - $$ = mm_strdup("struct"); + @$ = mm_strdup("struct"); } | UNION { - $$ = mm_strdup("union"); + @$ = mm_strdup("union"); } ; -simple_type: unsigned_type { $$ = $1; } +simple_type: unsigned_type | opt_signed signed_type { $$ = $2; } ; @@ -1151,15 +1044,12 @@ opt_signed: SQL_SIGNED ; variable_list: variable - { - $$ = $1; - } | variable_list ',' variable { if (actual_type[struct_level].type_enum == ECPGt_varchar || actual_type[struct_level].type_enum == ECPGt_bytea) - $$ = cat_str(4, $1, mm_strdup(";"), mm_strdup(actual_type[struct_level].type_storage), $3); + @$ = cat_str(4, @1, mm_strdup(";"), mm_strdup(actual_type[struct_level].type_storage), @3); else - $$ = cat_str(3, $1, mm_strdup(","), $3); + @$ = cat_str(3, @1, mm_strdup(","), @3); } ; @@ -1173,7 +1063,7 @@ variable: opt_pointer ECPGColLabel opt_array_bounds opt_bit_field opt_initialize int *varlen_type_counter; char *struct_name; - adjust_array(actual_type[struct_level].type_enum, &dimension, &length, actual_type[struct_level].type_dimension,actual_type[struct_level].type_index, strlen($1), false); + adjust_array(actual_type[struct_level].type_enum, &dimension, &length, actual_type[struct_level].type_dimension,actual_type[struct_level].type_index, strlen(@1), false); switch (actual_type[struct_level].type_enum) { case ECPGt_struct: @@ -1183,7 +1073,7 @@ variable: opt_pointer ECPGColLabel opt_array_bounds opt_bit_field opt_initialize else type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level], actual_type[struct_level].type_enum,actual_type[struct_level].type_str, actual_type[struct_level].type_sizeof), dimension); - $$ = cat_str(5, $1, mm_strdup($2), $3.str, $4, $5); + @$ = cat_str(5, @1, mm_strdup(@2), $3.str, @4, @5); break; case ECPGt_varchar: @@ -1222,9 +1112,9 @@ variable: opt_pointer ECPGColLabel opt_array_bounds opt_bit_field opt_initialize vcn = (char *) mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); sprintf(vcn, "%d", *varlen_type_counter); if (strcmp(dimension, "0") == 0) - $$ = cat_str(7, make2_str(mm_strdup(struct_name), vcn), mm_strdup(" { int len; char arr["), mm_strdup(length),mm_strdup("]; } *"), mm_strdup($2), $4, $5); + @$ = cat_str(7, make2_str(mm_strdup(struct_name), vcn), mm_strdup(" { int len; char arr["), mm_strdup(length),mm_strdup("]; } *"), mm_strdup(@2), @4, @5); else - $$ = cat_str(8, make2_str(mm_strdup(struct_name), vcn), mm_strdup(" { int len; char arr["), mm_strdup(length),mm_strdup("]; } "), mm_strdup($2), dim_str, $4, $5); + @$ = cat_str(8, make2_str(mm_strdup(struct_name), vcn), mm_strdup(" { int len; char arr["), mm_strdup(length),mm_strdup("]; } "), mm_strdup(@2), dim_str, @4, @5); (*varlen_type_counter)++; break; @@ -1233,7 +1123,7 @@ variable: opt_pointer ECPGColLabel opt_array_bounds opt_bit_field opt_initialize case ECPGt_string: if (atoi(dimension) == -1) { - int i = strlen($5); + int i = strlen(@5); if (atoi(length) == -1 && i > 0) /* char <var>[] = * "string" */ @@ -1244,14 +1134,14 @@ variable: opt_pointer ECPGColLabel opt_array_bounds opt_bit_field opt_initialize */ free(length); length = mm_alloc(i + sizeof("sizeof()")); - sprintf(length, "sizeof(%s)", $5 + 2); + sprintf(length, "sizeof(%s)", @5 + 2); } type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length, 0); } else type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length, 0), dimension); - $$ = cat_str(5, $1, mm_strdup($2), $3.str, $4, $5); + @$ = cat_str(5, @1, mm_strdup(@2), $3.str, @4, @5); break; default: @@ -1260,41 +1150,29 @@ variable: opt_pointer ECPGColLabel opt_array_bounds opt_bit_field opt_initialize else type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, mm_strdup("1"),0), dimension); - $$ = cat_str(5, $1, mm_strdup($2), $3.str, $4, $5); + @$ = cat_str(5, @1, mm_strdup(@2), $3.str, @4, @5); break; } if (struct_level == 0) - new_variable($2, type, braces_open); + new_variable(@2, type, braces_open); else - ECPGmake_struct_member($2, type, &(struct_member_list[struct_level - 1])); - - free($2); + ECPGmake_struct_member(@2, type, &(struct_member_list[struct_level - 1])); } ; opt_initializer: /* EMPTY */ - { - $$ = EMPTY; - } | '=' c_term { initializer = 1; - $$ = cat2_str(mm_strdup("="), $2); } ; opt_pointer: /* EMPTY */ - { - $$ = EMPTY; - } | '*' - { - $$ = mm_strdup("*"); - } | '*' '*' { - $$ = mm_strdup("**"); + @$ = mm_strdup("**"); } ; @@ -1304,7 +1182,7 @@ opt_pointer: /* EMPTY */ ECPGDeclare: DECLARE STATEMENT ecpg_ident { /* this is only supported for compatibility */ - $$ = cat_str(3, mm_strdup("/* declare statement"), $3, mm_strdup("*/")); + @$ = cat_str(3, mm_strdup("/* declare statement"), @3, mm_strdup("*/")); } ; /* @@ -1312,49 +1190,40 @@ ECPGDeclare: DECLARE STATEMENT ecpg_ident */ ECPGDisconnect: SQL_DISCONNECT dis_name { - $$ = $2; + @$ = @2; } ; dis_name: connection_object - { - $$ = $1; - } | CURRENT_P { - $$ = mm_strdup("\"CURRENT\""); + @$ = mm_strdup("\"CURRENT\""); } | ALL { - $$ = mm_strdup("\"ALL\""); + @$ = mm_strdup("\"ALL\""); } | /* EMPTY */ { - $$ = mm_strdup("\"CURRENT\""); + @$ = mm_strdup("\"CURRENT\""); } ; connection_object: name { - $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); + @$ = make3_str(mm_strdup("\""), @1, mm_strdup("\"")); } | DEFAULT { - $$ = mm_strdup("\"DEFAULT\""); + @$ = mm_strdup("\"DEFAULT\""); } | char_variable - { - $$ = $1; - } ; execstring: char_variable - { - $$ = $1; - } | CSTRING { - $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); + @$ = make3_str(mm_strdup("\""), @1, mm_strdup("\"")); } ; @@ -1364,11 +1233,11 @@ execstring: char_variable */ ECPGFree: SQL_FREE cursor_name { - $$ = $2; + @$ = @2; } | SQL_FREE ALL { - $$ = mm_strdup("all"); + @$ = mm_strdup("all"); } ; @@ -1377,60 +1246,51 @@ ECPGFree: SQL_FREE cursor_name */ ECPGOpen: SQL_OPEN cursor_name opt_ecpg_using { - if ($2[0] == ':') - remove_variable_from_list(&argsinsert, find_variable($2 + 1)); - $$ = $2; + if (@2[0] == ':') + remove_variable_from_list(&argsinsert, find_variable(@2 + 1)); + @$ = @2; } ; opt_ecpg_using: /* EMPTY */ - { - $$ = EMPTY; - } | ecpg_using - { - $$ = $1; - } ; ecpg_using: USING using_list { - $$ = EMPTY; + @$ = EMPTY; } | using_descriptor - { - $$ = $1; - } ; using_descriptor: USING SQL_P SQL_DESCRIPTOR quoted_ident_stringvar { - add_variable_to_head(&argsinsert, descriptor_variable($4, 0), &no_indicator); - $$ = EMPTY; + add_variable_to_head(&argsinsert, descriptor_variable(@4, 0), &no_indicator); + @$ = EMPTY; } | USING SQL_DESCRIPTOR name { - add_variable_to_head(&argsinsert, sqlda_variable($3), &no_indicator); - $$ = EMPTY; + add_variable_to_head(&argsinsert, sqlda_variable(@3), &no_indicator); + @$ = EMPTY; } ; into_descriptor: INTO SQL_P SQL_DESCRIPTOR quoted_ident_stringvar { - add_variable_to_head(&argsresult, descriptor_variable($4, 1), &no_indicator); - $$ = EMPTY; + add_variable_to_head(&argsresult, descriptor_variable(@4, 1), &no_indicator); + @$ = EMPTY; } | INTO SQL_DESCRIPTOR name { - add_variable_to_head(&argsresult, sqlda_variable($3), &no_indicator); - $$ = EMPTY; + add_variable_to_head(&argsresult, sqlda_variable(@3), &no_indicator); + @$ = EMPTY; } ; into_sqlda: INTO name { - add_variable_to_head(&argsresult, sqlda_variable($2), &no_indicator); - $$ = EMPTY; + add_variable_to_head(&argsresult, sqlda_variable(@2), &no_indicator); + @$ = EMPTY; } ; @@ -1441,55 +1301,28 @@ UsingValue: UsingConst { char *length = mm_alloc(32); - sprintf(length, "%zu", strlen($1)); - add_variable_to_head(&argsinsert, new_variable($1, ECPGmake_simple_type(ECPGt_const, length, 0), 0), &no_indicator); + sprintf(length, "%zu", strlen(@1)); + add_variable_to_head(&argsinsert, new_variable(@1, ECPGmake_simple_type(ECPGt_const, length, 0), 0), &no_indicator); } | civar { - $$ = EMPTY; + @$ = EMPTY; } | civarind { - $$ = EMPTY; + @$ = EMPTY; } ; UsingConst: Iconst - { - $$ = $1; - } | '+' Iconst - { - $$ = cat_str(2, mm_strdup("+"), $2); - } | '-' Iconst - { - $$ = cat_str(2, mm_strdup("-"), $2); - } | ecpg_fconst - { - $$ = $1; - } | '+' ecpg_fconst - { - $$ = cat_str(2, mm_strdup("+"), $2); - } | '-' ecpg_fconst - { - $$ = cat_str(2, mm_strdup("-"), $2); - } | ecpg_sconst - { - $$ = $1; - } | ecpg_bconst - { - $$ = $1; - } | ecpg_xconst - { - $$ = $1; - } ; /* @@ -1498,7 +1331,7 @@ UsingConst: Iconst ECPGDescribe: SQL_DESCRIBE INPUT_P prepared_name using_descriptor { $$.input = 1; - $$.stmt_name = $3; + $$.stmt_name = @3; } | SQL_DESCRIBE opt_output prepared_name using_descriptor { @@ -1509,33 +1342,27 @@ ECPGDescribe: SQL_DESCRIBE INPUT_P prepared_name using_descriptor add_variable_to_head(&argsresult, var, &no_indicator); $$.input = 0; - $$.stmt_name = $3; + $$.stmt_name = @3; } | SQL_DESCRIBE opt_output prepared_name into_descriptor { $$.input = 0; - $$.stmt_name = $3; + $$.stmt_name = @3; } | SQL_DESCRIBE INPUT_P prepared_name into_sqlda { $$.input = 1; - $$.stmt_name = $3; + $$.stmt_name = @3; } | SQL_DESCRIBE opt_output prepared_name into_sqlda { $$.input = 0; - $$.stmt_name = $3; + $$.stmt_name = @3; } ; opt_output: SQL_OUTPUT - { - $$ = mm_strdup("output"); - } | /* EMPTY */ - { - $$ = EMPTY; - } ; /* @@ -1549,8 +1376,8 @@ opt_output: SQL_OUTPUT */ ECPGAllocateDescr: SQL_ALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar { - add_descriptor($3, connection); - $$ = $3; + add_descriptor(@3, connection); + @$ = @3; } ; @@ -1560,8 +1387,8 @@ ECPGAllocateDescr: SQL_ALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar */ ECPGDeallocateDescr: DEALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar { - drop_descriptor($3, connection); - $$ = $3; + drop_descriptor(@3, connection); + @$ = @3; } ; @@ -1571,7 +1398,7 @@ ECPGDeallocateDescr: DEALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar ECPGGetDescriptorHeader: SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar ECPGGetDescHeaderItems { - $$ = $3; + @$ = @3; } ; @@ -1581,13 +1408,13 @@ ECPGGetDescHeaderItems: ECPGGetDescHeaderItem ECPGGetDescHeaderItem: cvariable '=' desc_header_item { - push_assignment($1, $3); + push_assignment(@1, $3); } ; ECPGSetDescriptorHeader: SET SQL_DESCRIPTOR quoted_ident_stringvar ECPGSetDescHeaderItems { - $$ = $3; + @$ = @3; } ; @@ -1597,7 +1424,7 @@ ECPGSetDescHeaderItems: ECPGSetDescHeaderItem ECPGSetDescHeaderItem: desc_header_item '=' IntConstVar { - push_assignment($3, $1); + push_assignment(@3, $1); } ; @@ -1605,14 +1432,10 @@ IntConstVar: Iconst { char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); - sprintf(length, "%zu", strlen($1)); - new_variable($1, ECPGmake_simple_type(ECPGt_const, length, 0), 0); - $$ = $1; + sprintf(length, "%zu", strlen(@1)); + new_variable(@1, ECPGmake_simple_type(ECPGt_const, length, 0), 0); } | cvariable - { - $$ = $1; - } ; desc_header_item: SQL_COUNT @@ -1627,8 +1450,8 @@ desc_header_item: SQL_COUNT ECPGGetDescriptor: SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar VALUE_P IntConstVar ECPGGetDescItems { - $$.str = $5; - $$.name = $3; + $$.str = @5; + $$.name = @3; } ; @@ -1638,14 +1461,14 @@ ECPGGetDescItems: ECPGGetDescItem ECPGGetDescItem: cvariable '=' descriptor_item { - push_assignment($1, $3); + push_assignment(@1, $3); } ; ECPGSetDescriptor: SET SQL_DESCRIPTOR quoted_ident_stringvar VALUE_P IntConstVar ECPGSetDescItems { - $$.str = $5; - $$.name = $3; + $$.str = @5; + $$.name = @3; } ; @@ -1655,7 +1478,7 @@ ECPGSetDescItems: ECPGSetDescItem ECPGSetDescItem: descriptor_item '=' AllConstVar { - push_assignment($3, $1); + push_assignment(@3, $1); } ; @@ -1663,41 +1486,37 @@ AllConstVar: ecpg_fconst { char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); - sprintf(length, "%zu", strlen($1)); - new_variable($1, ECPGmake_simple_type(ECPGt_const, length, 0), 0); - $$ = $1; + sprintf(length, "%zu", strlen(@1)); + new_variable(@1, ECPGmake_simple_type(ECPGt_const, length, 0), 0); } | IntConstVar - { - $$ = $1; - } | '-' ecpg_fconst { char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); - char *var = cat2_str(mm_strdup("-"), $2); + char *var = cat2_str(mm_strdup("-"), @2); sprintf(length, "%zu", strlen(var)); new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0); - $$ = var; + @$ = var; } | '-' Iconst { char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); - char *var = cat2_str(mm_strdup("-"), $2); + char *var = cat2_str(mm_strdup("-"), @2); sprintf(length, "%zu", strlen(var)); new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0); - $$ = var; + @$ = var; } | ecpg_sconst { char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); - char *var = $1 + 1; + char *var = @1 + 1; var[strlen(var) - 1] = '\0'; sprintf(length, "%zu", strlen(var)); new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0); - $$ = var; + @$ = var; } ; @@ -1724,22 +1543,16 @@ descriptor_item: SQL_CARDINALITY { $$ = ECPGd_cardinality; } */ ECPGSetAutocommit: SET SQL_AUTOCOMMIT '=' on_off { - $$ = $4; + @$ = @4; } | SET SQL_AUTOCOMMIT TO on_off { - $$ = $4; + @$ = @4; } ; on_off: ON - { - $$ = mm_strdup("on"); - } | OFF - { - $$ = mm_strdup("off"); - } ; /* @@ -1748,15 +1561,15 @@ on_off: ON */ ECPGSetConnection: SET CONNECTION TO connection_object { - $$ = $4; + @$ = @4; } | SET CONNECTION '=' connection_object { - $$ = $4; + @$ = @4; } | SET CONNECTION connection_object { - $$ = $3; + @$ = @3; } ; @@ -1771,23 +1584,17 @@ ECPGTypedef: TYPE_P } ECPGColLabel IS var_type opt_array_bounds opt_reference { - add_typedef($3, $6.index1, $6.index2, $5.type_enum, $5.type_dimension, $5.type_index, initializer, *$7 ? 1 : 0); + add_typedef(@3, $6.index1, $6.index2, $5.type_enum, $5.type_dimension, $5.type_index, initializer, *@7 ? 1 : 0); if (auto_create_c == false) - $$ = cat_str(7, mm_strdup("/* exec sql type"), mm_strdup($3), mm_strdup("is"), mm_strdup($5.type_str), mm_strdup($6.str),$7, mm_strdup("*/")); + @$ = cat_str(7, mm_strdup("/* exec sql type"), mm_strdup(@3), mm_strdup("is"), mm_strdup($5.type_str), mm_strdup($6.str),@7, mm_strdup("*/")); else - $$ = cat_str(6, mm_strdup("typedef "), mm_strdup($5.type_str), *$7 ? mm_strdup("*") : mm_strdup(""), mm_strdup($3),mm_strdup($6.str), mm_strdup(";")); + @$ = cat_str(6, mm_strdup("typedef "), mm_strdup($5.type_str), *@7 ? mm_strdup("*") : mm_strdup(""), mm_strdup(@3),mm_strdup($6.str), mm_strdup(";")); } ; opt_reference: SQL_REFERENCE - { - $$ = mm_strdup("reference"); - } | /* EMPTY */ - { - $$ = EMPTY; - } ; /* @@ -1801,7 +1608,7 @@ ECPGVar: SQL_VAR } ColLabel IS var_type opt_array_bounds opt_reference { - struct variable *p = find_variable($3); + struct variable *p = find_variable(@3); char *dimension = $6.index1; char *length = $6.index2; struct ECPGtype *type; @@ -1812,7 +1619,7 @@ ECPGVar: SQL_VAR mmerror(PARSE_ERROR, ET_ERROR, "initializer not allowed in EXEC SQL VAR command"); else { - adjust_array($5.type_enum, &dimension, &length, $5.type_dimension, $5.type_index, *$7 ? 1 : 0, false); + adjust_array($5.type_enum, &dimension, &length, $5.type_dimension, $5.type_index, *@7 ? 1 : 0, false); switch ($5.type_enum) { @@ -1856,7 +1663,7 @@ ECPGVar: SQL_VAR p->type = type; } - $$ = cat_str(7, mm_strdup("/* exec sql var"), mm_strdup($3), mm_strdup("is"), mm_strdup($5.type_str),mm_strdup($6.str), $7, mm_strdup("*/")); + @$ = cat_str(7, mm_strdup("/* exec sql var"), mm_strdup(@3), mm_strdup("is"), mm_strdup($5.type_str),mm_strdup($6.str), @7, mm_strdup("*/")); } ; @@ -1868,19 +1675,19 @@ ECPGWhenever: SQL_WHENEVER SQL_SQLERROR action { when_error.code = $<action>3.code; when_error.command = $<action>3.command; - $$ = cat_str(3, mm_strdup("/* exec sql whenever sqlerror "), $3.str, mm_strdup("; */")); + @$ = cat_str(3, mm_strdup("/* exec sql whenever sqlerror "), $3.str, mm_strdup("; */")); } | SQL_WHENEVER NOT SQL_FOUND action { when_nf.code = $<action>4.code; when_nf.command = $<action>4.command; - $$ = cat_str(3, mm_strdup("/* exec sql whenever not found "), $4.str, mm_strdup("; */")); + @$ = cat_str(3, mm_strdup("/* exec sql whenever not found "), $4.str, mm_strdup("; */")); } | SQL_WHENEVER SQL_SQLWARNING action { when_warn.code = $<action>3.code; when_warn.command = $<action>3.command; - $$ = cat_str(3, mm_strdup("/* exec sql whenever sql_warning "), $3.str, mm_strdup("; */")); + @$ = cat_str(3, mm_strdup("/* exec sql whenever sql_warning "), $3.str, mm_strdup("; */")); } ; @@ -1905,19 +1712,19 @@ action: CONTINUE_P | SQL_GOTO name { $<action>$.code = W_GOTO; - $<action>$.command = mm_strdup($2); - $<action>$.str = cat2_str(mm_strdup("goto "), $2); + $<action>$.command = mm_strdup(@2); + $<action>$.str = cat2_str(mm_strdup("goto "), @2); } | SQL_GO TO name { $<action>$.code = W_GOTO; - $<action>$.command = mm_strdup($3); - $<action>$.str = cat2_str(mm_strdup("goto "), $3); + $<action>$.command = mm_strdup(@3); + $<action>$.str = cat2_str(mm_strdup("goto "), @3); } | DO name '(' c_args ')' { $<action>$.code = W_DO; - $<action>$.command = cat_str(4, $2, mm_strdup("("), $4, mm_strdup(")")); + $<action>$.command = cat_str(4, @2, mm_strdup("("), @4, mm_strdup(")")); $<action>$.str = cat2_str(mm_strdup("do"), mm_strdup($<action>$.command)); } | DO SQL_BREAK @@ -1935,13 +1742,13 @@ action: CONTINUE_P | CALL name '(' c_args ')' { $<action>$.code = W_DO; - $<action>$.command = cat_str(4, $2, mm_strdup("("), $4, mm_strdup(")")); + $<action>$.command = cat_str(4, @2, mm_strdup("("), @4, mm_strdup(")")); $<action>$.str = cat2_str(mm_strdup("call"), mm_strdup($<action>$.command)); } | CALL name { $<action>$.code = W_DO; - $<action>$.command = cat2_str($2, mm_strdup("()")); + $<action>$.command = cat2_str(@2, mm_strdup("()")); $<action>$.str = cat2_str(mm_strdup("call"), mm_strdup($<action>$.command)); } ; @@ -1949,63 +1756,63 @@ action: CONTINUE_P /* some other stuff for ecpg */ /* additional unreserved keywords */ -ECPGKeywords: ECPGKeywords_vanames { $$ = $1; } - | ECPGKeywords_rest { $$ = $1; } - ; - -ECPGKeywords_vanames: SQL_BREAK { $$ = mm_strdup("break"); } - | SQL_CARDINALITY { $$ = mm_strdup("cardinality"); } - | SQL_COUNT { $$ = mm_strdup("count"); } - | SQL_DATETIME_INTERVAL_CODE { $$ = mm_strdup("datetime_interval_code"); } - | SQL_DATETIME_INTERVAL_PRECISION { $$ = mm_strdup("datetime_interval_precision"); } - | SQL_FOUND { $$ = mm_strdup("found"); } - | SQL_GO { $$ = mm_strdup("go"); } - | SQL_GOTO { $$ = mm_strdup("goto"); } - | SQL_IDENTIFIED { $$ = mm_strdup("identified"); } - | SQL_INDICATOR { $$ = mm_strdup("indicator"); } - | SQL_KEY_MEMBER { $$ = mm_strdup("key_member"); } - | SQL_LENGTH { $$ = mm_strdup("length"); } - | SQL_NULLABLE { $$ = mm_strdup("nullable"); } - | SQL_OCTET_LENGTH { $$ = mm_strdup("octet_length"); } - | SQL_RETURNED_LENGTH { $$ = mm_strdup("returned_length"); } - | SQL_RETURNED_OCTET_LENGTH { $$ = mm_strdup("returned_octet_length"); } - | SQL_SCALE { $$ = mm_strdup("scale"); } - | SQL_SECTION { $$ = mm_strdup("section"); } - | SQL_SQLERROR { $$ = mm_strdup("sqlerror"); } - | SQL_SQLPRINT { $$ = mm_strdup("sqlprint"); } - | SQL_SQLWARNING { $$ = mm_strdup("sqlwarning"); } - | SQL_STOP { $$ = mm_strdup("stop"); } - ; - -ECPGKeywords_rest: SQL_CONNECT { $$ = mm_strdup("connect"); } - | SQL_DESCRIBE { $$ = mm_strdup("describe"); } - | SQL_DISCONNECT { $$ = mm_strdup("disconnect"); } - | SQL_OPEN { $$ = mm_strdup("open"); } - | SQL_VAR { $$ = mm_strdup("var"); } - | SQL_WHENEVER { $$ = mm_strdup("whenever"); } +ECPGKeywords: ECPGKeywords_vanames + | ECPGKeywords_rest + ; + +ECPGKeywords_vanames: SQL_BREAK + | SQL_CARDINALITY + | SQL_COUNT + | SQL_DATETIME_INTERVAL_CODE + | SQL_DATETIME_INTERVAL_PRECISION + | SQL_FOUND + | SQL_GO + | SQL_GOTO + | SQL_IDENTIFIED + | SQL_INDICATOR + | SQL_KEY_MEMBER + | SQL_LENGTH + | SQL_NULLABLE + | SQL_OCTET_LENGTH + | SQL_RETURNED_LENGTH + | SQL_RETURNED_OCTET_LENGTH + | SQL_SCALE + | SQL_SECTION + | SQL_SQLERROR + | SQL_SQLPRINT + | SQL_SQLWARNING + | SQL_STOP + ; + +ECPGKeywords_rest: SQL_CONNECT + | SQL_DESCRIBE + | SQL_DISCONNECT + | SQL_OPEN + | SQL_VAR + | SQL_WHENEVER ; /* additional keywords that can be SQL type names (but not ECPGColLabels) */ -ECPGTypeName: SQL_BOOL { $$ = mm_strdup("bool"); } - | SQL_LONG { $$ = mm_strdup("long"); } - | SQL_OUTPUT { $$ = mm_strdup("output"); } - | SQL_SHORT { $$ = mm_strdup("short"); } - | SQL_STRUCT { $$ = mm_strdup("struct"); } - | SQL_SIGNED { $$ = mm_strdup("signed"); } - | SQL_UNSIGNED { $$ = mm_strdup("unsigned"); } +ECPGTypeName: SQL_BOOL + | SQL_LONG + | SQL_OUTPUT + | SQL_SHORT + | SQL_STRUCT + | SQL_SIGNED + | SQL_UNSIGNED ; -symbol: ColLabel { $$ = $1; } +symbol: ColLabel ; -ECPGColId: ecpg_ident { $$ = $1; } - | unreserved_keyword { $$ = $1; } - | col_name_keyword { $$ = $1; } - | ECPGunreserved_interval { $$ = $1; } - | ECPGKeywords { $$ = $1; } - | ECPGCKeywords { $$ = $1; } - | CHAR_P { $$ = mm_strdup("char"); } - | VALUES { $$ = mm_strdup("values"); } +ECPGColId: ecpg_ident + | unreserved_keyword + | col_name_keyword + | ECPGunreserved_interval + | ECPGKeywords + | ECPGCKeywords + | CHAR_P + | VALUES ; /* @@ -2018,58 +1825,58 @@ ECPGColId: ecpg_ident { $$ = $1; } /* Column identifier --- names that can be column, table, etc names. */ -ColId: ecpg_ident { $$ = $1; } - | all_unreserved_keyword { $$ = $1; } - | col_name_keyword { $$ = $1; } - | ECPGKeywords { $$ = $1; } - | ECPGCKeywords { $$ = $1; } - | CHAR_P { $$ = mm_strdup("char"); } - | VALUES { $$ = mm_strdup("values"); } +ColId: ecpg_ident + | all_unreserved_keyword + | col_name_keyword + | ECPGKeywords + | ECPGCKeywords + | CHAR_P + | VALUES ; /* Type/function identifier --- names that can be type or function names. */ -type_function_name: ecpg_ident { $$ = $1; } - | all_unreserved_keyword { $$ = $1; } - | type_func_name_keyword { $$ = $1; } - | ECPGKeywords { $$ = $1; } - | ECPGCKeywords { $$ = $1; } - | ECPGTypeName { $$ = $1; } +type_function_name: ecpg_ident + | all_unreserved_keyword + | type_func_name_keyword + | ECPGKeywords + | ECPGCKeywords + | ECPGTypeName ; /* Column label --- allowed labels in "AS" clauses. * This presently includes *all* Postgres keywords. */ -ColLabel: ECPGColLabel { $$ = $1; } - | ECPGTypeName { $$ = $1; } - | CHAR_P { $$ = mm_strdup("char"); } - | CURRENT_P { $$ = mm_strdup("current"); } - | INPUT_P { $$ = mm_strdup("input"); } - | INT_P { $$ = mm_strdup("int"); } - | TO { $$ = mm_strdup("to"); } - | UNION { $$ = mm_strdup("union"); } - | VALUES { $$ = mm_strdup("values"); } - | ECPGCKeywords { $$ = $1; } - | ECPGunreserved_interval { $$ = $1; } - ; - -ECPGColLabel: ecpg_ident { $$ = $1; } - | unreserved_keyword { $$ = $1; } - | col_name_keyword { $$ = $1; } - | type_func_name_keyword { $$ = $1; } - | reserved_keyword { $$ = $1; } - | ECPGKeywords_vanames { $$ = $1; } - | ECPGKeywords_rest { $$ = $1; } - | CONNECTION { $$ = mm_strdup("connection"); } - ; - -ECPGCKeywords: S_AUTO { $$ = mm_strdup("auto"); } - | S_CONST { $$ = mm_strdup("const"); } - | S_EXTERN { $$ = mm_strdup("extern"); } - | S_REGISTER { $$ = mm_strdup("register"); } - | S_STATIC { $$ = mm_strdup("static"); } - | S_TYPEDEF { $$ = mm_strdup("typedef"); } - | S_VOLATILE { $$ = mm_strdup("volatile"); } +ColLabel: ECPGColLabel + | ECPGTypeName + | CHAR_P + | CURRENT_P + | INPUT_P + | INT_P + | TO + | UNION + | VALUES + | ECPGCKeywords + | ECPGunreserved_interval + ; + +ECPGColLabel: ecpg_ident + | unreserved_keyword + | col_name_keyword + | type_func_name_keyword + | reserved_keyword + | ECPGKeywords_vanames + | ECPGKeywords_rest + | CONNECTION + ; + +ECPGCKeywords: S_AUTO + | S_CONST + | S_EXTERN + | S_REGISTER + | S_STATIC + | S_TYPEDEF + | S_VOLATILE ; /* "Unreserved" keywords --- available for use as any kind of name. @@ -2086,17 +1893,17 @@ ECPGCKeywords: S_AUTO { $$ = mm_strdup("auto"); } * * The mentioned exclusions are done by $replace_line settings in parse.pl. */ -all_unreserved_keyword: unreserved_keyword { $$ = $1; } - | ECPGunreserved_interval { $$ = $1; } - | CONNECTION { $$ = mm_strdup("connection"); } +all_unreserved_keyword: unreserved_keyword + | ECPGunreserved_interval + | CONNECTION ; -ECPGunreserved_interval: DAY_P { $$ = mm_strdup("day"); } - | HOUR_P { $$ = mm_strdup("hour"); } - | MINUTE_P { $$ = mm_strdup("minute"); } - | MONTH_P { $$ = mm_strdup("month"); } - | SECOND_P { $$ = mm_strdup("second"); } - | YEAR_P { $$ = mm_strdup("year"); } +ECPGunreserved_interval: DAY_P + | HOUR_P + | MINUTE_P + | MONTH_P + | SECOND_P + | YEAR_P ; into_list: coutputvariable | into_list ',' coutputvariable @@ -2106,73 +1913,66 @@ ecpgstart: SQL_START { reset_variables(); pacounter = 1; + @$ = EMPTY; } ; c_args: /* EMPTY */ - { - $$ = EMPTY; - } | c_list - { - $$ = $1; - } ; coutputvariable: cvariable indicator { - add_variable_to_head(&argsresult, find_variable($1), find_variable($2)); + add_variable_to_head(&argsresult, find_variable(@1), find_variable(@2)); } | cvariable { - add_variable_to_head(&argsresult, find_variable($1), &no_indicator); + add_variable_to_head(&argsresult, find_variable(@1), &no_indicator); } ; civarind: cvariable indicator { - if (find_variable($2)->type->type == ECPGt_array) + if (find_variable(@2)->type->type == ECPGt_array) mmerror(PARSE_ERROR, ET_ERROR, "arrays of indicators are not allowed on input"); - add_variable_to_head(&argsinsert, find_variable($1), find_variable($2)); - $$ = create_questionmarks($1, false); + add_variable_to_head(&argsinsert, find_variable(@1), find_variable(@2)); + @$ = create_questionmarks(@1, false); } ; char_civar: char_variable { - char *ptr = strstr($1, ".arr"); + char *ptr = strstr(@1, ".arr"); if (ptr) /* varchar, we need the struct name here, not * the struct element */ *ptr = '\0'; - add_variable_to_head(&argsinsert, find_variable($1), &no_indicator); - $$ = $1; + add_variable_to_head(&argsinsert, find_variable(@1), &no_indicator); } ; civar: cvariable { - add_variable_to_head(&argsinsert, find_variable($1), &no_indicator); - $$ = create_questionmarks($1, false); + add_variable_to_head(&argsinsert, find_variable(@1), &no_indicator); + @$ = create_questionmarks(@1, false); } ; indicator: cvariable { - check_indicator((find_variable($1))->type); - $$ = $1; + check_indicator((find_variable(@1))->type); } | SQL_INDICATOR cvariable { - check_indicator((find_variable($2))->type); - $$ = $2; + check_indicator((find_variable(@2))->type); + @$ = @2; } | SQL_INDICATOR name { - check_indicator((find_variable($2))->type); - $$ = $2; + check_indicator((find_variable(@2))->type); + @$ = @2; } ; @@ -2182,7 +1982,7 @@ cvariable: CVARIABLE * As long as multidimensional arrays are not implemented we have to * check for those here */ - char *ptr = $1; + char *ptr = @1; int brace_open = 0, brace = false; @@ -2209,57 +2009,44 @@ cvariable: CVARIABLE break; } } - $$ = $1; } ; ecpg_param: PARAM { - $$ = make_name(); + @$ = make_name(); } ; ecpg_bconst: BCONST - { - $$ = $1; - } ; ecpg_fconst: FCONST { - $$ = make_name(); + @$ = make_name(); } ; ecpg_sconst: SCONST - { - $$ = $1; - } ; ecpg_xconst: XCONST - { - $$ = $1; - } ; ecpg_ident: IDENT - { - $$ = $1; - } | CSTRING { - $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); + @$ = make3_str(mm_strdup("\""), @1, mm_strdup("\"")); } ; quoted_ident_stringvar: name { - $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); + @$ = make3_str(mm_strdup("\""), @1, mm_strdup("\"")); } | char_variable { - $$ = make3_str(mm_strdup("("), $1, mm_strdup(")")); + @$ = make3_str(mm_strdup("("), @1, mm_strdup(")")); } ; @@ -2268,221 +2055,151 @@ quoted_ident_stringvar: name */ c_stuff_item: c_anything - { - $$ = $1; - } | '(' ')' { - $$ = mm_strdup("()"); + @$ = mm_strdup("()"); } | '(' c_stuff ')' - { - $$ = cat_str(3, mm_strdup("("), $2, mm_strdup(")")); - } ; c_stuff: c_stuff_item - { - $$ = $1; - } | c_stuff c_stuff_item - { - $$ = cat2_str($1, $2); - } ; c_list: c_term - { - $$ = $1; - } | c_list ',' c_term - { - $$ = cat_str(3, $1, mm_strdup(","), $3); - } ; c_term: c_stuff - { - $$ = $1; - } | '{' c_list '}' - { - $$ = cat_str(3, mm_strdup("{"), $2, mm_strdup("}")); - } - ; - -c_thing: c_anything { $$ = $1; } - | '(' { $$ = mm_strdup("("); } - | ')' { $$ = mm_strdup(")"); } - | ',' { $$ = mm_strdup(","); } - | ';' { $$ = mm_strdup(";"); } - ; - -c_anything: ecpg_ident { $$ = $1; } - | Iconst { $$ = $1; } - | ecpg_fconst { $$ = $1; } - | ecpg_sconst { $$ = $1; } - | '*' { $$ = mm_strdup("*"); } - | '+' { $$ = mm_strdup("+"); } - | '-' { $$ = mm_strdup("-"); } - | '/' { $$ = mm_strdup("/"); } - | '%' { $$ = mm_strdup("%"); } - | NULL_P { $$ = mm_strdup("NULL"); } - | S_ADD { $$ = mm_strdup("+="); } - | S_AND { $$ = mm_strdup("&&"); } - | S_ANYTHING { $$ = make_name(); } - | S_AUTO { $$ = mm_strdup("auto"); } - | S_CONST { $$ = mm_strdup("const"); } - | S_DEC { $$ = mm_strdup("--"); } - | S_DIV { $$ = mm_strdup("/="); } - | S_DOTPOINT { $$ = mm_strdup(".*"); } - | S_EQUAL { $$ = mm_strdup("=="); } - | S_EXTERN { $$ = mm_strdup("extern"); } - | S_INC { $$ = mm_strdup("++"); } - | S_LSHIFT { $$ = mm_strdup("<<"); } - | S_MEMBER { $$ = mm_strdup("->"); } - | S_MEMPOINT { $$ = mm_strdup("->*"); } - | S_MOD { $$ = mm_strdup("%="); } - | S_MUL { $$ = mm_strdup("*="); } - | S_NEQUAL { $$ = mm_strdup("!="); } - | S_OR { $$ = mm_strdup("||"); } - | S_REGISTER { $$ = mm_strdup("register"); } - | S_RSHIFT { $$ = mm_strdup(">>"); } - | S_STATIC { $$ = mm_strdup("static"); } - | S_SUB { $$ = mm_strdup("-="); } - | S_TYPEDEF { $$ = mm_strdup("typedef"); } - | S_VOLATILE { $$ = mm_strdup("volatile"); } - | SQL_BOOL { $$ = mm_strdup("bool"); } - | ENUM_P { $$ = mm_strdup("enum"); } - | HOUR_P { $$ = mm_strdup("hour"); } - | INT_P { $$ = mm_strdup("int"); } - | SQL_LONG { $$ = mm_strdup("long"); } - | MINUTE_P { $$ = mm_strdup("minute"); } - | MONTH_P { $$ = mm_strdup("month"); } - | SECOND_P { $$ = mm_strdup("second"); } - | SQL_SHORT { $$ = mm_strdup("short"); } - | SQL_SIGNED { $$ = mm_strdup("signed"); } - | SQL_STRUCT { $$ = mm_strdup("struct"); } - | SQL_UNSIGNED { $$ = mm_strdup("unsigned"); } - | YEAR_P { $$ = mm_strdup("year"); } - | CHAR_P { $$ = mm_strdup("char"); } - | FLOAT_P { $$ = mm_strdup("float"); } - | TO { $$ = mm_strdup("to"); } - | UNION { $$ = mm_strdup("union"); } - | VARCHAR { $$ = mm_strdup("varchar"); } - | '[' { $$ = mm_strdup("["); } - | ']' { $$ = mm_strdup("]"); } - | '=' { $$ = mm_strdup("="); } - | ':' { $$ = mm_strdup(":"); } + ; + +c_thing: c_anything + | '(' + | ')' + | ',' + | ';' + ; + +/* + * Note: NULL_P is treated specially to force it to be output in upper case, + * since it's likely meant as a reference to the standard C macro NULL. + */ +c_anything: ecpg_ident + | Iconst + | ecpg_fconst + | ecpg_sconst + | '*' + | '+' + | '-' + | '/' + | '%' + | NULL_P { @$ = mm_strdup("NULL"); } + | S_ADD + | S_AND + | S_ANYTHING + | S_AUTO + | S_CONST + | S_DEC + | S_DIV + | S_DOTPOINT + | S_EQUAL + | S_EXTERN + | S_INC + | S_LSHIFT + | S_MEMBER + | S_MEMPOINT + | S_MOD + | S_MUL + | S_NEQUAL + | S_OR + | S_REGISTER + | S_RSHIFT + | S_STATIC + | S_SUB + | S_TYPEDEF + | S_VOLATILE + | SQL_BOOL + | ENUM_P + | HOUR_P + | INT_P + | SQL_LONG + | MINUTE_P + | MONTH_P + | SECOND_P + | SQL_SHORT + | SQL_SIGNED + | SQL_STRUCT + | SQL_UNSIGNED + | YEAR_P + | CHAR_P + | FLOAT_P + | TO + | UNION + | VARCHAR + | '[' + | ']' + | '=' + | ':' ; DeallocateStmt: DEALLOCATE prepared_name { - check_declared_list($2); - $$ = $2; + check_declared_list(@2); + @$ = @2; } | DEALLOCATE PREPARE prepared_name { - check_declared_list($3); - $$ = $3; + check_declared_list(@3); + @$ = @3; } | DEALLOCATE ALL { - $$ = mm_strdup("all"); + @$ = mm_strdup("all"); } | DEALLOCATE PREPARE ALL { - $$ = mm_strdup("all"); + @$ = mm_strdup("all"); } ; Iresult: Iconst - { - $$ = $1; - } | '(' Iresult ')' - { - $$ = cat_str(3, mm_strdup("("), $2, mm_strdup(")")); - } | Iresult '+' Iresult - { - $$ = cat_str(3, $1, mm_strdup("+"), $3); - } | Iresult '-' Iresult - { - $$ = cat_str(3, $1, mm_strdup("-"), $3); - } | Iresult '*' Iresult - { - $$ = cat_str(3, $1, mm_strdup("*"), $3); - } | Iresult '/' Iresult - { - $$ = cat_str(3, $1, mm_strdup("/"), $3); - } | Iresult '%' Iresult - { - $$ = cat_str(3, $1, mm_strdup("%"), $3); - } | ecpg_sconst - { - $$ = $1; - } | ColId - { - $$ = $1; - } | ColId '(' var_type ')' { - if (pg_strcasecmp($1, "sizeof") != 0) + if (pg_strcasecmp(@1, "sizeof") != 0) mmerror(PARSE_ERROR, ET_ERROR, "operator not allowed in variable definition"); else - $$ = cat_str(4, $1, mm_strdup("("), $3.type_str, mm_strdup(")")); + @$ = cat_str(4, @1, mm_strdup("("), $3.type_str, mm_strdup(")")); } ; execute_rest: /* EMPTY */ - { - $$ = EMPTY; - } | ecpg_using opt_ecpg_into - { - $$ = EMPTY; - } | ecpg_into ecpg_using - { - $$ = EMPTY; - } | ecpg_into - { - $$ = EMPTY; - } ; ecpg_into: INTO into_list { - $$ = EMPTY; + /* always suppress this from the constructed string */ + @$ = EMPTY; } | into_descriptor - { - $$ = $1; - } ; opt_ecpg_into: /* EMPTY */ - { - $$ = EMPTY; - } | ecpg_into - { - $$ = $1; - } ; ecpg_fetch_into: ecpg_into - { - $$ = $1; - } | using_descriptor { struct variable *var; @@ -2490,18 +2207,11 @@ ecpg_fetch_into: ecpg_into var = argsinsert->variable; remove_variable_from_list(&argsinsert, var); add_variable_to_head(&argsresult, var, &no_indicator); - $$ = $1; } ; opt_ecpg_fetch_into: /* EMPTY */ - { - $$ = EMPTY; - } | ecpg_fetch_into - { - $$ = $1; - } ; %% diff --git a/src/interfaces/ecpg/preproc/ecpg.type b/src/interfaces/ecpg/preproc/ecpg.type index 4fe80a5a4b..2929f358ff 100644 --- a/src/interfaces/ecpg/preproc/ecpg.type +++ b/src/interfaces/ecpg/preproc/ecpg.type @@ -1,131 +1,4 @@ /* src/interfaces/ecpg/preproc/ecpg.type */ -%type <str> ECPGAllocateDescr -%type <str> ECPGCKeywords -%type <str> ECPGColId -%type <str> ECPGColLabel -%type <str> ECPGConnect -%type <str> ECPGCursorStmt -%type <str> ECPGDeallocateDescr -%type <str> ECPGDeclaration -%type <str> ECPGDeclare -%type <str> ECPGDeclareStmt -%type <str> ECPGDisconnect -%type <str> ECPGExecuteImmediateStmt -%type <str> ECPGFree -%type <str> ECPGGetDescHeaderItem -%type <str> ECPGGetDescItem -%type <str> ECPGGetDescriptorHeader -%type <str> ECPGKeywords -%type <str> ECPGKeywords_rest -%type <str> ECPGKeywords_vanames -%type <str> ECPGOpen -%type <str> ECPGSetAutocommit -%type <str> ECPGSetConnection -%type <str> ECPGSetDescHeaderItem -%type <str> ECPGSetDescItem -%type <str> ECPGSetDescriptorHeader -%type <str> ECPGTypeName -%type <str> ECPGTypedef -%type <str> ECPGVar -%type <str> ECPGVarDeclaration -%type <str> ECPGWhenever -%type <str> ECPGunreserved_interval -%type <str> UsingConst -%type <str> UsingValue -%type <str> all_unreserved_keyword -%type <str> c_anything -%type <str> c_args -%type <str> c_list -%type <str> c_stuff -%type <str> c_stuff_item -%type <str> c_term -%type <str> c_thing -%type <str> char_variable -%type <str> char_civar -%type <str> civar -%type <str> civarind -%type <str> ColId -%type <str> ColLabel -%type <str> connect_options -%type <str> connection_object -%type <str> connection_target -%type <str> coutputvariable -%type <str> cvariable -%type <str> db_prefix -%type <str> CreateAsStmt -%type <str> DeallocateStmt -%type <str> dis_name -%type <str> ecpg_bconst -%type <str> ecpg_fconst -%type <str> ecpg_ident -%type <str> ecpg_interval -%type <str> ecpg_into -%type <str> ecpg_fetch_into -%type <str> ecpg_param -%type <str> ecpg_sconst -%type <str> ecpg_using -%type <str> ecpg_xconst -%type <str> enum_definition -%type <str> enum_type -%type <str> execstring -%type <str> execute_rest -%type <str> indicator -%type <str> into_descriptor -%type <str> into_sqlda -%type <str> Iresult -%type <str> on_off -%type <str> opt_bit_field -%type <str> opt_connection_name -%type <str> opt_database_name -%type <str> opt_ecpg_into -%type <str> opt_ecpg_fetch_into -%type <str> opt_ecpg_using -%type <str> opt_initializer -%type <str> opt_options -%type <str> opt_output -%type <str> opt_pointer -%type <str> opt_port -%type <str> opt_reference -%type <str> opt_scale -%type <str> opt_server -%type <str> opt_user -%type <str> opt_opt_value -%type <str> ora_user -%type <str> precision -%type <str> prepared_name -%type <str> quoted_ident_stringvar -%type <str> s_struct_union -%type <str> server -%type <str> server_name -%type <str> single_vt_declaration -%type <str> storage_clause -%type <str> storage_declaration -%type <str> storage_modifier -%type <str> struct_union_type -%type <str> struct_union_type_with_symbol -%type <str> symbol -%type <str> type_declaration -%type <str> type_function_name -%type <str> user_name -%type <str> using_descriptor -%type <str> var_declaration -%type <str> var_type_declarations -%type <str> variable -%type <str> variable_declarations -%type <str> variable_list -%type <str> vt_declarations - -%type <str> Op -%type <str> IntConstVar -%type <str> AllConstVar -%type <str> CSTRING -%type <str> CPP_LINE -%type <str> CVARIABLE -%type <str> BCONST -%type <str> SCONST -%type <str> XCONST -%type <str> IDENT - %type <struct_union> s_struct_union_symbol %type <descriptor> ECPGGetDescriptor diff --git a/src/interfaces/ecpg/preproc/output.c b/src/interfaces/ecpg/preproc/output.c index 6c0b8a27b1..8d2b6e7cb8 100644 --- a/src/interfaces/ecpg/preproc/output.c +++ b/src/interfaces/ecpg/preproc/output.c @@ -4,7 +4,7 @@ #include "preproc_extern.h" -static void output_escaped_str(char *str, bool quoted); +static void output_escaped_str(const char *str, bool quoted); void output_line_number(void) @@ -16,13 +16,12 @@ output_line_number(void) } void -output_simple_statement(char *stmt, int whenever_mode) +output_simple_statement(const char *stmt, int whenever_mode) { output_escaped_str(stmt, false); if (whenever_mode) whenever_action(whenever_mode); output_line_number(); - free(stmt); } @@ -133,7 +132,7 @@ static char *ecpg_statement_type_name[] = { }; void -output_statement(char *stmt, int whenever_mode, enum ECPG_statement_type st) +output_statement(const char *stmt, int whenever_mode, enum ECPG_statement_type st) { fprintf(base_yyout, "{ ECPGdo(__LINE__, %d, %d, %s, %d, ", compat, force_indicator, connection ? connection : "NULL",questionmarks); @@ -163,11 +162,10 @@ output_statement(char *stmt, int whenever_mode, enum ECPG_statement_type st) reset_variables(); whenever_action(whenever_mode | 2); - free(stmt); } void -output_prepare_statement(char *name, char *stmt) +output_prepare_statement(const char *name, const char *stmt) { fprintf(base_yyout, "{ ECPGprepare(__LINE__, %s, %d, ", connection ? connection : "NULL", questionmarks); output_escaped_str(name, true); @@ -175,11 +173,10 @@ output_prepare_statement(char *name, char *stmt) output_escaped_str(stmt, true); fputs(");", base_yyout); whenever_action(2); - free(name); } void -output_deallocate_prepare_statement(char *name) +output_deallocate_prepare_statement(const char *name) { const char *con = connection ? connection : "NULL"; @@ -193,11 +190,10 @@ output_deallocate_prepare_statement(char *name) fprintf(base_yyout, "{ ECPGdeallocate_all(__LINE__, %d, %s);", compat, con); whenever_action(2); - free(name); } static void -output_escaped_str(char *str, bool quoted) +output_escaped_str(const char *str, bool quoted) { int i = 0; int len = strlen(str); diff --git a/src/interfaces/ecpg/preproc/parse.pl b/src/interfaces/ecpg/preproc/parse.pl index 7e53401dd9..15bdef7dca 100644 --- a/src/interfaces/ecpg/preproc/parse.pl +++ b/src/interfaces/ecpg/preproc/parse.pl @@ -44,27 +44,10 @@ my %replace_token = ( 'IDENT' => 'ecpg_ident', 'PARAM' => 'ecpg_param',); -# Substitutions to apply to terminal token names to reconstruct the -# literal form of the token. (There is also a hard-wired substitution -# rule that strips trailing '_P'.) -my %replace_string = ( - 'FORMAT_LA' => 'format', - 'NOT_LA' => 'not', - 'NULLS_LA' => 'nulls', - 'WITH_LA' => 'with', - 'WITHOUT_LA' => 'without', - 'TYPECAST' => '::', - 'DOT_DOT' => '..', - 'COLON_EQUALS' => ':=', - 'EQUALS_GREATER' => '=>', - 'LESS_EQUALS' => '<=', - 'GREATER_EQUALS' => '>=', - 'NOT_EQUALS' => '<>',); - -# This hash can provide a result type to override '<str>' for nonterminals +# This hash can provide a result type to override "void" for nonterminals # that need that, or it can specify 'ignore' to cause us to skip the rule -# for that nonterminal. (In that case, ecpg.trailer had better provide -# a substitute rule.) +# for that nonterminal. (In either case, ecpg.trailer had better provide +# a substitute rule, since the default won't do.) my %replace_types = ( 'PrepareStmt' => '<prep>', 'ExecuteStmt' => '<exec>', @@ -175,11 +158,8 @@ my $non_term_id; # we plan to emit for the current rule. my $line = ''; -# @fields holds the items to be emitted in the token-concatenation action -# for the current rule (assuming we emit one). "$N" refers to the N'th -# input token of the rule; anything else is a string to emit literally. -# (We assume no such string can need to start with '$'.) -my @fields; +# count of tokens included in $line. +my $line_count = 0; # Open parser / output file early, to raise errors early. @@ -244,10 +224,6 @@ sub main $has_if_command = 1 if /^\s*if/; } - # We track %prec per-line, not per-rule, which is not quite right - # but there are no counterexamples in gram.y at present. - my $prec = 0; - # Make sure any braces are split into separate fields s/{/ { /g; s/}/ } /g; @@ -296,7 +272,7 @@ sub main } # If it's "<something>", it's a type in a %token declaration, - # which we can just drop. + # which we should just drop so that the tokens have void type. if (substr($a, 0, 1) eq '<') { next; @@ -376,7 +352,7 @@ sub main if ($copymode) { # Print the accumulated rule. - emit_rule(\@fields); + emit_rule(); add_to_buffer('rules', ";\n\n"); } else @@ -386,8 +362,8 @@ sub main } # Reset for the next rule. - @fields = (); $line = ''; + $line_count = 0; $in_rule = 0; $alt_count = 0; $has_feature_not_supported = 0; @@ -401,11 +377,10 @@ sub main { # Print the accumulated alternative. # Increment $alt_count for each non-ignored alternative. - $alt_count += emit_rule(\@fields); + $alt_count += emit_rule(); } # Reset for the next alternative. - @fields = (); # Start the next line with '|' if we've printed at least one # alternative. if ($alt_count > 1) @@ -416,6 +391,7 @@ sub main { $line = ''; } + $line_count = 0; $has_feature_not_supported = 0; $has_if_command = 0; next; @@ -444,13 +420,9 @@ sub main $fieldIndexer++; } - # Check for %replace_types override of nonterminal's type - if (not defined $replace_types{$non_term_id}) - { - # By default, the type is <str> - $replace_types{$non_term_id} = '<str>'; - } - elsif ($replace_types{$non_term_id} eq 'ignore') + # Check for %replace_types entry indicating to ignore it. + if (defined $replace_types{$non_term_id} + && $replace_types{$non_term_id} eq 'ignore') { # We'll ignore this nonterminal and rule altogether. $copymode = 0; @@ -470,22 +442,26 @@ sub main $stmt_mode = 0; } - # Emit appropriate %type declaration for this nonterminal. - my $tstr = - '%type ' - . $replace_types{$non_term_id} . ' ' - . $non_term_id; - add_to_buffer('types', $tstr); + # Emit appropriate %type declaration for this nonterminal, + # if it has a type; otherwise omit that. + if (defined $replace_types{$non_term_id}) + { + my $tstr = + '%type ' + . $replace_types{$non_term_id} . ' ' + . $non_term_id; + add_to_buffer('types', $tstr); + } # Emit the target part of the rule. # Note: the leading space is just to match # the old, rather weird output logic. - $tstr = ' ' . $non_term_id . ':'; + my $tstr = ' ' . $non_term_id . ':'; add_to_buffer('rules', $tstr); - # Prepare for reading the fields (tokens) of the rule. + # Prepare for reading the tokens of the rule. $line = ''; - @fields = (); + $line_count = 0; die "unterminated rule at grammar line $.\n" if $in_rule; $in_rule = 1; @@ -496,48 +472,7 @@ sub main { # Not a nonterminal declaration, so just add it to $line. $line = $line . ' ' . $arr[$fieldIndexer]; - } - - # %prec and whatever follows it should get added to $line, - # but not to @fields. - if ($arr[$fieldIndexer] eq '%prec') - { - $prec = 1; - next; - } - - # Emit transformed version of token to @fields if appropriate. - if ( $copymode - && !$prec - && !$comment - && $in_rule) - { - my $S = $arr[$fieldIndexer]; - - # If it's a known terminal token (other than Op) or a literal - # character, we need to emit the equivalent string, which'll - # later get wrapped into a C string literal, perhaps after - # merging with adjacent strings. - if ($S ne 'Op' - && (defined $tokens{$S} - || $S =~ /^'.+'$/)) - { - # Apply replace_string substitution if any. - $S = $replace_string{$S} if (exists $replace_string{$S}); - # Automatically strip _P if present. - $S =~ s/_P$//; - # And get rid of quotes if it's a literal character. - $S =~ tr/'//d; - # Finally, downcase and push into @fields. - push(@fields, lc($S)); - } - else - { - # Otherwise, push a $N reference to this input token. - # (We assume this cannot be confused with anything the - # above code would produce.) - push(@fields, '$' . (scalar(@fields) + 1)); - } + $line_count++; } } } @@ -568,13 +503,13 @@ sub include_file # by an ecpg.addons entry. sub emit_rule_action { - my ($tag, $fields) = @_; + my ($tag) = @_; # See if we have an addons entry; if not, just emit default action my $rec = $addons{$tag}; if (!$rec) { - emit_default_action($fields, 0); + emit_default_action(0); return; } @@ -585,7 +520,7 @@ sub emit_rule_action if ($rectype eq 'rule') { # Emit default action and then the code block. - emit_default_action($fields, 0); + emit_default_action(0); } elsif ($rectype eq 'addon') { @@ -600,7 +535,7 @@ sub emit_rule_action if ($rectype eq 'addon') { - emit_default_action($fields, 1); + emit_default_action(1); } return; } @@ -626,12 +561,11 @@ sub dump_buffer } # Emit the default action (usually token concatenation) for the current rule. -# Pass: fields array, brace_printed boolean +# Pass: brace_printed boolean # brace_printed should be true if caller already printed action's open brace. sub emit_default_action { - my ($flds, $brace_printed) = @_; - my $len = scalar(@$flds); + my ($brace_printed) = @_; if ($stmt_mode == 0) { @@ -651,91 +585,21 @@ sub emit_default_action ); } - if ($len == 0) - { - # Empty rule - if (!$brace_printed) - { - add_to_buffer('rules', ' { '); - $brace_printed = 1; - } - add_to_buffer('rules', ' $$=EMPTY; }'); - } - else - { - # Go through each field and aggregate consecutive literal tokens - # into a single 'mm_strdup' call. - my @flds_new; - my $str; - for (my $z = 0; $z < $len; $z++) - { - if (substr($flds->[$z], 0, 1) eq '$') - { - push(@flds_new, $flds->[$z]); - next; - } - - $str = $flds->[$z]; - - while (1) - { - if ($z >= $len - 1 - || substr($flds->[ $z + 1 ], 0, 1) eq '$') - { - # Can't combine any more literals; push to @flds_new. - # This code would need work if any literals contain - # backslash or double quote, but right now that never - # happens. - push(@flds_new, "mm_strdup(\"$str\")"); - last; - } - $z++; - $str = $str . ' ' . $flds->[$z]; - } - } - - # So - how many fields did we end up with ? - $len = scalar(@flds_new); - if ($len == 1) - { - # Single field can be handled by straight assignment - if (!$brace_printed) - { - add_to_buffer('rules', ' { '); - $brace_printed = 1; - } - $str = ' $$ = ' . $flds_new[0] . ';'; - add_to_buffer('rules', $str); - } - else - { - # Need to concatenate the results to form our final string - if (!$brace_printed) - { - add_to_buffer('rules', ' { '); - $brace_printed = 1; - } - $str = - ' $$ = cat_str(' . $len . ',' . join(',', @flds_new) . ');'; - add_to_buffer('rules', $str); - } - add_to_buffer('rules', '}') if ($brace_printed); - } + add_to_buffer('rules', '}') if ($brace_printed); } else { # We're in the "stmt:" rule, where we need to output special actions. # This code assumes that no ecpg.addons entry applies. - if ($len) + if ($line_count) { # Any regular kind of statement calls output_statement add_to_buffer('rules', - ' { output_statement($1, 0, ECPGst_normal); }'); + ' { output_statement(@1, 0, ECPGst_normal); }'); } else { # The empty production for stmt: do nothing - add_to_buffer('rules', ' { $$ = NULL; }'); } } return; @@ -746,8 +610,6 @@ sub emit_default_action # entry in %replace_line, then do nothing and return 0. sub emit_rule { - my ($fields) = @_; - # compute tag to be used as lookup key in %replace_line and %addons my $tag = $non_term_id . $line; $tag =~ tr/ |//d; @@ -761,7 +623,8 @@ sub emit_rule return 0; } - # non-ignore entries replace the line, but we'd better keep any '|' + # non-ignore entries replace the line, but we'd better keep any '|'; + # we don't bother to update $line_count here. if (index($line, '|') != -1) { $line = '| ' . $rep; @@ -778,7 +641,7 @@ sub emit_rule # Emit $line, then print the appropriate action. add_to_buffer('rules', $line); - emit_rule_action($tag, $fields); + emit_rule_action($tag); return 1; } diff --git a/src/interfaces/ecpg/preproc/parser.c b/src/interfaces/ecpg/preproc/parser.c index 9daeee3303..8807c22cb6 100644 --- a/src/interfaces/ecpg/preproc/parser.c +++ b/src/interfaces/ecpg/preproc/parser.c @@ -31,6 +31,7 @@ static YYSTYPE lookahead_yylval; /* yylval for lookahead token */ static YYLTYPE lookahead_yylloc; /* yylloc for lookahead token */ static char *lookahead_yytext; /* start current token */ +static int base_yylex_location(void); static bool check_uescapechar(unsigned char escape); static bool ecpg_isspace(char ch); @@ -71,7 +72,7 @@ filtered_base_yylex(void) have_lookahead = false; } else - cur_token = base_yylex(); + cur_token = base_yylex_location(); /* * If this token isn't one that requires lookahead, just return it. @@ -96,7 +97,7 @@ filtered_base_yylex(void) cur_yytext = base_yytext; /* Get next token, saving outputs into lookahead variables */ - next_token = base_yylex(); + next_token = base_yylex_location(); lookahead_token = next_token; lookahead_yylval = base_yylval; @@ -184,7 +185,7 @@ filtered_base_yylex(void) cur_yytext = base_yytext; /* Get third token */ - next_token = base_yylex(); + next_token = base_yylex_location(); if (next_token != SCONST) mmerror(PARSE_ERROR, ET_ERROR, "UESCAPE must be followed by a simple string literal"); @@ -203,6 +204,7 @@ filtered_base_yylex(void) /* Combine 3 tokens into 1 */ base_yylval.str = psprintf("%s UESCAPE %s", base_yylval.str, escstr); + base_yylloc = mm_strdup(base_yylval.str); /* Clear have_lookahead, thereby consuming all three tokens */ have_lookahead = false; @@ -218,6 +220,56 @@ filtered_base_yylex(void) return cur_token; } +/* + * Call base_yylex() and fill in base_yylloc. + * + * pgc.l does not worry about setting yylloc, and given what we want for + * that, trying to set it there would be pretty inconvenient. What we + * want is: if the returned token has type <str>, then duplicate its + * string value as yylloc; otherwise, make a downcased copy of yytext. + * The downcasing is ASCII-only because all that we care about there + * is producing uniformly-cased output of keywords. (That's mostly + * cosmetic, but there are places in ecpglib that expect to receive + * downcased keywords, plus it keeps us regression-test-compatible + * with the old implementation of ecpg.) + */ +static int +base_yylex_location(void) +{ + int token = base_yylex(); + + switch (token) + { + /* List a token here if pgc.l assigns to base_yylval.str for it */ + case Op: + case CSTRING: + case CPP_LINE: + case CVARIABLE: + case BCONST: + case SCONST: + case USCONST: + case XCONST: + case FCONST: + case IDENT: + case UIDENT: + case IP: + /* Duplicate the <str> value */ + base_yylloc = mm_strdup(base_yylval.str); + break; + default: + /* Else just use the input, i.e., yytext */ + base_yylloc = mm_strdup(base_yytext); + /* Apply an ASCII-only downcasing */ + for (unsigned char *ptr = (unsigned char *) base_yylloc; *ptr; ptr++) + { + if (*ptr >= 'A' && *ptr <= 'Z') + *ptr += 'a' - 'A'; + } + break; + } + return token; +} + /* * check_uescapechar() and ecpg_isspace() should match their equivalents * in pgc.l. diff --git a/src/interfaces/ecpg/preproc/preproc_extern.h b/src/interfaces/ecpg/preproc/preproc_extern.h index c5fd07fbd8..da93967462 100644 --- a/src/interfaces/ecpg/preproc/preproc_extern.h +++ b/src/interfaces/ecpg/preproc/preproc_extern.h @@ -15,6 +15,13 @@ #define STRUCT_DEPTH 128 #define EMPTY mm_strdup("") +/* + * "Location tracking" support --- see ecpg.header for more comments. + */ +typedef char *YYLTYPE; + +#define YYLTYPE_IS_DECLARED 1 + /* variables */ extern bool autocommit, @@ -65,10 +72,10 @@ extern const uint16 SQLScanKeywordTokens[]; extern const char *get_dtype(enum ECPGdtype); extern void lex_init(void); extern void output_line_number(void); -extern void output_statement(char *stmt, int whenever_mode, enum ECPG_statement_type st); -extern void output_prepare_statement(char *name, char *stmt); -extern void output_deallocate_prepare_statement(char *name); -extern void output_simple_statement(char *stmt, int whenever_mode); +extern void output_statement(const char *stmt, int whenever_mode, enum ECPG_statement_type st); +extern void output_prepare_statement(const char *name, const char *stmt); +extern void output_deallocate_prepare_statement(const char *name); +extern void output_simple_statement(const char *stmt, int whenever_mode); extern char *hashline_number(void); extern int base_yyparse(void); extern int base_yylex(void); -- 2.43.5 From 355105082517d5ae2f479956a11ca4c8865a744d Mon Sep 17 00:00:00 2001 From: Tom Lane <tgl@sss.pgh.pa.us> Date: Fri, 5 Jul 2024 11:43:21 -0400 Subject: [PATCH v2 5/6] Move some functions into a new file ecpg/preproc/util.c. mm_alloc and mm_strdup were in type.c, which seems a completely random choice. No doubt the original author thought two small functions didn't deserve their own file. But I'm about to add some more memory-management stuff beside them, so let's put them in a less surprising place. This seems like a better home for mmerror and mmfatal, too. --- src/interfaces/ecpg/preproc/Makefile | 1 + src/interfaces/ecpg/preproc/ecpg.header | 65 --------------- src/interfaces/ecpg/preproc/meson.build | 1 + src/interfaces/ecpg/preproc/type.c | 24 ------ src/interfaces/ecpg/preproc/util.c | 105 ++++++++++++++++++++++++ 5 files changed, 107 insertions(+), 89 deletions(-) create mode 100644 src/interfaces/ecpg/preproc/util.c diff --git a/src/interfaces/ecpg/preproc/Makefile b/src/interfaces/ecpg/preproc/Makefile index 934b7cef1b..7866037cbb 100644 --- a/src/interfaces/ecpg/preproc/Makefile +++ b/src/interfaces/ecpg/preproc/Makefile @@ -36,6 +36,7 @@ OBJS = \ preproc.o \ type.o \ typename.o \ + util.o \ variable.o # where to find gen_keywordlist.pl and subsidiary files diff --git a/src/interfaces/ecpg/preproc/ecpg.header b/src/interfaces/ecpg/preproc/ecpg.header index 46023a0106..48a4670191 100644 --- a/src/interfaces/ecpg/preproc/ecpg.header +++ b/src/interfaces/ecpg/preproc/ecpg.header @@ -55,73 +55,8 @@ struct variable no_indicator = {"no_indicator", &ecpg_no_indicator, 0, NULL}; static struct ECPGtype ecpg_query = {ECPGt_char_variable, NULL, NULL, NULL, {NULL}, 0}; -static void vmmerror(int error_code, enum errortype type, const char *error, va_list ap) pg_attribute_printf(3, 0); - static bool check_declared_list(const char *name); -/* - * Handle parsing errors and warnings - */ -static void -vmmerror(int error_code, enum errortype type, const char *error, va_list ap) -{ - /* localize the error message string */ - error = _(error); - - fprintf(stderr, "%s:%d: ", input_filename, base_yylineno); - - switch (type) - { - case ET_WARNING: - fprintf(stderr, _("WARNING: ")); - break; - case ET_ERROR: - fprintf(stderr, _("ERROR: ")); - break; - } - - vfprintf(stderr, error, ap); - - fprintf(stderr, "\n"); - - switch (type) - { - case ET_WARNING: - break; - case ET_ERROR: - ret_value = error_code; - break; - } -} - -void -mmerror(int error_code, enum errortype type, const char *error,...) -{ - va_list ap; - - va_start(ap, error); - vmmerror(error_code, type, error, ap); - va_end(ap); -} - -void -mmfatal(int error_code, const char *error,...) -{ - va_list ap; - - va_start(ap, error); - vmmerror(error_code, ET_ERROR, error, ap); - va_end(ap); - - if (base_yyin) - fclose(base_yyin); - if (base_yyout) - fclose(base_yyout); - - if (strcmp(output_filename, "-") != 0 && unlink(output_filename) != 0) - fprintf(stderr, _("could not remove output file \"%s\"\n"), output_filename); - exit(error_code); -} /* * string concatenation diff --git a/src/interfaces/ecpg/preproc/meson.build b/src/interfaces/ecpg/preproc/meson.build index ddd7a66547..f680e5d59e 100644 --- a/src/interfaces/ecpg/preproc/meson.build +++ b/src/interfaces/ecpg/preproc/meson.build @@ -10,6 +10,7 @@ ecpg_sources = files( 'output.c', 'parser.c', 'type.c', + 'util.c', 'variable.c', ) diff --git a/src/interfaces/ecpg/preproc/type.c b/src/interfaces/ecpg/preproc/type.c index a842bb6a1f..5610a8dc76 100644 --- a/src/interfaces/ecpg/preproc/type.c +++ b/src/interfaces/ecpg/preproc/type.c @@ -8,30 +8,6 @@ static struct ECPGstruct_member struct_no_indicator = {"no_indicator", &ecpg_no_indicator, NULL}; -/* malloc + error check */ -void * -mm_alloc(size_t size) -{ - void *ptr = malloc(size); - - if (ptr == NULL) - mmfatal(OUT_OF_MEMORY, "out of memory"); - - return ptr; -} - -/* strdup + error check */ -char * -mm_strdup(const char *string) -{ - char *new = strdup(string); - - if (new == NULL) - mmfatal(OUT_OF_MEMORY, "out of memory"); - - return new; -} - /* duplicate memberlist */ struct ECPGstruct_member * ECPGstruct_member_dup(struct ECPGstruct_member *rm) diff --git a/src/interfaces/ecpg/preproc/util.c b/src/interfaces/ecpg/preproc/util.c new file mode 100644 index 0000000000..b80802ca9f --- /dev/null +++ b/src/interfaces/ecpg/preproc/util.c @@ -0,0 +1,105 @@ +/* src/interfaces/ecpg/preproc/util.c */ + +#include "postgres_fe.h" + +#include <unistd.h> + +#include "preproc_extern.h" + +static void vmmerror(int error_code, enum errortype type, const char *error, va_list ap) pg_attribute_printf(3, 0); + + +/* + * Handle preprocessor errors and warnings + */ +static void +vmmerror(int error_code, enum errortype type, const char *error, va_list ap) +{ + /* localize the error message string */ + error = _(error); + + fprintf(stderr, "%s:%d: ", input_filename, base_yylineno); + + switch (type) + { + case ET_WARNING: + fprintf(stderr, _("WARNING: ")); + break; + case ET_ERROR: + fprintf(stderr, _("ERROR: ")); + break; + } + + vfprintf(stderr, error, ap); + + fprintf(stderr, "\n"); + + /* If appropriate, set error code to be inspected by ecpg.c */ + switch (type) + { + case ET_WARNING: + break; + case ET_ERROR: + ret_value = error_code; + break; + } +} + +/* Report an error or warning */ +void +mmerror(int error_code, enum errortype type, const char *error,...) +{ + va_list ap; + + va_start(ap, error); + vmmerror(error_code, type, error, ap); + va_end(ap); +} + +/* Report an error and abandon execution */ +void +mmfatal(int error_code, const char *error,...) +{ + va_list ap; + + va_start(ap, error); + vmmerror(error_code, ET_ERROR, error, ap); + va_end(ap); + + if (base_yyin) + fclose(base_yyin); + if (base_yyout) + fclose(base_yyout); + + if (strcmp(output_filename, "-") != 0 && unlink(output_filename) != 0) + fprintf(stderr, _("could not remove output file \"%s\"\n"), output_filename); + exit(error_code); +} + +/* + * Basic memory management support + */ + +/* malloc + error check */ +void * +mm_alloc(size_t size) +{ + void *ptr = malloc(size); + + if (ptr == NULL) + mmfatal(OUT_OF_MEMORY, "out of memory"); + + return ptr; +} + +/* strdup + error check */ +char * +mm_strdup(const char *string) +{ + char *new = strdup(string); + + if (new == NULL) + mmfatal(OUT_OF_MEMORY, "out of memory"); + + return new; +} -- 2.43.5 From 410f4e031e15910cff89d45c6acc3ae12372bf99 Mon Sep 17 00:00:00 2001 From: Tom Lane <tgl@sss.pgh.pa.us> Date: Fri, 5 Jul 2024 11:47:00 -0400 Subject: [PATCH v2 6/6] Improve ecpg preprocessor's memory management. Invent a notion of "local" storage that will automatically be reclaimed at the end of each statement. Use this for location strings as well as other visibly short-lived data within the parser. Also, make cat_str and make_str return local storage and not free their inputs, which allows dispensing with a whole lot of retail mm_strdup calls. We do have to add some new ones in places where a local-lifetime string needs to be added to a longer-lived data structure, but on balance there are a lot less mm_strdup calls than before. I've not attempted to do any performance testing, but this should result in substantially less malloc/free traffic than there was in the old implementation. In hopes of flushing out places where changes were necessary, I changed YYLTYPE from "char *" to "const char *", which forced const-ification of various function arguments that probably should've been like that all along. --- src/interfaces/ecpg/preproc/descriptor.c | 32 +- src/interfaces/ecpg/preproc/ecpg.addons | 144 +++-- src/interfaces/ecpg/preproc/ecpg.header | 191 ++++--- src/interfaces/ecpg/preproc/ecpg.trailer | 548 ++++++++++--------- src/interfaces/ecpg/preproc/output.c | 5 +- src/interfaces/ecpg/preproc/parser.c | 6 +- src/interfaces/ecpg/preproc/preproc_extern.h | 30 +- src/interfaces/ecpg/preproc/type.c | 8 +- src/interfaces/ecpg/preproc/type.h | 30 +- src/interfaces/ecpg/preproc/util.c | 87 +++ src/interfaces/ecpg/preproc/variable.c | 31 +- src/tools/pgindent/typedefs.list | 1 + 12 files changed, 596 insertions(+), 517 deletions(-) diff --git a/src/interfaces/ecpg/preproc/descriptor.c b/src/interfaces/ecpg/preproc/descriptor.c index f4b1878289..9b87d07d09 100644 --- a/src/interfaces/ecpg/preproc/descriptor.c +++ b/src/interfaces/ecpg/preproc/descriptor.c @@ -18,13 +18,12 @@ static struct assignment *assignments; void -push_assignment(char *var, enum ECPGdtype value) +push_assignment(const char *var, enum ECPGdtype value) { struct assignment *new = (struct assignment *) mm_alloc(sizeof(struct assignment)); new->next = assignments; - new->variable = mm_alloc(strlen(var) + 1); - strcpy(new->variable, var); + new->variable = mm_strdup(var); new->value = value; assignments = new; } @@ -73,7 +72,7 @@ ECPGnumeric_lvalue(char *name) static struct descriptor *descriptors; void -add_descriptor(char *name, char *connection) +add_descriptor(const char *name, const char *connection) { struct descriptor *new; @@ -83,20 +82,16 @@ add_descriptor(char *name, char *connection) new = (struct descriptor *) mm_alloc(sizeof(struct descriptor)); new->next = descriptors; - new->name = mm_alloc(strlen(name) + 1); - strcpy(new->name, name); + new->name = mm_strdup(name); if (connection) - { - new->connection = mm_alloc(strlen(connection) + 1); - strcpy(new->connection, connection); - } + new->connection = mm_strdup(connection); else - new->connection = connection; + new->connection = NULL; descriptors = new; } void -drop_descriptor(char *name, char *connection) +drop_descriptor(const char *name, const char *connection) { struct descriptor *i; struct descriptor **lastptr = &descriptors; @@ -126,9 +121,8 @@ drop_descriptor(char *name, char *connection) mmerror(PARSE_ERROR, ET_WARNING, "descriptor %s bound to the default connection does not exist", name); } -struct descriptor - * -lookup_descriptor(char *name, char *connection) +struct descriptor * +lookup_descriptor(const char *name, const char *connection) { struct descriptor *i; @@ -159,7 +153,7 @@ lookup_descriptor(char *name, char *connection) } void -output_get_descr_header(char *desc_name) +output_get_descr_header(const char *desc_name) { struct assignment *results; @@ -178,7 +172,7 @@ output_get_descr_header(char *desc_name) } void -output_get_descr(char *desc_name, char *index) +output_get_descr(const char *desc_name, const char *index) { struct assignment *results; @@ -211,7 +205,7 @@ output_get_descr(char *desc_name, char *index) } void -output_set_descr_header(char *desc_name) +output_set_descr_header(const char *desc_name) { struct assignment *results; @@ -272,7 +266,7 @@ descriptor_item_name(enum ECPGdtype itemcode) } void -output_set_descr(char *desc_name, char *index) +output_set_descr(const char *desc_name, const char *index) { struct assignment *results; diff --git a/src/interfaces/ecpg/preproc/ecpg.addons b/src/interfaces/ecpg/preproc/ecpg.addons index 24ee54554e..0120757312 100644 --- a/src/interfaces/ecpg/preproc/ecpg.addons +++ b/src/interfaces/ecpg/preproc/ecpg.addons @@ -45,18 +45,16 @@ ECPG: stmtExecuteStmt block else { /* case of ecpg_ident or CSTRING */ - char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); - char *str = mm_strdup($1.name + 1); + char *length = loc_alloc(32); + char *str; - /* - * It must be cut off double quotation because new_variable() - * double-quotes. - */ + /* Remove double quotes from name */ + str = loc_strdup($1.name + 1); str[strlen(str) - 1] = '\0'; - sprintf(length, "%zu", strlen(str)); + snprintf(length, 32, "%zu", strlen(str)); add_variable_to_tail(&argsinsert, new_variable(str, ECPGmake_simple_type(ECPGt_const, length, 0), 0), &no_indicator); } - output_statement(cat_str(3, mm_strdup("execute"), mm_strdup("$0"), $1.type), 0, ECPGst_exec_with_exprlist); + output_statement(cat_str(3, "execute", "$0", $1.type), 0, ECPGst_exec_with_exprlist); } } ECPG: stmtPrepareStmt block @@ -66,7 +64,7 @@ ECPG: stmtPrepareStmt block output_prepare_statement($1.name, $1.stmt); else if (strlen($1.type) == 0) { - char *stmt = cat_str(3, mm_strdup("\""), $1.stmt, mm_strdup("\"")); + char *stmt = cat_str(3, "\"", $1.stmt, "\""); output_prepare_statement($1.name, stmt); } @@ -77,18 +75,16 @@ ECPG: stmtPrepareStmt block add_variable_to_tail(&argsinsert, find_variable($1.name), &no_indicator); else { - char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); - char *str = mm_strdup($1.name + 1); + char *length = loc_alloc(32); + char *str; - /* - * It must be cut off double quotation because new_variable() - * double-quotes. - */ + /* Remove double quotes from name */ + str = loc_strdup($1.name + 1); str[strlen(str) - 1] = '\0'; - sprintf(length, "%zu", strlen(str)); + snprintf(length, 32, "%zu", strlen(str)); add_variable_to_tail(&argsinsert, new_variable(str, ECPGmake_simple_type(ECPGt_const, length, 0), 0), &no_indicator); } - output_statement(cat_str(5, mm_strdup("prepare"), mm_strdup("$0"), $1.type, mm_strdup("as"), $1.stmt), 0, ECPGst_prepare); + output_statement(cat_str(5, "prepare", "$0", $1.type, "as", $1.stmt), 0, ECPGst_prepare); } } ECPG: stmtTransactionStmt block @@ -142,8 +138,6 @@ ECPG: stmtViewStmt rule fputs("ECPGt_EORT);", base_yyout); fprintf(base_yyout, "}"); output_line_number(); - - free($1.stmt_name); } | ECPGDisconnect { @@ -175,8 +169,6 @@ ECPG: stmtViewStmt rule { lookup_descriptor($1.name, connection); output_get_descr($1.name, $1.str); - free($1.name); - free($1.str); } | ECPGGetDescriptorHeader { @@ -190,7 +182,7 @@ ECPG: stmtViewStmt rule if ((ptr = add_additional_variables(@1, true)) != NULL) { connection = ptr->connection ? mm_strdup(ptr->connection) : NULL; - output_statement(mm_strdup(ptr->command), 0, ECPGst_normal); + output_statement(ptr->command, 0, ECPGst_normal); ptr->opened = true; } } @@ -211,8 +203,6 @@ ECPG: stmtViewStmt rule { lookup_descriptor($1.name, connection); output_set_descr($1.name, $1.str); - free($1.name); - free($1.str); } | ECPGSetDescriptorHeader { @@ -243,9 +233,9 @@ ECPG: stmtViewStmt rule } ECPG: where_or_current_clauseWHERECURRENT_POFcursor_name block { - char *cursor_marker = @4[0] == ':' ? mm_strdup("$0") : @4; + const char *cursor_marker = @4[0] == ':' ? "$0" : @4; - @$ = cat_str(2, mm_strdup("where current of"), cursor_marker); + @$ = cat_str(2, "where current of", cursor_marker); } ECPG: CopyStmtCOPYopt_binaryqualified_nameopt_column_listcopy_fromopt_programcopy_file_namecopy_delimiteropt_withcopy_optionswhere_clause addon if (strcmp(@6, "from") == 0 && @@ -253,21 +243,21 @@ ECPG: CopyStmtCOPYopt_binaryqualified_nameopt_column_listcopy_fromopt_programcop mmerror(PARSE_ERROR, ET_WARNING, "COPY FROM STDIN is not implemented"); ECPG: var_valueNumericOnly addon if (@1[0] == '$') - @$ = mm_strdup("$0"); + @$ = "$0"; ECPG: fetch_argscursor_name addon struct cursor *ptr = add_additional_variables(@1, false); if (ptr->connection) connection = mm_strdup(ptr->connection); if (@1[0] == ':') - @$ = mm_strdup("$0"); + @$ = "$0"; ECPG: fetch_argsfrom_incursor_name addon struct cursor *ptr = add_additional_variables(@2, false); if (ptr->connection) connection = mm_strdup(ptr->connection); if (@2[0] == ':') - @$ = cat2_str(mm_strdup(@1), mm_strdup("$0")); + @$ = cat2_str(@1, "$0"); ECPG: fetch_argsNEXTopt_from_incursor_name addon ECPG: fetch_argsPRIORopt_from_incursor_name addon ECPG: fetch_argsFIRST_Popt_from_incursor_name addon @@ -278,7 +268,7 @@ ECPG: fetch_argsALLopt_from_incursor_name addon if (ptr->connection) connection = mm_strdup(ptr->connection); if (@3[0] == ':') - @$ = cat_str(3, mm_strdup(@1), mm_strdup(@2), mm_strdup("$0")); + @$ = cat_str(3, @1, @2, "$0"); ECPG: fetch_argsSignedIconstopt_from_incursor_name addon struct cursor *ptr = add_additional_variables(@3, false); bool replace = false; @@ -287,16 +277,16 @@ ECPG: fetch_argsSignedIconstopt_from_incursor_name addon connection = mm_strdup(ptr->connection); if (@3[0] == ':') { - @3 = mm_strdup("$0"); + @3 = "$0"; replace = true; } if (@1[0] == '$') { - @1 = mm_strdup("$0"); + @1 = "$0"; replace = true; } if (replace) - @$ = cat_str(3, mm_strdup(@1), mm_strdup(@2), mm_strdup(@3)); + @$ = cat_str(3, @1, @2, @3); ECPG: fetch_argsFORWARDALLopt_from_incursor_name addon ECPG: fetch_argsBACKWARDALLopt_from_incursor_name addon struct cursor *ptr = add_additional_variables(@4, false); @@ -304,7 +294,7 @@ ECPG: fetch_argsBACKWARDALLopt_from_incursor_name addon if (ptr->connection) connection = mm_strdup(ptr->connection); if (@4[0] == ':') - @$ = cat_str(4, mm_strdup(@1), mm_strdup(@2), mm_strdup(@3), mm_strdup("$0")); + @$ = cat_str(4, @1, @2, @3, "$0"); ECPG: fetch_argsABSOLUTE_PSignedIconstopt_from_incursor_name addon ECPG: fetch_argsRELATIVE_PSignedIconstopt_from_incursor_name addon ECPG: fetch_argsFORWARDSignedIconstopt_from_incursor_name addon @@ -316,20 +306,20 @@ ECPG: fetch_argsBACKWARDSignedIconstopt_from_incursor_name addon connection = mm_strdup(ptr->connection); if (@4[0] == ':') { - @4 = mm_strdup("$0"); + @4 = "$0"; replace = true; } if (@2[0] == '$') { - @2 = mm_strdup("$0"); + @2 = "$0"; replace = true; } if (replace) - @$ = cat_str(4, mm_strdup(@1), mm_strdup(@2), mm_strdup(@3), mm_strdup(@4)); + @$ = cat_str(4, @1, @2, @3, @4); ECPG: cursor_namename block | char_civar { - char *curname = mm_alloc(strlen(@1) + 2); + char *curname = loc_alloc(strlen(@1) + 2); sprintf(curname, ":%s", @1); @$ = curname; @@ -367,7 +357,7 @@ ECPG: DeclareCursorStmtDECLAREcursor_namecursor_optionsCURSORopt_holdFORSelectSt { struct cursor *ptr, *this; - char *cursor_marker = @2[0] == ':' ? mm_strdup("$0") : mm_strdup(@2); + const char *cursor_marker = @2[0] == ':' ? "$0" : @2; char *comment, *c1, *c2; @@ -394,7 +384,7 @@ ECPG: DeclareCursorStmtDECLAREcursor_namecursor_optionsCURSORopt_holdFORSelectSt this->function = (current_function ? mm_strdup(current_function) : NULL); this->connection = connection ? mm_strdup(connection) : NULL; this->opened = false; - this->command = cat_str(7, mm_strdup("declare"), cursor_marker, @3, mm_strdup("cursor"), @5, mm_strdup("for"), @7); + this->command = mm_strdup(cat_str(7, "declare", cursor_marker, @3, "cursor", @5, "for", @7)); this->argsinsert = argsinsert; this->argsinsert_oos = NULL; this->argsresult = argsresult; @@ -402,20 +392,20 @@ ECPG: DeclareCursorStmtDECLAREcursor_namecursor_optionsCURSORopt_holdFORSelectSt argsinsert = argsresult = NULL; cur = this; - c1 = mm_strdup(this->command); - if ((c2 = strstr(c1, "*/")) != NULL) + c1 = loc_strdup(this->command); + while ((c2 = strstr(c1, "*/")) != NULL) { /* We put this text into a comment, so we better remove [*][/]. */ c2[0] = '.'; c2[1] = '.'; } - comment = cat_str(3, mm_strdup("/*"), c1, mm_strdup("*/")); + comment = cat_str(3, "/*", c1, "*/"); @$ = cat2_str(adjust_outofscope_cursor_vars(this), comment); } ECPG: ClosePortalStmtCLOSEcursor_name block { - char *cursor_marker = @2[0] == ':' ? mm_strdup("$0") : @2; + const char *cursor_marker = @2[0] == ':' ? "$0" : @2; struct cursor *ptr = NULL; for (ptr = cur; ptr != NULL; ptr = ptr->next) @@ -427,23 +417,23 @@ ECPG: ClosePortalStmtCLOSEcursor_name block break; } } - @$ = cat2_str(mm_strdup("close"), cursor_marker); + @$ = cat2_str("close", cursor_marker); } ECPG: opt_hold block { if (compat == ECPG_COMPAT_INFORMIX_SE && autocommit) - @$ = mm_strdup("with hold"); + @$ = "with hold"; else - @$ = EMPTY; + @$ = ""; } ECPG: into_clauseINTOOptTempTableName block { FoundInto = 1; - @$ = cat2_str(mm_strdup("into"), @2); + @$ = cat2_str("into", @2); } | ecpg_into { - @$ = EMPTY; + @$ = ""; } ECPG: TypenameSimpleTypenameopt_array_bounds block { @@ -451,37 +441,33 @@ ECPG: TypenameSimpleTypenameopt_array_bounds block } ECPG: TypenameSETOFSimpleTypenameopt_array_bounds block { - @$ = cat_str(3, mm_strdup("setof"), @2, $3.str); + @$ = cat_str(3, "setof", @2, $3.str); } ECPG: opt_array_boundsopt_array_bounds'['']' block { $$.index1 = $1.index1; $$.index2 = $1.index2; if (strcmp($$.index1, "-1") == 0) - $$.index1 = mm_strdup("0"); + $$.index1 = "0"; else if (strcmp($1.index2, "-1") == 0) - $$.index2 = mm_strdup("0"); - $$.str = cat_str(2, $1.str, mm_strdup("[]")); + $$.index2 = "0"; + $$.str = cat_str(2, $1.str, "[]"); } | opt_array_bounds '[' Iresult ']' { $$.index1 = $1.index1; $$.index2 = $1.index2; if (strcmp($1.index1, "-1") == 0) - $$.index1 = mm_strdup(@3); + $$.index1 = @3; else if (strcmp($1.index2, "-1") == 0) - $$.index2 = mm_strdup(@3); - $$.str = cat_str(4, $1.str, mm_strdup("["), @3, mm_strdup("]")); + $$.index2 = @3; + $$.str = cat_str(4, $1.str, "[", @3, "]"); } ECPG: opt_array_bounds block { - $$.index1 = mm_strdup("-1"); - $$.index2 = mm_strdup("-1"); - $$.str = EMPTY; - } -ECPG: IconstICONST block - { - @$ = make_name(); + $$.index1 = "-1"; + $$.index2 = "-1"; + $$.str = ""; } ECPG: AexprConstNULL_P rule | civar @@ -494,83 +480,83 @@ ECPG: FetchStmtMOVEfetch_args rule | FETCH fetch_args ecpg_fetch_into | FETCH FORWARD cursor_name opt_ecpg_fetch_into { - char *cursor_marker = @3[0] == ':' ? mm_strdup("$0") : @3; + const char *cursor_marker = @3[0] == ':' ? "$0" : @3; struct cursor *ptr = add_additional_variables(@3, false); if (ptr->connection) connection = mm_strdup(ptr->connection); - @$ = cat_str(2, mm_strdup("fetch forward"), cursor_marker); + @$ = cat_str(2, "fetch forward", cursor_marker); } | FETCH FORWARD from_in cursor_name opt_ecpg_fetch_into { - char *cursor_marker = @4[0] == ':' ? mm_strdup("$0") : @4; + const char *cursor_marker = @4[0] == ':' ? "$0" : @4; struct cursor *ptr = add_additional_variables(@4, false); if (ptr->connection) connection = mm_strdup(ptr->connection); - @$ = cat_str(2, mm_strdup("fetch forward from"), cursor_marker); + @$ = cat_str(2, "fetch forward from", cursor_marker); } | FETCH BACKWARD cursor_name opt_ecpg_fetch_into { - char *cursor_marker = @3[0] == ':' ? mm_strdup("$0") : @3; + const char *cursor_marker = @3[0] == ':' ? "$0" : @3; struct cursor *ptr = add_additional_variables(@3, false); if (ptr->connection) connection = mm_strdup(ptr->connection); - @$ = cat_str(2, mm_strdup("fetch backward"), cursor_marker); + @$ = cat_str(2, "fetch backward", cursor_marker); } | FETCH BACKWARD from_in cursor_name opt_ecpg_fetch_into { - char *cursor_marker = @4[0] == ':' ? mm_strdup("$0") : @4; + const char *cursor_marker = @4[0] == ':' ? "$0" : @4; struct cursor *ptr = add_additional_variables(@4, false); if (ptr->connection) connection = mm_strdup(ptr->connection); - @$ = cat_str(2, mm_strdup("fetch backward from"), cursor_marker); + @$ = cat_str(2, "fetch backward from", cursor_marker); } | MOVE FORWARD cursor_name { - char *cursor_marker = @3[0] == ':' ? mm_strdup("$0") : @3; + const char *cursor_marker = @3[0] == ':' ? "$0" : @3; struct cursor *ptr = add_additional_variables(@3, false); if (ptr->connection) connection = mm_strdup(ptr->connection); - @$ = cat_str(2, mm_strdup("move forward"), cursor_marker); + @$ = cat_str(2, "move forward", cursor_marker); } | MOVE FORWARD from_in cursor_name { - char *cursor_marker = @4[0] == ':' ? mm_strdup("$0") : @4; + const char *cursor_marker = @4[0] == ':' ? "$0" : @4; struct cursor *ptr = add_additional_variables(@4, false); if (ptr->connection) connection = mm_strdup(ptr->connection); - @$ = cat_str(2, mm_strdup("move forward from"), cursor_marker); + @$ = cat_str(2, "move forward from", cursor_marker); } | MOVE BACKWARD cursor_name { - char *cursor_marker = @3[0] == ':' ? mm_strdup("$0") : @3; + const char *cursor_marker = @3[0] == ':' ? "$0" : @3; struct cursor *ptr = add_additional_variables(@3, false); if (ptr->connection) connection = mm_strdup(ptr->connection); - @$ = cat_str(2, mm_strdup("move backward"), cursor_marker); + @$ = cat_str(2, "move backward", cursor_marker); } | MOVE BACKWARD from_in cursor_name { - char *cursor_marker = @4[0] == ':' ? mm_strdup("$0") : @4; + const char *cursor_marker = @4[0] == ':' ? "$0" : @4; struct cursor *ptr = add_additional_variables(@4, false); if (ptr->connection) connection = mm_strdup(ptr->connection); - @$ = cat_str(2, mm_strdup("move backward from"), cursor_marker); + @$ = cat_str(2, "move backward from", cursor_marker); } ECPG: limit_clauseLIMITselect_limit_value','select_offset_value block { diff --git a/src/interfaces/ecpg/preproc/ecpg.header b/src/interfaces/ecpg/preproc/ecpg.header index 48a4670191..395b68331e 100644 --- a/src/interfaces/ecpg/preproc/ecpg.header +++ b/src/interfaces/ecpg/preproc/ecpg.header @@ -34,8 +34,6 @@ char *input_filename = NULL; static int FoundInto = 0; static int initializer = 0; static int pacounter = 1; -static char pacounter_buffer[sizeof(int) * CHAR_BIT * 10 / 3]; /* a rough guess at the - * size we need */ static struct this_type actual_type[STRUCT_DEPTH]; static char *actual_startline[STRUCT_DEPTH]; static int varchar_counter = 1; @@ -59,23 +57,24 @@ static bool check_declared_list(const char *name); /* - * string concatenation + * String concatenation support routines. These return "local" (transient) + * storage. cat2_str and cat_str insert spaces between nonempty inputs; + * make2_str and make3_str do not. */ static char * -cat2_str(char *str1, char *str2) +cat2_str(const char *str1, const char *str2) { - char *res_str = (char *) mm_alloc(strlen(str1) + strlen(str2) + 2); + char *res_str = (char *) loc_alloc(strlen(str1) + strlen(str2) + 2); strcpy(res_str, str1); if (strlen(str1) != 0 && strlen(str2) != 0) strcat(res_str, " "); strcat(res_str, str2); - free(str1); - free(str2); return res_str; } +/* Concatenate N inputs */ static char * cat_str(int count,...) { @@ -97,28 +96,23 @@ cat_str(int count,...) } static char * -make2_str(char *str1, char *str2) +make2_str(const char *str1, const char *str2) { - char *res_str = (char *) mm_alloc(strlen(str1) + strlen(str2) + 1); + char *res_str = (char *) loc_alloc(strlen(str1) + strlen(str2) + 1); strcpy(res_str, str1); strcat(res_str, str2); - free(str1); - free(str2); return res_str; } static char * -make3_str(char *str1, char *str2, char *str3) +make3_str(const char *str1, const char *str2, const char *str3) { - char *res_str = (char *) mm_alloc(strlen(str1) + strlen(str2) + strlen(str3) + 1); + char *res_str = (char *) loc_alloc(strlen(str1) + strlen(str2) + strlen(str3) + 1); strcpy(res_str, str1); strcat(res_str, str2); strcat(res_str, str3); - free(str1); - free(str2); - free(str3); return res_str; } @@ -154,7 +148,7 @@ yylloc_default(YYLTYPE *target, YYLTYPE *rhs, int N) needed++; needed += thislen; } - result = (char *) mm_alloc(needed + 1); + result = (char *) loc_alloc(needed + 1); ptr = result; for (int i = 1; i <= N; i++) { @@ -174,22 +168,19 @@ yylloc_default(YYLTYPE *target, YYLTYPE *rhs, int N) *target = rhs[1]; } else - *target = EMPTY; + { + /* No need to allocate any space */ + *target = ""; + } } /* and the rest */ static char * -make_name(void) -{ - return mm_strdup(base_yytext); -} - -static char * -create_questionmarks(char *name, bool array) +create_questionmarks(const char *name, bool array) { struct variable *p = find_variable(name); int count; - char *result = EMPTY; + char *result = ""; /* * In case we have a struct, we have to print as many "?" as there are @@ -217,12 +208,13 @@ create_questionmarks(char *name, bool array) for (; count > 0; count--) { - sprintf(pacounter_buffer, "$%d", pacounter++); - result = cat_str(3, result, mm_strdup(pacounter_buffer), mm_strdup(" , ")); - } + char buf[32]; - /* removed the trailing " ," */ + snprintf(buf, sizeof(buf), "$%d", pacounter++); + result = cat_str(3, result, buf, " , "); + } + /* remove the trailing " ," */ result[strlen(result) - 3] = '\0'; return result; } @@ -242,8 +234,7 @@ adjust_outofscope_cursor_vars(struct cursor *cur) * pointer instead of the variable. Do it only for local variables, not * for globals. */ - - char *result = EMPTY; + char *result = ""; int insert; for (insert = 1; insert >= 0; insert--) @@ -265,7 +256,7 @@ adjust_outofscope_cursor_vars(struct cursor *cur) /* change variable name to "ECPGget_var(<counter>)" */ original_var = ptr->variable->name; - sprintf(var_text, "%d))", ecpg_internal_var); + snprintf(var_text, sizeof(var_text), "%d))", ecpg_internal_var); /* Don't emit ECPGset_var() calls for global variables */ if (ptr->variable->brace_level == 0) @@ -286,12 +277,12 @@ adjust_outofscope_cursor_vars(struct cursor *cur) && ptr->variable->type->type != ECPGt_bytea) && atoi(ptr->variable->type->size) > 1) { - newvar = new_variable(cat_str(4, mm_strdup("("), - mm_strdup(ecpg_type_name(ptr->variable->type->u.element->type)), - mm_strdup(" *)(ECPGget_var("), - mm_strdup(var_text)), + newvar = new_variable(cat_str(4, "(", + ecpg_type_name(ptr->variable->type->u.element->type), + " *)(ECPGget_var(", + var_text), ECPGmake_array_type(ECPGmake_simple_type(ptr->variable->type->u.element->type, - mm_strdup("1"), + "1", ptr->variable->type->u.element->counter), ptr->variable->type->size), 0); @@ -303,10 +294,10 @@ adjust_outofscope_cursor_vars(struct cursor *cur) || ptr->variable->type->type == ECPGt_bytea) && atoi(ptr->variable->type->size) > 1) { - newvar = new_variable(cat_str(4, mm_strdup("("), - mm_strdup(ecpg_type_name(ptr->variable->type->type)), - mm_strdup(" *)(ECPGget_var("), - mm_strdup(var_text)), + newvar = new_variable(cat_str(4, "(", + ecpg_type_name(ptr->variable->type->type), + " *)(ECPGget_var(", + var_text), ECPGmake_simple_type(ptr->variable->type->type, ptr->variable->type->size, ptr->variable->type->counter), @@ -318,11 +309,11 @@ adjust_outofscope_cursor_vars(struct cursor *cur) else if (ptr->variable->type->type == ECPGt_struct || ptr->variable->type->type == ECPGt_union) { - newvar = new_variable(cat_str(5, mm_strdup("(*("), - mm_strdup(ptr->variable->type->type_name), - mm_strdup(" *)(ECPGget_var("), - mm_strdup(var_text), - mm_strdup(")")), + newvar = new_variable(cat_str(5, "(*(", + ptr->variable->type->type_name, + " *)(ECPGget_var(", + var_text, + ")"), ECPGmake_struct_type(ptr->variable->type->u.members, ptr->variable->type->type, ptr->variable->type->type_name, @@ -335,11 +326,11 @@ adjust_outofscope_cursor_vars(struct cursor *cur) if (ptr->variable->type->u.element->type == ECPGt_struct || ptr->variable->type->u.element->type == ECPGt_union) { - newvar = new_variable(cat_str(5, mm_strdup("(*("), - mm_strdup(ptr->variable->type->u.element->type_name), - mm_strdup(" *)(ECPGget_var("), - mm_strdup(var_text), - mm_strdup(")")), + newvar = new_variable(cat_str(5, "(*(", + ptr->variable->type->u.element->type_name, + " *)(ECPGget_var(", + var_text, + ")"), ECPGmake_struct_type(ptr->variable->type->u.element->u.members, ptr->variable->type->u.element->type, ptr->variable->type->u.element->type_name, @@ -348,10 +339,10 @@ adjust_outofscope_cursor_vars(struct cursor *cur) } else { - newvar = new_variable(cat_str(4, mm_strdup("("), - mm_strdup(ecpg_type_name(ptr->variable->type->u.element->type)), - mm_strdup(" *)(ECPGget_var("), - mm_strdup(var_text)), + newvar = new_variable(cat_str(4, "(", + ecpg_type_name(ptr->variable->type->u.element->type), + " *)(ECPGget_var(", + var_text), ECPGmake_array_type(ECPGmake_simple_type(ptr->variable->type->u.element->type, ptr->variable->type->u.element->size, ptr->variable->type->u.element->counter), @@ -362,10 +353,10 @@ adjust_outofscope_cursor_vars(struct cursor *cur) } else { - newvar = new_variable(cat_str(4, mm_strdup("*("), - mm_strdup(ecpg_type_name(ptr->variable->type->type)), - mm_strdup(" *)(ECPGget_var("), - mm_strdup(var_text)), + newvar = new_variable(cat_str(4, "*(", + ecpg_type_name(ptr->variable->type->type), + " *)(ECPGget_var(", + var_text), ECPGmake_simple_type(ptr->variable->type->type, ptr->variable->type->size, ptr->variable->type->counter), @@ -379,10 +370,11 @@ adjust_outofscope_cursor_vars(struct cursor *cur) */ if (!skip_set_var) { - sprintf(var_text, "%d, %s", ecpg_internal_var++, var_ptr ? "&(" : "("); - result = cat_str(5, result, mm_strdup("ECPGset_var("), - mm_strdup(var_text), mm_strdup(original_var), - mm_strdup("), __LINE__);\n")); + snprintf(var_text, sizeof(var_text), "%d, %s", + ecpg_internal_var++, var_ptr ? "&(" : "("); + result = cat_str(5, result, "ECPGset_var(", + var_text, original_var, + "), __LINE__);\n"); } /* @@ -397,17 +389,17 @@ adjust_outofscope_cursor_vars(struct cursor *cur) { /* change variable name to "ECPGget_var(<counter>)" */ original_var = ptr->indicator->name; - sprintf(var_text, "%d))", ecpg_internal_var); + snprintf(var_text, sizeof(var_text), "%d))", ecpg_internal_var); var_ptr = false; if (ptr->indicator->type->type == ECPGt_struct || ptr->indicator->type->type == ECPGt_union) { - newind = new_variable(cat_str(5, mm_strdup("(*("), - mm_strdup(ptr->indicator->type->type_name), - mm_strdup(" *)(ECPGget_var("), - mm_strdup(var_text), - mm_strdup(")")), + newind = new_variable(cat_str(5, "(*(", + ptr->indicator->type->type_name, + " *)(ECPGget_var(", + var_text, + ")"), ECPGmake_struct_type(ptr->indicator->type->u.members, ptr->indicator->type->type, ptr->indicator->type->type_name, @@ -420,11 +412,11 @@ adjust_outofscope_cursor_vars(struct cursor *cur) if (ptr->indicator->type->u.element->type == ECPGt_struct || ptr->indicator->type->u.element->type == ECPGt_union) { - newind = new_variable(cat_str(5, mm_strdup("(*("), - mm_strdup(ptr->indicator->type->u.element->type_name), - mm_strdup(" *)(ECPGget_var("), - mm_strdup(var_text), - mm_strdup(")")), + newind = new_variable(cat_str(5, "(*(", + ptr->indicator->type->u.element->type_name, + " *)(ECPGget_var(", + var_text, + ")"), ECPGmake_struct_type(ptr->indicator->type->u.element->u.members, ptr->indicator->type->u.element->type, ptr->indicator->type->u.element->type_name, @@ -433,9 +425,10 @@ adjust_outofscope_cursor_vars(struct cursor *cur) } else { - newind = new_variable(cat_str(4, mm_strdup("("), - mm_strdup(ecpg_type_name(ptr->indicator->type->u.element->type)), - mm_strdup(" *)(ECPGget_var("), mm_strdup(var_text)), + newind = new_variable(cat_str(4, "(", + ecpg_type_name(ptr->indicator->type->u.element->type), + " *)(ECPGget_var(", + var_text), ECPGmake_array_type(ECPGmake_simple_type(ptr->indicator->type->u.element->type, ptr->indicator->type->u.element->size, ptr->indicator->type->u.element->counter), @@ -446,10 +439,10 @@ adjust_outofscope_cursor_vars(struct cursor *cur) } else if (atoi(ptr->indicator->type->size) > 1) { - newind = new_variable(cat_str(4, mm_strdup("("), - mm_strdup(ecpg_type_name(ptr->indicator->type->type)), - mm_strdup(" *)(ECPGget_var("), - mm_strdup(var_text)), + newind = new_variable(cat_str(4, "(", + ecpg_type_name(ptr->indicator->type->type), + " *)(ECPGget_var(", + var_text), ECPGmake_simple_type(ptr->indicator->type->type, ptr->indicator->type->size, ptr->variable->type->counter), @@ -457,10 +450,10 @@ adjust_outofscope_cursor_vars(struct cursor *cur) } else { - newind = new_variable(cat_str(4, mm_strdup("*("), - mm_strdup(ecpg_type_name(ptr->indicator->type->type)), - mm_strdup(" *)(ECPGget_var("), - mm_strdup(var_text)), + newind = new_variable(cat_str(4, "*(", + ecpg_type_name(ptr->indicator->type->type), + " *)(ECPGget_var(", + var_text), ECPGmake_simple_type(ptr->indicator->type->type, ptr->indicator->type->size, ptr->variable->type->counter), @@ -472,10 +465,11 @@ adjust_outofscope_cursor_vars(struct cursor *cur) * create call to "ECPGset_var(<counter>, <pointer>. <line * number>)" */ - sprintf(var_text, "%d, %s", ecpg_internal_var++, var_ptr ? "&(" : "("); - result = cat_str(5, result, mm_strdup("ECPGset_var("), - mm_strdup(var_text), mm_strdup(original_var), - mm_strdup("), __LINE__);\n")); + snprintf(var_text, sizeof(var_text), "%d, %s", + ecpg_internal_var++, var_ptr ? "&(" : "("); + result = cat_str(5, result, "ECPGset_var(", + var_text, original_var, + "), __LINE__);\n"); } add_variable_to_tail(&newlist, newvar, newind); @@ -496,7 +490,7 @@ adjust_outofscope_cursor_vars(struct cursor *cur) (cur->function != NULL && strcmp(cur->function, current_function) == 0)) static struct cursor * -add_additional_variables(char *name, bool insert) +add_additional_variables(const char *name, bool insert) { struct cursor *ptr; struct arguments *p; @@ -534,8 +528,10 @@ add_additional_variables(char *name, bool insert) } static void -add_typedef(char *name, char *dimension, char *length, enum ECPGttype type_enum, - char *type_dimension, char *type_index, int initializer, int array) +add_typedef(const char *name, const char *dimension, const char *length, + enum ECPGttype type_enum, + const char *type_dimension, const char *type_index, + int initializer, int array) { /* add entry to list */ struct typedefs *ptr, @@ -555,19 +551,20 @@ add_typedef(char *name, char *dimension, char *length, enum ECPGttype type_enum, /* re-definition is a bug */ mmerror(PARSE_ERROR, ET_ERROR, "type \"%s\" is already defined", name); } - adjust_array(type_enum, &dimension, &length, type_dimension, type_index, array, true); + adjust_array(type_enum, &dimension, &length, + type_dimension, type_index, array, true); this = (struct typedefs *) mm_alloc(sizeof(struct typedefs)); /* initial definition */ this->next = types; - this->name = name; + this->name = mm_strdup(name); this->brace_level = braces_open; this->type = (struct this_type *) mm_alloc(sizeof(struct this_type)); this->type->type_enum = type_enum; this->type->type_str = mm_strdup(name); - this->type->type_dimension = dimension; /* dimension of array */ - this->type->type_index = length; /* length of string */ + this->type->type_dimension = mm_strdup(dimension); /* dimension of array */ + this->type->type_index = mm_strdup(length); /* length of string */ this->type->type_sizeof = ECPGstruct_sizeof; this->struct_member_list = (type_enum == ECPGt_struct || type_enum == ECPGt_union) ? ECPGstruct_member_dup(struct_member_list[struct_level]) : NULL; diff --git a/src/interfaces/ecpg/preproc/ecpg.trailer b/src/interfaces/ecpg/preproc/ecpg.trailer index e6475e170d..392b5032bf 100644 --- a/src/interfaces/ecpg/preproc/ecpg.trailer +++ b/src/interfaces/ecpg/preproc/ecpg.trailer @@ -2,6 +2,12 @@ statements: /* EMPTY */ | statements statement + { + /* Reclaim local storage used while processing statement */ + reclaim_local_storage(); + /* Clean up now-dangling location pointer */ + @$ = ""; + } ; statement: ecpgstart at toplevel_stmt ';' @@ -68,7 +74,7 @@ CreateAsStmt: CREATE OptTemp TABLE create_as_target AS at: AT connection_object { - connection = @2; + connection = mm_strdup(@2); /* * Do we have a variable as connection target? Remove the variable @@ -84,20 +90,20 @@ at: AT connection_object */ ECPGConnect: SQL_CONNECT TO connection_target opt_connection_name opt_user { - @$ = cat_str(5, @3, mm_strdup(","), @5, mm_strdup(","), @4); + @$ = cat_str(5, @3, ",", @5, ",", @4); } | SQL_CONNECT TO DEFAULT { - @$ = mm_strdup("NULL, NULL, NULL, \"DEFAULT\""); + @$ = "NULL, NULL, NULL, \"DEFAULT\""; } /* also allow ORACLE syntax */ | SQL_CONNECT ora_user { - @$ = cat_str(3, mm_strdup("NULL,"), @2, mm_strdup(", NULL")); + @$ = cat_str(3, "NULL,", @2, ", NULL"); } | DATABASE connection_target { - @$ = cat2_str(@2, mm_strdup(", NULL, NULL, NULL")); + @$ = cat2_str(@2, ", NULL, NULL, NULL"); } ; @@ -111,7 +117,7 @@ connection_target: opt_database_name opt_server opt_port if (@1[0] == '\"') @$ = @1; else - @$ = make3_str(mm_strdup("\""), make3_str(@1, @2, @3), mm_strdup("\"")); + @$ = make3_str("\"", make3_str(@1, @2, @3), "\""); } | db_prefix ':' server opt_port '/' opt_database_name opt_options { @@ -127,19 +133,21 @@ connection_target: opt_database_name opt_server opt_port strncmp(@3 + strlen("//"), "127.0.0.1", strlen("127.0.0.1")) != 0) mmerror(PARSE_ERROR, ET_ERROR, "Unix-domain sockets only work on \"localhost\" but not on \"%s\"", @3 + strlen("//")); - @$ = make3_str(make3_str(mm_strdup("\""), @1, mm_strdup(":")), @3, make3_str(make3_str(@4, mm_strdup("/"), @6),@7, mm_strdup("\""))); + @$ = make3_str(make3_str("\"", @1, ":"), @3, make3_str(make3_str(@4, "/", @6), @7, "\"")); } | char_variable | ecpg_sconst { /* - * We can only process double quoted strings not single quotes ones, - * so we change the quotes. Note, that the rule for ecpg_sconst adds + * We can only process double quoted strings not single quoted ones, + * so we change the quotes. Note that the rule for ecpg_sconst adds * these single quotes. */ - @1[0] = '\"'; - @1[strlen(@1) - 1] = '\"'; - @$ = @1; + char *str = loc_strdup(@1); + + str[0] = '\"'; + str[strlen(str) - 1] = '\"'; + @$ = str; } ; @@ -155,7 +163,7 @@ db_prefix: ecpg_ident cvariable if (strcmp(@1, "tcp") != 0 && strcmp(@1, "unix") != 0) mmerror(PARSE_ERROR, ET_ERROR, "invalid connection type: %s", @1); - @$ = make3_str(@1, mm_strdup(":"), @2); + @$ = make3_str(@1, ":", @2); } ; @@ -175,14 +183,11 @@ opt_server: server server_name: ColId | ColId '.' server_name | IP - { - @$ = make_name(); - } ; opt_port: ':' Iconst { - @$ = make2_str(mm_strdup(":"), @2); + @$ = make2_str(":", @2); } | /* EMPTY */ ; @@ -193,7 +198,7 @@ opt_connection_name: AS connection_object } | /* EMPTY */ { - @$ = mm_strdup("NULL"); + @$ = "NULL"; } ; @@ -203,25 +208,25 @@ opt_user: USER ora_user } | /* EMPTY */ { - @$ = mm_strdup("NULL, NULL"); + @$ = "NULL, NULL"; } ; ora_user: user_name { - @$ = cat2_str(@1, mm_strdup(", NULL")); + @$ = cat2_str(@1, ", NULL"); } | user_name '/' user_name { - @$ = cat_str(3, @1, mm_strdup(","), @3); + @$ = cat_str(3, @1, ",", @3); } | user_name SQL_IDENTIFIED BY user_name { - @$ = cat_str(3, @1, mm_strdup(","), @4); + @$ = cat_str(3, @1, ",", @4); } | user_name USING user_name { - @$ = cat_str(3, @1, mm_strdup(","), @3); + @$ = cat_str(3, @1, ",", @3); } ; @@ -230,14 +235,14 @@ user_name: RoleId if (@1[0] == '\"') @$ = @1; else - @$ = make3_str(mm_strdup("\""), @1, mm_strdup("\"")); + @$ = make3_str("\"", @1, "\""); } | ecpg_sconst { if (@1[0] == '\"') @$ = @1; else - @$ = make3_str(mm_strdup("\""), @1, mm_strdup("\"")); + @$ = make3_str("\"", @1, "\""); } | civar { @@ -249,9 +254,9 @@ user_name: RoleId /* handle varchars */ if (type == ECPGt_varchar) - @$ = make2_str(mm_strdup(argsinsert->variable->name), mm_strdup(".arr")); + @$ = make2_str(argsinsert->variable->name, ".arr"); else - @$ = mm_strdup(argsinsert->variable->name); + @$ = argsinsert->variable->name; } ; @@ -278,7 +283,7 @@ char_variable: cvariable @$ = @1; break; case ECPGt_varchar: - @$ = make2_str(@1, mm_strdup(".arr")); + @$ = make2_str(@1, ".arr"); break; default: mmerror(PARSE_ERROR, ET_ERROR, "invalid data type"); @@ -297,7 +302,7 @@ opt_options: Op connect_options if (strcmp(@1, "?") != 0) mmerror(PARSE_ERROR, ET_ERROR, "unrecognized token \"%s\"", @1); - @$ = make2_str(mm_strdup("?"), @2); + @$ = make2_str("?", @2); } | /* EMPTY */ ; @@ -321,30 +326,34 @@ connect_options: ColId opt_opt_value opt_opt_value: /* EMPTY */ | '=' Iconst { - @$ = make2_str(mm_strdup("="), @2); + @$ = make2_str("=", @2); } | '=' ecpg_ident { - @$ = make2_str(mm_strdup("="), @2); + @$ = make2_str("=", @2); } | '=' civar { - @$ = make2_str(mm_strdup("="), @2); + @$ = make2_str("=", @2); } ; prepared_name: name { - if (@1[0] == '\"' && @1[strlen(@1) - 1] == '\"') /* already quoted? */ + size_t slen = strlen(@1); + + if (@1[0] == '\"' && @1[slen - 1] == '\"') /* already quoted? */ @$ = @1; else /* not quoted => convert to lowercase */ { - size_t i; - - for (i = 0; i < strlen(@1); i++) - @1[i] = tolower((unsigned char) @1[i]); - - @$ = make3_str(mm_strdup("\""), @1, mm_strdup("\"")); + char *str = loc_alloc(slen + 3); + + str[0] = '\"'; + for (size_t i = 0; i < slen; i++) + str[i + 1] = tolower((unsigned char) @1[i]); + str[slen + 1] = '\"'; + str[slen + 2] = '\0'; + @$ = str; } } | char_variable @@ -355,7 +364,7 @@ prepared_name: name */ ECPGDeclareStmt: DECLARE prepared_name STATEMENT { - struct declared_list *ptr = NULL; + struct declared_list *ptr; /* Check whether the declared name has been defined or not */ for (ptr = g_declared_list; ptr != NULL; ptr = ptr->next) @@ -368,12 +377,11 @@ ECPGDeclareStmt: DECLARE prepared_name STATEMENT } /* Add a new declared name into the g_declared_list */ - ptr = NULL; ptr = (struct declared_list *) mm_alloc(sizeof(struct declared_list)); if (ptr) { /* initial definition */ - ptr->name = @2; + ptr->name = mm_strdup(@2); if (connection) ptr->connection = mm_strdup(connection); else @@ -383,7 +391,7 @@ ECPGDeclareStmt: DECLARE prepared_name STATEMENT g_declared_list = ptr; } - @$ = cat_str(3, mm_strdup("/* declare "), mm_strdup(@2), mm_strdup(" as an SQL identifier */")); + @$ = cat_str(3, "/* declare ", @2, " as an SQL identifier */"); } ; @@ -395,7 +403,7 @@ ECPGCursorStmt: DECLARE cursor_name cursor_options CURSOR opt_hold FOR prepared_ { struct cursor *ptr, *this; - char *cursor_marker = @2[0] == ':' ? mm_strdup("$0") : mm_strdup(@2); + const char *cursor_marker = @2[0] == ':' ? "$0" : @2; int (*strcmp_fn) (const char *, const char *) = ((@2[0] == ':' || @2[0] == '"') ? strcmp : pg_strcasecmp); struct variable *thisquery = (struct variable *) mm_alloc(sizeof(struct variable)); char *comment; @@ -422,10 +430,10 @@ ECPGCursorStmt: DECLARE cursor_name cursor_options CURSOR opt_hold FOR prepared_ /* initial definition */ this->next = cur; - this->name = @2; + this->name = mm_strdup(@2); this->function = (current_function ? mm_strdup(current_function) : NULL); this->connection = connection ? mm_strdup(connection) : NULL; - this->command = cat_str(6, mm_strdup("declare"), cursor_marker, @3, mm_strdup("cursor"), @5, mm_strdup("for $1")); + this->command = mm_strdup(cat_str(6, "declare", cursor_marker, @3, "cursor", @5, "for $1")); this->argsresult = NULL; this->argsresult_oos = NULL; @@ -448,7 +456,7 @@ ECPGCursorStmt: DECLARE cursor_name cursor_options CURSOR opt_hold FOR prepared_ cur = this; - comment = cat_str(3, mm_strdup("/*"), mm_strdup(this->command), mm_strdup("*/")); + comment = cat_str(3, "/*", this->command, "*/"); @$ = cat_str(2, adjust_outofscope_cursor_vars(this), comment); @@ -541,45 +549,44 @@ type_declaration: S_TYPEDEF fprintf(base_yyout, "typedef %s %s %s %s;\n", $3.type_str, *@4 ? "*" : "", @5, $6.str); output_line_number(); - @$ = EMPTY; + @$ = ""; } ; var_declaration: storage_declaration var_type { - actual_type[struct_level].type_storage = @1; + actual_type[struct_level].type_storage = mm_strdup(@1); actual_type[struct_level].type_enum = $2.type_enum; - actual_type[struct_level].type_str = $2.type_str; - actual_type[struct_level].type_dimension = $2.type_dimension; - actual_type[struct_level].type_index = $2.type_index; - actual_type[struct_level].type_sizeof = $2.type_sizeof; + actual_type[struct_level].type_str = mm_strdup($2.type_str); + actual_type[struct_level].type_dimension = mm_strdup($2.type_dimension); + actual_type[struct_level].type_index = mm_strdup($2.type_index); + actual_type[struct_level].type_sizeof = + $2.type_sizeof ? mm_strdup($2.type_sizeof) : NULL; actual_startline[struct_level] = hashline_number(); } variable_list ';' { - @$ = cat_str(5, actual_startline[struct_level], @1, $2.type_str, @4, mm_strdup(";\n")); + @$ = cat_str(5, actual_startline[struct_level], @1, $2.type_str, @4, ";\n"); } | var_type { - actual_type[struct_level].type_storage = EMPTY; + actual_type[struct_level].type_storage = mm_strdup(""); actual_type[struct_level].type_enum = $1.type_enum; - actual_type[struct_level].type_str = $1.type_str; - actual_type[struct_level].type_dimension = $1.type_dimension; - actual_type[struct_level].type_index = $1.type_index; - actual_type[struct_level].type_sizeof = $1.type_sizeof; + actual_type[struct_level].type_str = mm_strdup($1.type_str); + actual_type[struct_level].type_dimension = mm_strdup($1.type_dimension); + actual_type[struct_level].type_index = mm_strdup($1.type_index); + actual_type[struct_level].type_sizeof = + $1.type_sizeof ? mm_strdup($1.type_sizeof) : NULL; actual_startline[struct_level] = hashline_number(); } variable_list ';' { - @$ = cat_str(4, actual_startline[struct_level], $1.type_str, @3, mm_strdup(";\n")); + @$ = cat_str(4, actual_startline[struct_level], $1.type_str, @3, ";\n"); } | struct_union_type_with_symbol ';' - { - @$ = cat2_str(@1, mm_strdup(";")); - } ; opt_bit_field: ':' Iconst @@ -604,16 +611,16 @@ storage_modifier: S_CONST var_type: simple_type { $$.type_enum = $1; - $$.type_str = mm_strdup(ecpg_type_name($1)); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); + $$.type_str = loc_strdup(ecpg_type_name($1)); + $$.type_dimension = "-1"; + $$.type_index = "-1"; $$.type_sizeof = NULL; } | struct_union_type { - $$.type_str = @1; - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); + $$.type_str = loc_strdup(@1); + $$.type_dimension = "-1"; + $$.type_index = "-1"; if (strncmp(@1, "struct", sizeof("struct") - 1) == 0) { @@ -628,26 +635,26 @@ var_type: simple_type } | enum_type { - $$.type_str = @1; + $$.type_str = loc_strdup(@1); $$.type_enum = ECPGt_int; - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); + $$.type_dimension = "-1"; + $$.type_index = "-1"; $$.type_sizeof = NULL; } | NUMERIC '(' precision opt_scale ')' { $$.type_enum = ECPGt_numeric; - $$.type_str = mm_strdup("numeric"); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); + $$.type_str = "numeric"; + $$.type_dimension = "-1"; + $$.type_index = "-1"; $$.type_sizeof = NULL; } | DECIMAL_P '(' precision opt_scale ')' { $$.type_enum = ECPGt_decimal; - $$.type_str = mm_strdup("decimal"); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); + $$.type_str = "decimal"; + $$.type_dimension = "-1"; + $$.type_index = "-1"; $$.type_sizeof = NULL; } | IDENT '(' precision opt_scale ')' @@ -660,63 +667,63 @@ var_type: simple_type if (strcmp(@1, "numeric") == 0) { $$.type_enum = ECPGt_numeric; - $$.type_str = mm_strdup("numeric"); + $$.type_str = "numeric"; } else if (strcmp(@1, "decimal") == 0) { $$.type_enum = ECPGt_decimal; - $$.type_str = mm_strdup("decimal"); + $$.type_str = "decimal"; } else { mmerror(PARSE_ERROR, ET_ERROR, "only data types numeric and decimal have precision/scale argument"); $$.type_enum = ECPGt_numeric; - $$.type_str = mm_strdup("numeric"); + $$.type_str = "numeric"; } - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); + $$.type_dimension = "-1"; + $$.type_index = "-1"; $$.type_sizeof = NULL; } | VARCHAR { $$.type_enum = ECPGt_varchar; - $$.type_str = EMPTY; /* mm_strdup("varchar"); */ - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); + $$.type_str = ""; /* "varchar"; */ + $$.type_dimension = "-1"; + $$.type_index = "-1"; $$.type_sizeof = NULL; } | FLOAT_P { /* Note: DOUBLE is handled in simple_type */ $$.type_enum = ECPGt_float; - $$.type_str = mm_strdup("float"); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); + $$.type_str = "float"; + $$.type_dimension = "-1"; + $$.type_index = "-1"; $$.type_sizeof = NULL; } | NUMERIC { $$.type_enum = ECPGt_numeric; - $$.type_str = mm_strdup("numeric"); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); + $$.type_str = "numeric"; + $$.type_dimension = "-1"; + $$.type_index = "-1"; $$.type_sizeof = NULL; } | DECIMAL_P { $$.type_enum = ECPGt_decimal; - $$.type_str = mm_strdup("decimal"); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); + $$.type_str = "decimal"; + $$.type_dimension = "-1"; + $$.type_index = "-1"; $$.type_sizeof = NULL; } | TIMESTAMP { $$.type_enum = ECPGt_timestamp; - $$.type_str = mm_strdup("timestamp"); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); + $$.type_str = "timestamp"; + $$.type_dimension = "-1"; + $$.type_index = "-1"; $$.type_sizeof = NULL; } | STRING_P @@ -725,9 +732,9 @@ var_type: simple_type { /* In Informix mode, "string" is automatically a typedef */ $$.type_enum = ECPGt_string; - $$.type_str = mm_strdup("char"); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); + $$.type_str = "char"; + $$.type_dimension = "-1"; + $$.type_index = "-1"; $$.type_sizeof = NULL; } else @@ -735,14 +742,14 @@ var_type: simple_type /* Otherwise, legal only if user typedef'ed it */ struct typedefs *this = get_typedef("string", false); - $$.type_str = (this->type->type_enum == ECPGt_varchar || this->type->type_enum == ECPGt_bytea) ? EMPTY : mm_strdup(this->name); + $$.type_str = (this->type->type_enum == ECPGt_varchar || this->type->type_enum == ECPGt_bytea) ? mm_strdup(""): mm_strdup(this->name); $$.type_enum = this->type->type_enum; $$.type_dimension = this->type->type_dimension; $$.type_index = this->type->type_index; if (this->type->type_sizeof && strlen(this->type->type_sizeof) != 0) $$.type_sizeof = this->type->type_sizeof; else - $$.type_sizeof = cat_str(3, mm_strdup("sizeof("), mm_strdup(this->name), mm_strdup(")")); + $$.type_sizeof = cat_str(3, "sizeof(", this->name, ")"); struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list); } @@ -750,9 +757,9 @@ var_type: simple_type | INTERVAL ecpg_interval { $$.type_enum = ECPGt_interval; - $$.type_str = mm_strdup("interval"); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); + $$.type_str = "interval"; + $$.type_dimension = "-1"; + $$.type_index = "-1"; $$.type_sizeof = NULL; } | IDENT ecpg_interval @@ -772,89 +779,89 @@ var_type: simple_type if (strcmp(@1, "varchar") == 0) { $$.type_enum = ECPGt_varchar; - $$.type_str = EMPTY; /* mm_strdup("varchar"); */ - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); + $$.type_str = ""; /* "varchar"; */ + $$.type_dimension = "-1"; + $$.type_index = "-1"; $$.type_sizeof = NULL; } else if (strcmp(@1, "bytea") == 0) { $$.type_enum = ECPGt_bytea; - $$.type_str = EMPTY; - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); + $$.type_str = ""; + $$.type_dimension = "-1"; + $$.type_index = "-1"; $$.type_sizeof = NULL; } else if (strcmp(@1, "float") == 0) { $$.type_enum = ECPGt_float; - $$.type_str = mm_strdup("float"); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); + $$.type_str = "float"; + $$.type_dimension = "-1"; + $$.type_index = "-1"; $$.type_sizeof = NULL; } else if (strcmp(@1, "double") == 0) { $$.type_enum = ECPGt_double; - $$.type_str = mm_strdup("double"); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); + $$.type_str = "double"; + $$.type_dimension = "-1"; + $$.type_index = "-1"; $$.type_sizeof = NULL; } else if (strcmp(@1, "numeric") == 0) { $$.type_enum = ECPGt_numeric; - $$.type_str = mm_strdup("numeric"); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); + $$.type_str = "numeric"; + $$.type_dimension = "-1"; + $$.type_index = "-1"; $$.type_sizeof = NULL; } else if (strcmp(@1, "decimal") == 0) { $$.type_enum = ECPGt_decimal; - $$.type_str = mm_strdup("decimal"); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); + $$.type_str = "decimal"; + $$.type_dimension = "-1"; + $$.type_index = "-1"; $$.type_sizeof = NULL; } else if (strcmp(@1, "date") == 0) { $$.type_enum = ECPGt_date; - $$.type_str = mm_strdup("date"); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); + $$.type_str = "date"; + $$.type_dimension = "-1"; + $$.type_index = "-1"; $$.type_sizeof = NULL; } else if (strcmp(@1, "timestamp") == 0) { $$.type_enum = ECPGt_timestamp; - $$.type_str = mm_strdup("timestamp"); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); + $$.type_str = "timestamp"; + $$.type_dimension = "-1"; + $$.type_index = "-1"; $$.type_sizeof = NULL; } else if (strcmp(@1, "interval") == 0) { $$.type_enum = ECPGt_interval; - $$.type_str = mm_strdup("interval"); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); + $$.type_str = "interval"; + $$.type_dimension = "-1"; + $$.type_index = "-1"; $$.type_sizeof = NULL; } else if (strcmp(@1, "datetime") == 0) { $$.type_enum = ECPGt_timestamp; - $$.type_str = mm_strdup("timestamp"); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); + $$.type_str = "timestamp"; + $$.type_dimension = "-1"; + $$.type_index = "-1"; $$.type_sizeof = NULL; } else if ((strcmp(@1, "string") == 0) && INFORMIX_MODE) { $$.type_enum = ECPGt_string; - $$.type_str = mm_strdup("char"); - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); + $$.type_str = "char"; + $$.type_dimension = "-1"; + $$.type_index = "-1"; $$.type_sizeof = NULL; } else @@ -862,14 +869,14 @@ var_type: simple_type /* Otherwise, it must be a user-defined typedef name */ struct typedefs *this = get_typedef(@1, false); - $$.type_str = (this->type->type_enum == ECPGt_varchar || this->type->type_enum == ECPGt_bytea) ? EMPTY : mm_strdup(this->name); + $$.type_str = (this->type->type_enum == ECPGt_varchar || this->type->type_enum == ECPGt_bytea) ? mm_strdup(""): mm_strdup(this->name); $$.type_enum = this->type->type_enum; $$.type_dimension = this->type->type_dimension; $$.type_index = this->type->type_index; if (this->type->type_sizeof && strlen(this->type->type_sizeof) != 0) $$.type_sizeof = this->type->type_sizeof; else - $$.type_sizeof = cat_str(3, mm_strdup("sizeof("), mm_strdup(this->name), mm_strdup(")")); + $$.type_sizeof = cat_str(3, "sizeof(", this->name, ")"); struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list); } @@ -888,21 +895,20 @@ var_type: simple_type /* No */ this = get_typedef(name, false); - $$.type_str = mm_strdup(this->name); + $$.type_str = this->name; $$.type_enum = this->type->type_enum; $$.type_dimension = this->type->type_dimension; $$.type_index = this->type->type_index; $$.type_sizeof = this->type->type_sizeof; struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list); - free(name); } else { $$.type_str = name; $$.type_enum = ECPGt_long; - $$.type_dimension = mm_strdup("-1"); - $$.type_index = mm_strdup("-1"); - $$.type_sizeof = mm_strdup(""); + $$.type_dimension = "-1"; + $$.type_index = "-1"; + $$.type_sizeof = ""; struct_member_list[struct_level] = NULL; } } @@ -932,7 +938,7 @@ struct_union_type_with_symbol: s_struct_union_symbol ECPGfree_struct_member(struct_member_list[struct_level]); struct_member_list[struct_level] = NULL; struct_level--; - if (strncmp($1.su, "struct", sizeof("struct") - 1) == 0) + if (strcmp($1.su, "struct") == 0) su_type.type_enum = ECPGt_struct; else su_type.type_enum = ECPGt_union; @@ -967,7 +973,7 @@ struct_union_type_with_symbol: s_struct_union_symbol this->struct_member_list = struct_member_list[struct_level]; types = this; - @$ = cat_str(4, su_type.type_str, mm_strdup("{"), @4, mm_strdup("}")); + @$ = cat_str(4, su_type.type_str, "{", @4, "}"); } ; @@ -983,19 +989,21 @@ struct_union_type: struct_union_type_with_symbol ECPGfree_struct_member(struct_member_list[struct_level]); struct_member_list[struct_level] = NULL; struct_level--; - @$ = cat_str(4, @1, mm_strdup("{"), @4, mm_strdup("}")); + @$ = cat_str(4, @1, "{", @4, "}"); } ; s_struct_union_symbol: SQL_STRUCT symbol { - $$.su = mm_strdup("struct"); + $$.su = "struct"; $$.symbol = @2; - ECPGstruct_sizeof = cat_str(3, mm_strdup("sizeof("), cat2_str(mm_strdup($$.su), mm_strdup($$.symbol)), mm_strdup(")")); + ECPGstruct_sizeof = mm_strdup(cat_str(3, "sizeof(", + cat2_str($$.su, $$.symbol), + ")")); } | UNION symbol { - $$.su = mm_strdup("union"); + $$.su = "union"; $$.symbol = @2; } ; @@ -1004,11 +1012,11 @@ s_struct_union: SQL_STRUCT { ECPGstruct_sizeof = mm_strdup(""); /* This must not be NULL to * distinguish from simple types. */ - @$ = mm_strdup("struct"); + @$ = "struct"; } | UNION { - @$ = mm_strdup("union"); + @$ = "union"; } ; @@ -1047,23 +1055,27 @@ variable_list: variable | variable_list ',' variable { if (actual_type[struct_level].type_enum == ECPGt_varchar || actual_type[struct_level].type_enum == ECPGt_bytea) - @$ = cat_str(4, @1, mm_strdup(";"), mm_strdup(actual_type[struct_level].type_storage), @3); + @$ = cat_str(4, @1, ";", actual_type[struct_level].type_storage, @3); else - @$ = cat_str(3, @1, mm_strdup(","), @3); + @$ = cat_str(3, @1, ",", @3); } ; variable: opt_pointer ECPGColLabel opt_array_bounds opt_bit_field opt_initializer { struct ECPGtype *type; - char *dimension = $3.index1; /* dimension of array */ - char *length = $3.index2; /* length of string */ + const char *dimension = $3.index1; /* dimension of array */ + const char *length = $3.index2; /* length of string */ char *dim_str; char *vcn; int *varlen_type_counter; char *struct_name; - adjust_array(actual_type[struct_level].type_enum, &dimension, &length, actual_type[struct_level].type_dimension,actual_type[struct_level].type_index, strlen(@1), false); + adjust_array(actual_type[struct_level].type_enum, + &dimension, &length, + actual_type[struct_level].type_dimension, + actual_type[struct_level].type_index, + strlen(@1), false); switch (actual_type[struct_level].type_enum) { case ECPGt_struct: @@ -1073,7 +1085,7 @@ variable: opt_pointer ECPGColLabel opt_array_bounds opt_bit_field opt_initialize else type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level], actual_type[struct_level].type_enum,actual_type[struct_level].type_str, actual_type[struct_level].type_sizeof), dimension); - @$ = cat_str(5, @1, mm_strdup(@2), $3.str, @4, @5); + @$ = cat_str(5, @1, @2, $3.str, @4, @5); break; case ECPGt_varchar: @@ -1094,9 +1106,9 @@ variable: opt_pointer ECPGColLabel opt_array_bounds opt_bit_field opt_initialize type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length, *varlen_type_counter),dimension); if (strcmp(dimension, "0") == 0 || abs(atoi(dimension)) == 1) - dim_str = mm_strdup(""); + dim_str = ""; else - dim_str = cat_str(3, mm_strdup("["), mm_strdup(dimension), mm_strdup("]")); + dim_str = cat_str(3, "[", dimension, "]"); /* * cannot check for atoi <= 0 because a defined constant will @@ -1109,12 +1121,12 @@ variable: opt_pointer ECPGColLabel opt_array_bounds opt_bit_field opt_initialize * make sure varchar struct name is unique by adding a unique * counter to its definition */ - vcn = (char *) mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); - sprintf(vcn, "%d", *varlen_type_counter); + vcn = (char *) loc_alloc(32); + snprintf(vcn, 32, "%d", *varlen_type_counter); if (strcmp(dimension, "0") == 0) - @$ = cat_str(7, make2_str(mm_strdup(struct_name), vcn), mm_strdup(" { int len; char arr["), mm_strdup(length),mm_strdup("]; } *"), mm_strdup(@2), @4, @5); + @$ = cat_str(7, make2_str(struct_name, vcn), " { int len; char arr[", length, "]; } *", @2, @4, @5); else - @$ = cat_str(8, make2_str(mm_strdup(struct_name), vcn), mm_strdup(" { int len; char arr["), mm_strdup(length),mm_strdup("]; } "), mm_strdup(@2), dim_str, @4, @5); + @$ = cat_str(8, make2_str(struct_name, vcn), " { int len; char arr[", length, "]; } ", @2, dim_str,@4, @5); (*varlen_type_counter)++; break; @@ -1132,25 +1144,26 @@ variable: opt_pointer ECPGColLabel opt_array_bounds opt_bit_field opt_initialize * if we have an initializer but no string size set, * let's use the initializer's length */ - free(length); - length = mm_alloc(i + sizeof("sizeof()")); - sprintf(length, "sizeof(%s)", @5 + 2); + char *buf = loc_alloc(32); + + snprintf(buf, 32, "sizeof(%s)", @5 + 2); + length = buf; } type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length, 0); } else type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length, 0), dimension); - @$ = cat_str(5, @1, mm_strdup(@2), $3.str, @4, @5); + @$ = cat_str(5, @1, @2, $3.str, @4, @5); break; default: if (atoi(dimension) < 0) - type = ECPGmake_simple_type(actual_type[struct_level].type_enum, mm_strdup("1"), 0); + type = ECPGmake_simple_type(actual_type[struct_level].type_enum, "1", 0); else - type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, mm_strdup("1"),0), dimension); + type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, "1", 0), dimension); - @$ = cat_str(5, @1, mm_strdup(@2), $3.str, @4, @5); + @$ = cat_str(5, @1, @2, $3.str, @4, @5); break; } @@ -1172,7 +1185,7 @@ opt_pointer: /* EMPTY */ | '*' | '*' '*' { - @$ = mm_strdup("**"); + @$ = "**"; } ; @@ -1182,7 +1195,7 @@ opt_pointer: /* EMPTY */ ECPGDeclare: DECLARE STATEMENT ecpg_ident { /* this is only supported for compatibility */ - @$ = cat_str(3, mm_strdup("/* declare statement"), @3, mm_strdup("*/")); + @$ = cat_str(3, "/* declare statement", @3, "*/"); } ; /* @@ -1197,25 +1210,25 @@ ECPGDisconnect: SQL_DISCONNECT dis_name dis_name: connection_object | CURRENT_P { - @$ = mm_strdup("\"CURRENT\""); + @$ = "\"CURRENT\""; } | ALL { - @$ = mm_strdup("\"ALL\""); + @$ = "\"ALL\""; } | /* EMPTY */ { - @$ = mm_strdup("\"CURRENT\""); + @$ = "\"CURRENT\""; } ; connection_object: name { - @$ = make3_str(mm_strdup("\""), @1, mm_strdup("\"")); + @$ = make3_str("\"", @1, "\""); } | DEFAULT { - @$ = mm_strdup("\"DEFAULT\""); + @$ = "\"DEFAULT\""; } | char_variable ; @@ -1223,7 +1236,7 @@ connection_object: name execstring: char_variable | CSTRING { - @$ = make3_str(mm_strdup("\""), @1, mm_strdup("\"")); + @$ = make3_str("\"", @1, "\""); } ; @@ -1237,7 +1250,7 @@ ECPGFree: SQL_FREE cursor_name } | SQL_FREE ALL { - @$ = mm_strdup("all"); + @$ = "all"; } ; @@ -1258,7 +1271,7 @@ opt_ecpg_using: /* EMPTY */ ecpg_using: USING using_list { - @$ = EMPTY; + @$ = ""; } | using_descriptor ; @@ -1266,31 +1279,31 @@ ecpg_using: USING using_list using_descriptor: USING SQL_P SQL_DESCRIPTOR quoted_ident_stringvar { add_variable_to_head(&argsinsert, descriptor_variable(@4, 0), &no_indicator); - @$ = EMPTY; + @$ = ""; } | USING SQL_DESCRIPTOR name { add_variable_to_head(&argsinsert, sqlda_variable(@3), &no_indicator); - @$ = EMPTY; + @$ = ""; } ; into_descriptor: INTO SQL_P SQL_DESCRIPTOR quoted_ident_stringvar { add_variable_to_head(&argsresult, descriptor_variable(@4, 1), &no_indicator); - @$ = EMPTY; + @$ = ""; } | INTO SQL_DESCRIPTOR name { add_variable_to_head(&argsresult, sqlda_variable(@3), &no_indicator); - @$ = EMPTY; + @$ = ""; } ; into_sqlda: INTO name { add_variable_to_head(&argsresult, sqlda_variable(@2), &no_indicator); - @$ = EMPTY; + @$ = ""; } ; @@ -1299,18 +1312,18 @@ using_list: UsingValue | UsingValue ',' using_list UsingValue: UsingConst { - char *length = mm_alloc(32); + char *length = loc_alloc(32); - sprintf(length, "%zu", strlen(@1)); + snprintf(length, 32, "%zu", strlen(@1)); add_variable_to_head(&argsinsert, new_variable(@1, ECPGmake_simple_type(ECPGt_const, length, 0), 0), &no_indicator); } | civar { - @$ = EMPTY; + @$ = ""; } | civarind { - @$ = EMPTY; + @$ = ""; } ; @@ -1430,9 +1443,9 @@ ECPGSetDescHeaderItem: desc_header_item '=' IntConstVar IntConstVar: Iconst { - char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); + char *length = loc_alloc(32); - sprintf(length, "%zu", strlen(@1)); + snprintf(length, 32, "%zu", strlen(@1)); new_variable(@1, ECPGmake_simple_type(ECPGt_const, length, 0), 0); } | cvariable @@ -1484,37 +1497,39 @@ ECPGSetDescItem: descriptor_item '=' AllConstVar AllConstVar: ecpg_fconst { - char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); + char *length = loc_alloc(32); - sprintf(length, "%zu", strlen(@1)); + snprintf(length, 32, "%zu", strlen(@1)); new_variable(@1, ECPGmake_simple_type(ECPGt_const, length, 0), 0); } | IntConstVar | '-' ecpg_fconst { - char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); - char *var = cat2_str(mm_strdup("-"), @2); + char *length = loc_alloc(32); + char *var = cat2_str("-", @2); - sprintf(length, "%zu", strlen(var)); + snprintf(length, 32, "%zu", strlen(var)); new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0); @$ = var; } | '-' Iconst { - char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); - char *var = cat2_str(mm_strdup("-"), @2); + char *length = loc_alloc(32); + char *var = cat2_str("-", @2); - sprintf(length, "%zu", strlen(var)); + snprintf(length, 32, "%zu", strlen(var)); new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0); @$ = var; } | ecpg_sconst { - char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); - char *var = @1 + 1; + char *length = loc_alloc(32); + char *var; + /* Strip single quotes from ecpg_sconst */ + var = loc_strdup(@1 + 1); var[strlen(var) - 1] = '\0'; - sprintf(length, "%zu", strlen(var)); + snprintf(length, 32, "%zu", strlen(var)); new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0); @$ = var; } @@ -1587,9 +1602,9 @@ ECPGTypedef: TYPE_P add_typedef(@3, $6.index1, $6.index2, $5.type_enum, $5.type_dimension, $5.type_index, initializer, *@7 ? 1 : 0); if (auto_create_c == false) - @$ = cat_str(7, mm_strdup("/* exec sql type"), mm_strdup(@3), mm_strdup("is"), mm_strdup($5.type_str), mm_strdup($6.str),@7, mm_strdup("*/")); + @$ = cat_str(7, "/* exec sql type", @3, "is", $5.type_str, $6.str, @7, "*/"); else - @$ = cat_str(6, mm_strdup("typedef "), mm_strdup($5.type_str), *@7 ? mm_strdup("*") : mm_strdup(""), mm_strdup(@3),mm_strdup($6.str), mm_strdup(";")); + @$ = cat_str(6, "typedef ", $5.type_str, *@7 ? "*" : "", @3, $6.str, ";"); } ; @@ -1609,8 +1624,8 @@ ECPGVar: SQL_VAR ColLabel IS var_type opt_array_bounds opt_reference { struct variable *p = find_variable(@3); - char *dimension = $6.index1; - char *length = $6.index2; + const char *dimension = $6.index1; + const char *length = $6.index2; struct ECPGtype *type; if (($5.type_enum == ECPGt_struct || @@ -1619,7 +1634,8 @@ ECPGVar: SQL_VAR mmerror(PARSE_ERROR, ET_ERROR, "initializer not allowed in EXEC SQL VAR command"); else { - adjust_array($5.type_enum, &dimension, &length, $5.type_dimension, $5.type_index, *@7 ? 1 : 0, false); + adjust_array($5.type_enum, &dimension, &length, + $5.type_dimension, $5.type_index, *@7 ? 1 : 0, false); switch ($5.type_enum) { @@ -1653,9 +1669,9 @@ ECPGVar: SQL_VAR mmerror(PARSE_ERROR, ET_ERROR, "multidimensional arrays for simple data types are not supported"); if (atoi(dimension) < 0) - type = ECPGmake_simple_type($5.type_enum, mm_strdup("1"), 0); + type = ECPGmake_simple_type($5.type_enum, "1", 0); else - type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, mm_strdup("1"), 0), dimension); + type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, "1", 0), dimension); break; } @@ -1663,7 +1679,7 @@ ECPGVar: SQL_VAR p->type = type; } - @$ = cat_str(7, mm_strdup("/* exec sql var"), mm_strdup(@3), mm_strdup("is"), mm_strdup($5.type_str),mm_strdup($6.str), @7, mm_strdup("*/")); + @$ = cat_str(7, "/* exec sql var", @3, "is", $5.type_str, $6.str, @7, "*/"); } ; @@ -1673,83 +1689,83 @@ ECPGVar: SQL_VAR */ ECPGWhenever: SQL_WHENEVER SQL_SQLERROR action { - when_error.code = $<action>3.code; - when_error.command = $<action>3.command; - @$ = cat_str(3, mm_strdup("/* exec sql whenever sqlerror "), $3.str, mm_strdup("; */")); + when_error.code = $3.code; + when_error.command = $3.command ? mm_strdup($3.command) : NULL; + @$ = cat_str(3, "/* exec sql whenever sqlerror ", $3.str, "; */"); } | SQL_WHENEVER NOT SQL_FOUND action { - when_nf.code = $<action>4.code; - when_nf.command = $<action>4.command; - @$ = cat_str(3, mm_strdup("/* exec sql whenever not found "), $4.str, mm_strdup("; */")); + when_nf.code = $4.code; + when_nf.command = $4.command ? mm_strdup($4.command) : NULL; + @$ = cat_str(3, "/* exec sql whenever not found ", $4.str, "; */"); } | SQL_WHENEVER SQL_SQLWARNING action { - when_warn.code = $<action>3.code; - when_warn.command = $<action>3.command; - @$ = cat_str(3, mm_strdup("/* exec sql whenever sql_warning "), $3.str, mm_strdup("; */")); + when_warn.code = $3.code; + when_warn.command = $3.command ? mm_strdup($3.command) : NULL; + @$ = cat_str(3, "/* exec sql whenever sql_warning ", $3.str, "; */"); } ; action: CONTINUE_P { - $<action>$.code = W_NOTHING; - $<action>$.command = NULL; - $<action>$.str = mm_strdup("continue"); + $$.code = W_NOTHING; + $$.command = NULL; + $$.str = "continue"; } | SQL_SQLPRINT { - $<action>$.code = W_SQLPRINT; - $<action>$.command = NULL; - $<action>$.str = mm_strdup("sqlprint"); + $$.code = W_SQLPRINT; + $$.command = NULL; + $$.str = "sqlprint"; } | SQL_STOP { - $<action>$.code = W_STOP; - $<action>$.command = NULL; - $<action>$.str = mm_strdup("stop"); + $$.code = W_STOP; + $$.command = NULL; + $$.str = "stop"; } | SQL_GOTO name { - $<action>$.code = W_GOTO; - $<action>$.command = mm_strdup(@2); - $<action>$.str = cat2_str(mm_strdup("goto "), @2); + $$.code = W_GOTO; + $$.command = loc_strdup(@2); + $$.str = cat2_str("goto ", @2); } | SQL_GO TO name { - $<action>$.code = W_GOTO; - $<action>$.command = mm_strdup(@3); - $<action>$.str = cat2_str(mm_strdup("goto "), @3); + $$.code = W_GOTO; + $$.command = loc_strdup(@3); + $$.str = cat2_str("goto ", @3); } | DO name '(' c_args ')' { - $<action>$.code = W_DO; - $<action>$.command = cat_str(4, @2, mm_strdup("("), @4, mm_strdup(")")); - $<action>$.str = cat2_str(mm_strdup("do"), mm_strdup($<action>$.command)); + $$.code = W_DO; + $$.command = cat_str(4, @2, "(", @4, ")"); + $$.str = cat2_str("do", $$.command); } | DO SQL_BREAK { - $<action>$.code = W_BREAK; - $<action>$.command = NULL; - $<action>$.str = mm_strdup("break"); + $$.code = W_BREAK; + $$.command = NULL; + $$.str = "break"; } | DO CONTINUE_P { - $<action>$.code = W_CONTINUE; - $<action>$.command = NULL; - $<action>$.str = mm_strdup("continue"); + $$.code = W_CONTINUE; + $$.command = NULL; + $$.str = "continue"; } | CALL name '(' c_args ')' { - $<action>$.code = W_DO; - $<action>$.command = cat_str(4, @2, mm_strdup("("), @4, mm_strdup(")")); - $<action>$.str = cat2_str(mm_strdup("call"), mm_strdup($<action>$.command)); + $$.code = W_DO; + $$.command = cat_str(4, @2, "(", @4, ")"); + $$.str = cat2_str("call", $$.command); } | CALL name { - $<action>$.code = W_DO; - $<action>$.command = cat2_str(@2, mm_strdup("()")); - $<action>$.str = cat2_str(mm_strdup("call"), mm_strdup($<action>$.command)); + $$.code = W_DO; + $$.command = cat2_str(@2, "()"); + $$.str = cat2_str("call", $$.command); } ; @@ -1913,7 +1929,7 @@ ecpgstart: SQL_START { reset_variables(); pacounter = 1; - @$ = EMPTY; + @$ = ""; } ; @@ -1982,7 +1998,7 @@ cvariable: CVARIABLE * As long as multidimensional arrays are not implemented we have to * check for those here */ - char *ptr = @1; + const char *ptr = @1; int brace_open = 0, brace = false; @@ -2013,18 +2029,12 @@ cvariable: CVARIABLE ; ecpg_param: PARAM - { - @$ = make_name(); - } ; ecpg_bconst: BCONST ; ecpg_fconst: FCONST - { - @$ = make_name(); - } ; ecpg_sconst: SCONST @@ -2036,17 +2046,17 @@ ecpg_xconst: XCONST ecpg_ident: IDENT | CSTRING { - @$ = make3_str(mm_strdup("\""), @1, mm_strdup("\"")); + @$ = make3_str("\"", @1, "\""); } ; quoted_ident_stringvar: name { - @$ = make3_str(mm_strdup("\""), @1, mm_strdup("\"")); + @$ = make3_str("\"", @1, "\""); } | char_variable { - @$ = make3_str(mm_strdup("("), @1, mm_strdup(")")); + @$ = make3_str("(", @1, ")"); } ; @@ -2057,7 +2067,7 @@ quoted_ident_stringvar: name c_stuff_item: c_anything | '(' ')' { - @$ = mm_strdup("()"); + @$ = "()"; } | '(' c_stuff ')' ; @@ -2094,7 +2104,7 @@ c_anything: ecpg_ident | '-' | '/' | '%' - | NULL_P { @$ = mm_strdup("NULL"); } + | NULL_P { @$ = "NULL"; } | S_ADD | S_AND | S_ANYTHING @@ -2155,11 +2165,11 @@ DeallocateStmt: DEALLOCATE prepared_name } | DEALLOCATE ALL { - @$ = mm_strdup("all"); + @$ = "all"; } | DEALLOCATE PREPARE ALL { - @$ = mm_strdup("all"); + @$ = "all"; } ; @@ -2177,7 +2187,7 @@ Iresult: Iconst if (pg_strcasecmp(@1, "sizeof") != 0) mmerror(PARSE_ERROR, ET_ERROR, "operator not allowed in variable definition"); else - @$ = cat_str(4, @1, mm_strdup("("), $3.type_str, mm_strdup(")")); + @$ = cat_str(4, @1, "(", $3.type_str, ")"); } ; @@ -2190,7 +2200,7 @@ execute_rest: /* EMPTY */ ecpg_into: INTO into_list { /* always suppress this from the constructed string */ - @$ = EMPTY; + @$ = ""; } | into_descriptor ; diff --git a/src/interfaces/ecpg/preproc/output.c b/src/interfaces/ecpg/preproc/output.c index 8d2b6e7cb8..a18904f88b 100644 --- a/src/interfaces/ecpg/preproc/output.c +++ b/src/interfaces/ecpg/preproc/output.c @@ -12,7 +12,6 @@ output_line_number(void) char *line = hashline_number(); fprintf(base_yyout, "%s", line); - free(line); } void @@ -100,7 +99,7 @@ hashline_number(void) ) { /* "* 2" here is for escaping '\' and '"' below */ - char *line = mm_alloc(strlen("\n#line %d \"%s\"\n") + sizeof(int) * CHAR_BIT * 10 / 3 + strlen(input_filename)* 2); + char *line = loc_alloc(strlen("\n#line %d \"%s\"\n") + sizeof(int) * CHAR_BIT * 10 / 3 + strlen(input_filename)* 2); char *src, *dest; @@ -119,7 +118,7 @@ hashline_number(void) return line; } - return EMPTY; + return ""; } static char *ecpg_statement_type_name[] = { diff --git a/src/interfaces/ecpg/preproc/parser.c b/src/interfaces/ecpg/preproc/parser.c index 8807c22cb6..78eeb78466 100644 --- a/src/interfaces/ecpg/preproc/parser.c +++ b/src/interfaces/ecpg/preproc/parser.c @@ -204,7 +204,7 @@ filtered_base_yylex(void) /* Combine 3 tokens into 1 */ base_yylval.str = psprintf("%s UESCAPE %s", base_yylval.str, escstr); - base_yylloc = mm_strdup(base_yylval.str); + base_yylloc = loc_strdup(base_yylval.str); /* Clear have_lookahead, thereby consuming all three tokens */ have_lookahead = false; @@ -254,11 +254,11 @@ base_yylex_location(void) case UIDENT: case IP: /* Duplicate the <str> value */ - base_yylloc = mm_strdup(base_yylval.str); + base_yylloc = loc_strdup(base_yylval.str); break; default: /* Else just use the input, i.e., yytext */ - base_yylloc = mm_strdup(base_yytext); + base_yylloc = loc_strdup(base_yytext); /* Apply an ASCII-only downcasing */ for (unsigned char *ptr = (unsigned char *) base_yylloc; *ptr; ptr++) { diff --git a/src/interfaces/ecpg/preproc/preproc_extern.h b/src/interfaces/ecpg/preproc/preproc_extern.h index da93967462..2e41870ea8 100644 --- a/src/interfaces/ecpg/preproc/preproc_extern.h +++ b/src/interfaces/ecpg/preproc/preproc_extern.h @@ -13,12 +13,11 @@ /* defines */ #define STRUCT_DEPTH 128 -#define EMPTY mm_strdup("") /* * "Location tracking" support --- see ecpg.header for more comments. */ -typedef char *YYLTYPE; +typedef const char *YYLTYPE; #define YYLTYPE_IS_DECLARED 1 @@ -82,18 +81,21 @@ extern int base_yylex(void); extern void base_yyerror(const char *error); extern void *mm_alloc(size_t size); extern char *mm_strdup(const char *string); +extern void *loc_alloc(size_t size); +extern char *loc_strdup(const char *string); +extern void reclaim_local_storage(void); extern void mmerror(int error_code, enum errortype type, const char *error,...) pg_attribute_printf(3, 4); extern void mmfatal(int error_code, const char *error,...) pg_attribute_printf(2, 3) pg_attribute_noreturn(); -extern void output_get_descr_header(char *desc_name); -extern void output_get_descr(char *desc_name, char *index); -extern void output_set_descr_header(char *desc_name); -extern void output_set_descr(char *desc_name, char *index); -extern void push_assignment(char *var, enum ECPGdtype value); -extern struct variable *find_variable(char *name); +extern void output_get_descr_header(const char *desc_name); +extern void output_get_descr(const char *desc_name, const char *index); +extern void output_set_descr_header(const char *desc_name); +extern void output_set_descr(const char *desc_name, const char *index); +extern void push_assignment(const char *var, enum ECPGdtype value); +extern struct variable *find_variable(const char *name); extern void whenever_action(int mode); -extern void add_descriptor(char *name, char *connection); -extern void drop_descriptor(char *name, char *connection); -extern struct descriptor *lookup_descriptor(char *name, char *connection); +extern void add_descriptor(const char *name, const char *connection); +extern void drop_descriptor(const char *name, const char *connection); +extern struct descriptor *lookup_descriptor(const char *name, const char *connection); extern struct variable *descriptor_variable(const char *name, int input); extern struct variable *sqlda_variable(const char *name); extern void add_variable_to_head(struct arguments **list, @@ -105,9 +107,9 @@ extern void add_variable_to_tail(struct arguments **list, extern void remove_variable_from_list(struct arguments **list, struct variable *var); extern void dump_variables(struct arguments *list, int mode); extern struct typedefs *get_typedef(const char *name, bool noerror); -extern void adjust_array(enum ECPGttype type_enum, char **dimension, - char **length, char *type_dimension, - char *type_index, int pointer_len, +extern void adjust_array(enum ECPGttype type_enum, const char **dimension, + const char **length, const char *type_dimension, + const char *type_index, int pointer_len, bool type_definition); extern void reset_variables(void); extern void check_indicator(struct ECPGtype *var); diff --git a/src/interfaces/ecpg/preproc/type.c b/src/interfaces/ecpg/preproc/type.c index 5610a8dc76..7f52521dbf 100644 --- a/src/interfaces/ecpg/preproc/type.c +++ b/src/interfaces/ecpg/preproc/type.c @@ -69,13 +69,13 @@ ECPGmake_struct_member(const char *name, struct ECPGtype *type, struct ECPGstruc } struct ECPGtype * -ECPGmake_simple_type(enum ECPGttype type, char *size, int counter) +ECPGmake_simple_type(enum ECPGttype type, const char *size, int counter) { struct ECPGtype *ne = (struct ECPGtype *) mm_alloc(sizeof(struct ECPGtype)); ne->type = type; ne->type_name = NULL; - ne->size = size; + ne->size = mm_strdup(size); ne->u.element = NULL; ne->struct_sizeof = NULL; ne->counter = counter; /* only needed for varchar and bytea */ @@ -84,7 +84,7 @@ ECPGmake_simple_type(enum ECPGttype type, char *size, int counter) } struct ECPGtype * -ECPGmake_array_type(struct ECPGtype *type, char *size) +ECPGmake_array_type(struct ECPGtype *type, const char *size) { struct ECPGtype *ne = ECPGmake_simple_type(ECPGt_array, size, 0); @@ -96,7 +96,7 @@ ECPGmake_array_type(struct ECPGtype *type, char *size) struct ECPGtype * ECPGmake_struct_type(struct ECPGstruct_member *rm, enum ECPGttype type, char *type_name, char *struct_sizeof) { - struct ECPGtype *ne = ECPGmake_simple_type(type, mm_strdup("1"), 0); + struct ECPGtype *ne = ECPGmake_simple_type(type, "1", 0); ne->type_name = mm_strdup(type_name); ne->u.members = ECPGstruct_member_dup(rm); diff --git a/src/interfaces/ecpg/preproc/type.h b/src/interfaces/ecpg/preproc/type.h index ce2124361f..90126551d1 100644 --- a/src/interfaces/ecpg/preproc/type.h +++ b/src/interfaces/ecpg/preproc/type.h @@ -35,8 +35,8 @@ struct ECPGtype /* Everything is malloced. */ void ECPGmake_struct_member(const char *name, struct ECPGtype *type, struct ECPGstruct_member **start); -struct ECPGtype *ECPGmake_simple_type(enum ECPGttype type, char *size, int counter); -struct ECPGtype *ECPGmake_array_type(struct ECPGtype *type, char *size); +struct ECPGtype *ECPGmake_simple_type(enum ECPGttype type, const char *size, int counter); +struct ECPGtype *ECPGmake_array_type(struct ECPGtype *type, const char *size); struct ECPGtype *ECPGmake_struct_type(struct ECPGstruct_member *rm, enum ECPGttype type, char *type_name, char *struct_sizeof); @@ -93,28 +93,28 @@ struct when struct index { - char *index1; - char *index2; - char *str; + const char *index1; + const char *index2; + const char *str; }; struct su_symbol { - char *su; - char *symbol; + const char *su; + const char *symbol; }; struct prep { - char *name; - char *stmt; - char *type; + const char *name; + const char *stmt; + const char *type; }; struct exec { - char *name; - char *type; + const char *name; + const char *type; }; struct this_type @@ -221,14 +221,14 @@ enum errortype struct fetch_desc { - char *str; - char *name; + const char *str; + const char *name; }; struct describe { int input; - char *stmt_name; + const char *stmt_name; }; #endif /* _ECPG_PREPROC_TYPE_H */ diff --git a/src/interfaces/ecpg/preproc/util.c b/src/interfaces/ecpg/preproc/util.c index b80802ca9f..e2613cb499 100644 --- a/src/interfaces/ecpg/preproc/util.c +++ b/src/interfaces/ecpg/preproc/util.c @@ -103,3 +103,90 @@ mm_strdup(const char *string) return new; } + +/* + * "Local" (or "location"?) memory management support + * + * These functions manage memory that is only needed for a short time + * (processing of one input statement) within the ecpg grammar. + * Data allocated with these is not meant to be freed separately; + * rather it's freed by calling reclaim_local_storage() at the end + * of each statement cycle. + */ + +typedef struct loc_chunk +{ + struct loc_chunk *next; /* list link */ + unsigned int chunk_used; /* index of first unused byte in data[] */ + unsigned int chunk_avail; /* # bytes still available in data[] */ + char data[FLEXIBLE_ARRAY_MEMBER]; /* actual storage */ +} loc_chunk; + +#define LOC_CHUNK_OVERHEAD MAXALIGN(offsetof(loc_chunk, data)) +#define LOC_CHUNK_MIN_SIZE 8192 + +/* Head of list of loc_chunks */ +static loc_chunk *loc_chunks = NULL; + +/* + * Allocate local space of the requested size. + * + * Exits on OOM. + */ +void * +loc_alloc(size_t size) +{ + void *result; + loc_chunk *cur_chunk = loc_chunks; + + /* Ensure all allocations are adequately aligned */ + size = MAXALIGN(size); + + /* Need a new chunk? */ + if (cur_chunk == NULL || size > cur_chunk->chunk_avail) + { + size_t chunk_size = Max(size, LOC_CHUNK_MIN_SIZE); + + cur_chunk = mm_alloc(chunk_size + LOC_CHUNK_OVERHEAD); + /* Depending on alignment rules, we could waste a bit here */ + cur_chunk->chunk_used = LOC_CHUNK_OVERHEAD - offsetof(loc_chunk, data); + cur_chunk->chunk_avail = chunk_size; + /* New chunk becomes the head of the list */ + cur_chunk->next = loc_chunks; + loc_chunks = cur_chunk; + } + + result = cur_chunk->data + cur_chunk->chunk_used; + cur_chunk->chunk_used += size; + cur_chunk->chunk_avail -= size; + return result; +} + +/* + * Copy given string into local storage + */ +char * +loc_strdup(const char *string) +{ + char *result = loc_alloc(strlen(string) + 1); + + strcpy(result, string); + return result; +} + +/* + * Reclaim local storage when appropriate + */ +void +reclaim_local_storage(void) +{ + loc_chunk *cur_chunk, + *next_chunk; + + for (cur_chunk = loc_chunks; cur_chunk; cur_chunk = next_chunk) + { + next_chunk = cur_chunk->next; + free(cur_chunk); + } + loc_chunks = NULL; +} diff --git a/src/interfaces/ecpg/preproc/variable.c b/src/interfaces/ecpg/preproc/variable.c index b23ed5edf4..6b87d5ff3d 100644 --- a/src/interfaces/ecpg/preproc/variable.c +++ b/src/interfaces/ecpg/preproc/variable.c @@ -22,7 +22,7 @@ new_variable(const char *name, struct ECPGtype *type, int brace_level) } static struct variable * -find_struct_member(char *name, char *str, struct ECPGstruct_member *members, int brace_level) +find_struct_member(const char *name, char *str, struct ECPGstruct_member *members, int brace_level) { char *next = strpbrk(++str, ".-["), *end, @@ -123,7 +123,7 @@ find_struct_member(char *name, char *str, struct ECPGstruct_member *members, int } static struct variable * -find_struct(char *name, char *next, char *end) +find_struct(const char *name, char *next, char *end) { struct variable *p; char c = *next; @@ -174,7 +174,7 @@ find_struct(char *name, char *next, char *end) } static struct variable * -find_simple(char *name) +find_simple(const char *name) { struct variable *p; @@ -190,7 +190,7 @@ find_simple(char *name) /* Note that this function will end the program in case of an unknown */ /* variable */ struct variable * -find_variable(char *name) +find_variable(const char *name) { char *next, *end; @@ -513,7 +513,10 @@ get_typedef(const char *name, bool noerror) } void -adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *type_dimension, char *type_index, int pointer_len,bool type_definition) +adjust_array(enum ECPGttype type_enum, + const char **dimension, const char **length, + const char *type_dimension, const char *type_index, + int pointer_len, bool type_definition) { if (atoi(type_index) >= 0) { @@ -556,7 +559,7 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty if (pointer_len) { *length = *dimension; - *dimension = mm_strdup("0"); + *dimension = "0"; } if (atoi(*length) >= 0) @@ -567,13 +570,13 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty case ECPGt_bytea: /* pointer has to get dimension 0 */ if (pointer_len) - *dimension = mm_strdup("0"); + *dimension = "0"; /* one index is the string length */ if (atoi(*length) < 0) { *length = *dimension; - *dimension = mm_strdup("-1"); + *dimension = "-1"; } break; @@ -583,13 +586,13 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty /* char ** */ if (pointer_len == 2) { - *length = *dimension = mm_strdup("0"); + *length = *dimension = "0"; break; } /* pointer has to get length 0 */ if (pointer_len == 1) - *length = mm_strdup("0"); + *length = "0"; /* one index is the string length */ if (atoi(*length) < 0) @@ -604,13 +607,13 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty * do not change this for typedefs since it will be * changed later on when the variable is defined */ - *length = mm_strdup("1"); + *length = "1"; else if (strcmp(*dimension, "0") == 0) - *length = mm_strdup("-1"); + *length = "-1"; else *length = *dimension; - *dimension = mm_strdup("-1"); + *dimension = "-1"; } break; default: @@ -618,7 +621,7 @@ adjust_array(enum ECPGttype type_enum, char **dimension, char **length, char *ty if (pointer_len) { *length = *dimension; - *dimension = mm_strdup("0"); + *dimension = "0"; } if (atoi(*length) >= 0) diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index e710fa48e5..ce4f445ae7 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -3582,6 +3582,7 @@ libpq_source line_t lineno_t list_sort_comparator +loc_chunk local_relopt local_relopts local_source -- 2.43.5
pgsql-hackers by date: