diff options
-rw-r--r-- | src/interfaces/ecpg/preproc/README.parser | 32 | ||||
-rw-r--r-- | src/interfaces/ecpg/preproc/ecpg.addons | 294 | ||||
-rw-r--r-- | src/interfaces/ecpg/preproc/ecpg.header | 63 | ||||
-rw-r--r-- | src/interfaces/ecpg/preproc/ecpg.trailer | 1148 | ||||
-rw-r--r-- | src/interfaces/ecpg/preproc/ecpg.type | 127 | ||||
-rw-r--r-- | src/interfaces/ecpg/preproc/output.c | 16 | ||||
-rw-r--r-- | src/interfaces/ecpg/preproc/parse.pl | 215 | ||||
-rw-r--r-- | src/interfaces/ecpg/preproc/parser.c | 58 | ||||
-rw-r--r-- | src/interfaces/ecpg/preproc/preproc_extern.h | 15 |
9 files changed, 752 insertions, 1216 deletions
diff --git a/src/interfaces/ecpg/preproc/README.parser b/src/interfaces/ecpg/preproc/README.parser index 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 <str> type, which is parse.pl's default assumption for -nonterminals found in gram.y. That can be overridden at need by -making an entry in parse.pl's %replace_types table. %replace_types +given void type, which is parse.pl's default assumption for +nonterminals found in gram.y. If the result should be of some other +type, make an entry in parse.pl's %replace_types table. %replace_types can also be used to suppress output of a nonterminal's rules altogether (in which case ecpg.trailer had better provide replacement rules, since the nonterminal will still be referred to elsewhere). diff --git a/src/interfaces/ecpg/preproc/ecpg.addons b/src/interfaces/ecpg/preproc/ecpg.addons index 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 <str> result. This allows the majority of those productions to + * have default semantic actions, reducing the size of the parser, and also + * greatly reducing its compilation time on some versions of clang. + * + * To do this, we make YYLTYPE be a pointer to a malloc'd string, and then + * merge the location strings of the input tokens in the default YYLLOC + * computation. Productions that are okay with the standard merge need not + * do anything more; otherwise, they can override it by assigning to @$. + */ +#define YYLLOC_DEFAULT(Current, Rhs, N) yylloc_default(&(Current), Rhs, N) + +static void +yylloc_default(YYLTYPE *target, YYLTYPE *rhs, int N) +{ + if (N > 1) + { + /* Concatenate non-empty inputs with one space between them */ + char *result, + *ptr; + size_t needed = 0; + + for (int i = 1; i <= N; i++) + { + size_t thislen = strlen(rhs[i]); + + if (needed > 0 && thislen > 0) + needed++; + needed += thislen; + } + result = (char *) mm_alloc(needed + 1); + ptr = result; + for (int i = 1; i <= N; i++) + { + size_t thislen = strlen(rhs[i]); + + if (ptr > result && thislen > 0) + *ptr++ = ' '; + memcpy(ptr, rhs[i], thislen); + ptr += thislen; + } + *ptr = '\0'; + *target = result; + } + else if (N == 1) + { + /* Just re-use the single input */ + *target = rhs[1]; + } + else + *target = EMPTY; +} + /* and the rest */ static char * make_name(void) diff --git a/src/interfaces/ecpg/preproc/ecpg.trailer b/src/interfaces/ecpg/preproc/ecpg.trailer index 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: <tcp|unix>:postgresql://server[:port][/dbname] */ - if (strncmp($1, "unix:postgresql", strlen("unix:postgresql")) != 0 && strncmp($1, "tcp:postgresql", strlen("tcp:postgresql")) != 0) + if (strncmp(@1, "unix:postgresql", strlen("unix:postgresql")) != 0 && strncmp(@1, "tcp:postgresql", strlen("tcp:postgresql")) != 0) mmerror(PARSE_ERROR, ET_ERROR, "only protocols \"tcp\" and \"unix\" and database type \"postgresql\" are supported"); - if (strncmp($3, "//", strlen("//")) != 0) - mmerror(PARSE_ERROR, ET_ERROR, "expected \"://\", found \"%s\"", $3); + if (strncmp(@3, "//", strlen("//")) != 0) + mmerror(PARSE_ERROR, ET_ERROR, "expected \"://\", found \"%s\"", @3); - if (strncmp($1, "unix", strlen("unix")) == 0 && - strncmp($3 + strlen("//"), "localhost", strlen("localhost")) != 0 && - strncmp($3 + strlen("//"), "127.0.0.1", strlen("127.0.0.1")) != 0) - mmerror(PARSE_ERROR, ET_ERROR, "Unix-domain sockets only work on \"localhost\" but not on \"%s\"", $3 + strlen("//")); + if (strncmp(@1, "unix", strlen("unix")) == 0 && + strncmp(@3 + strlen("//"), "localhost", strlen("localhost")) != 0 && + strncmp(@3 + strlen("//"), "127.0.0.1", strlen("127.0.0.1")) != 0) + mmerror(PARSE_ERROR, ET_ERROR, "Unix-domain sockets only work on \"localhost\" but not on \"%s\"", @3 + strlen("//")); - $$ = make3_str(make3_str(mm_strdup("\""), $1, mm_strdup(":")), $3, make3_str(make3_str($4, mm_strdup("/"), $6), $7, mm_strdup("\""))); + @$ = make3_str(make3_str(mm_strdup("\""), @1, mm_strdup(":")), @3, make3_str(make3_str(@4, mm_strdup("/"), @6), @7, mm_strdup("\""))); } | char_variable - { - $$ = $1; - } | ecpg_sconst { /* @@ -147,128 +137,107 @@ connection_target: opt_database_name opt_server opt_port * so we change the quotes. Note, that the rule for ecpg_sconst adds * these single quotes. */ - $1[0] = '\"'; - $1[strlen($1) - 1] = '\"'; - $$ = $1; + @1[0] = '\"'; + @1[strlen(@1) - 1] = '\"'; + @$ = @1; } ; opt_database_name: name - { - $$ = $1; - } | /* EMPTY */ - { - $$ = EMPTY; - } ; db_prefix: ecpg_ident cvariable { - if (strcmp($2, "postgresql") != 0 && strcmp($2, "postgres") != 0) - mmerror(PARSE_ERROR, ET_ERROR, "expected \"postgresql\", found \"%s\"", $2); + if (strcmp(@2, "postgresql") != 0 && strcmp(@2, "postgres") != 0) + mmerror(PARSE_ERROR, ET_ERROR, "expected \"postgresql\", found \"%s\"", @2); - if (strcmp($1, "tcp") != 0 && strcmp($1, "unix") != 0) - mmerror(PARSE_ERROR, ET_ERROR, "invalid connection type: %s", $1); + if (strcmp(@1, "tcp") != 0 && strcmp(@1, "unix") != 0) + mmerror(PARSE_ERROR, ET_ERROR, "invalid connection type: %s", @1); - $$ = make3_str($1, mm_strdup(":"), $2); + @$ = make3_str(@1, mm_strdup(":"), @2); } ; server: Op server_name { - if (strcmp($1, "@") != 0 && strcmp($1, "//") != 0) - mmerror(PARSE_ERROR, ET_ERROR, "expected \"@\" or \"://\", found \"%s\"", $1); + if (strcmp(@1, "@") != 0 && strcmp(@1, "//") != 0) + mmerror(PARSE_ERROR, ET_ERROR, "expected \"@\" or \"://\", found \"%s\"", @1); - $$ = make2_str($1, $2); + @$ = make2_str(@1, @2); } ; opt_server: server - { - $$ = $1; - } | /* EMPTY */ - { - $$ = EMPTY; - } ; server_name: ColId - { - $$ = $1; - } | ColId '.' server_name - { - $$ = make3_str($1, mm_strdup("."), $3); - } | IP { - $$ = make_name(); + @$ = make_name(); } ; opt_port: ':' Iconst { - $$ = make2_str(mm_strdup(":"), $2); + @$ = make2_str(mm_strdup(":"), @2); } | /* EMPTY */ - { - $$ = EMPTY; - } ; opt_connection_name: AS connection_object { - $$ = $2; + @$ = @2; } | /* EMPTY */ { - $$ = mm_strdup("NULL"); + @$ = mm_strdup("NULL"); } ; opt_user: USER ora_user { - $$ = $2; + @$ = @2; } | /* EMPTY */ { - $$ = mm_strdup("NULL, NULL"); + @$ = mm_strdup("NULL, NULL"); } ; ora_user: user_name { - $$ = cat2_str($1, mm_strdup(", NULL")); + @$ = cat2_str(@1, mm_strdup(", NULL")); } | user_name '/' user_name { - $$ = cat_str(3, $1, mm_strdup(","), $3); + @$ = cat_str(3, @1, mm_strdup(","), @3); } | user_name SQL_IDENTIFIED BY user_name { - $$ = cat_str(3, $1, mm_strdup(","), $4); + @$ = cat_str(3, @1, mm_strdup(","), @4); } | user_name USING user_name { - $$ = cat_str(3, $1, mm_strdup(","), $3); + @$ = cat_str(3, @1, mm_strdup(","), @3); } ; user_name: RoleId { - if ($1[0] == '\"') - $$ = $1; + if (@1[0] == '\"') + @$ = @1; else - $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); + @$ = make3_str(mm_strdup("\""), @1, mm_strdup("\"")); } | ecpg_sconst { - if ($1[0] == '\"') - $$ = $1; + if (@1[0] == '\"') + @$ = @1; else - $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); + @$ = make3_str(mm_strdup("\""), @1, mm_strdup("\"")); } | civar { @@ -280,16 +249,16 @@ user_name: RoleId /* handle varchars */ if (type == ECPGt_varchar) - $$ = make2_str(mm_strdup(argsinsert->variable->name), mm_strdup(".arr")); + @$ = make2_str(mm_strdup(argsinsert->variable->name), mm_strdup(".arr")); else - $$ = mm_strdup(argsinsert->variable->name); + @$ = mm_strdup(argsinsert->variable->name); } ; char_variable: cvariable { /* check if we have a string variable */ - struct variable *p = find_variable($1); + struct variable *p = find_variable(@1); enum ECPGttype type = p->type->type; /* If we have just one character this is not a string */ @@ -306,14 +275,14 @@ char_variable: cvariable case ECPGt_char: case ECPGt_unsigned_char: case ECPGt_string: - $$ = $1; + @$ = @1; break; case ECPGt_varchar: - $$ = make2_str($1, mm_strdup(".arr")); + @$ = make2_str(@1, mm_strdup(".arr")); break; default: mmerror(PARSE_ERROR, ET_ERROR, "invalid data type"); - $$ = $1; + @$ = @1; break; } } @@ -322,72 +291,63 @@ char_variable: cvariable opt_options: Op connect_options { - if (strlen($1) == 0) + if (strlen(@1) == 0) mmerror(PARSE_ERROR, ET_ERROR, "incomplete statement"); - if (strcmp($1, "?") != 0) - mmerror(PARSE_ERROR, ET_ERROR, "unrecognized token \"%s\"", $1); + if (strcmp(@1, "?") != 0) + mmerror(PARSE_ERROR, ET_ERROR, "unrecognized token \"%s\"", @1); - $$ = make2_str(mm_strdup("?"), $2); + @$ = make2_str(mm_strdup("?"), @2); } | /* EMPTY */ - { - $$ = EMPTY; - } ; connect_options: ColId opt_opt_value { - $$ = make2_str($1, $2); + @$ = make2_str(@1, @2); } | ColId opt_opt_value Op connect_options { - if (strlen($3) == 0) + if (strlen(@3) == 0) mmerror(PARSE_ERROR, ET_ERROR, "incomplete statement"); - if (strcmp($3, "&") != 0) - mmerror(PARSE_ERROR, ET_ERROR, "unrecognized token \"%s\"", $3); + if (strcmp(@3, "&") != 0) + mmerror(PARSE_ERROR, ET_ERROR, "unrecognized token \"%s\"", @3); - $$ = 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 <var>[] = * "string" */ @@ -1244,14 +1134,14 @@ variable: opt_pointer ECPGColLabel opt_array_bounds opt_bit_field opt_initialize */ free(length); length = mm_alloc(i + sizeof("sizeof()")); - sprintf(length, "sizeof(%s)", $5 + 2); + sprintf(length, "sizeof(%s)", @5 + 2); } type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length, 0); } else type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length, 0), dimension); - $$ = cat_str(5, $1, mm_strdup($2), $3.str, $4, $5); + @$ = cat_str(5, @1, mm_strdup(@2), $3.str, @4, @5); break; default: @@ -1260,41 +1150,29 @@ variable: opt_pointer ECPGColLabel opt_array_bounds opt_bit_field opt_initialize else type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, mm_strdup("1"), 0), dimension); - $$ = cat_str(5, $1, mm_strdup($2), $3.str, $4, $5); + @$ = cat_str(5, @1, mm_strdup(@2), $3.str, @4, @5); break; } if (struct_level == 0) - new_variable($2, type, braces_open); + new_variable(@2, type, braces_open); else - ECPGmake_struct_member($2, type, &(struct_member_list[struct_level - 1])); - - free($2); + ECPGmake_struct_member(@2, type, &(struct_member_list[struct_level - 1])); } ; opt_initializer: /* EMPTY */ - { - $$ = EMPTY; - } | '=' c_term { initializer = 1; - $$ = cat2_str(mm_strdup("="), $2); } ; opt_pointer: /* EMPTY */ - { - $$ = EMPTY; - } | '*' - { - $$ = mm_strdup("*"); - } | '*' '*' { - $$ = mm_strdup("**"); + @$ = mm_strdup("**"); } ; @@ -1304,7 +1182,7 @@ opt_pointer: /* EMPTY */ ECPGDeclare: DECLARE STATEMENT ecpg_ident { /* this is only supported for compatibility */ - $$ = cat_str(3, mm_strdup("/* declare statement"), $3, mm_strdup("*/")); + @$ = cat_str(3, mm_strdup("/* declare statement"), @3, mm_strdup("*/")); } ; /* @@ -1312,49 +1190,40 @@ ECPGDeclare: DECLARE STATEMENT ecpg_ident */ ECPGDisconnect: SQL_DISCONNECT dis_name { - $$ = $2; + @$ = @2; } ; dis_name: connection_object - { - $$ = $1; - } | CURRENT_P { - $$ = mm_strdup("\"CURRENT\""); + @$ = mm_strdup("\"CURRENT\""); } | ALL { - $$ = mm_strdup("\"ALL\""); + @$ = mm_strdup("\"ALL\""); } | /* EMPTY */ { - $$ = mm_strdup("\"CURRENT\""); + @$ = mm_strdup("\"CURRENT\""); } ; connection_object: name { - $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); + @$ = make3_str(mm_strdup("\""), @1, mm_strdup("\"")); } | DEFAULT { - $$ = mm_strdup("\"DEFAULT\""); + @$ = mm_strdup("\"DEFAULT\""); } | char_variable - { - $$ = $1; - } ; execstring: char_variable - { - $$ = $1; - } | CSTRING { - $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); + @$ = make3_str(mm_strdup("\""), @1, mm_strdup("\"")); } ; @@ -1364,11 +1233,11 @@ execstring: char_variable */ ECPGFree: SQL_FREE cursor_name { - $$ = $2; + @$ = @2; } | SQL_FREE ALL { - $$ = mm_strdup("all"); + @$ = mm_strdup("all"); } ; @@ -1377,60 +1246,51 @@ ECPGFree: SQL_FREE cursor_name */ ECPGOpen: SQL_OPEN cursor_name opt_ecpg_using { - if ($2[0] == ':') - remove_variable_from_list(&argsinsert, find_variable($2 + 1)); - $$ = $2; + if (@2[0] == ':') + remove_variable_from_list(&argsinsert, find_variable(@2 + 1)); + @$ = @2; } ; opt_ecpg_using: /* EMPTY */ - { - $$ = EMPTY; - } | ecpg_using - { - $$ = $1; - } ; ecpg_using: USING using_list { - $$ = EMPTY; + @$ = EMPTY; } | using_descriptor - { - $$ = $1; - } ; using_descriptor: USING SQL_P SQL_DESCRIPTOR quoted_ident_stringvar { - add_variable_to_head(&argsinsert, descriptor_variable($4, 0), &no_indicator); - $$ = EMPTY; + add_variable_to_head(&argsinsert, descriptor_variable(@4, 0), &no_indicator); + @$ = EMPTY; } | USING SQL_DESCRIPTOR name { - add_variable_to_head(&argsinsert, sqlda_variable($3), &no_indicator); - $$ = EMPTY; + add_variable_to_head(&argsinsert, sqlda_variable(@3), &no_indicator); + @$ = EMPTY; } ; into_descriptor: INTO SQL_P SQL_DESCRIPTOR quoted_ident_stringvar { - add_variable_to_head(&argsresult, descriptor_variable($4, 1), &no_indicator); - $$ = EMPTY; + add_variable_to_head(&argsresult, descriptor_variable(@4, 1), &no_indicator); + @$ = EMPTY; } | INTO SQL_DESCRIPTOR name { - add_variable_to_head(&argsresult, sqlda_variable($3), &no_indicator); - $$ = EMPTY; + add_variable_to_head(&argsresult, sqlda_variable(@3), &no_indicator); + @$ = EMPTY; } ; into_sqlda: INTO name { - add_variable_to_head(&argsresult, sqlda_variable($2), &no_indicator); - $$ = EMPTY; + add_variable_to_head(&argsresult, sqlda_variable(@2), &no_indicator); + @$ = EMPTY; } ; @@ -1441,55 +1301,28 @@ UsingValue: UsingConst { char *length = mm_alloc(32); - sprintf(length, "%zu", strlen($1)); - add_variable_to_head(&argsinsert, new_variable($1, ECPGmake_simple_type(ECPGt_const, length, 0), 0), &no_indicator); + sprintf(length, "%zu", strlen(@1)); + add_variable_to_head(&argsinsert, new_variable(@1, ECPGmake_simple_type(ECPGt_const, length, 0), 0), &no_indicator); } | civar { - $$ = EMPTY; + @$ = EMPTY; } | civarind { - $$ = EMPTY; + @$ = EMPTY; } ; UsingConst: Iconst - { - $$ = $1; - } | '+' Iconst - { - $$ = cat_str(2, mm_strdup("+"), $2); - } | '-' Iconst - { - $$ = cat_str(2, mm_strdup("-"), $2); - } | ecpg_fconst - { - $$ = $1; - } | '+' ecpg_fconst - { - $$ = cat_str(2, mm_strdup("+"), $2); - } | '-' ecpg_fconst - { - $$ = cat_str(2, mm_strdup("-"), $2); - } | ecpg_sconst - { - $$ = $1; - } | ecpg_bconst - { - $$ = $1; - } | ecpg_xconst - { - $$ = $1; - } ; /* @@ -1498,7 +1331,7 @@ UsingConst: Iconst ECPGDescribe: SQL_DESCRIBE INPUT_P prepared_name using_descriptor { $$.input = 1; - $$.stmt_name = $3; + $$.stmt_name = @3; } | SQL_DESCRIBE opt_output prepared_name using_descriptor { @@ -1509,33 +1342,27 @@ ECPGDescribe: SQL_DESCRIBE INPUT_P prepared_name using_descriptor add_variable_to_head(&argsresult, var, &no_indicator); $$.input = 0; - $$.stmt_name = $3; + $$.stmt_name = @3; } | SQL_DESCRIBE opt_output prepared_name into_descriptor { $$.input = 0; - $$.stmt_name = $3; + $$.stmt_name = @3; } | SQL_DESCRIBE INPUT_P prepared_name into_sqlda { $$.input = 1; - $$.stmt_name = $3; + $$.stmt_name = @3; } | SQL_DESCRIBE opt_output prepared_name into_sqlda { $$.input = 0; - $$.stmt_name = $3; + $$.stmt_name = @3; } ; opt_output: SQL_OUTPUT - { - $$ = mm_strdup("output"); - } | /* EMPTY */ - { - $$ = EMPTY; - } ; /* @@ -1549,8 +1376,8 @@ opt_output: SQL_OUTPUT */ ECPGAllocateDescr: SQL_ALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar { - add_descriptor($3, connection); - $$ = $3; + add_descriptor(@3, connection); + @$ = @3; } ; @@ -1560,8 +1387,8 @@ ECPGAllocateDescr: SQL_ALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar */ ECPGDeallocateDescr: DEALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar { - drop_descriptor($3, connection); - $$ = $3; + drop_descriptor(@3, connection); + @$ = @3; } ; @@ -1571,7 +1398,7 @@ ECPGDeallocateDescr: DEALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar ECPGGetDescriptorHeader: SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar ECPGGetDescHeaderItems { - $$ = $3; + @$ = @3; } ; @@ -1581,13 +1408,13 @@ ECPGGetDescHeaderItems: ECPGGetDescHeaderItem ECPGGetDescHeaderItem: cvariable '=' desc_header_item { - push_assignment($1, $3); + push_assignment(@1, $3); } ; ECPGSetDescriptorHeader: SET SQL_DESCRIPTOR quoted_ident_stringvar ECPGSetDescHeaderItems { - $$ = $3; + @$ = @3; } ; @@ -1597,7 +1424,7 @@ ECPGSetDescHeaderItems: ECPGSetDescHeaderItem ECPGSetDescHeaderItem: desc_header_item '=' IntConstVar { - push_assignment($3, $1); + push_assignment(@3, $1); } ; @@ -1605,14 +1432,10 @@ IntConstVar: Iconst { char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); - sprintf(length, "%zu", strlen($1)); - new_variable($1, ECPGmake_simple_type(ECPGt_const, length, 0), 0); - $$ = $1; + sprintf(length, "%zu", strlen(@1)); + new_variable(@1, ECPGmake_simple_type(ECPGt_const, length, 0), 0); } | cvariable - { - $$ = $1; - } ; desc_header_item: SQL_COUNT @@ -1627,8 +1450,8 @@ desc_header_item: SQL_COUNT ECPGGetDescriptor: SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar VALUE_P IntConstVar ECPGGetDescItems { - $$.str = $5; - $$.name = $3; + $$.str = @5; + $$.name = @3; } ; @@ -1638,14 +1461,14 @@ ECPGGetDescItems: ECPGGetDescItem ECPGGetDescItem: cvariable '=' descriptor_item { - push_assignment($1, $3); + push_assignment(@1, $3); } ; ECPGSetDescriptor: SET SQL_DESCRIPTOR quoted_ident_stringvar VALUE_P IntConstVar ECPGSetDescItems { - $$.str = $5; - $$.name = $3; + $$.str = @5; + $$.name = @3; } ; @@ -1655,7 +1478,7 @@ ECPGSetDescItems: ECPGSetDescItem ECPGSetDescItem: descriptor_item '=' AllConstVar { - push_assignment($3, $1); + push_assignment(@3, $1); } ; @@ -1663,41 +1486,37 @@ AllConstVar: ecpg_fconst { char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); - sprintf(length, "%zu", strlen($1)); - new_variable($1, ECPGmake_simple_type(ECPGt_const, length, 0), 0); - $$ = $1; + sprintf(length, "%zu", strlen(@1)); + new_variable(@1, ECPGmake_simple_type(ECPGt_const, length, 0), 0); } | IntConstVar - { - $$ = $1; - } | '-' ecpg_fconst { char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); - char *var = cat2_str(mm_strdup("-"), $2); + char *var = cat2_str(mm_strdup("-"), @2); sprintf(length, "%zu", strlen(var)); new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0); - $$ = var; + @$ = var; } | '-' Iconst { char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); - char *var = cat2_str(mm_strdup("-"), $2); + char *var = cat2_str(mm_strdup("-"), @2); sprintf(length, "%zu", strlen(var)); new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0); - $$ = var; + @$ = var; } | ecpg_sconst { char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3); - char *var = $1 + 1; + char *var = @1 + 1; var[strlen(var) - 1] = '\0'; sprintf(length, "%zu", strlen(var)); new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0); - $$ = var; + @$ = var; } ; @@ -1724,22 +1543,16 @@ descriptor_item: SQL_CARDINALITY { $$ = ECPGd_cardinality; } */ ECPGSetAutocommit: SET SQL_AUTOCOMMIT '=' on_off { - $$ = $4; + @$ = @4; } | SET SQL_AUTOCOMMIT TO on_off { - $$ = $4; + @$ = @4; } ; on_off: ON - { - $$ = mm_strdup("on"); - } | OFF - { - $$ = mm_strdup("off"); - } ; /* @@ -1748,15 +1561,15 @@ on_off: ON */ ECPGSetConnection: SET CONNECTION TO connection_object { - $$ = $4; + @$ = @4; } | SET CONNECTION '=' connection_object { - $$ = $4; + @$ = @4; } | SET CONNECTION connection_object { - $$ = $3; + @$ = @3; } ; @@ -1771,23 +1584,17 @@ ECPGTypedef: TYPE_P } ECPGColLabel IS var_type opt_array_bounds opt_reference { - add_typedef($3, $6.index1, $6.index2, $5.type_enum, $5.type_dimension, $5.type_index, initializer, *$7 ? 1 : 0); + add_typedef(@3, $6.index1, $6.index2, $5.type_enum, $5.type_dimension, $5.type_index, initializer, *@7 ? 1 : 0); if (auto_create_c == false) - $$ = cat_str(7, mm_strdup("/* exec sql type"), mm_strdup($3), mm_strdup("is"), mm_strdup($5.type_str), mm_strdup($6.str), $7, mm_strdup("*/")); + @$ = cat_str(7, mm_strdup("/* exec sql type"), mm_strdup(@3), mm_strdup("is"), mm_strdup($5.type_str), mm_strdup($6.str), @7, mm_strdup("*/")); else - $$ = cat_str(6, mm_strdup("typedef "), mm_strdup($5.type_str), *$7 ? mm_strdup("*") : mm_strdup(""), mm_strdup($3), mm_strdup($6.str), mm_strdup(";")); + @$ = cat_str(6, mm_strdup("typedef "), mm_strdup($5.type_str), *@7 ? mm_strdup("*") : mm_strdup(""), mm_strdup(@3), mm_strdup($6.str), mm_strdup(";")); } ; opt_reference: SQL_REFERENCE - { - $$ = mm_strdup("reference"); - } | /* EMPTY */ - { - $$ = EMPTY; - } ; /* @@ -1801,7 +1608,7 @@ ECPGVar: SQL_VAR } ColLabel IS var_type opt_array_bounds opt_reference { - struct variable *p = find_variable($3); + struct variable *p = find_variable(@3); char *dimension = $6.index1; char *length = $6.index2; struct ECPGtype *type; @@ -1812,7 +1619,7 @@ ECPGVar: SQL_VAR mmerror(PARSE_ERROR, ET_ERROR, "initializer not allowed in EXEC SQL VAR command"); else { - adjust_array($5.type_enum, &dimension, &length, $5.type_dimension, $5.type_index, *$7 ? 1 : 0, false); + adjust_array($5.type_enum, &dimension, &length, $5.type_dimension, $5.type_index, *@7 ? 1 : 0, false); switch ($5.type_enum) { @@ -1856,7 +1663,7 @@ ECPGVar: SQL_VAR p->type = type; } - $$ = cat_str(7, mm_strdup("/* exec sql var"), mm_strdup($3), mm_strdup("is"), mm_strdup($5.type_str), mm_strdup($6.str), $7, mm_strdup("*/")); + @$ = cat_str(7, mm_strdup("/* exec sql var"), mm_strdup(@3), mm_strdup("is"), mm_strdup($5.type_str), mm_strdup($6.str), @7, mm_strdup("*/")); } ; @@ -1868,19 +1675,19 @@ ECPGWhenever: SQL_WHENEVER SQL_SQLERROR action { when_error.code = $<action>3.code; when_error.command = $<action>3.command; - $$ = cat_str(3, mm_strdup("/* exec sql whenever sqlerror "), $3.str, mm_strdup("; */")); + @$ = cat_str(3, mm_strdup("/* exec sql whenever sqlerror "), $3.str, mm_strdup("; */")); } | SQL_WHENEVER NOT SQL_FOUND action { when_nf.code = $<action>4.code; when_nf.command = $<action>4.command; - $$ = cat_str(3, mm_strdup("/* exec sql whenever not found "), $4.str, mm_strdup("; */")); + @$ = cat_str(3, mm_strdup("/* exec sql whenever not found "), $4.str, mm_strdup("; */")); } | SQL_WHENEVER SQL_SQLWARNING action { when_warn.code = $<action>3.code; when_warn.command = $<action>3.command; - $$ = cat_str(3, mm_strdup("/* exec sql whenever sql_warning "), $3.str, mm_strdup("; */")); + @$ = cat_str(3, mm_strdup("/* exec sql whenever sql_warning "), $3.str, mm_strdup("; */")); } ; @@ -1905,19 +1712,19 @@ action: CONTINUE_P | SQL_GOTO name { $<action>$.code = W_GOTO; - $<action>$.command = mm_strdup($2); - $<action>$.str = cat2_str(mm_strdup("goto "), $2); + $<action>$.command = mm_strdup(@2); + $<action>$.str = cat2_str(mm_strdup("goto "), @2); } | SQL_GO TO name { $<action>$.code = W_GOTO; - $<action>$.command = mm_strdup($3); - $<action>$.str = cat2_str(mm_strdup("goto "), $3); + $<action>$.command = mm_strdup(@3); + $<action>$.str = cat2_str(mm_strdup("goto "), @3); } | DO name '(' c_args ')' { $<action>$.code = W_DO; - $<action>$.command = cat_str(4, $2, mm_strdup("("), $4, mm_strdup(")")); + $<action>$.command = cat_str(4, @2, mm_strdup("("), @4, mm_strdup(")")); $<action>$.str = cat2_str(mm_strdup("do"), mm_strdup($<action>$.command)); } | DO SQL_BREAK @@ -1935,13 +1742,13 @@ action: CONTINUE_P | CALL name '(' c_args ')' { $<action>$.code = W_DO; - $<action>$.command = cat_str(4, $2, mm_strdup("("), $4, mm_strdup(")")); + $<action>$.command = cat_str(4, @2, mm_strdup("("), @4, mm_strdup(")")); $<action>$.str = cat2_str(mm_strdup("call"), mm_strdup($<action>$.command)); } | CALL name { $<action>$.code = W_DO; - $<action>$.command = cat2_str($2, mm_strdup("()")); + $<action>$.command = cat2_str(@2, mm_strdup("()")); $<action>$.str = cat2_str(mm_strdup("call"), mm_strdup($<action>$.command)); } ; @@ -1949,63 +1756,63 @@ action: CONTINUE_P /* some other stuff for ecpg */ /* additional unreserved keywords */ -ECPGKeywords: ECPGKeywords_vanames { $$ = $1; } - | ECPGKeywords_rest { $$ = $1; } - ; - -ECPGKeywords_vanames: SQL_BREAK { $$ = mm_strdup("break"); } - | SQL_CARDINALITY { $$ = mm_strdup("cardinality"); } - | SQL_COUNT { $$ = mm_strdup("count"); } - | SQL_DATETIME_INTERVAL_CODE { $$ = mm_strdup("datetime_interval_code"); } - | SQL_DATETIME_INTERVAL_PRECISION { $$ = mm_strdup("datetime_interval_precision"); } - | SQL_FOUND { $$ = mm_strdup("found"); } - | SQL_GO { $$ = mm_strdup("go"); } - | SQL_GOTO { $$ = mm_strdup("goto"); } - | SQL_IDENTIFIED { $$ = mm_strdup("identified"); } - | SQL_INDICATOR { $$ = mm_strdup("indicator"); } - | SQL_KEY_MEMBER { $$ = mm_strdup("key_member"); } - | SQL_LENGTH { $$ = mm_strdup("length"); } - | SQL_NULLABLE { $$ = mm_strdup("nullable"); } - | SQL_OCTET_LENGTH { $$ = mm_strdup("octet_length"); } - | SQL_RETURNED_LENGTH { $$ = mm_strdup("returned_length"); } - | SQL_RETURNED_OCTET_LENGTH { $$ = mm_strdup("returned_octet_length"); } - | SQL_SCALE { $$ = mm_strdup("scale"); } - | SQL_SECTION { $$ = mm_strdup("section"); } - | SQL_SQLERROR { $$ = mm_strdup("sqlerror"); } - | SQL_SQLPRINT { $$ = mm_strdup("sqlprint"); } - | SQL_SQLWARNING { $$ = mm_strdup("sqlwarning"); } - | SQL_STOP { $$ = mm_strdup("stop"); } - ; - -ECPGKeywords_rest: SQL_CONNECT { $$ = mm_strdup("connect"); } - | SQL_DESCRIBE { $$ = mm_strdup("describe"); } - | SQL_DISCONNECT { $$ = mm_strdup("disconnect"); } - | SQL_OPEN { $$ = mm_strdup("open"); } - | SQL_VAR { $$ = mm_strdup("var"); } - | SQL_WHENEVER { $$ = mm_strdup("whenever"); } +ECPGKeywords: ECPGKeywords_vanames + | ECPGKeywords_rest + ; + +ECPGKeywords_vanames: SQL_BREAK + | SQL_CARDINALITY + | SQL_COUNT + | SQL_DATETIME_INTERVAL_CODE + | SQL_DATETIME_INTERVAL_PRECISION + | SQL_FOUND + | SQL_GO + | SQL_GOTO + | SQL_IDENTIFIED + | SQL_INDICATOR + | SQL_KEY_MEMBER + | SQL_LENGTH + | SQL_NULLABLE + | SQL_OCTET_LENGTH + | SQL_RETURNED_LENGTH + | SQL_RETURNED_OCTET_LENGTH + | SQL_SCALE + | SQL_SECTION + | SQL_SQLERROR + | SQL_SQLPRINT + | SQL_SQLWARNING + | SQL_STOP + ; + +ECPGKeywords_rest: SQL_CONNECT + | SQL_DESCRIBE + | SQL_DISCONNECT + | SQL_OPEN + | SQL_VAR + | SQL_WHENEVER ; /* additional keywords that can be SQL type names (but not ECPGColLabels) */ -ECPGTypeName: SQL_BOOL { $$ = mm_strdup("bool"); } - | SQL_LONG { $$ = mm_strdup("long"); } - | SQL_OUTPUT { $$ = mm_strdup("output"); } - | SQL_SHORT { $$ = mm_strdup("short"); } - | SQL_STRUCT { $$ = mm_strdup("struct"); } - | SQL_SIGNED { $$ = mm_strdup("signed"); } - | SQL_UNSIGNED { $$ = mm_strdup("unsigned"); } +ECPGTypeName: SQL_BOOL + | SQL_LONG + | SQL_OUTPUT + | SQL_SHORT + | SQL_STRUCT + | SQL_SIGNED + | SQL_UNSIGNED ; -symbol: ColLabel { $$ = $1; } +symbol: ColLabel ; -ECPGColId: ecpg_ident { $$ = $1; } - | unreserved_keyword { $$ = $1; } - | col_name_keyword { $$ = $1; } - | ECPGunreserved_interval { $$ = $1; } - | ECPGKeywords { $$ = $1; } - | ECPGCKeywords { $$ = $1; } - | CHAR_P { $$ = mm_strdup("char"); } - | VALUES { $$ = mm_strdup("values"); } +ECPGColId: ecpg_ident + | unreserved_keyword + | col_name_keyword + | ECPGunreserved_interval + | ECPGKeywords + | ECPGCKeywords + | CHAR_P + | VALUES ; /* @@ -2018,58 +1825,58 @@ ECPGColId: ecpg_ident { $$ = $1; } /* Column identifier --- names that can be column, table, etc names. */ -ColId: ecpg_ident { $$ = $1; } - | all_unreserved_keyword { $$ = $1; } - | col_name_keyword { $$ = $1; } - | ECPGKeywords { $$ = $1; } - | ECPGCKeywords { $$ = $1; } - | CHAR_P { $$ = mm_strdup("char"); } - | VALUES { $$ = mm_strdup("values"); } +ColId: ecpg_ident + | all_unreserved_keyword + | col_name_keyword + | ECPGKeywords + | ECPGCKeywords + | CHAR_P + | VALUES ; /* Type/function identifier --- names that can be type or function names. */ -type_function_name: ecpg_ident { $$ = $1; } - | all_unreserved_keyword { $$ = $1; } - | type_func_name_keyword { $$ = $1; } - | ECPGKeywords { $$ = $1; } - | ECPGCKeywords { $$ = $1; } - | ECPGTypeName { $$ = $1; } +type_function_name: ecpg_ident + | all_unreserved_keyword + | type_func_name_keyword + | ECPGKeywords + | ECPGCKeywords + | ECPGTypeName ; /* Column label --- allowed labels in "AS" clauses. * This presently includes *all* Postgres keywords. */ -ColLabel: ECPGColLabel { $$ = $1; } - | ECPGTypeName { $$ = $1; } - | CHAR_P { $$ = mm_strdup("char"); } - | CURRENT_P { $$ = mm_strdup("current"); } - | INPUT_P { $$ = mm_strdup("input"); } - | INT_P { $$ = mm_strdup("int"); } - | TO { $$ = mm_strdup("to"); } - | UNION { $$ = mm_strdup("union"); } - | VALUES { $$ = mm_strdup("values"); } - | ECPGCKeywords { $$ = $1; } - | ECPGunreserved_interval { $$ = $1; } - ; - -ECPGColLabel: ecpg_ident { $$ = $1; } - | unreserved_keyword { $$ = $1; } - | col_name_keyword { $$ = $1; } - | type_func_name_keyword { $$ = $1; } - | reserved_keyword { $$ = $1; } - | ECPGKeywords_vanames { $$ = $1; } - | ECPGKeywords_rest { $$ = $1; } - | CONNECTION { $$ = mm_strdup("connection"); } - ; - -ECPGCKeywords: S_AUTO { $$ = mm_strdup("auto"); } - | S_CONST { $$ = mm_strdup("const"); } - | S_EXTERN { $$ = mm_strdup("extern"); } - | S_REGISTER { $$ = mm_strdup("register"); } - | S_STATIC { $$ = mm_strdup("static"); } - | S_TYPEDEF { $$ = mm_strdup("typedef"); } - | S_VOLATILE { $$ = mm_strdup("volatile"); } +ColLabel: ECPGColLabel + | ECPGTypeName + | CHAR_P + | CURRENT_P + | INPUT_P + | INT_P + | TO + | UNION + | VALUES + | ECPGCKeywords + | ECPGunreserved_interval + ; + +ECPGColLabel: ecpg_ident + | unreserved_keyword + | col_name_keyword + | type_func_name_keyword + | reserved_keyword + | ECPGKeywords_vanames + | ECPGKeywords_rest + | CONNECTION + ; + +ECPGCKeywords: S_AUTO + | S_CONST + | S_EXTERN + | S_REGISTER + | S_STATIC + | S_TYPEDEF + | S_VOLATILE ; /* "Unreserved" keywords --- available for use as any kind of name. @@ -2086,17 +1893,17 @@ ECPGCKeywords: S_AUTO { $$ = mm_strdup("auto"); } * * The mentioned exclusions are done by $replace_line settings in parse.pl. */ -all_unreserved_keyword: unreserved_keyword { $$ = $1; } - | ECPGunreserved_interval { $$ = $1; } - | CONNECTION { $$ = mm_strdup("connection"); } +all_unreserved_keyword: unreserved_keyword + | ECPGunreserved_interval + | CONNECTION ; -ECPGunreserved_interval: DAY_P { $$ = mm_strdup("day"); } - | HOUR_P { $$ = mm_strdup("hour"); } - | MINUTE_P { $$ = mm_strdup("minute"); } - | MONTH_P { $$ = mm_strdup("month"); } - | SECOND_P { $$ = mm_strdup("second"); } - | YEAR_P { $$ = mm_strdup("year"); } +ECPGunreserved_interval: DAY_P + | HOUR_P + | MINUTE_P + | MONTH_P + | SECOND_P + | YEAR_P ; into_list: coutputvariable | into_list ',' coutputvariable @@ -2106,73 +1913,66 @@ ecpgstart: SQL_START { reset_variables(); pacounter = 1; + @$ = EMPTY; } ; c_args: /* EMPTY */ - { - $$ = EMPTY; - } | c_list - { - $$ = $1; - } ; coutputvariable: cvariable indicator { - add_variable_to_head(&argsresult, find_variable($1), find_variable($2)); + add_variable_to_head(&argsresult, find_variable(@1), find_variable(@2)); } | cvariable { - add_variable_to_head(&argsresult, find_variable($1), &no_indicator); + add_variable_to_head(&argsresult, find_variable(@1), &no_indicator); } ; civarind: cvariable indicator { - if (find_variable($2)->type->type == ECPGt_array) + if (find_variable(@2)->type->type == ECPGt_array) mmerror(PARSE_ERROR, ET_ERROR, "arrays of indicators are not allowed on input"); - add_variable_to_head(&argsinsert, find_variable($1), find_variable($2)); - $$ = create_questionmarks($1, false); + add_variable_to_head(&argsinsert, find_variable(@1), find_variable(@2)); + @$ = create_questionmarks(@1, false); } ; char_civar: char_variable { - char *ptr = strstr($1, ".arr"); + char *ptr = strstr(@1, ".arr"); if (ptr) /* varchar, we need the struct name here, not * the struct element */ *ptr = '\0'; - add_variable_to_head(&argsinsert, find_variable($1), &no_indicator); - $$ = $1; + add_variable_to_head(&argsinsert, find_variable(@1), &no_indicator); } ; civar: cvariable { - add_variable_to_head(&argsinsert, find_variable($1), &no_indicator); - $$ = create_questionmarks($1, false); + add_variable_to_head(&argsinsert, find_variable(@1), &no_indicator); + @$ = create_questionmarks(@1, false); } ; indicator: cvariable { - check_indicator((find_variable($1))->type); - $$ = $1; + check_indicator((find_variable(@1))->type); } | SQL_INDICATOR cvariable { - check_indicator((find_variable($2))->type); - $$ = $2; + check_indicator((find_variable(@2))->type); + @$ = @2; } | SQL_INDICATOR name { - check_indicator((find_variable($2))->type); - $$ = $2; + check_indicator((find_variable(@2))->type); + @$ = @2; } ; @@ -2182,7 +1982,7 @@ cvariable: CVARIABLE * As long as multidimensional arrays are not implemented we have to * check for those here */ - char *ptr = $1; + char *ptr = @1; int brace_open = 0, brace = false; @@ -2209,57 +2009,44 @@ cvariable: CVARIABLE break; } } - $$ = $1; } ; ecpg_param: PARAM { - $$ = make_name(); + @$ = make_name(); } ; ecpg_bconst: BCONST - { - $$ = $1; - } ; ecpg_fconst: FCONST { - $$ = make_name(); + @$ = make_name(); } ; ecpg_sconst: SCONST - { - $$ = $1; - } ; ecpg_xconst: XCONST - { - $$ = $1; - } ; ecpg_ident: IDENT - { - $$ = $1; - } | CSTRING { - $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); + @$ = make3_str(mm_strdup("\""), @1, mm_strdup("\"")); } ; quoted_ident_stringvar: name { - $$ = make3_str(mm_strdup("\""), $1, mm_strdup("\"")); + @$ = make3_str(mm_strdup("\""), @1, mm_strdup("\"")); } | char_variable { - $$ = make3_str(mm_strdup("("), $1, mm_strdup(")")); + @$ = make3_str(mm_strdup("("), @1, mm_strdup(")")); } ; @@ -2268,221 +2055,151 @@ quoted_ident_stringvar: name */ c_stuff_item: c_anything - { - $$ = $1; - } | '(' ')' { - $$ = mm_strdup("()"); + @$ = mm_strdup("()"); } | '(' c_stuff ')' - { - $$ = cat_str(3, mm_strdup("("), $2, mm_strdup(")")); - } ; c_stuff: c_stuff_item - { - $$ = $1; - } | c_stuff c_stuff_item - { - $$ = cat2_str($1, $2); - } ; c_list: c_term - { - $$ = $1; - } | c_list ',' c_term - { - $$ = cat_str(3, $1, mm_strdup(","), $3); - } ; c_term: c_stuff - { - $$ = $1; - } | '{' c_list '}' - { - $$ = cat_str(3, mm_strdup("{"), $2, mm_strdup("}")); - } - ; - -c_thing: c_anything { $$ = $1; } - | '(' { $$ = mm_strdup("("); } - | ')' { $$ = mm_strdup(")"); } - | ',' { $$ = mm_strdup(","); } - | ';' { $$ = mm_strdup(";"); } - ; - -c_anything: ecpg_ident { $$ = $1; } - | Iconst { $$ = $1; } - | ecpg_fconst { $$ = $1; } - | ecpg_sconst { $$ = $1; } - | '*' { $$ = mm_strdup("*"); } - | '+' { $$ = mm_strdup("+"); } - | '-' { $$ = mm_strdup("-"); } - | '/' { $$ = mm_strdup("/"); } - | '%' { $$ = mm_strdup("%"); } - | NULL_P { $$ = mm_strdup("NULL"); } - | S_ADD { $$ = mm_strdup("+="); } - | S_AND { $$ = mm_strdup("&&"); } - | S_ANYTHING { $$ = make_name(); } - | S_AUTO { $$ = mm_strdup("auto"); } - | S_CONST { $$ = mm_strdup("const"); } - | S_DEC { $$ = mm_strdup("--"); } - | S_DIV { $$ = mm_strdup("/="); } - | S_DOTPOINT { $$ = mm_strdup(".*"); } - | S_EQUAL { $$ = mm_strdup("=="); } - | S_EXTERN { $$ = mm_strdup("extern"); } - | S_INC { $$ = mm_strdup("++"); } - | S_LSHIFT { $$ = mm_strdup("<<"); } - | S_MEMBER { $$ = mm_strdup("->"); } - | S_MEMPOINT { $$ = mm_strdup("->*"); } - | S_MOD { $$ = mm_strdup("%="); } - | S_MUL { $$ = mm_strdup("*="); } - | S_NEQUAL { $$ = mm_strdup("!="); } - | S_OR { $$ = mm_strdup("||"); } - | S_REGISTER { $$ = mm_strdup("register"); } - | S_RSHIFT { $$ = mm_strdup(">>"); } - | S_STATIC { $$ = mm_strdup("static"); } - | S_SUB { $$ = mm_strdup("-="); } - | S_TYPEDEF { $$ = mm_strdup("typedef"); } - | S_VOLATILE { $$ = mm_strdup("volatile"); } - | SQL_BOOL { $$ = mm_strdup("bool"); } - | ENUM_P { $$ = mm_strdup("enum"); } - | HOUR_P { $$ = mm_strdup("hour"); } - | INT_P { $$ = mm_strdup("int"); } - | SQL_LONG { $$ = mm_strdup("long"); } - | MINUTE_P { $$ = mm_strdup("minute"); } - | MONTH_P { $$ = mm_strdup("month"); } - | SECOND_P { $$ = mm_strdup("second"); } - | SQL_SHORT { $$ = mm_strdup("short"); } - | SQL_SIGNED { $$ = mm_strdup("signed"); } - | SQL_STRUCT { $$ = mm_strdup("struct"); } - | SQL_UNSIGNED { $$ = mm_strdup("unsigned"); } - | YEAR_P { $$ = mm_strdup("year"); } - | CHAR_P { $$ = mm_strdup("char"); } - | FLOAT_P { $$ = mm_strdup("float"); } - | TO { $$ = mm_strdup("to"); } - | UNION { $$ = mm_strdup("union"); } - | VARCHAR { $$ = mm_strdup("varchar"); } - | '[' { $$ = mm_strdup("["); } - | ']' { $$ = mm_strdup("]"); } - | '=' { $$ = mm_strdup("="); } - | ':' { $$ = mm_strdup(":"); } + ; + +c_thing: c_anything + | '(' + | ')' + | ',' + | ';' + ; + +/* + * Note: NULL_P is treated specially to force it to be output in upper case, + * since it's likely meant as a reference to the standard C macro NULL. + */ +c_anything: ecpg_ident + | Iconst + | ecpg_fconst + | ecpg_sconst + | '*' + | '+' + | '-' + | '/' + | '%' + | NULL_P { @$ = mm_strdup("NULL"); } + | S_ADD + | S_AND + | S_ANYTHING + | S_AUTO + | S_CONST + | S_DEC + | S_DIV + | S_DOTPOINT + | S_EQUAL + | S_EXTERN + | S_INC + | S_LSHIFT + | S_MEMBER + | S_MEMPOINT + | S_MOD + | S_MUL + | S_NEQUAL + | S_OR + | S_REGISTER + | S_RSHIFT + | S_STATIC + | S_SUB + | S_TYPEDEF + | S_VOLATILE + | SQL_BOOL + | ENUM_P + | HOUR_P + | INT_P + | SQL_LONG + | MINUTE_P + | MONTH_P + | SECOND_P + | SQL_SHORT + | SQL_SIGNED + | SQL_STRUCT + | SQL_UNSIGNED + | YEAR_P + | CHAR_P + | FLOAT_P + | TO + | UNION + | VARCHAR + | '[' + | ']' + | '=' + | ':' ; DeallocateStmt: DEALLOCATE prepared_name { - check_declared_list($2); - $$ = $2; + check_declared_list(@2); + @$ = @2; } | DEALLOCATE PREPARE prepared_name { - check_declared_list($3); - $$ = $3; + check_declared_list(@3); + @$ = @3; } | DEALLOCATE ALL { - $$ = mm_strdup("all"); + @$ = mm_strdup("all"); } | DEALLOCATE PREPARE ALL { - $$ = mm_strdup("all"); + @$ = mm_strdup("all"); } ; Iresult: Iconst - { - $$ = $1; - } | '(' Iresult ')' - { - $$ = cat_str(3, mm_strdup("("), $2, mm_strdup(")")); - } | Iresult '+' Iresult - { - $$ = cat_str(3, $1, mm_strdup("+"), $3); - } | Iresult '-' Iresult - { - $$ = cat_str(3, $1, mm_strdup("-"), $3); - } | Iresult '*' Iresult - { - $$ = cat_str(3, $1, mm_strdup("*"), $3); - } | Iresult '/' Iresult - { - $$ = cat_str(3, $1, mm_strdup("/"), $3); - } | Iresult '%' Iresult - { - $$ = cat_str(3, $1, mm_strdup("%"), $3); - } | ecpg_sconst - { - $$ = $1; - } | ColId - { - $$ = $1; - } | ColId '(' var_type ')' { - if (pg_strcasecmp($1, "sizeof") != 0) + if (pg_strcasecmp(@1, "sizeof") != 0) mmerror(PARSE_ERROR, ET_ERROR, "operator not allowed in variable definition"); else - $$ = cat_str(4, $1, mm_strdup("("), $3.type_str, mm_strdup(")")); + @$ = cat_str(4, @1, mm_strdup("("), $3.type_str, mm_strdup(")")); } ; execute_rest: /* EMPTY */ - { - $$ = EMPTY; - } | ecpg_using opt_ecpg_into - { - $$ = EMPTY; - } | ecpg_into ecpg_using - { - $$ = EMPTY; - } | ecpg_into - { - $$ = EMPTY; - } ; ecpg_into: INTO into_list { - $$ = EMPTY; + /* always suppress this from the constructed string */ + @$ = EMPTY; } | into_descriptor - { - $$ = $1; - } ; opt_ecpg_into: /* EMPTY */ - { - $$ = EMPTY; - } | ecpg_into - { - $$ = $1; - } ; ecpg_fetch_into: ecpg_into - { - $$ = $1; - } | using_descriptor { struct variable *var; @@ -2490,18 +2207,11 @@ ecpg_fetch_into: ecpg_into var = argsinsert->variable; remove_variable_from_list(&argsinsert, var); add_variable_to_head(&argsresult, var, &no_indicator); - $$ = $1; } ; opt_ecpg_fetch_into: /* EMPTY */ - { - $$ = EMPTY; - } | ecpg_fetch_into - { - $$ = $1; - } ; %% diff --git a/src/interfaces/ecpg/preproc/ecpg.type b/src/interfaces/ecpg/preproc/ecpg.type index 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 <str> ECPGAllocateDescr -%type <str> ECPGCKeywords -%type <str> ECPGColId -%type <str> ECPGColLabel -%type <str> ECPGConnect -%type <str> ECPGCursorStmt -%type <str> ECPGDeallocateDescr -%type <str> ECPGDeclaration -%type <str> ECPGDeclare -%type <str> ECPGDeclareStmt -%type <str> ECPGDisconnect -%type <str> ECPGExecuteImmediateStmt -%type <str> ECPGFree -%type <str> ECPGGetDescHeaderItem -%type <str> ECPGGetDescItem -%type <str> ECPGGetDescriptorHeader -%type <str> ECPGKeywords -%type <str> ECPGKeywords_rest -%type <str> ECPGKeywords_vanames -%type <str> ECPGOpen -%type <str> ECPGSetAutocommit -%type <str> ECPGSetConnection -%type <str> ECPGSetDescHeaderItem -%type <str> ECPGSetDescItem -%type <str> ECPGSetDescriptorHeader -%type <str> ECPGTypeName -%type <str> ECPGTypedef -%type <str> ECPGVar -%type <str> ECPGVarDeclaration -%type <str> ECPGWhenever -%type <str> ECPGunreserved_interval -%type <str> UsingConst -%type <str> UsingValue -%type <str> all_unreserved_keyword -%type <str> c_anything -%type <str> c_args -%type <str> c_list -%type <str> c_stuff -%type <str> c_stuff_item -%type <str> c_term -%type <str> c_thing -%type <str> char_variable -%type <str> char_civar -%type <str> civar -%type <str> civarind -%type <str> ColId -%type <str> ColLabel -%type <str> connect_options -%type <str> connection_object -%type <str> connection_target -%type <str> coutputvariable -%type <str> cvariable -%type <str> db_prefix -%type <str> CreateAsStmt -%type <str> DeallocateStmt -%type <str> dis_name -%type <str> ecpg_bconst -%type <str> ecpg_fconst -%type <str> ecpg_ident -%type <str> ecpg_interval -%type <str> ecpg_into -%type <str> ecpg_fetch_into -%type <str> ecpg_param -%type <str> ecpg_sconst -%type <str> ecpg_using -%type <str> ecpg_xconst -%type <str> enum_definition -%type <str> enum_type -%type <str> execstring -%type <str> execute_rest -%type <str> indicator -%type <str> into_descriptor -%type <str> into_sqlda -%type <str> Iresult -%type <str> on_off -%type <str> opt_bit_field -%type <str> opt_connection_name -%type <str> opt_database_name -%type <str> opt_ecpg_into -%type <str> opt_ecpg_fetch_into -%type <str> opt_ecpg_using -%type <str> opt_initializer -%type <str> opt_options -%type <str> opt_output -%type <str> opt_pointer -%type <str> opt_port -%type <str> opt_reference -%type <str> opt_scale -%type <str> opt_server -%type <str> opt_user -%type <str> opt_opt_value -%type <str> ora_user -%type <str> precision -%type <str> prepared_name -%type <str> quoted_ident_stringvar -%type <str> s_struct_union -%type <str> server -%type <str> server_name -%type <str> single_vt_declaration -%type <str> storage_clause -%type <str> storage_declaration -%type <str> storage_modifier -%type <str> struct_union_type -%type <str> struct_union_type_with_symbol -%type <str> symbol -%type <str> type_declaration -%type <str> type_function_name -%type <str> user_name -%type <str> using_descriptor -%type <str> var_declaration -%type <str> var_type_declarations -%type <str> variable -%type <str> variable_declarations -%type <str> variable_list -%type <str> vt_declarations - -%type <str> Op -%type <str> IntConstVar -%type <str> AllConstVar -%type <str> CSTRING -%type <str> CPP_LINE -%type <str> CVARIABLE -%type <str> BCONST -%type <str> SCONST -%type <str> XCONST -%type <str> IDENT - %type <struct_union> s_struct_union_symbol %type <descriptor> ECPGGetDescriptor diff --git a/src/interfaces/ecpg/preproc/output.c b/src/interfaces/ecpg/preproc/output.c index 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 '<str>' for nonterminals +# This hash can provide a result type to override "void" for nonterminals # that need that, or it can specify 'ignore' to cause us to skip the rule -# for that nonterminal. (In that case, ecpg.trailer had better provide -# a substitute rule.) +# for that nonterminal. (In either case, ecpg.trailer had better provide +# a substitute rule, since the default won't do.) my %replace_types = ( 'PrepareStmt' => '<prep>', 'ExecuteStmt' => '<exec>', @@ -175,11 +158,8 @@ my $non_term_id; # we plan to emit for the current rule. my $line = ''; -# @fields holds the items to be emitted in the token-concatenation action -# for the current rule (assuming we emit one). "$N" refers to the N'th -# input token of the rule; anything else is a string to emit literally. -# (We assume no such string can need to start with '$'.) -my @fields; +# count of tokens included in $line. +my $line_count = 0; # Open parser / output file early, to raise errors early. @@ -244,10 +224,6 @@ sub main $has_if_command = 1 if /^\s*if/; } - # We track %prec per-line, not per-rule, which is not quite right - # but there are no counterexamples in gram.y at present. - my $prec = 0; - # Make sure any braces are split into separate fields s/{/ { /g; s/}/ } /g; @@ -296,7 +272,7 @@ sub main } # If it's "<something>", it's a type in a %token declaration, - # which we can just drop. + # which we should just drop so that the tokens have void type. if (substr($a, 0, 1) eq '<') { next; @@ -376,7 +352,7 @@ sub main if ($copymode) { # Print the accumulated rule. - emit_rule(\@fields); + emit_rule(); add_to_buffer('rules', ";\n\n"); } else @@ -386,8 +362,8 @@ sub main } # Reset for the next rule. - @fields = (); $line = ''; + $line_count = 0; $in_rule = 0; $alt_count = 0; $has_feature_not_supported = 0; @@ -401,11 +377,10 @@ sub main { # Print the accumulated alternative. # Increment $alt_count for each non-ignored alternative. - $alt_count += emit_rule(\@fields); + $alt_count += emit_rule(); } # Reset for the next alternative. - @fields = (); # Start the next line with '|' if we've printed at least one # alternative. if ($alt_count > 1) @@ -416,6 +391,7 @@ sub main { $line = ''; } + $line_count = 0; $has_feature_not_supported = 0; $has_if_command = 0; next; @@ -444,13 +420,9 @@ sub main $fieldIndexer++; } - # Check for %replace_types override of nonterminal's type - if (not defined $replace_types{$non_term_id}) - { - # By default, the type is <str> - $replace_types{$non_term_id} = '<str>'; - } - elsif ($replace_types{$non_term_id} eq 'ignore') + # Check for %replace_types entry indicating to ignore it. + if (defined $replace_types{$non_term_id} + && $replace_types{$non_term_id} eq 'ignore') { # We'll ignore this nonterminal and rule altogether. $copymode = 0; @@ -470,22 +442,26 @@ sub main $stmt_mode = 0; } - # Emit appropriate %type declaration for this nonterminal. - my $tstr = - '%type ' - . $replace_types{$non_term_id} . ' ' - . $non_term_id; - add_to_buffer('types', $tstr); + # Emit appropriate %type declaration for this nonterminal, + # if it has a type; otherwise omit that. + if (defined $replace_types{$non_term_id}) + { + my $tstr = + '%type ' + . $replace_types{$non_term_id} . ' ' + . $non_term_id; + add_to_buffer('types', $tstr); + } # Emit the target part of the rule. # Note: the leading space is just to match # the 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; @@ -219,6 +221,56 @@ filtered_base_yylex(void) } /* + * Call base_yylex() and fill in base_yylloc. + * + * pgc.l does not worry about setting yylloc, and given what we want for + * that, trying to set it there would be pretty inconvenient. What we + * want is: if the returned token has type <str>, then duplicate its + * string value as yylloc; otherwise, make a downcased copy of yytext. + * The downcasing is ASCII-only because all that we care about there + * is producing uniformly-cased output of keywords. (That's mostly + * cosmetic, but there are places in ecpglib that expect to receive + * downcased keywords, plus it keeps us regression-test-compatible + * with the 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 <str> value */ + base_yylloc = mm_strdup(base_yylval.str); + break; + default: + /* Else just use the input, i.e., yytext */ + base_yylloc = mm_strdup(base_yytext); + /* Apply an ASCII-only downcasing */ + for (unsigned char *ptr = (unsigned char *) base_yylloc; *ptr; ptr++) + { + if (*ptr >= 'A' && *ptr <= 'Z') + *ptr += 'a' - 'A'; + } + break; + } + return token; +} + +/* * check_uescapechar() and ecpg_isspace() should match their equivalents * in pgc.l. */ diff --git a/src/interfaces/ecpg/preproc/preproc_extern.h b/src/interfaces/ecpg/preproc/preproc_extern.h index 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); |