summaryrefslogtreecommitdiffstats
path: root/src/test/isolation/specscanner.l
blob: aa6e89268ef069377411335e0d60dabf4c4c5f8a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
%{
/*-------------------------------------------------------------------------
 *
 * specscanner.l
 *	  a lexical scanner for an isolation test specification
 *
 * Portions Copyright (c) 1996-2022, 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);
}