testlang_conf.l revision 1.25 1 1.1 blymn %{
2 1.25 rillig /* $NetBSD: testlang_conf.l,v 1.25 2021/02/25 00:50:10 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.1 blymn *q++ = *p++;
90 1.1 blymn }
91 1.23 rillig continue;
92 1.23 rillig }
93 1.23 rillig
94 1.23 rillig switch (*p) {
95 1.23 rillig case 'e':
96 1.23 rillig /* escape */
97 1.23 rillig *q++ = '\e';
98 1.23 rillig p++;
99 1.23 rillig break;
100 1.23 rillig
101 1.23 rillig case 'n':
102 1.23 rillig /* newline */
103 1.23 rillig *q++ = '\n';
104 1.23 rillig p++;
105 1.23 rillig break;
106 1.23 rillig
107 1.23 rillig case 'r':
108 1.23 rillig /* carriage return */
109 1.23 rillig *q++ = '\r';
110 1.23 rillig p++;
111 1.23 rillig break;
112 1.23 rillig
113 1.23 rillig case 't':
114 1.23 rillig /* tab */
115 1.23 rillig *q++ = '\t';
116 1.23 rillig p++;
117 1.23 rillig break;
118 1.23 rillig
119 1.23 rillig case '\\':
120 1.23 rillig /* backslash */
121 1.23 rillig *q++ = '\\';
122 1.23 rillig p++;
123 1.23 rillig break;
124 1.23 rillig
125 1.23 rillig default:
126 1.23 rillig if (isalpha(*p))
127 1.23 rillig errx(2,
128 1.25 rillig "%s:%zu: Invalid escape sequence "
129 1.25 rillig "'\\%c' in string literal",
130 1.23 rillig cur_file, line, *p);
131 1.23 rillig *q++ = *p++;
132 1.1 blymn }
133 1.1 blymn } else
134 1.1 blymn *q++ = *p++;
135 1.1 blymn }
136 1.1 blymn *q++ = '\0';
137 1.1 blymn
138 1.1 blymn return buf;
139 1.1 blymn }
140 1.1 blymn %}
141 1.1 blymn
142 1.1 blymn HEX 0[xX][0-9a-zA-Z]+
143 1.1 blymn STRING [0-9a-z!#-&(-^ \t%._\\]+
144 1.1 blymn numeric [-0-9]+
145 1.15 rillig PCHAR (\\.|[!-~])
146 1.13 rillig ASSIGN assign
147 1.13 rillig CALL2 call2
148 1.13 rillig CALL3 call3
149 1.13 rillig CALL4 call4
150 1.13 rillig CALL call
151 1.13 rillig CHECK check
152 1.13 rillig DELAY delay
153 1.13 rillig INPUT input
154 1.13 rillig NOINPUT noinput
155 1.13 rillig OK_RET OK
156 1.13 rillig ERR_RET ERR
157 1.13 rillig COMPARE compare
158 1.13 rillig COMPAREND comparend
159 1.1 blymn FILENAME [A-Za-z0-9.][A-Za-z0-9./_-]+
160 1.1 blymn VARNAME [A-Za-z][A-Za-z0-9_-]+
161 1.1 blymn NULL_RET NULL
162 1.1 blymn NON_NULL NON_NULL
163 1.13 rillig CCHAR cchar
164 1.13 rillig WCHAR wchar
165 1.1 blymn BYTE BYTE
166 1.1 blymn OR \|
167 1.12 rillig LPAREN \(
168 1.12 rillig RPAREN \)
169 1.12 rillig LBRACK \[
170 1.12 rillig RBRACK \]
171 1.8 blymn MULTIPLIER \*
172 1.16 rillig COMMA ,
173 1.1 blymn
174 1.1 blymn %x incl
175 1.5 joerg %option noinput nounput
176 1.1 blymn
177 1.1 blymn %%
178 1.1 blymn
179 1.1 blymn include BEGIN(incl);
180 1.1 blymn
181 1.10 rillig <incl>[ \t]* /* eat the whitespace */
182 1.10 rillig <incl>[^ \t\n]+ { /* got the include file name */
183 1.19 rillig char *inc_file;
184 1.1 blymn
185 1.1 blymn if (include_ptr > MAX_INCLUDES) {
186 1.25 rillig errx(2,
187 1.25 rillig "%s:%zu: Maximum number of nested includes "
188 1.25 rillig "exceeded", cur_file, line);
189 1.1 blymn }
190 1.1 blymn
191 1.19 rillig const char *dir_begin;
192 1.19 rillig int dir_len;
193 1.19 rillig if (yytext[0] == '/') {
194 1.19 rillig dir_begin = "";
195 1.19 rillig dir_len = 0;
196 1.1 blymn } else {
197 1.19 rillig dir_begin = cur_file;
198 1.19 rillig const char *dir_end = strrchr(cur_file, '/');
199 1.19 rillig if (dir_end != NULL) {
200 1.19 rillig dir_len = (int)(dir_end + 1 - dir_begin);
201 1.19 rillig } else {
202 1.19 rillig dir_begin = ".";
203 1.19 rillig dir_len = 1;
204 1.19 rillig }
205 1.1 blymn }
206 1.1 blymn
207 1.19 rillig if (asprintf(&inc_file, "%.*s%s",
208 1.19 rillig dir_len, dir_begin, yytext) == -1)
209 1.19 rillig err(2, "Cannot construct include path");
210 1.1 blymn
211 1.19 rillig yyin = fopen(inc_file, "r");
212 1.1 blymn
213 1.4 christos if (!yyin)
214 1.4 christos err(1, "Error opening %s", inc_file);
215 1.1 blymn
216 1.1 blymn yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE));
217 1.1 blymn
218 1.1 blymn include_stack[include_ptr] = line;
219 1.1 blymn include_files[include_ptr++] = cur_file;
220 1.19 rillig cur_file = inc_file;
221 1.18 rillig line = 1;
222 1.1 blymn BEGIN(INITIAL);
223 1.1 blymn }
224 1.1 blymn
225 1.1 blymn <<EOF>> {
226 1.1 blymn yypop_buffer_state();
227 1.1 blymn
228 1.10 rillig if (!YY_CURRENT_BUFFER)
229 1.1 blymn yyterminate();
230 1.1 blymn
231 1.1 blymn if (--include_ptr < 0)
232 1.21 rillig errx(2, "Include stack underflow");
233 1.1 blymn
234 1.1 blymn free(cur_file);
235 1.1 blymn cur_file = include_files[include_ptr];
236 1.1 blymn line = include_stack[include_ptr];
237 1.1 blymn }
238 1.1 blymn
239 1.10 rillig {ASSIGN} return ASSIGN;
240 1.10 rillig {CALL2} return CALL2;
241 1.10 rillig {CALL3} return CALL3;
242 1.10 rillig {CALL4} return CALL4;
243 1.10 rillig {CALL} return CALL;
244 1.10 rillig {CHECK} return CHECK;
245 1.10 rillig {DELAY} return DELAY;
246 1.10 rillig {INPUT} return INPUT;
247 1.10 rillig {NOINPUT} return NOINPUT;
248 1.10 rillig {COMPARE} return COMPARE;
249 1.10 rillig {COMPAREND} return COMPAREND;
250 1.10 rillig {NON_NULL} return NON_NULL;
251 1.10 rillig {NULL_RET} return NULL_RET;
252 1.10 rillig {OK_RET} return OK_RET;
253 1.10 rillig {ERR_RET} return ERR_RET;
254 1.10 rillig {MULTIPLIER} return MULTIPLIER;
255 1.16 rillig {COMMA} return COMMA;
256 1.10 rillig {CCHAR} return CCHAR;
257 1.10 rillig {WCHAR} return WCHAR;
258 1.10 rillig {OR} return OR;
259 1.12 rillig {LPAREN} return LPAREN;
260 1.12 rillig {RPAREN} return RPAREN;
261 1.12 rillig {LBRACK} return LBRACK;
262 1.12 rillig {RBRACK} return RBRACK;
263 1.8 blymn
264 1.1 blymn {HEX} {
265 1.1 blymn /* Hex value, convert to decimal and return numeric */
266 1.1 blymn unsigned long val;
267 1.1 blymn
268 1.1 blymn if (sscanf(yytext, "%lx", &val) != 1)
269 1.21 rillig errx(1, "Bad hex conversion");
270 1.1 blymn
271 1.1 blymn asprintf(&yylval.string, "%ld", val);
272 1.1 blymn return numeric;
273 1.1 blymn }
274 1.1 blymn
275 1.10 rillig {numeric} {
276 1.1 blymn if ((yylval.string = strdup(yytext)) == NULL)
277 1.1 blymn err(1, "Cannot allocate numeric string");
278 1.1 blymn return numeric;
279 1.10 rillig }
280 1.1 blymn
281 1.1 blymn {VARNAME} {
282 1.1 blymn if ((yylval.string = strdup(yytext)) == NULL)
283 1.1 blymn err(1, "Cannot allocate string for varname");
284 1.1 blymn return VARNAME;
285 1.1 blymn }
286 1.1 blymn
287 1.1 blymn {FILENAME} {
288 1.1 blymn size_t len;
289 1.1 blymn
290 1.1 blymn if ((yylval.string = dequote(yytext, &len)) == NULL)
291 1.1 blymn err(1, "Cannot allocate filename string");
292 1.1 blymn return FILENAME;
293 1.1 blymn }
294 1.1 blymn
295 1.1 blymn /* path */
296 1.1 blymn \/{PCHAR}+ {
297 1.1 blymn size_t len;
298 1.1 blymn if ((yylval.string = dequote(yytext, &len)) == NULL)
299 1.1 blymn err(1, "Cannot allocate string");
300 1.1 blymn return PATH;
301 1.1 blymn }
302 1.1 blymn
303 1.1 blymn \'{STRING}\' {
304 1.1 blymn char *p;
305 1.1 blymn size_t len;
306 1.1 blymn
307 1.8 blymn if ((yylval.retval = malloc(sizeof(ct_data_t))) == NULL)
308 1.1 blymn err(1, "Cannot allocate return struct");
309 1.1 blymn p = yytext;
310 1.1 blymn p++; /* skip the leading ' */
311 1.8 blymn if ((yylval.retval->data_value = dequote(p, &len))
312 1.1 blymn == NULL)
313 1.1 blymn err(1, "Cannot allocate string");
314 1.1 blymn
315 1.8 blymn yylval.retval->data_type = data_byte;
316 1.1 blymn /* trim trailing ' */
317 1.8 blymn yylval.retval->data_len = len - 1;
318 1.1 blymn return BYTE;
319 1.1 blymn }
320 1.1 blymn
321 1.1 blymn \`{STRING}\` {
322 1.1 blymn char *p, *str;
323 1.1 blymn size_t len, chlen;
324 1.4 christos size_t i;
325 1.1 blymn chtype *rv;
326 1.1 blymn
327 1.8 blymn if ((yylval.retval = malloc(sizeof(ct_data_t))) == NULL)
328 1.1 blymn err(1, "Cannot allocate return struct");
329 1.1 blymn p = yytext;
330 1.9 blymn p++; /* skip the leading ` */
331 1.1 blymn if ((str = dequote(p, &len)) == NULL)
332 1.1 blymn err(1, "Cannot allocate string");
333 1.1 blymn len--; /* trim trailing ` */
334 1.1 blymn if ((len % 2) != 0)
335 1.1 blymn len--;
336 1.1 blymn
337 1.1 blymn chlen = ((len / 2) + 1) * sizeof(chtype);
338 1.8 blymn if ((yylval.retval->data_value = malloc(chlen))
339 1.1 blymn == NULL)
340 1.1 blymn err(1, "Cannot allocate chtype array");
341 1.1 blymn
342 1.8 blymn rv = yylval.retval->data_value;
343 1.1 blymn for (i = 0; i < len; i += 2)
344 1.1 blymn *rv++ = (str[i] << 8) | str[i+1];
345 1.19 rillig *rv = __NORMAL | '\0'; /* terminates chtype array */
346 1.8 blymn yylval.retval->data_type = data_byte;
347 1.8 blymn yylval.retval->data_len = chlen;
348 1.1 blymn return BYTE;
349 1.1 blymn }
350 1.1 blymn
351 1.1 blymn \"{STRING}\" {
352 1.1 blymn char *p;
353 1.1 blymn size_t len;
354 1.1 blymn
355 1.1 blymn p = yytext;
356 1.1 blymn p++; /* skip the leading " */
357 1.1 blymn if ((yylval.string = dequote(p, &len)) == NULL)
358 1.1 blymn err(1, "Cannot allocate string");
359 1.1 blymn
360 1.1 blymn /* remove trailing " */
361 1.1 blymn yylval.string[len - 1] = '\0';
362 1.1 blymn return STRING;
363 1.1 blymn }
364 1.1 blymn
365 1.1 blymn \${VARNAME} {
366 1.1 blymn char *p;
367 1.1 blymn
368 1.1 blymn p = yytext;
369 1.1 blymn p++; /* skip $ before var name */
370 1.1 blymn if ((yylval.string = strdup(p)) == NULL)
371 1.1 blymn err(1, "Cannot allocate string for varname");
372 1.1 blymn return VARIABLE;
373 1.1 blymn }
374 1.10 rillig
375 1.11 rillig /* whitespace, comments */
376 1.1 blymn [ \t\r] |
377 1.1 blymn #.* ;
378 1.11 rillig
379 1.11 rillig ^[ \t\r]*#.*\n |
380 1.1 blymn \\\n |
381 1.10 rillig ^\n line++;
382 1.1 blymn
383 1.1 blymn /* eol on a line with data. need to process, return eol */
384 1.11 rillig #.*\n |
385 1.1 blymn \n {
386 1.1 blymn line++;
387 1.1 blymn return EOL;
388 1.1 blymn }
389 1.1 blymn
390 1.1 blymn . {
391 1.14 rillig if (isprint((unsigned char)yytext[0]))
392 1.14 rillig errx(1, "%s:%zu: Invalid character '%c'",
393 1.14 rillig cur_file, line + 1, yytext[0]);
394 1.14 rillig else
395 1.14 rillig errx(1, "%s:%zu: Invalid character '0x%02x'",
396 1.14 rillig cur_file, line + 1, yytext[0]);
397 1.1 blymn }
398 1.1 blymn
399 1.1 blymn %%
400 1.1 blymn
401 1.1 blymn int
402 1.1 blymn yywrap(void)
403 1.1 blymn {
404 1.1 blymn return 1;
405 1.1 blymn }
406