]> granicus.if.org Git - postgresql/commitdiff
Use %option bison-bridge in psql/pgbench lexers.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 21 Mar 2016 01:59:03 +0000 (21:59 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 21 Mar 2016 01:59:03 +0000 (21:59 -0400)
The point of this change is to use %pure-parser in pgbench's exprparse.y.
The immediate reason is that it turns out very ancient versions of bison
have a bug with the combination of a reentrant lexer and non-reentrant
parser.  We could consider dropping support for such ancient bisons; but
considering that we might well need exprparse.y to be reentrant some day,
it seems better to make it so right now than to move the portability
goalposts.  (AFAICT there's no particular performance consequence to this
change, either, so there's no good reason not to do it.)

Now, %pure-parser assumes that the called lexer is built with %option
bison-bridge.  Because we're assuming bitwise compatibility of yyscan_t
(yyguts_t) data structures among all the psql/pgbench lexers, that
requirement propagates back to psql's lexers as well.  But it's just a
few lines of change on that side too; and if psqlscan.l is to set the
baseline for a possibly-large family of lexers, it should err on the
side of including not omitting useful features.

src/bin/pgbench/exprparse.y
src/bin/pgbench/exprscan.l
src/bin/pgbench/pgbench.h
src/bin/psql/psqlscan.l
src/bin/psql/psqlscanslash.l

index 5d0d97272f7cf7877befaebd8e8e185004657136..4948ff3b8132854d867dad1c33172bb33ef9ab18 100644 (file)
@@ -28,6 +28,7 @@ static PgBenchExpr *make_func(yyscan_t yyscanner, int fnumber, PgBenchExprList *
 
 %}
 
+%pure-parser
 %expect 0
 %name-prefix="expr_yy"
 
@@ -263,5 +264,7 @@ make_func(yyscan_t yyscanner, int fnumber, PgBenchExprList *args)
 
 /* First, get rid of "#define yyscan_t" from pgbench.h */
 #undef yyscan_t
+/* ... and the yylval macro, which flex will have its own definition for */
+#undef yylval
 
 #include "exprscan.c"
index d069c5b05b0e39ce687a92a6fb0420375b4e5033..825dacc0af3f944ccb1378ee444054c3f12cd33d 100644 (file)
@@ -47,6 +47,7 @@ extern void expr_yyset_column(int column_no, yyscan_t yyscanner);
 
 /* Except for the prefix, these options should match psqlscan.l */
 %option reentrant
+%option bison-bridge
 %option 8bit
 %option never-interactive
 %option nodefault
@@ -117,15 +118,15 @@ newline                   [\n]
 ","                            { return ','; }
 
 :{alnum}+              {
-                                       yylval.str = pg_strdup(yytext + 1);
+                                       yylval->str = pg_strdup(yytext + 1);
                                        return VARIABLE;
                                }
 {digit}+               {
-                                       yylval.ival = strtoint64(yytext);
+                                       yylval->ival = strtoint64(yytext);
                                        return INTEGER;
                                }
 {alpha}{alnum}*        {
-                                       yylval.str = pg_strdup(yytext);
+                                       yylval->str = pg_strdup(yytext);
                                        return FUNCTION;
                                }
 
@@ -169,6 +170,7 @@ expr_yyerror_more(yyscan_t yyscanner, const char *message, const char *more)
 {
        PsqlScanState state = yyget_extra(yyscanner);
        int                     error_detection_offset = expr_scanner_offset(state) - 1;
+       YYSTYPE         lval;
        char       *full_line;
        size_t          l;
 
@@ -179,7 +181,7 @@ expr_yyerror_more(yyscan_t yyscanner, const char *message, const char *more)
         */
        if (!last_was_newline)
        {
-               while (yylex(yyscanner))
+               while (yylex(&lval, yyscanner))
                         /* skip */ ;
        }
 
@@ -210,6 +212,7 @@ bool
 expr_lex_one_word(PsqlScanState state, PQExpBuffer word_buf, int *offset)
 {
        int                     lexresult;
+       YYSTYPE         lval;
 
        /* Must be scanning already */
        Assert(state->scanbufhandle != NULL);
@@ -228,7 +231,7 @@ expr_lex_one_word(PsqlScanState state, PQExpBuffer word_buf, int *offset)
        state->start_state = INITIAL;
 
        /* And lex. */
-       lexresult = yylex(state->scanner);
+       lexresult = yylex(&lval, state->scanner);
 
        /*
         * Save start offset of word, if any.  We could do this more efficiently,
index a9db9c5b8317bc6497d0c2f64c51ef7db24fb0a2..101b0bdbf3bef5972ce9f054f0bc067e410db343 100644 (file)
  * This file is included outside exprscan.l, in places where we can't see
  * flex's definition of typedef yyscan_t.  Fortunately, it's documented as
  * being "void *", so we can use a macro to keep the function declarations
- * here looking like the definitions in exprscan.l.  exprparse.y also
- * uses this to be able to declare things as "yyscan_t".
+ * here looking like the definitions in exprscan.l.  exprparse.y and
+ * pgbench.c also use this to be able to declare things as "yyscan_t".
  */
 #define yyscan_t  void *
 
+/*
+ * Likewise, we can't see exprparse.y's definition of union YYSTYPE here,
+ * but for now there's no need to know what the union contents are.
+ */
+union YYSTYPE;
+
 /* Types of expression nodes */
 typedef enum PgBenchExprType
 {
@@ -85,7 +91,7 @@ struct PgBenchExprList
 extern PgBenchExpr *expr_parse_result;
 
 extern int     expr_yyparse(yyscan_t yyscanner);
-extern int     expr_yylex(yyscan_t yyscanner);
+extern int     expr_yylex(union YYSTYPE *lvalp, yyscan_t yyscanner);
 extern void expr_yyerror(yyscan_t yyscanner, const char *str) pg_attribute_noreturn();
 extern void expr_yyerror_more(yyscan_t yyscanner, const char *str,
                                  const char *more) pg_attribute_noreturn();
index 26ad45c7f988ed55923f2e25daf3cb1f8380fa11..93c735596025aa0e960ca6bbd5866ccea58c6d02 100644 (file)
 %{
 #include "psqlscan_int.h"
 
+/*
+ * We must have a typedef YYSTYPE for yylex's first argument, but this lexer
+ * doesn't presently make use of that argument, so just declare it as int.
+ */
+typedef int YYSTYPE;
+
 /*
  * Set the type of yyextra; we use it as a pointer back to the containing
  * PsqlScanState.
@@ -64,6 +70,7 @@ extern void psql_yyset_column(int column_no, yyscan_t yyscanner);
 %}
 
 %option reentrant
+%option bison-bridge
 %option 8bit
 %option never-interactive
 %option nodefault
@@ -1002,7 +1009,7 @@ psql_scan(PsqlScanState state,
                yy_switch_to_buffer(state->scanbufhandle, state->scanner);
 
        /* And lex. */
-       lexresult = yylex(state->scanner);
+       lexresult = yylex(NULL, state->scanner);
 
        /*
         * Check termination state and return appropriate result info.
index e3cef7c5c5d0c305e45fbb0a11c4c90a1d816cbe..a89ce15ad4cf366506790034742c7908a1556a44 100644 (file)
 %{
 #include "psqlscan_int.h"
 
+/*
+ * We must have a typedef YYSTYPE for yylex's first argument, but this lexer
+ * doesn't presently make use of that argument, so just declare it as int.
+ */
+typedef int YYSTYPE;
+
 /*
  * Set the type of yyextra; we use it as a pointer back to the containing
  * PsqlScanState.
@@ -62,7 +68,9 @@ extern void slash_yyset_column(int column_no, yyscan_t yyscanner);
 
 %}
 
+/* Except for the prefix, these options should match psqlscan.l */
 %option reentrant
+%option bison-bridge
 %option 8bit
 %option never-interactive
 %option nodefault
@@ -447,7 +455,7 @@ psql_scan_slash_command(PsqlScanState state)
        state->start_state = xslashcmd;
 
        /* And lex. */
-       yylex(state->scanner);
+       yylex(NULL, state->scanner);
 
        /* There are no possible errors in this lex state... */
 
@@ -521,7 +529,7 @@ psql_scan_slash_option(PsqlScanState state,
                state->start_state = xslashargstart;
 
        /* And lex. */
-       lexresult = yylex(state->scanner);
+       lexresult = yylex(NULL, state->scanner);
 
        /* Save final state for a moment... */
        final_state = state->start_state;
@@ -648,7 +656,7 @@ psql_scan_slash_command_end(PsqlScanState state)
        state->start_state = xslashend;
 
        /* And lex. */
-       yylex(state->scanner);
+       yylex(NULL, state->scanner);
 
        /* There are no possible errors in this lex state... */