v0-0004-seg-pure-parser-and-reentrant-scanner.patch

text/plain

Filename: v0-0004-seg-pure-parser-and-reentrant-scanner.patch
Type: text/plain
Part: 3
Message: pure parsers and reentrant scanners

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: format-patch
Series: patch v0-0004
Subject: seg: pure parser and reentrant scanner
File+
contrib/seg/seg.c 5 4
contrib/seg/segdata.h 9 4
contrib/seg/segparse.y 5 4
contrib/seg/segscan.l 22 25
From 7a4cd3ffee3009a5f6f5cbfd2fed362e6b87ad2c Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Mon, 2 Dec 2024 10:35:37 +0100
Subject: [PATCH v0 04/15] 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