| %{ |
| /*------------------------------------------------------------------------- |
| * |
| * specscanner.l |
| * a lexical scanner for an isolation test specification |
| * |
| * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group |
| * Portions Copyright (c) 1994, Regents of the University of California |
| * |
| *------------------------------------------------------------------------- |
| */ |
| |
| 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} { |
| yylval.str = pg_strdup(yytext); |
| return(identifier); |
| } |
| |
| /* Quoted identifiers: "foo" */ |
| \" { |
| litbufpos = 0; |
| BEGIN(qident); |
| } |
| <qident>\"\" { addlitchar(yytext[0]); } |
| <qident>\" { |
| litbuf[litbufpos] = '\0'; |
| yylval.str = pg_strdup(litbuf); |
| BEGIN(INITIAL); |
| return(identifier); |
| } |
| <qident>. { addlitchar(yytext[0]); } |
| <qident>\n { yyerror("unexpected newline in quoted identifier"); } |
| <qident><<EOF>> { 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'; |
| yylval.str = pg_strdup(litbuf); |
| BEGIN(INITIAL); |
| return(sqlblock); |
| } |
| <sql>. { |
| addlitchar(yytext[0]); |
| } |
| <sql>\n { |
| yyline++; |
| addlitchar(yytext[0]); |
| } |
| <sql><<EOF>> { |
| yyerror("unterminated sql block"); |
| } |
| |
| /* Numbers and punctuation */ |
| {digit}+ { |
| 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 |
| yyerror(const char *message) |
| { |
| fprintf(stderr, "%s at line %d\n", message, yyline); |
| exit(1); |
| } |