1 %{
2 /*-------------------------------------------------------------------------
3  *
4  * specscanner.l
5  *	  a lexical scanner for an isolation test specification
6  *
7  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  *-------------------------------------------------------------------------
11  */
12 
13 static int	yyline = 1;			/* line number for error reporting */
14 
15 #define LITBUF_INIT	1024		/* initial size of litbuf */
16 static char *litbuf = NULL;
17 static size_t litbufsize = 0;
18 static size_t litbufpos = 0;
19 
20 static void addlitchar(char c);
21 
22 /* LCOV_EXCL_START */
23 
24 %}
25 
26 %option 8bit
27 %option never-interactive
28 %option nodefault
29 %option noinput
30 %option nounput
31 %option noyywrap
32 %option warn
33 %option prefix="spec_yy"
34 
35 
36 %x sql
37 %x qident
38 
39 non_newline		[^\n\r]
40 space			[ \t\r\f]
41 
42 comment			("#"{non_newline}*)
43 
44 digit			[0-9]
45 ident_start		[A-Za-z\200-\377_]
46 ident_cont		[A-Za-z\200-\377_0-9\$]
47 
48 identifier		{ident_start}{ident_cont}*
49 
50 self			[,()*]
51 
52 %%
53 
54 %{
55 	/* Allocate litbuf in first call of yylex() */
56 	if (litbuf == NULL)
57 	{
58 		litbuf = pg_malloc(LITBUF_INIT);
59 		litbufsize = LITBUF_INIT;
60 	}
61 %}
62 
63  /* Keywords (must appear before the {identifier} rule!) */
64 notices			{ return NOTICES; }
65 permutation		{ return PERMUTATION; }
66 session			{ return SESSION; }
67 setup			{ return SETUP; }
68 step			{ return STEP; }
69 teardown		{ return TEARDOWN; }
70 
71  /* Whitespace and comments */
72 [\n]			{ yyline++; }
73 {comment}		{ /* ignore */ }
74 {space}			{ /* ignore */ }
75 
76  /* Plain identifiers */
77 {identifier}	{
78 					yylval.str = pg_strdup(yytext);
79 					return(identifier);
80 				}
81 
82  /* Quoted identifiers: "foo" */
83 \"				{
84 					litbufpos = 0;
85 					BEGIN(qident);
86 				}
87 <qident>\"\"	{ addlitchar(yytext[0]); }
88 <qident>\"		{
89 					litbuf[litbufpos] = '\0';
90 					yylval.str = pg_strdup(litbuf);
91 					BEGIN(INITIAL);
92 					return(identifier);
93 				}
94 <qident>.		{ addlitchar(yytext[0]); }
95 <qident>\n		{ yyerror("unexpected newline in quoted identifier"); }
96 <qident><<EOF>>	{ yyerror("unterminated quoted identifier"); }
97 
98  /* SQL blocks: { UPDATE ... } */
99  /* We trim leading/trailing whitespace, otherwise they're unprocessed */
100 "{"{space}*		{
101 
102 					litbufpos = 0;
103 					BEGIN(sql);
104 				}
105 <sql>{space}*"}" {
106 					litbuf[litbufpos] = '\0';
107 					yylval.str = pg_strdup(litbuf);
108 					BEGIN(INITIAL);
109 					return(sqlblock);
110 				}
111 <sql>.			{
112 					addlitchar(yytext[0]);
113 				}
114 <sql>\n			{
115 					yyline++;
116 					addlitchar(yytext[0]);
117 				}
118 <sql><<EOF>>	{
119 					yyerror("unterminated sql block");
120 				}
121 
122  /* Numbers and punctuation */
123 {digit}+		{
124 					yylval.integer = atoi(yytext);
125 					return INTEGER;
126 				}
127 
128 {self}			{ return yytext[0]; }
129 
130  /* Anything else is an error */
131 .				{
132 					fprintf(stderr, "syntax error at line %d: unexpected character \"%s\"\n", yyline, yytext);
133 					exit(1);
134 				}
135 %%
136 
137 /* LCOV_EXCL_STOP */
138 
139 static void
140 addlitchar(char c)
141 {
142 	/* We must always leave room to add a trailing \0 */
143 	if (litbufpos >= litbufsize - 1)
144 	{
145 		/* Double the size of litbuf if it gets full */
146 		litbufsize += litbufsize;
147 		litbuf = pg_realloc(litbuf, litbufsize);
148 	}
149 	litbuf[litbufpos++] = c;
150 }
151 
152 void
153 yyerror(const char *message)
154 {
155 	fprintf(stderr, "%s at line %d\n", message, yyline);
156 	exit(1);
157 }
158