From 2ddc3321d6357d6533177ba5c086ebdf879102dd Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Mon, 2 Dec 2024 10:35:37 +0100 Subject: [PATCH v1 04/19] seg: pure parser and reentrant scanner --- contrib/seg/seg.c | 9 ++++---- contrib/seg/segdata.h | 13 ++++++++---- contrib/seg/segparse.y | 9 ++++---- contrib/seg/segscan.l | 47 ++++++++++++++++++++---------------------- 4 files changed, 41 insertions(+), 37 deletions(-) diff --git a/contrib/seg/seg.c b/contrib/seg/seg.c index 7f9fc24eb4b..fd4216edc5d 100644 --- a/contrib/seg/seg.c +++ b/contrib/seg/seg.c @@ -105,13 +105,14 @@ seg_in(PG_FUNCTION_ARGS) { char *str = PG_GETARG_CSTRING(0); SEG *result = palloc(sizeof(SEG)); + yyscan_t scanner; - seg_scanner_init(str); + seg_scanner_init(str, &scanner); - if (seg_yyparse(result, fcinfo->context) != 0) - seg_yyerror(result, fcinfo->context, "bogus input"); + if (seg_yyparse(result, fcinfo->context, scanner) != 0) + seg_yyerror(result, fcinfo->context, scanner, "bogus input"); - seg_scanner_finish(); + seg_scanner_finish(scanner); PG_RETURN_POINTER(result); } diff --git a/contrib/seg/segdata.h b/contrib/seg/segdata.h index 3d6e3e3f245..7bc7c83dca3 100644 --- a/contrib/seg/segdata.h +++ b/contrib/seg/segdata.h @@ -14,12 +14,17 @@ typedef struct SEG /* in seg.c */ extern int significant_digits(const char *s); +/* for segscan.l and segparse.y */ +union YYSTYPE; +typedef void *yyscan_t; + /* in segscan.l */ -extern int seg_yylex(void); +extern int seg_yylex(union YYSTYPE *yylval_param, yyscan_t yyscanner); extern void seg_yyerror(SEG *result, struct Node *escontext, + yyscan_t yyscanner, const char *message); -extern void seg_scanner_init(const char *str); -extern void seg_scanner_finish(void); +extern void seg_scanner_init(const char *str, yyscan_t *yyscannerp); +extern void seg_scanner_finish(yyscan_t yyscanner); /* in segparse.y */ -extern int seg_yyparse(SEG *result, struct Node *escontext); +extern int seg_yyparse(SEG *result, struct Node *escontext, yyscan_t yyscanner); diff --git a/contrib/seg/segparse.y b/contrib/seg/segparse.y index 3e4aa31cada..0358ddb182c 100644 --- a/contrib/seg/segparse.y +++ b/contrib/seg/segparse.y @@ -14,10 +14,6 @@ #include "segdata.h" #include "segparse.h" -/* silence -Wmissing-variable-declarations */ -extern int seg_yychar; -extern int seg_yynerrs; - /* * Bison doesn't allocate anything that needs to live across parser calls, * so we can easily have it use palloc instead of malloc. This prevents @@ -35,6 +31,9 @@ static int sig_digits(const char *value); /* BISON Declarations */ %parse-param {SEG *result} %parse-param {struct Node *escontext} +%parse-param {yyscan_t yyscanner} +%lex-param {yyscan_t yyscanner} +%pure-parser %expect 0 %name-prefix="seg_yy" @@ -72,6 +71,8 @@ range: boundary PLUMIN deviation result->u_sigd = Max(sig_digits(strbuf), Max($1.sigd, $3.sigd)); result->l_ext = '\0'; result->u_ext = '\0'; + + (void) yynerrs; /* suppress compiler warning */ } | boundary RANGE boundary diff --git a/contrib/seg/segscan.l b/contrib/seg/segscan.l index 4ad529eccc4..35c3a11ac14 100644 --- a/contrib/seg/segscan.l +++ b/contrib/seg/segscan.l @@ -6,12 +6,8 @@ #include "nodes/miscnodes.h" -/* - * NB: include segparse.h only AFTER including segdata.h, because segdata.h - * contains the definition for SEG. - */ #include "segdata.h" -#include "segparse.h" +#include "segparse.h" /* must be after segdata.h SEG */ } %{ @@ -31,10 +27,11 @@ fprintf_to_ereport(const char *fmt, const char *msg) } /* Handles to the buffer that the lexer uses internally */ -static YY_BUFFER_STATE scanbufhandle; -static char *scanbuf; +static char *scanbuf; // FIXME %} +%option reentrant +%option bison-bridge %option 8bit %option never-interactive %option nodefault @@ -53,12 +50,12 @@ float ({integer}|{real})([eE]{integer})? %% -{range} seg_yylval.text = yytext; return RANGE; -{plumin} seg_yylval.text = yytext; return PLUMIN; -{float} seg_yylval.text = yytext; return SEGFLOAT; -\< seg_yylval.text = "<"; return EXTENSION; -\> seg_yylval.text = ">"; return EXTENSION; -\~ seg_yylval.text = "~"; return EXTENSION; +{range} yylval->text = yytext; return RANGE; +{plumin} yylval->text = yytext; return PLUMIN; +{float} yylval->text = yytext; return SEGFLOAT; +\< yylval->text = "<"; return EXTENSION; +\> yylval->text = ">"; return EXTENSION; +\~ yylval->text = "~"; return EXTENSION; [ \t\n\r\f\v]+ /* discard spaces */ . return yytext[0]; /* alert parser of the garbage */ @@ -67,8 +64,10 @@ float ({integer}|{real})([eE]{integer})? /* LCOV_EXCL_STOP */ void -seg_yyerror(SEG *result, struct Node *escontext, const char *message) +seg_yyerror(SEG *result, struct Node *escontext, yyscan_t yyscanner, const char *message) { + struct yyguts_t * yyg = (struct yyguts_t *) yyscanner; /* needed for yytext macro */ + /* if we already reported an error, don't overwrite it */ if (SOFT_ERROR_OCCURRED(escontext)) return; @@ -96,15 +95,15 @@ seg_yyerror(SEG *result, struct Node *escontext, const char *message) * Called before any actual parsing is done */ void -seg_scanner_init(const char *str) +seg_scanner_init(const char *str, yyscan_t *yyscannerp) { Size slen = strlen(str); + yyscan_t yyscanner; - /* - * Might be left over after ereport() - */ - if (YY_CURRENT_BUFFER) - yy_delete_buffer(YY_CURRENT_BUFFER); + if (yylex_init(yyscannerp) != 0) + elog(ERROR, "yylex_init() failed: %m"); + + yyscanner = *yyscannerp; /* * Make a scan buffer with special termination needed by flex. @@ -112,9 +111,7 @@ seg_scanner_init(const char *str) scanbuf = palloc(slen + 2); memcpy(scanbuf, str, slen); scanbuf[slen] = scanbuf[slen + 1] = YY_END_OF_BUFFER_CHAR; - scanbufhandle = yy_scan_buffer(scanbuf, slen + 2); - - BEGIN(INITIAL); + yy_scan_buffer(scanbuf, slen + 2, yyscanner); } @@ -122,8 +119,8 @@ seg_scanner_init(const char *str) * Called after parsing is done to clean up after seg_scanner_init() */ void -seg_scanner_finish(void) +seg_scanner_finish(yyscan_t yyscanner) { - yy_delete_buffer(scanbufhandle); + yylex_destroy(yyscanner); pfree(scanbuf); } -- 2.47.1