postgresql/src/test/isolation/specscanner.l

168 lines
3.4 KiB
Plaintext

%top{
/*-------------------------------------------------------------------------
*
* specscanner.l
* a lexical scanner for an isolation test specification
*
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*-------------------------------------------------------------------------
*/
#include "postgres_fe.h"
/*
* NB: include specparse.h only AFTER including isolationtester.h, because
* isolationtester.h includes node definitions needed for YYSTYPE.
*/
#include "isolationtester.h"
#include "specparse.h"
}
%{
static int yyline = 1; /* line number for error reporting */
#define LITBUF_INIT 1024 /* initial size of litbuf */
static char *litbuf = NULL;
static size_t litbufsize = 0;
static size_t litbufpos = 0;
static void addlitchar(char c);
/* LCOV_EXCL_START */
%}
%option 8bit
%option never-interactive
%option nodefault
%option noinput
%option nounput
%option noyywrap
%option warn
%option prefix="spec_yy"
%x sql
%x qident
non_newline [^\n\r]
space [ \t\r\f]
comment ("#"{non_newline}*)
digit [0-9]
ident_start [A-Za-z\200-\377_]
ident_cont [A-Za-z\200-\377_0-9\$]
identifier {ident_start}{ident_cont}*
self [,()*]
%%
%{
/* Allocate litbuf in first call of yylex() */
if (litbuf == NULL)
{
litbuf = pg_malloc(LITBUF_INIT);
litbufsize = LITBUF_INIT;
}
%}
/* Keywords (must appear before the {identifier} rule!) */
notices { return NOTICES; }
permutation { return PERMUTATION; }
session { return SESSION; }
setup { return SETUP; }
step { return STEP; }
teardown { return TEARDOWN; }
/* Whitespace and comments */
[\n] { yyline++; }
{comment} { /* ignore */ }
{space} { /* ignore */ }
/* Plain identifiers */
{identifier} {
spec_yylval.str = pg_strdup(yytext);
return(identifier);
}
/* Quoted identifiers: "foo" */
\" {
litbufpos = 0;
BEGIN(qident);
}
<qident>\"\" { addlitchar(yytext[0]); }
<qident>\" {
litbuf[litbufpos] = '\0';
spec_yylval.str = pg_strdup(litbuf);
BEGIN(INITIAL);
return(identifier);
}
<qident>. { addlitchar(yytext[0]); }
<qident>\n { spec_yyerror("unexpected newline in quoted identifier"); }
<qident><<EOF>> { spec_yyerror("unterminated quoted identifier"); }
/* SQL blocks: { UPDATE ... } */
/* We trim leading/trailing whitespace, otherwise they're unprocessed */
"{"{space}* {
litbufpos = 0;
BEGIN(sql);
}
<sql>{space}*"}" {
litbuf[litbufpos] = '\0';
spec_yylval.str = pg_strdup(litbuf);
BEGIN(INITIAL);
return(sqlblock);
}
<sql>. {
addlitchar(yytext[0]);
}
<sql>\n {
yyline++;
addlitchar(yytext[0]);
}
<sql><<EOF>> {
spec_yyerror("unterminated sql block");
}
/* Numbers and punctuation */
{digit}+ {
spec_yylval.integer = atoi(yytext);
return INTEGER;
}
{self} { return yytext[0]; }
/* Anything else is an error */
. {
fprintf(stderr, "syntax error at line %d: unexpected character \"%s\"\n", yyline, yytext);
exit(1);
}
%%
/* LCOV_EXCL_STOP */
static void
addlitchar(char c)
{
/* We must always leave room to add a trailing \0 */
if (litbufpos >= litbufsize - 1)
{
/* Double the size of litbuf if it gets full */
litbufsize += litbufsize;
litbuf = pg_realloc(litbuf, litbufsize);
}
litbuf[litbufpos++] = c;
}
void
spec_yyerror(const char *message)
{
fprintf(stderr, "%s at line %d\n", message, yyline);
exit(1);
}