* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
+ * src/bin/pgbench/exprparse.y
+ *
*-------------------------------------------------------------------------
*/
static PgBenchExprList *make_elist(PgBenchExpr *exp, PgBenchExprList *list);
static PgBenchExpr *make_integer_constant(int64 ival);
static PgBenchExpr *make_variable(char *varname);
-static PgBenchExpr *make_op(const char *operator, PgBenchExpr *lexpr,
- PgBenchExpr *rexpr);
-static int find_func(const char *fname);
-static PgBenchExpr *make_func(const int fnumber, PgBenchExprList *args);
+static PgBenchExpr *make_op(yyscan_t yyscanner, const char *operator,
+ PgBenchExpr *lexpr, PgBenchExpr *rexpr);
+static int find_func(yyscan_t yyscanner, const char *fname);
+static PgBenchExpr *make_func(yyscan_t yyscanner, int fnumber, PgBenchExprList *args);
%}
%expect 0
%name-prefix="expr_yy"
+%parse-param {yyscan_t yyscanner}
+%lex-param {yyscan_t yyscanner}
+
%union
{
int64 ival;
%type <str> VARIABLE FUNCTION
%token INTEGER VARIABLE FUNCTION
-%token CHAR_ERROR /* never used, will raise a syntax error */
/* Precedence: lowest to highest */
%left '+' '-'
expr: '(' expr ')' { $$ = $2; }
| '+' expr %prec UMINUS { $$ = $2; }
- | '-' expr %prec UMINUS { $$ = make_op("-", make_integer_constant(0), $2); }
- | expr '+' expr { $$ = make_op("+", $1, $3); }
- | expr '-' expr { $$ = make_op("-", $1, $3); }
- | expr '*' expr { $$ = make_op("*", $1, $3); }
- | expr '/' expr { $$ = make_op("/", $1, $3); }
- | expr '%' expr { $$ = make_op("%", $1, $3); }
+ | '-' expr %prec UMINUS { $$ = make_op(yyscanner, "-",
+ make_integer_constant(0), $2); }
+ | expr '+' expr { $$ = make_op(yyscanner, "+", $1, $3); }
+ | expr '-' expr { $$ = make_op(yyscanner, "-", $1, $3); }
+ | expr '*' expr { $$ = make_op(yyscanner, "*", $1, $3); }
+ | expr '/' expr { $$ = make_op(yyscanner, "/", $1, $3); }
+ | expr '%' expr { $$ = make_op(yyscanner, "%", $1, $3); }
| INTEGER { $$ = make_integer_constant($1); }
| VARIABLE { $$ = make_variable($1); }
- | function '(' elist ')'{ $$ = make_func($1, $3); }
+ | function '(' elist ')' { $$ = make_func(yyscanner, $1, $3); }
;
-function: FUNCTION { $$ = find_func($1); pg_free($1); }
+function: FUNCTION { $$ = find_func(yyscanner, $1); pg_free($1); }
;
%%
}
static PgBenchExpr *
-make_op(const char *operator, PgBenchExpr *lexpr, PgBenchExpr *rexpr)
+make_op(yyscan_t yyscanner, const char *operator,
+ PgBenchExpr *lexpr, PgBenchExpr *rexpr)
{
- return make_func(find_func(operator),
+ return make_func(yyscanner, find_func(yyscanner, operator),
make_elist(rexpr, make_elist(lexpr, NULL)));
}
* or fail if the function is unknown.
*/
static int
-find_func(const char * fname)
+find_func(yyscan_t yyscanner, const char *fname)
{
int i = 0;
i++;
}
- expr_yyerror_more("unexpected function name", fname);
+ expr_yyerror_more(yyscanner, "unexpected function name", fname);
/* not reached */
return -1;
/* Build function call expression */
static PgBenchExpr *
-make_func(const int fnumber, PgBenchExprList *args)
+make_func(yyscan_t yyscanner, int fnumber, PgBenchExprList *args)
{
PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
if (PGBENCH_FUNCTIONS[fnumber].nargs >= 0 &&
PGBENCH_FUNCTIONS[fnumber].nargs != elist_length(args))
- expr_yyerror_more("unexpected number of arguments",
+ expr_yyerror_more(yyscanner, "unexpected number of arguments",
PGBENCH_FUNCTIONS[fnumber].fname);
/* check at least one arg for min & max */
if (PGBENCH_FUNCTIONS[fnumber].nargs == -1 &&
elist_length(args) == 0)
- expr_yyerror_more("at least one argument expected",
+ expr_yyerror_more(yyscanner, "at least one argument expected",
PGBENCH_FUNCTIONS[fnumber].fname);
expr->etype = ENODE_FUNCTION;
return expr;
}
+/*
+ * exprscan.l is compiled as part of exprparse.y. Currently, this is
+ * unavoidable because exprparse does not create a .h file to export
+ * its token symbols. If these files ever grow large enough to be
+ * worth compiling separately, that could be fixed; but for now it
+ * seems like useless complication.
+ */
+
+/* First, get rid of "#define yyscan_t" from pgbench.h */
+#undef yyscan_t
+
#include "exprscan.c"
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
+ * src/bin/pgbench/exprscan.l
+ *
*-------------------------------------------------------------------------
*/
/* Handles to the buffer that the lexer uses internally */
static YY_BUFFER_STATE scanbufhandle;
static char *scanbuf;
-static int scanbuflen;
/* context information for error reporting */
-static char *expr_source = NULL;
+static const char *expr_source = NULL;
static int expr_lineno = 0;
-static char *expr_full_line = NULL;
-static char *expr_command = NULL;
+static const char *expr_full_line = NULL;
+static const char *expr_command = NULL;
static int expr_col = 0;
+
+/*
+ * Work around a bug in flex 2.5.35: it emits a couple of functions that
+ * it forgets to emit declarations for. Since we use -Wmissing-prototypes,
+ * this would cause warnings. Providing our own declarations should be
+ * harmless even when the bug gets fixed.
+ */
+extern int expr_yyget_column(yyscan_t yyscanner);
+extern void expr_yyset_column(int column_no, yyscan_t yyscanner);
+
%}
+/* Except for the prefix, these options should match psqlscan.l */
+%option reentrant
%option 8bit
%option never-interactive
%option nodefault
%%
+%{
+ /*
+ * Force flex into the appropriate start state ... which, for this
+ * case, is always INITIAL. This ensures that we can transition
+ * between different lexers sharing the same yyscan_t.
+ */
+ BEGIN(INITIAL);
+%}
+
"+" { yycol += yyleng; return '+'; }
"-" { yycol += yyleng; return '-'; }
"*" { yycol += yyleng; return '*'; }
[\n] { yycol = 0; yyline++; }
-{space}+ { yycol += yyleng; /* ignore */ }
+{space}+ { yycol += yyleng; /* otherwise ignore */ }
. {
yycol += yyleng;
syntax_error(expr_source, expr_lineno, expr_full_line, expr_command,
"unexpected character", yytext, expr_col + yycol);
- /* dead code, exit is called from syntax_error */
- return CHAR_ERROR;
+ /* NOTREACHED, exit is called from syntax_error */
+ return 0;
}
%%
void
-expr_yyerror_more(const char *message, const char *more)
+expr_yyerror_more(yyscan_t yyscanner, const char *message, const char *more)
{
syntax_error(expr_source, expr_lineno, expr_full_line, expr_command,
message, more, expr_col + yycol);
}
void
-yyerror(const char *message)
+yyerror(yyscan_t yyscanner, const char *message)
{
- expr_yyerror_more(message, NULL);
+ expr_yyerror_more(yyscanner, message, NULL);
}
/*
* Called before any actual parsing is done
*/
-void
+yyscan_t
expr_scanner_init(const char *str, const char *source,
- const int lineno, const char *line,
- const char *cmd, const int ecol)
+ int lineno, const char *line,
+ const char *cmd, int ecol)
{
+ yyscan_t yyscanner;
Size slen = strlen(str);
- /* save context informations for error messages */
- expr_source = (char *) source;
- expr_lineno = (int) lineno;
- expr_full_line = (char *) line;
- expr_command = (char *) cmd;
- expr_col = (int) ecol;
+ /* Set up yyscan_t */
+ yylex_init(&yyscanner);
+
+ /* save context information for error messages */
+ expr_source = source;
+ expr_lineno = lineno;
+ expr_full_line = line;
+ expr_command = cmd;
+ expr_col = ecol;
/* reset error pointers for this scan */
yycol = yyline = 0;
- /*
- * Might be left over after error
- */
- if (YY_CURRENT_BUFFER)
- yy_delete_buffer(YY_CURRENT_BUFFER);
-
/*
* Make a scan buffer with special termination needed by flex.
*/
- scanbuflen = slen;
scanbuf = pg_malloc(slen + 2);
memcpy(scanbuf, str, slen);
scanbuf[slen] = scanbuf[slen + 1] = YY_END_OF_BUFFER_CHAR;
- scanbufhandle = yy_scan_buffer(scanbuf, slen + 2);
+ scanbufhandle = yy_scan_buffer(scanbuf, slen + 2, yyscanner);
- BEGIN(INITIAL);
+ return yyscanner;
}
/*
- * Called after parsing is done to clean up after seg_scanner_init()
+ * Called after parsing is done to clean up after expr_scanner_init()
*/
void
-expr_scanner_finish(void)
+expr_scanner_finish(yyscan_t yyscanner)
{
- yy_delete_buffer(scanbufhandle);
+ yy_delete_buffer(scanbufhandle, yyscanner);
pg_free(scanbuf);
+ yylex_destroy(yyscanner);
+
expr_source = NULL;
expr_lineno = 0;
expr_full_line = NULL;
}
else if (pg_strcasecmp(my_commands->argv[0], "set") == 0)
{
+ yyscan_t yyscanner;
+
if (my_commands->argc < 3)
{
syntax_error(source, lineno, my_commands->line, my_commands->argv[0],
"missing argument", NULL, -1);
}
- expr_scanner_init(my_commands->argv[2], source, lineno,
- my_commands->line, my_commands->argv[0],
- my_commands->cols[2] - 1);
+ yyscanner = expr_scanner_init(my_commands->argv[2],
+ source,
+ lineno,
+ my_commands->line,
+ my_commands->argv[0],
+ my_commands->cols[2] - 1);
- if (expr_yyparse() != 0)
+ if (expr_yyparse(yyscanner) != 0)
{
/* dead code: exit done from syntax_error called by yyerror */
exit(1);
my_commands->expr = expr_parse_result;
- expr_scanner_finish();
+ expr_scanner_finish(yyscanner);
}
else if (pg_strcasecmp(my_commands->argv[0], "sleep") == 0)
{
#ifndef PGBENCH_H
#define PGBENCH_H
+/*
+ * 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".
+ */
+#define yyscan_t void *
+
/* Types of expression nodes */
typedef enum PgBenchExprType
{
extern PgBenchExpr *expr_parse_result;
-extern int expr_yyparse(void);
-extern int expr_yylex(void);
-extern void expr_yyerror(const char *str);
-extern void expr_yyerror_more(const char *str, const char *more);
-extern void expr_scanner_init(const char *str, const char *source,
- const int lineno, const char *line,
- const char *cmd, const int ecol);
+extern int expr_yyparse(yyscan_t yyscanner);
+extern int expr_yylex(yyscan_t yyscanner);
+extern void expr_yyerror(yyscan_t yyscanner, const char *str);
+extern void expr_yyerror_more(yyscan_t yyscanner, const char *str,
+ const char *more);
+extern yyscan_t expr_scanner_init(const char *str, const char *source,
+ int lineno, const char *line,
+ const char *cmd, int ecol);
extern void syntax_error(const char *source, const int lineno, const char *line,
const char *cmd, const char *msg, const char *more,
const int col);
-extern void expr_scanner_finish(void);
+extern void expr_scanner_finish(yyscan_t yyscanner);
extern int64 strtoint64(const char *str);