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