testlang_conf.l revision 1.27 1 1.1 blymn %{
2 1.27 rillig /* $NetBSD: testlang_conf.l,v 1.27 2023/12/10 18:04:55 rillig Exp $ */
3 1.1 blymn
4 1.1 blymn /*-
5 1.1 blymn * Copyright 2009 Brett Lymn <blymn (at) NetBSD.org>
6 1.20 rillig * Copyright 2021 Roland Illig <rillig (at) NetBSD.org>
7 1.1 blymn *
8 1.1 blymn * All rights reserved.
9 1.1 blymn *
10 1.1 blymn * This code has been donated to The NetBSD Foundation by the Author.
11 1.1 blymn *
12 1.1 blymn * Redistribution and use in source and binary forms, with or without
13 1.1 blymn * modification, are permitted provided that the following conditions
14 1.1 blymn * are met:
15 1.1 blymn * 1. Redistributions of source code must retain the above copyright
16 1.1 blymn * notice, this list of conditions and the following disclaimer.
17 1.1 blymn * 2. The name of the author may not be used to endorse or promote products
18 1.17 rillig * derived from this software without specific prior written permission
19 1.1 blymn *
20 1.1 blymn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 1.1 blymn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 1.1 blymn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 1.1 blymn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 1.1 blymn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 1.1 blymn * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 1.1 blymn * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 1.1 blymn * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 1.1 blymn * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 1.1 blymn * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 1.1 blymn */
31 1.1 blymn
32 1.1 blymn #include <curses.h>
33 1.3 christos #include <ctype.h>
34 1.1 blymn #include <stdio.h>
35 1.1 blymn #include <stdlib.h>
36 1.1 blymn #include <string.h>
37 1.1 blymn #include <sys/param.h>
38 1.1 blymn #include <err.h>
39 1.1 blymn #include "returns.h"
40 1.1 blymn #include "testlang_parse.h"
41 1.1 blymn
42 1.1 blymn #define MAX_INCLUDES 32 /* limit for the number of nested includes */
43 1.1 blymn
44 1.1 blymn int yylex(void);
45 1.1 blymn
46 1.1 blymn extern size_t line;
47 1.1 blymn extern char *cur_file; /* from director.c */
48 1.1 blymn
49 1.1 blymn static int include_stack[MAX_INCLUDES];
50 1.1 blymn static char *include_files[MAX_INCLUDES];
51 1.1 blymn static int include_ptr = 0;
52 1.1 blymn
53 1.1 blymn static char *
54 1.1 blymn dequote(const char *s, size_t *len)
55 1.1 blymn {
56 1.4 christos const unsigned char *p;
57 1.4 christos char *buf, *q;
58 1.1 blymn
59 1.1 blymn *len = 0;
60 1.4 christos p = (const unsigned char *)s;
61 1.1 blymn while (*p) {
62 1.24 rillig if (*p == '\\' && p[1]) {
63 1.24 rillig if (isdigit(p[1]) && isdigit(p[2]) && isdigit(p[3]))
64 1.1 blymn p += 3;
65 1.1 blymn else
66 1.1 blymn ++p;
67 1.1 blymn }
68 1.1 blymn ++(*len);
69 1.1 blymn ++p;
70 1.1 blymn }
71 1.1 blymn
72 1.1 blymn buf = malloc(*len + 1);
73 1.1 blymn if (buf == NULL)
74 1.1 blymn return NULL;
75 1.1 blymn
76 1.4 christos p = (const unsigned char *)s;
77 1.1 blymn q = buf;
78 1.1 blymn while (*p) {
79 1.24 rillig if (*p == '\\' && p[1]) {
80 1.1 blymn ++p;
81 1.23 rillig
82 1.24 rillig if (isdigit(p[0])) {
83 1.24 rillig if (isdigit(p[1]) && isdigit(p[2])) {
84 1.24 rillig *q++ = (p[0] - '0') * 64 +
85 1.24 rillig (p[1] - '0') * 8 +
86 1.24 rillig (p[2] - '0');
87 1.1 blymn p += 3;
88 1.1 blymn } else {
89 1.27 rillig errx(2,
90 1.27 rillig "%s:%zu: Invalid escape sequence "
91 1.27 rillig "'\\%c' in string literal; octal "
92 1.27 rillig "numbers must be 3 digits wide",
93 1.27 rillig cur_file, line, *p);
94 1.1 blymn }
95 1.23 rillig continue;
96 1.23 rillig }
97 1.23 rillig
98 1.23 rillig switch (*p) {
99 1.26 blymn case 'b':
100 1.26 blymn /* backspace */
101 1.26 blymn *q++ = '\b';
102 1.26 blymn p++;
103 1.26 blymn break;
104 1.26 blymn
105 1.23 rillig case 'e':
106 1.23 rillig /* escape */
107 1.23 rillig *q++ = '\e';
108 1.23 rillig p++;
109 1.23 rillig break;
110 1.23 rillig
111 1.23 rillig case 'n':
112 1.23 rillig /* newline */
113 1.23 rillig *q++ = '\n';
114 1.23 rillig p++;
115 1.23 rillig break;
116 1.23 rillig
117 1.23 rillig case 'r':
118 1.23 rillig /* carriage return */
119 1.23 rillig *q++ = '\r';
120 1.23 rillig p++;
121 1.23 rillig break;
122 1.23 rillig
123 1.23 rillig case 't':
124 1.23 rillig /* tab */
125 1.23 rillig *q++ = '\t';
126 1.23 rillig p++;
127 1.23 rillig break;
128 1.23 rillig
129 1.23 rillig case '\\':
130 1.23 rillig /* backslash */
131 1.23 rillig *q++ = '\\';
132 1.23 rillig p++;
133 1.23 rillig break;
134 1.23 rillig
135 1.23 rillig default:
136 1.23 rillig if (isalpha(*p))
137 1.23 rillig errx(2,
138 1.25 rillig "%s:%zu: Invalid escape sequence "
139 1.25 rillig "'\\%c' in string literal",
140 1.23 rillig cur_file, line, *p);
141 1.23 rillig *q++ = *p++;
142 1.1 blymn }
143 1.1 blymn } else
144 1.1 blymn *q++ = *p++;
145 1.1 blymn }
146 1.1 blymn *q++ = '\0';
147 1.1 blymn
148 1.1 blymn return buf;
149 1.1 blymn }
150 1.1 blymn %}
151 1.1 blymn
152 1.1 blymn HEX 0[xX][0-9a-zA-Z]+
153 1.1 blymn STRING [0-9a-z!#-&(-^ \t%._\\]+
154 1.1 blymn numeric [-0-9]+
155 1.15 rillig PCHAR (\\.|[!-~])
156 1.13 rillig ASSIGN assign
157 1.13 rillig CALL2 call2
158 1.13 rillig CALL3 call3
159 1.13 rillig CALL4 call4
160 1.13 rillig CALL call
161 1.13 rillig CHECK check
162 1.13 rillig DELAY delay
163 1.13 rillig INPUT input
164 1.13 rillig NOINPUT noinput
165 1.13 rillig OK_RET OK
166 1.13 rillig ERR_RET ERR
167 1.13 rillig COMPARE compare
168 1.13 rillig COMPAREND comparend
169 1.1 blymn FILENAME [A-Za-z0-9.][A-Za-z0-9./_-]+
170 1.1 blymn VARNAME [A-Za-z][A-Za-z0-9_-]+
171 1.1 blymn NULL_RET NULL
172 1.1 blymn NON_NULL NON_NULL
173 1.13 rillig CCHAR cchar
174 1.13 rillig WCHAR wchar
175 1.1 blymn BYTE BYTE
176 1.1 blymn OR \|
177 1.12 rillig LPAREN \(
178 1.12 rillig RPAREN \)
179 1.12 rillig LBRACK \[
180 1.12 rillig RBRACK \]
181 1.8 blymn MULTIPLIER \*
182 1.16 rillig COMMA ,
183 1.1 blymn
184 1.1 blymn %x incl
185 1.5 joerg %option noinput nounput
186 1.1 blymn
187 1.1 blymn %%
188 1.1 blymn
189 1.1 blymn include BEGIN(incl);
190 1.1 blymn
191 1.10 rillig <incl>[ \t]* /* eat the whitespace */
192 1.10 rillig <incl>[^ \t\n]+ { /* got the include file name */
193 1.19 rillig char *inc_file;
194 1.1 blymn
195 1.1 blymn if (include_ptr > MAX_INCLUDES) {
196 1.25 rillig errx(2,
197 1.25 rillig "%s:%zu: Maximum number of nested includes "
198 1.25 rillig "exceeded", cur_file, line);
199 1.1 blymn }
200 1.1 blymn
201 1.19 rillig const char *dir_begin;
202 1.19 rillig int dir_len;
203 1.19 rillig if (yytext[0] == '/') {
204 1.19 rillig dir_begin = "";
205 1.19 rillig dir_len = 0;
206 1.1 blymn } else {
207 1.19 rillig dir_begin = cur_file;
208 1.19 rillig const char *dir_end = strrchr(cur_file, '/');
209 1.19 rillig if (dir_end != NULL) {
210 1.19 rillig dir_len = (int)(dir_end + 1 - dir_begin);
211 1.19 rillig } else {
212 1.19 rillig dir_begin = ".";
213 1.19 rillig dir_len = 1;
214 1.19 rillig }
215 1.1 blymn }
216 1.1 blymn
217 1.19 rillig if (asprintf(&inc_file, "%.*s%s",
218 1.19 rillig dir_len, dir_begin, yytext) == -1)
219 1.19 rillig err(2, "Cannot construct include path");
220 1.1 blymn
221 1.19 rillig yyin = fopen(inc_file, "r");
222 1.1 blymn
223 1.4 christos if (!yyin)
224 1.4 christos err(1, "Error opening %s", inc_file);
225 1.1 blymn
226 1.1 blymn yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE));
227 1.1 blymn
228 1.1 blymn include_stack[include_ptr] = line;
229 1.1 blymn include_files[include_ptr++] = cur_file;
230 1.19 rillig cur_file = inc_file;
231 1.18 rillig line = 1;
232 1.1 blymn BEGIN(INITIAL);
233 1.1 blymn }
234 1.1 blymn
235 1.1 blymn <<EOF>> {
236 1.1 blymn yypop_buffer_state();
237 1.1 blymn
238 1.10 rillig if (!YY_CURRENT_BUFFER)
239 1.1 blymn yyterminate();
240 1.1 blymn
241 1.1 blymn if (--include_ptr < 0)
242 1.21 rillig errx(2, "Include stack underflow");
243 1.1 blymn
244 1.1 blymn free(cur_file);
245 1.1 blymn cur_file = include_files[include_ptr];
246 1.1 blymn line = include_stack[include_ptr];
247 1.1 blymn }
248 1.1 blymn
249 1.10 rillig {ASSIGN} return ASSIGN;
250 1.10 rillig {CALL2} return CALL2;
251 1.10 rillig {CALL3} return CALL3;
252 1.10 rillig {CALL4} return CALL4;
253 1.10 rillig {CALL} return CALL;
254 1.10 rillig {CHECK} return CHECK;
255 1.10 rillig {DELAY} return DELAY;
256 1.10 rillig {INPUT} return INPUT;
257 1.10 rillig {NOINPUT} return NOINPUT;
258 1.10 rillig {COMPARE} return COMPARE;
259 1.10 rillig {COMPAREND} return COMPAREND;
260 1.10 rillig {NON_NULL} return NON_NULL;
261 1.10 rillig {NULL_RET} return NULL_RET;
262 1.10 rillig {OK_RET} return OK_RET;
263 1.10 rillig {ERR_RET} return ERR_RET;
264 1.10 rillig {MULTIPLIER} return MULTIPLIER;
265 1.16 rillig {COMMA} return COMMA;
266 1.10 rillig {CCHAR} return CCHAR;
267 1.10 rillig {WCHAR} return WCHAR;
268 1.10 rillig {OR} return OR;
269 1.12 rillig {LPAREN} return LPAREN;
270 1.12 rillig {RPAREN} return RPAREN;
271 1.12 rillig {LBRACK} return LBRACK;
272 1.12 rillig {RBRACK} return RBRACK;
273 1.8 blymn
274 1.1 blymn {HEX} {
275 1.1 blymn /* Hex value, convert to decimal and return numeric */
276 1.1 blymn unsigned long val;
277 1.1 blymn
278 1.1 blymn if (sscanf(yytext, "%lx", &val) != 1)
279 1.21 rillig errx(1, "Bad hex conversion");
280 1.1 blymn
281 1.1 blymn asprintf(&yylval.string, "%ld", val);
282 1.1 blymn return numeric;
283 1.1 blymn }
284 1.1 blymn
285 1.10 rillig {numeric} {
286 1.1 blymn if ((yylval.string = strdup(yytext)) == NULL)
287 1.1 blymn err(1, "Cannot allocate numeric string");
288 1.1 blymn return numeric;
289 1.10 rillig }
290 1.1 blymn
291 1.1 blymn {VARNAME} {
292 1.1 blymn if ((yylval.string = strdup(yytext)) == NULL)
293 1.1 blymn err(1, "Cannot allocate string for varname");
294 1.1 blymn return VARNAME;
295 1.1 blymn }
296 1.1 blymn
297 1.1 blymn {FILENAME} {
298 1.1 blymn size_t len;
299 1.1 blymn
300 1.1 blymn if ((yylval.string = dequote(yytext, &len)) == NULL)
301 1.1 blymn err(1, "Cannot allocate filename string");
302 1.1 blymn return FILENAME;
303 1.1 blymn }
304 1.1 blymn
305 1.1 blymn /* path */
306 1.1 blymn \/{PCHAR}+ {
307 1.1 blymn size_t len;
308 1.1 blymn if ((yylval.string = dequote(yytext, &len)) == NULL)
309 1.1 blymn err(1, "Cannot allocate string");
310 1.1 blymn return PATH;
311 1.1 blymn }
312 1.1 blymn
313 1.1 blymn \'{STRING}\' {
314 1.1 blymn char *p;
315 1.1 blymn size_t len;
316 1.1 blymn
317 1.8 blymn if ((yylval.retval = malloc(sizeof(ct_data_t))) == NULL)
318 1.1 blymn err(1, "Cannot allocate return struct");
319 1.1 blymn p = yytext;
320 1.1 blymn p++; /* skip the leading ' */
321 1.8 blymn if ((yylval.retval->data_value = dequote(p, &len))
322 1.1 blymn == NULL)
323 1.1 blymn err(1, "Cannot allocate string");
324 1.1 blymn
325 1.8 blymn yylval.retval->data_type = data_byte;
326 1.1 blymn /* trim trailing ' */
327 1.8 blymn yylval.retval->data_len = len - 1;
328 1.1 blymn return BYTE;
329 1.1 blymn }
330 1.1 blymn
331 1.1 blymn \`{STRING}\` {
332 1.1 blymn char *p, *str;
333 1.1 blymn size_t len, chlen;
334 1.4 christos size_t i;
335 1.1 blymn chtype *rv;
336 1.1 blymn
337 1.8 blymn if ((yylval.retval = malloc(sizeof(ct_data_t))) == NULL)
338 1.1 blymn err(1, "Cannot allocate return struct");
339 1.1 blymn p = yytext;
340 1.9 blymn p++; /* skip the leading ` */
341 1.1 blymn if ((str = dequote(p, &len)) == NULL)
342 1.1 blymn err(1, "Cannot allocate string");
343 1.1 blymn len--; /* trim trailing ` */
344 1.1 blymn if ((len % 2) != 0)
345 1.1 blymn len--;
346 1.1 blymn
347 1.1 blymn chlen = ((len / 2) + 1) * sizeof(chtype);
348 1.8 blymn if ((yylval.retval->data_value = malloc(chlen))
349 1.1 blymn == NULL)
350 1.1 blymn err(1, "Cannot allocate chtype array");
351 1.1 blymn
352 1.8 blymn rv = yylval.retval->data_value;
353 1.1 blymn for (i = 0; i < len; i += 2)
354 1.1 blymn *rv++ = (str[i] << 8) | str[i+1];
355 1.19 rillig *rv = __NORMAL | '\0'; /* terminates chtype array */
356 1.8 blymn yylval.retval->data_type = data_byte;
357 1.8 blymn yylval.retval->data_len = chlen;
358 1.1 blymn return BYTE;
359 1.1 blymn }
360 1.1 blymn
361 1.1 blymn \"{STRING}\" {
362 1.1 blymn char *p;
363 1.1 blymn size_t len;
364 1.1 blymn
365 1.1 blymn p = yytext;
366 1.1 blymn p++; /* skip the leading " */
367 1.1 blymn if ((yylval.string = dequote(p, &len)) == NULL)
368 1.1 blymn err(1, "Cannot allocate string");
369 1.1 blymn
370 1.1 blymn /* remove trailing " */
371 1.1 blymn yylval.string[len - 1] = '\0';
372 1.1 blymn return STRING;
373 1.1 blymn }
374 1.1 blymn
375 1.1 blymn \${VARNAME} {
376 1.1 blymn char *p;
377 1.1 blymn
378 1.1 blymn p = yytext;
379 1.1 blymn p++; /* skip $ before var name */
380 1.1 blymn if ((yylval.string = strdup(p)) == NULL)
381 1.1 blymn err(1, "Cannot allocate string for varname");
382 1.1 blymn return VARIABLE;
383 1.1 blymn }
384 1.10 rillig
385 1.11 rillig /* whitespace, comments */
386 1.1 blymn [ \t\r] |
387 1.1 blymn #.* ;
388 1.11 rillig
389 1.11 rillig ^[ \t\r]*#.*\n |
390 1.1 blymn \\\n |
391 1.10 rillig ^\n line++;
392 1.1 blymn
393 1.1 blymn /* eol on a line with data. need to process, return eol */
394 1.11 rillig #.*\n |
395 1.1 blymn \n {
396 1.1 blymn line++;
397 1.1 blymn return EOL;
398 1.1 blymn }
399 1.1 blymn
400 1.1 blymn . {
401 1.14 rillig if (isprint((unsigned char)yytext[0]))
402 1.14 rillig errx(1, "%s:%zu: Invalid character '%c'",
403 1.14 rillig cur_file, line + 1, yytext[0]);
404 1.14 rillig else
405 1.14 rillig errx(1, "%s:%zu: Invalid character '0x%02x'",
406 1.14 rillig cur_file, line + 1, yytext[0]);
407 1.1 blymn }
408 1.1 blymn
409 1.1 blymn %%
410 1.1 blymn
411 1.1 blymn int
412 1.1 blymn yywrap(void)
413 1.1 blymn {
414 1.1 blymn return 1;
415 1.1 blymn }
416