From: Tom Lane Date: Mon, 14 Oct 2024 17:44:42 +0000 (-0400) Subject: ecpg: re-implement preprocessor's string management. X-Git-Tag: REL_18_BETA1~1717 X-Git-Url: http://git.postgresql.org/gitweb/?a=commitdiff_plain;h=a542d5614bdb6430094556162b9ca2f01d35f9dc;p=postgresql.git ecpg: re-implement 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 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, and is visibly helpful with gcc too.) 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.) Most of the changes here are mindless substitution of "@N" for "$N" in grammar rules; see the changes to README.parser for an explanation. Discussion: https://postgr.es/m/2011420.1713493114@sss.pgh.pa.us --- diff --git a/src/interfaces/ecpg/preproc/README.parser b/src/interfaces/ecpg/preproc/README.parser index 5698f5ab328..378cb9344c4 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 pre-v18 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 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 6a1893553b4..24ee54554e3 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 28e1b2aac40..8df6248c976 100644 --- a/src/interfaces/ecpg/preproc/ecpg.header +++ b/src/interfaces/ecpg/preproc/ecpg.header @@ -13,14 +13,6 @@ extern int base_yychar; extern int base_yynerrs; -/* 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 @@ -200,6 +192,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 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 f3ab73bed61..2a3949ca035 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: :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); - $$ = make3_str(make2_str($1, $2), $3, $4); + @$ = make3_str(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 [] = * "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 = $3.code; when_error.command = $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 = $4.code; when_nf.command = $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 = $3.code; when_warn.command = $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 { $$.code = W_GOTO; - $$.command = mm_strdup($2); - $$.str = cat2_str(mm_strdup("goto "), $2); + $$.command = mm_strdup(@2); + $$.str = cat2_str(mm_strdup("goto "), @2); } | SQL_GO TO name { $$.code = W_GOTO; - $$.command = mm_strdup($3); - $$.str = cat2_str(mm_strdup("goto "), $3); + $$.command = mm_strdup(@3); + $$.str = cat2_str(mm_strdup("goto "), @3); } | DO name '(' c_args ')' { $$.code = W_DO; - $$.command = cat_str(4, $2, mm_strdup("("), $4, mm_strdup(")")); + $$.command = cat_str(4, @2, mm_strdup("("), @4, mm_strdup(")")); $$.str = cat2_str(mm_strdup("do"), mm_strdup($$.command)); } | DO SQL_BREAK @@ -1935,13 +1742,13 @@ action: CONTINUE_P | CALL name '(' c_args ')' { $$.code = W_DO; - $$.command = cat_str(4, $2, mm_strdup("("), $4, mm_strdup(")")); + $$.command = cat_str(4, @2, mm_strdup("("), @4, mm_strdup(")")); $$.str = cat2_str(mm_strdup("call"), mm_strdup($$.command)); } | CALL name { $$.code = W_DO; - $$.command = cat2_str($2, mm_strdup("()")); + $$.command = cat2_str(@2, mm_strdup("()")); $$.str = cat2_str(mm_strdup("call"), mm_strdup($$.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 4fe80a5a4be..2929f358ff4 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 ECPGAllocateDescr -%type ECPGCKeywords -%type ECPGColId -%type ECPGColLabel -%type ECPGConnect -%type ECPGCursorStmt -%type ECPGDeallocateDescr -%type ECPGDeclaration -%type ECPGDeclare -%type ECPGDeclareStmt -%type ECPGDisconnect -%type ECPGExecuteImmediateStmt -%type ECPGFree -%type ECPGGetDescHeaderItem -%type ECPGGetDescItem -%type ECPGGetDescriptorHeader -%type ECPGKeywords -%type ECPGKeywords_rest -%type ECPGKeywords_vanames -%type ECPGOpen -%type ECPGSetAutocommit -%type ECPGSetConnection -%type ECPGSetDescHeaderItem -%type ECPGSetDescItem -%type ECPGSetDescriptorHeader -%type ECPGTypeName -%type ECPGTypedef -%type ECPGVar -%type ECPGVarDeclaration -%type ECPGWhenever -%type ECPGunreserved_interval -%type UsingConst -%type UsingValue -%type all_unreserved_keyword -%type c_anything -%type c_args -%type c_list -%type c_stuff -%type c_stuff_item -%type c_term -%type c_thing -%type char_variable -%type char_civar -%type civar -%type civarind -%type ColId -%type ColLabel -%type connect_options -%type connection_object -%type connection_target -%type coutputvariable -%type cvariable -%type db_prefix -%type CreateAsStmt -%type DeallocateStmt -%type dis_name -%type ecpg_bconst -%type ecpg_fconst -%type ecpg_ident -%type ecpg_interval -%type ecpg_into -%type ecpg_fetch_into -%type ecpg_param -%type ecpg_sconst -%type ecpg_using -%type ecpg_xconst -%type enum_definition -%type enum_type -%type execstring -%type execute_rest -%type indicator -%type into_descriptor -%type into_sqlda -%type Iresult -%type on_off -%type opt_bit_field -%type opt_connection_name -%type opt_database_name -%type opt_ecpg_into -%type opt_ecpg_fetch_into -%type opt_ecpg_using -%type opt_initializer -%type opt_options -%type opt_output -%type opt_pointer -%type opt_port -%type opt_reference -%type opt_scale -%type opt_server -%type opt_user -%type opt_opt_value -%type ora_user -%type precision -%type prepared_name -%type quoted_ident_stringvar -%type s_struct_union -%type server -%type server_name -%type single_vt_declaration -%type storage_clause -%type storage_declaration -%type storage_modifier -%type struct_union_type -%type struct_union_type_with_symbol -%type symbol -%type type_declaration -%type type_function_name -%type user_name -%type using_descriptor -%type var_declaration -%type var_type_declarations -%type variable -%type variable_declarations -%type variable_list -%type vt_declarations - -%type Op -%type IntConstVar -%type AllConstVar -%type CSTRING -%type CPP_LINE -%type CVARIABLE -%type BCONST -%type SCONST -%type XCONST -%type IDENT - %type s_struct_union_symbol %type ECPGGetDescriptor diff --git a/src/interfaces/ecpg/preproc/output.c b/src/interfaces/ecpg/preproc/output.c index 6c0b8a27b1e..8d2b6e7cb81 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 3df94a24af0..9ebe4bd7930 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 '' 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' => '', 'ExecuteStmt' => '', @@ -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 "", 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 - $replace_types{$non_term_id} = ''; - } - 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 rather weird pre-v18 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 9daeee33034..ca0dead26d0 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 , 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 pre-v18 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 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 c5fd07fbd8b..da939674620 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);