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