1 /*
2  * Copyright 2012-2013, Jakub Zawadzki <darkjames-ws@darkjames.pl>
3  *
4  * SPDX-License-Identifier: GPL-2.0-or-later
5  */
6 
7 %option noyywrap
8 %option nounput
9 
10 %option noyy_scan_buffer
11 %option noyy_scan_bytes
12 %option noyy_scan_string
13 
14 %option yylineno
15 %option never-interactive
16 
17 %option case-insensitive
18 
19 %{
20 #define YY_DECL static token_type_t yylex(void)
21 
22 #include <setjmp.h>
23 #include "ast.h"
24 #include "xmem.h"
25 
26 typedef enum {
27 	TOKEN_ERROR = -1,
28 	TOKEN_EOF = 0,
29 
30 	TOKEN_INCLUDE,
31 	TOKEN_STRUCT,
32 	TOKEN_PRIVATE_STRUCT,
33 	TOKEN_CONST,
34 	TOKEN_PROTOCOL,
35 
36 	TOKEN_WHILE,
37 
38 	TOKEN_DYNAMIC_SWITCH,
39 	TOKEN_SWITCH,
40 	TOKEN_TABLE,
41 	TOKEN_CASE,
42 	TOKEN_DEFAULT,
43 
44 	TOKEN_ID,
45 	TOKEN_STR,
46 	TOKEN_CHAR,
47 	TOKEN_DIGIT,
48 	TOKEN_FLOAT,
49 
50 	TOKEN_LPAREN,
51 	TOKEN_RPAREN,
52 	TOKEN_LBRACKET,
53 	TOKEN_RBRACKET,
54 	TOKEN_LCURLY,
55 	TOKEN_RCURLY,
56 
57 	TOKEN_ANDAND,
58 	TOKEN_OROR,
59 
60 	TOKEN_EQUAL,
61 	TOKEN_NOTEQUAL,
62 	TOKEN_NOTEQUAL2,
63 
64 	TOKEN_LEQUAL,
65 	TOKEN_GEQUAL,
66 
67 	TOKEN_ASSIGN,
68 	TOKEN_ASSIGN_PLUS,
69 	TOKEN_PLUS,
70 	TOKEN_MINUS,
71 	TOKEN_MULTIPLY,
72 	TOKEN_DIV,
73 	TOKEN_LOGIC_OR,
74 	TOKEN_OR,
75 	TOKEN_LOGIC_AND,
76 	TOKEN_AND,
77 	TOKEN_NOT,
78 	TOKEN_NEG,
79 	TOKEN_XOR,
80 
81 	TOKEN_SHL,
82 	TOKEN_SHR,
83 
84 	TOKEN_PERCENT,
85 	TOKEN_DOLLAR,
86 	TOKEN_COND,
87 	TOKEN_COLON,
88 
89 	TOKEN_SEMICOLON,
90 	TOKEN_DOT,
91 	TOKEN_COMMA,
92 
93 	TOKEN_LESS,
94 	TOKEN_GREATER,
95 
96 	TOKEN_NUMBER,
97 	TOKEN_UNSIGNED_NUMBER,
98 	TOKEN_DECIMAL,
99 	TOKEN_TIME,
100 	TOKEN_BYTE_ORDER,
101 	TOKEN_DISPLAY_FORMAT,
102 	TOKEN_SIZE
103 
104 } token_type_t;
105 
106 %}
107 
108 %x cppcomment
109 %x lch
110 %x lstr
111 %x lstrescape
112 
113 DIGIT10  [0-9]
114 DIGIT16  [0-9a-fA-F]
115 
116 ID       [_a-zA-Z][_a-zA-Z0-9]*
117 
118 %%
119 
120 include return TOKEN_INCLUDE;
121 struct return TOKEN_STRUCT;
122 _struct return TOKEN_PRIVATE_STRUCT;
123 
124 const return TOKEN_CONST;
125 protocol return TOKEN_PROTOCOL;
126 
127 while return TOKEN_WHILE;
128 
129 DynamicSwitch return TOKEN_DYNAMIC_SWITCH;
130 switch return TOKEN_SWITCH;
131 table return TOKEN_TABLE;
132 case return TOKEN_CASE;
133 default return TOKEN_DEFAULT;
134 
135 Number return TOKEN_NUMBER;
136 UnsignedNumber return TOKEN_UNSIGNED_NUMBER;
137 Decimal return TOKEN_DECIMAL;
138 Time return TOKEN_TIME;
139 ByteOrder return TOKEN_BYTE_ORDER;
140 DisplayFormat return TOKEN_DISPLAY_FORMAT;
141 Size return TOKEN_SIZE;
142 
143 "(" return TOKEN_LPAREN;
144 ")" return TOKEN_RPAREN;
145 "[" return TOKEN_LBRACKET;
146 "]" return TOKEN_RBRACKET;
147 "{" return TOKEN_LCURLY;
148 "}" return TOKEN_RCURLY;
149 
150 and  return TOKEN_ANDAND;
151 or   return TOKEN_OROR;
152 
153 "==" return TOKEN_EQUAL;
154 "!=" return TOKEN_NOTEQUAL;
155 "<>" return TOKEN_NOTEQUAL2;
156 
157 ">=" return TOKEN_GEQUAL;
158 "<=" return TOKEN_LEQUAL;
159 
160 "+=" return TOKEN_ASSIGN_PLUS;
161 "=" return TOKEN_ASSIGN;
162 "+" return TOKEN_PLUS;
163 "-" return TOKEN_MINUS;
164 "*" return TOKEN_MULTIPLY;
165 "/" return TOKEN_DIV;
166 "||" return TOKEN_LOGIC_OR;
167 "|" return TOKEN_OR;
168 "&&" return TOKEN_LOGIC_AND;
169 "&" return TOKEN_AND;
170 "!" return TOKEN_NOT;
171 "~" return TOKEN_NEG;
172 "^" return TOKEN_XOR;
173 "<<" return TOKEN_SHL;
174 ">>" return TOKEN_SHR;
175 "%" return TOKEN_PERCENT;
176 "$" return TOKEN_DOLLAR;
177 "?" return TOKEN_COND;
178 
179 ";" return TOKEN_SEMICOLON;
180 "." return TOKEN_DOT;
181 "," return TOKEN_COMMA;
182 ":" return TOKEN_COLON;
183 
184 "<" return TOKEN_LESS;
185 ">" return TOKEN_GREATER;
186 
187 "'" yymore(); BEGIN(lch);
188 <lch>{
189 	"'" BEGIN(INITIAL); return TOKEN_CHAR;
190 	"\n" return TOKEN_ERROR;
191 	. yymore();
192 }
193 
194 "\"" yymore(); BEGIN(lstr);
195 <lstr>{
196 	"\"" BEGIN(INITIAL); return TOKEN_STR;
197 	"\\" yymore(); BEGIN(lstrescape);
198 	"\n" return TOKEN_ERROR;
199 	. yymore();
200 }
201 
202 <lstrescape>{
203 	"\n" return TOKEN_ERROR;
204 	. yymore(); BEGIN(lstr);
205 }
206 
207 "//" BEGIN(cppcomment);
208 <cppcomment>{
209 	"\n" BEGIN(INITIAL);
210 	. ;
211 }
212 
213 "/*" {
214 	int nested = 1;
215 	int ch, last_ch;
216 
217 	last_ch = '*';
218 
219 	/* XXX, can comments be nested? (can't be determinated by current example file set) */
220 
221 	do {
222 		ch = input();
223 
224 		if (last_ch == '*' && ch == '/')
225 			nested--;
226 
227 		if (last_ch == '/' && ch == '*')
228 			nested++;
229 
230 		if (ch == EOF)
231 			return TOKEN_ERROR;
232 
233 		last_ch = ch;
234 
235 	} while(nested);
236 }
237 
238 {ID} return TOKEN_ID;
239 {DIGIT10}+"."{DIGIT10}* return TOKEN_FLOAT;
240 {DIGIT10}+ return TOKEN_DIGIT;
241 "0x"{DIGIT16}+ return TOKEN_DIGIT;
242 
243 [[:space:]] ;
244 
245 .      return TOKEN_ERROR;
246 
247 %%
248 
249 static const char *yyfilename;
250 static int token;
251 
token_name(token_type_t tok)252 static const char *token_name(token_type_t tok) {
253 	static char buf[64];
254 
255 	switch (tok) {
256 		case TOKEN_EOF: return "<<eof>>";
257 		case TOKEN_ERROR: return "<<error>>";
258 
259 		case TOKEN_ID:
260 			return "<ID>";
261 		case TOKEN_STR:
262 			return "<STR>";
263 		case TOKEN_CHAR:
264 			return "<CHAR>";
265 		case TOKEN_DIGIT:
266 			return "<DIGIT>";
267 		case TOKEN_FLOAT:
268 			return "<FLOAT>";
269 
270 		case TOKEN_STRUCT:
271 			return "struct";
272 		case TOKEN_PRIVATE_STRUCT:
273 			return "_struct";
274 		case TOKEN_CONST:
275 			return "const";
276 		case TOKEN_WHILE:
277 			return "while";
278 		case TOKEN_SWITCH:
279 			return "switch";
280 		case TOKEN_DYNAMIC_SWITCH:
281 			return "dynamic switch";
282 		case TOKEN_CASE:
283 			return "case";
284 
285 		/* ... */
286 		default:
287 			;
288 	}
289 
290 	snprintf(buf, sizeof(buf), "<token #%d>", tok);
291 	return buf;
292 }
293 
294 static jmp_buf parser_exception;
295 
xfail(void)296 static void xfail(void) { longjmp(parser_exception, 1); }
297 
next_token(void)298 static void next_token(void) { token = yylex(); }
299 
is_token(token_type_t tok)300 static inline int is_token(token_type_t tok) { return (token == tok); }
301 
_strange(int line)302 static void _strange(int line) {
303 	fprintf(stdout, "?!?!? %s:%d got: %d (%s) @%s:%d\n", __FILE__, line, token, yytext, yyfilename, yylineno);
304 }
305 #define strange() _strange(__LINE__)
306 
_nomatch(int line)307 static void _nomatch(int line) {
308 	fprintf(stdout, "!!!! %s:%d got: %d (%s) @%s:%d\n", __FILE__, line, token, yytext, yyfilename, yylineno);
309 	xfail();
310 }
311 #define nomatch() _nomatch(__LINE__)
312 
_accept(token_type_t tok,int line)313 static void _accept(token_type_t tok, int line) {
314 	if (tok != token) {
315 		fprintf(stdout, "%s:%d got: %d (%s) expected %s @%s:%d\n", __FILE__, line, token, yytext, token_name(tok), yyfilename, yylineno);
316 		xfail();
317 	}
318 	next_token();
319 }
320 #define accept(tok) _accept(tok, __LINE__)
321 
is_id(void)322 static int is_id(void) {
323 	/* Some NPL files use keyword as ID (sucks...) */
324 	return
325 		is_token(TOKEN_PROTOCOL) ||
326 		is_token(TOKEN_SIZE) ||
327 		is_token(TOKEN_DEFAULT) ||
328 		is_token(TOKEN_NUMBER) ||
329 		is_token(TOKEN_DECIMAL) ||
330 		is_token(TOKEN_TIME) ||
331 		is_token(TOKEN_BYTE_ORDER) ||
332 		is_token(TOKEN_OROR) || is_token(TOKEN_ANDAND) ||
333 		is_token(TOKEN_STRUCT) || is_token(TOKEN_TABLE) ||
334 		is_token(TOKEN_ID);
335 }
336 
_accept_id(int line)337 static char *_accept_id(int line) {
338 	char *id;
339 
340 	if (!is_id()) {
341 		fprintf(stdout, "%s:%d got: %d (%s) expected %s @%s:%d\n", __FILE__, line, token, yytext, token_name(TOKEN_ID), yyfilename, yylineno);
342 		xfail();
343 	}
344 
345 	id = xstrdup(yytext);
346 	next_token();
347 
348 	return id;
349 }
350 
351 #define accept_id() _accept_id(__LINE__)
352 
_accept_int(int line)353 static unsigned int _accept_int(int line) {
354 	unsigned int num;
355 
356 	if (token != TOKEN_DIGIT) {
357 		fprintf(stdout, "%s:%d got: %d (%s) expected %s @%s:%d\n", __FILE__, line, token, yytext, token_name(TOKEN_DIGIT), yyfilename, yylineno);
358 		xfail();
359 	}
360 
361 	if (yytext[0] == '0' && yytext[1] == 'x')
362 		num = strtol(yytext + 2, NULL, 16);
363 	else
364 		num = strtol(yytext, NULL, 10);
365 
366 	next_token();
367 
368 	return num;
369 }
370 
371 #define accept_int() _accept_int(__LINE__)
372 
373 
_accept_str(int line)374 static char *_accept_str(int line) {
375 	size_t len;
376 	char *str;
377 
378 	if (token != TOKEN_STR) {
379 		fprintf(stdout, "%s:%d got: %d (%s) expected %s @%s:%d\n", __FILE__, line, token, yytext, token_name(TOKEN_STR), yyfilename, yylineno);
380 		xfail();
381 	}
382 
383 	len = strlen(yytext);
384 
385 	if (len < 2 || yytext[0] != '"' || yytext[len-1] != '"')
386 		xfail();
387 #if 0
388 	char *ptr;
389 	size_t i;
390 
391 	ptr = str = xmalloc(len-2+1);
392 	for (i = 1; i < len-1; i++) {
393 		if (yytext[i] == '\\') {
394 			i++;
395 
396 			if (yytext[i] == '0' && yytext[i+1] == 'x') {
397 				i += 2;
398 
399 				// XXX
400 				*ptr++ = yytext[i];
401 			} else
402 				switch (yytext[i]) {
403 					case '0':
404 						*ptr++ = '\0';
405 						break;
406 					case '\\':
407 						*ptr++ = '\\';
408 						break;
409 					case 'r':
410 						*ptr++ = '\r';
411 						break;
412 					case 'n':
413 						*ptr++ = '\n';
414 						break;
415 					case 't':
416 						*ptr++ = '\t';
417 						break;
418 
419 					case '"':
420 						*ptr++ = '"';
421 						break;
422 					case '\'':
423 						*ptr++ = '\'';
424 						break;
425 
426 					default:
427 						fprintf(stdout, "unrecog: %c @ %d\n", yytext[i], yylineno);
428 						*ptr++ = yytext[i];
429 				}
430 
431 		} else
432 			*ptr++ = yytext[i];
433 	}
434 
435 	*ptr = '\0';
436 #else
437 	len -= 2;
438 	/* escaping is done almost like in C so don't unescape (cause it'd require escaping later...) */
439 	str = xmalloc(len + 1);
440 	memcpy(str, yytext + 1, len);
441 	str[len] = '\0';
442 #endif
443 
444 	next_token();
445 
446 	return str;
447 }
448 #define accept_str() _accept_str(__LINE__)
449 
is_token_accept(token_type_t tok)450 static int is_token_accept(token_type_t tok) {
451 	if (is_token(tok)) {
452 		next_token();
453 		return 1;
454 	}
455 	return 0;
456 }
457 
is_params(void)458 static int is_params(void) { return is_token(TOKEN_LPAREN); }
459 
460 static void
parse_params(npl_params_t * p)461 parse_params(npl_params_t *p)
462 {
463 	int i = 0;
464 
465 	accept(TOKEN_LPAREN);
466 	do {
467 		if (i == NPL_PARAMS_MAX) {
468 			fprintf(stdout, "i == NPL_PARAMS_MAX");
469 			xfail();
470 		}
471 
472 		p->args[i++] = accept_id();
473 
474 	} while (is_token_accept(TOKEN_COMMA));
475 	accept(TOKEN_RPAREN);
476 
477 	p->count = i;
478 }
479 
480 static void parse_expression(npl_expression_t *expr);
481 static npl_expression_t *xparse_expression(void);
482 
483 static void
parse_primary(npl_expression_t * expr)484 parse_primary(npl_expression_t *expr)
485 {
486 	if (is_id()) {
487 		expr->type = EXPRESSION_ID;
488 		expr->id.id = accept_id();
489 		return;
490 	}
491 
492 	if (is_token(TOKEN_DIGIT)) {
493 		expr->type = EXPRESSION_INT;
494 		expr->num.digit = accept_int();
495 		return;
496 	}
497 
498 	if (is_token(TOKEN_FLOAT)) {
499 		// XXX ast
500 		accept(TOKEN_FLOAT);
501 		expr->type = -1;
502 		return;
503 	}
504 
505 	if (is_token(TOKEN_CHAR)) {
506 		// XXX ast
507 		accept(TOKEN_CHAR);
508 		expr->type = -2;
509 		return;
510 	}
511 
512 	if (is_token(TOKEN_STR)) {
513 		expr->type = EXPRESSION_STR;
514 		expr->str.str = accept_str();
515 		return;
516 	}
517 
518 	if (is_token_accept(TOKEN_LPAREN)) {
519 		parse_expression(expr);
520 		accept(TOKEN_RPAREN);
521 		return;
522 	}
523 
524 	nomatch();
525 }
526 
527 /* ExpressionList = Expression, { ",", Expression } ; */
528 static void
parse_expression_list(npl_expression_list_t ** ptr)529 parse_expression_list(npl_expression_list_t **ptr)
530 {
531 	do {
532 		npl_expression_list_t *cur = xnew(npl_expression_list_t);
533 
534 		*ptr = cur;
535 		ptr = &(cur->next);
536 		cur->expr = xparse_expression();
537 
538 	} while (is_token_accept(TOKEN_COMMA));
539 
540 	*ptr = NULL;
541 }
542 
543 static void
parse_expression1(npl_expression_t * expr)544 parse_expression1(npl_expression_t *expr)
545 {
546 	parse_primary(expr);
547 
548 	do {
549 		if (is_token_accept(TOKEN_LPAREN)) {	/* foo() */
550 			npl_expression_t *fun = xdup(npl_expression_t, expr);
551 			npl_expression_list_t *args = NULL;
552 
553 			if (!is_token(TOKEN_RPAREN))
554 				parse_expression_list(&args);
555 			accept(TOKEN_RPAREN);
556 
557 			expr->type = EXPRESSION_CALL;
558 			expr->call.fn = fun;
559 			expr->call.args = args;
560 
561 		} else if (is_token_accept(TOKEN_DOLLAR)) { /* arr$[field1, field2, ...] */
562 			npl_expression_t *base = xdup(npl_expression_t, expr);
563 			npl_expression_list_t *indexes;
564 
565 			accept(TOKEN_LBRACKET);
566 			parse_expression_list(&indexes);
567 			accept(TOKEN_RBRACKET);
568 
569 			expr->type = EXPRESSION_MULTI_INDEX;
570 			expr->aarr.base = base;
571 			expr->aarr.indexes = indexes;
572 
573 		} else if (is_token_accept(TOKEN_LBRACKET)) { /* arr[10] */
574 			npl_expression_t *base = xdup(npl_expression_t, expr);
575 			npl_expression_t *idx;
576 
577 			idx = xparse_expression();
578 			accept(TOKEN_RBRACKET);
579 
580 			expr->type = EXPRESSION_INDEX;
581 			expr->arr.base = base;
582 			expr->arr.index = idx;
583 
584 		} else if (is_token_accept(TOKEN_DOT)) {
585 			npl_expression_t *base = xdup(npl_expression_t, expr);
586 			char *field;
587 
588 			field = accept_id();
589 
590 			expr->type = EXPRESSION_FIELD;
591 			expr->fld.base = base;
592 			expr->fld.field = field;
593 
594 		} else
595 			break;
596 
597 	} while (1);
598 }
599 
600 static void
parse_expression2(npl_expression_t * expr)601 parse_expression2(npl_expression_t *expr)
602 {
603 	npl_op1_t op;
604 
605 	do {
606 		op =
607 			(is_token_accept(TOKEN_MINUS)) ? OP1_MINUS :
608 			(is_token_accept(TOKEN_NOT)) ? OP1_NOT :
609 			(is_token_accept(TOKEN_NEG)) ? OP1_NEG :
610 			OP1_INVALID;
611 
612 		if (op != OP1_INVALID) {
613 			expr->type = EXPRESSION_UNARY;
614 			expr->u.operator = op;
615 
616 			expr = expr->u.operand = xnew(npl_expression_t);
617 		}
618 	} while (op != OP1_INVALID);
619 
620 	parse_expression1(expr);
621 }
622 
623 static void
parse_expression3(npl_expression_t * expr)624 parse_expression3(npl_expression_t *expr)
625 {
626 	npl_op2_t op;
627 
628 	parse_expression2(expr);
629 again:
630 	op =
631 		(is_token_accept(TOKEN_MULTIPLY)) ? OP2_MULTIPLY :
632 		(is_token_accept(TOKEN_DIV)) ? OP2_DIV :
633 		(is_token_accept(TOKEN_PERCENT)) ? OP2_MOD :
634 		OP2_INVALID;
635 
636 	if (op != OP2_INVALID) {
637 		npl_expression_t *operand = xdup(npl_expression_t, expr);
638 		npl_expression_t *e;
639 
640 		expr->b.operand2 = e = xnew(npl_expression_t);
641 		parse_expression3(e);
642 
643 		expr->b.operator = op;
644 		expr->b.operand1 = operand;
645 		expr->type = EXPRESSION_BINARY;
646 		goto again;
647 	}
648 }
649 
650 static void
parse_expression4(npl_expression_t * expr)651 parse_expression4(npl_expression_t *expr)
652 {
653 	npl_op2_t op;
654 
655 	parse_expression3(expr);
656 again:
657 	op =
658 		(is_token_accept(TOKEN_PLUS)) ? OP2_PLUS :
659 		(is_token_accept(TOKEN_MINUS)) ? OP2_MINUS :
660 		OP2_INVALID;
661 
662 	if (op != OP2_INVALID) {
663 		npl_expression_t *operand = xdup(npl_expression_t, expr);
664 		npl_expression_t *e;
665 
666 		expr->b.operand2 = e = xnew(npl_expression_t);
667 		parse_expression4(e);
668 
669 		expr->b.operator = op;
670 		expr->b.operand1 = operand;
671 		expr->type = EXPRESSION_BINARY;
672 		goto again;
673 	}
674 }
675 
676 static void
parse_expression5(npl_expression_t * expr)677 parse_expression5(npl_expression_t *expr)
678 {
679 	npl_op2_t op;
680 
681 	parse_expression4(expr);
682 again:
683 	op =
684 		(is_token_accept(TOKEN_SHL)) ? OP2_SHL :
685 		(is_token_accept(TOKEN_SHR)) ? OP2_SHR :
686 		OP2_INVALID;
687 
688 	if (op != OP2_INVALID) {
689 		npl_expression_t *operand = xdup(npl_expression_t, expr);
690 		npl_expression_t *e;
691 
692 		expr->b.operand2 = e = xnew(npl_expression_t);
693 		parse_expression5(e);
694 
695 		expr->b.operator = op;
696 		expr->b.operand1 = operand;
697 		expr->type = EXPRESSION_BINARY;
698 		goto again;
699 	}
700 }
701 
702 static void
parse_expression6(npl_expression_t * expr)703 parse_expression6(npl_expression_t *expr)
704 {
705 	npl_op2_t op;
706 
707 	parse_expression5(expr);
708 again:
709 	op =
710 		(is_token_accept(TOKEN_LESS)) ? OP2_LESS :
711 		(is_token_accept(TOKEN_GREATER)) ? OP2_GREATER :
712 		(is_token_accept(TOKEN_LEQUAL)) ? OP2_LEQUAL :
713 		(is_token_accept(TOKEN_GEQUAL)) ? OP2_GEQUAL :
714 		OP2_INVALID;
715 
716 	if (op != OP2_INVALID) {
717 		npl_expression_t *operand = xdup(npl_expression_t, expr);
718 		npl_expression_t *e;
719 
720 		expr->b.operand2 = e = xnew(npl_expression_t);
721 		parse_expression6(e);
722 
723 		expr->b.operator = op;
724 		expr->b.operand1 = operand;
725 		expr->type = EXPRESSION_BINARY;
726 		goto again;
727 	}
728 }
729 
730 static void
parse_expression7(npl_expression_t * expr)731 parse_expression7(npl_expression_t *expr)
732 {
733 	npl_op2_t op;
734 
735 	parse_expression6(expr);
736 again:
737 	op =
738 		(is_token_accept(TOKEN_EQUAL)) ? OP2_EQUAL :
739 		(is_token_accept(TOKEN_NOTEQUAL)) ? OP2_NOTEQUAL :
740 		(is_token_accept(TOKEN_NOTEQUAL2)) ? OP2_NOTEQUAL :
741 		OP2_INVALID;
742 
743 	if (op != OP2_INVALID) {
744 		npl_expression_t *operand = xdup(npl_expression_t, expr);
745 		npl_expression_t *e;
746 
747 		expr->b.operand2 = e = xnew(npl_expression_t);
748 		parse_expression7(e);
749 
750 		expr->b.operator = op;
751 		expr->b.operand1 = operand;
752 		expr->type = EXPRESSION_BINARY;
753 		goto again;
754 	}
755 }
756 
757 static void
parse_expression8(npl_expression_t * expr)758 parse_expression8(npl_expression_t *expr)
759 {
760 	parse_expression7(expr);
761 again:
762 	if (is_token_accept(TOKEN_AND)) {
763 		npl_expression_t *operand = xdup(npl_expression_t, expr);
764 		npl_expression_t *e;
765 
766 		expr->b.operand2 = e = xnew(npl_expression_t);
767 		parse_expression8(e);
768 
769 		expr->b.operator = OP2_AND;
770 		expr->b.operand1 = operand;
771 		expr->type = EXPRESSION_BINARY;
772 		goto again;
773 	}
774 }
775 
776 static void
parse_expression9(npl_expression_t * expr)777 parse_expression9(npl_expression_t *expr)
778 {
779 	parse_expression8(expr);
780 again:
781 	if (is_token_accept(TOKEN_XOR)) {
782 		npl_expression_t *operand = xdup(npl_expression_t, expr);
783 		npl_expression_t *e;
784 
785 		expr->b.operand2 = e = xnew(npl_expression_t);
786 		parse_expression9(e);
787 
788 		expr->b.operator = OP2_XOR;
789 		expr->b.operand1 = operand;
790 		expr->type = EXPRESSION_BINARY;
791 		goto again;
792 	}
793 }
794 
795 static void
parse_expression10(npl_expression_t * expr)796 parse_expression10(npl_expression_t *expr)
797 {
798 	parse_expression9(expr);
799 again:
800 	if (is_token_accept(TOKEN_OR)) {
801 		npl_expression_t *operand = xdup(npl_expression_t, expr);
802 		npl_expression_t *e;
803 
804 		expr->b.operand2 = e = xnew(npl_expression_t);
805 		parse_expression10(e);
806 
807 		expr->b.operator = OP2_OR;
808 		expr->b.operand1 = operand;
809 		expr->type = EXPRESSION_BINARY;
810 		goto again;
811 	}
812 }
813 
814 static void
parse_expression11(npl_expression_t * expr)815 parse_expression11(npl_expression_t *expr)
816 {
817 	npl_op2_t op;
818 
819 	parse_expression10(expr);
820 again:
821 	op =
822 		(is_token_accept(TOKEN_LOGIC_AND)) ? OP2_LOGIC_AND :
823 		(is_token_accept(TOKEN_ANDAND)) ? OP2_LOGIC_AND :
824 		OP2_INVALID;
825 
826 	if (op != OP2_INVALID) {
827 		npl_expression_t *operand = xdup(npl_expression_t, expr);
828 		npl_expression_t *e;
829 
830 		expr->b.operand2 = e = xnew(npl_expression_t);
831 		parse_expression11(e);
832 
833 		expr->b.operator = op;
834 		expr->b.operand1 = operand;
835 		expr->type = EXPRESSION_BINARY;
836 		goto again;
837 	}
838 }
839 
840 static void
parse_expression12(npl_expression_t * expr)841 parse_expression12(npl_expression_t *expr)
842 {
843 	npl_op2_t op;
844 
845 	parse_expression11(expr);
846 again:
847 	op =
848 		(is_token_accept(TOKEN_LOGIC_OR)) ? OP2_LOGIC_OR :
849 		(is_token_accept(TOKEN_OROR)) ? OP2_LOGIC_OR :
850 		OP2_INVALID;
851 
852 	if (op != OP2_INVALID) {
853 		npl_expression_t *operand = xdup(npl_expression_t, expr);
854 		npl_expression_t *e;
855 
856 		expr->b.operand2 = e = xnew(npl_expression_t);
857 		parse_expression12(e);
858 
859 		expr->b.operator = op;
860 		expr->b.operand1 = operand;
861 		expr->type = EXPRESSION_BINARY;
862 		goto again;
863 	}
864 }
865 
866 static void
parse_expression13(npl_expression_t * expr)867 parse_expression13(npl_expression_t *expr)
868 {
869 	parse_expression12(expr);
870 
871 	if (is_token_accept(TOKEN_COND)) {
872 		npl_expression_t *operand = xdup(npl_expression_t, expr);
873 		npl_expression_t *e;
874 
875 		expr->c.test_expr = operand;
876 
877 		e = xnew(npl_expression_t);
878 		parse_expression(e);
879 		expr->c.true_expr = e;
880 		accept(TOKEN_COLON);
881 
882 		e = xnew(npl_expression_t);
883 		parse_expression13(e);
884 		expr->c.false_expr = e;
885 
886 		expr->type = EXPRESSION_COND;
887 	}
888 }
889 
890 static npl_expression_t *
xparse_expression(void)891 xparse_expression(void)
892 {
893 	npl_expression_t *expr = xnew(npl_expression_t);
894 
895 	parse_expression(expr);
896 	return expr;
897 }
898 
899 static void
parse_expression(npl_expression_t * expr)900 parse_expression(npl_expression_t *expr)
901 {
902 	npl_op2_t op;
903 
904 	parse_expression13(expr);
905 
906 	op =
907 		(is_token_accept(TOKEN_ASSIGN)) ? OP2_ASSIGN :
908 		(is_token_accept(TOKEN_ASSIGN_PLUS)) ? OP2_ASSIGN_PLUS :
909 		OP2_INVALID;
910 
911 	if (op != OP2_INVALID) {
912 		npl_expression_t *operand = xdup(npl_expression_t, expr);
913 
914 		expr->b.operand2 = xparse_expression();
915 
916 		expr->b.operator = op;
917 		expr->b.operand1 = operand;
918 		expr->type = EXPRESSION_BINARY;
919 	}
920 }
921 
is_attribute(void)922 static int is_attribute(void) { return is_token(TOKEN_LBRACKET); }
923 
924 static npl_attribute_list_t **
pparse_attributes(npl_attribute_list_t ** ptr)925 pparse_attributes(npl_attribute_list_t **ptr)
926 {
927 	accept(TOKEN_LBRACKET);
928 
929 	do {
930 		npl_attribute_list_t *cur = xnew(npl_attribute_list_t);
931 
932 		*ptr = cur;
933 		ptr = &(cur->next);
934 		cur->expr = xparse_expression();
935 
936 		if (is_token_accept(TOKEN_SEMICOLON))
937 			{ }
938 		else if (is_token_accept(TOKEN_COMMA))
939 			{ }
940 	}
941 	while (!is_token(TOKEN_RBRACKET));
942 //	while (is_token_accept(TOKEN_COMMA));
943 
944 	accept(TOKEN_RBRACKET);
945 	return ptr;
946 }
947 
948 static void
parse_all_attributes(npl_attribute_list_t ** attr_ptr)949 parse_all_attributes(npl_attribute_list_t **attr_ptr)
950 {
951 	while (is_attribute())
952 		attr_ptr = pparse_attributes(attr_ptr);
953 	*attr_ptr = NULL;
954 }
955 
956 static void parse_statement(npl_statement_t *st);
957 
958 static npl_statement_t *
xparse_statement(void)959 xparse_statement(void)
960 {
961 	npl_statement_t *st = xnew(npl_statement_t);
962 
963 	parse_statement(st);
964 	return st;
965 }
966 
967 static void
parse_switch_body(npl_switch_t * sw)968 parse_switch_body(npl_switch_t *sw)
969 {
970 	struct npl_switch_case **ptr = &sw->cases;
971 
972 	while (is_token(TOKEN_CASE)) {
973 		struct npl_switch_case *cur = xnew(struct npl_switch_case);
974 
975 		*ptr = cur;
976 
977 		ptr = &(cur->next);
978 
979 		accept(TOKEN_CASE);
980 		parse_expression(&cur->e);
981 		accept(TOKEN_COLON);
982 
983 		if (!is_token(TOKEN_CASE) && !is_token(TOKEN_DEFAULT)) {
984 			cur->st = xparse_statement();
985 			is_token_accept(TOKEN_SEMICOLON);
986 		}
987 	}
988 	*ptr = NULL;
989 
990 	if (is_token_accept(TOKEN_DEFAULT)) {
991 		accept(TOKEN_COLON);
992 		sw->default_st = xparse_statement();
993 	}
994 }
995 
996 static void
parse_switch(npl_switch_t * sw)997 parse_switch(npl_switch_t *sw)
998 {
999 	accept(TOKEN_SWITCH);
1000 
1001 	if (is_token_accept(TOKEN_LPAREN)) {
1002 		sw->switch_expr = xparse_expression();
1003 		accept(TOKEN_RPAREN);
1004 	}
1005 
1006 	accept(TOKEN_LCURLY);
1007 	parse_switch_body(sw);
1008 	accept(TOKEN_RCURLY);
1009 	is_token_accept(TOKEN_SEMICOLON);
1010 }
1011 
1012 static void
parse_dynamic_switch(npl_switch_t * sw)1013 parse_dynamic_switch(npl_switch_t *sw)
1014 {
1015 	accept(TOKEN_DYNAMIC_SWITCH);
1016 
1017 	sw->switch_expr = xparse_expression();
1018 
1019 	accept(TOKEN_LCURLY);
1020 	parse_switch_body(sw);
1021 	accept(TOKEN_RCURLY);
1022 	is_token_accept(TOKEN_SEMICOLON);
1023 }
1024 
is_statement(void)1025 static int is_statement(void) {
1026 	return
1027 		is_token(TOKEN_WHILE) ||
1028 		is_token(TOKEN_TABLE) ||
1029 		is_token(TOKEN_STRUCT) || is_token(TOKEN_PRIVATE_STRUCT) ||
1030 		is_token(TOKEN_SWITCH) || is_token(TOKEN_DYNAMIC_SWITCH) ||
1031 		is_id() || is_attribute() ||
1032 #if 1
1033 		is_token(TOKEN_SEMICOLON) ||
1034 #endif
1035 		0
1036 		;
1037 }
1038 
1039 /* Statements = { Statement } ; */
1040 static struct _npl_statements *
xparse_statements(void)1041 xparse_statements(void)
1042 {
1043 	struct _npl_statements *ret;
1044 	struct _npl_statements **ptr = &ret;
1045 
1046 	while (is_statement()) {
1047 		struct _npl_statements *cur = xnew(struct _npl_statements);
1048 
1049 		parse_statement(&cur->st);
1050 
1051 		*ptr = cur;
1052 		ptr = &(cur->next);
1053 	}
1054 	*ptr = NULL;
1055 
1056 	return ret;
1057 }
1058 
1059 static void
parse_while(npl_statement_t * st)1060 parse_while(npl_statement_t *st)
1061 {
1062 	accept(TOKEN_WHILE);
1063 
1064 	if (is_id())
1065 		st->w.id = accept_id();
1066 
1067 	accept(TOKEN_LBRACKET);
1068 	parse_expression(&st->w.expr);
1069 	accept(TOKEN_RBRACKET);
1070 
1071 	accept(TOKEN_LCURLY);
1072 	st->w.sts = xparse_statements();
1073 	accept(TOKEN_RCURLY);
1074 	is_token_accept(TOKEN_SEMICOLON);
1075 }
1076 
is_formatting(void)1077 static int is_formatting(void) { return is_token(TOKEN_ASSIGN); }
1078 
1079 /* Formatting = "=", Expression ; */
1080 static npl_expression_t *
xparse_formatting(void)1081 xparse_formatting(void)
1082 {
1083 	npl_expression_t *format;
1084 
1085 	accept(TOKEN_ASSIGN);
1086 
1087 	format = xnew(npl_expression_t);
1088 	parse_expression(format);
1089 	return format;
1090 }
1091 
1092 static void parse_table(npl_table_t *);
1093 static void parse_struct(npl_struct_t *s, int statement);
1094 
1095 static void
parse_statement(npl_statement_t * st)1096 parse_statement(npl_statement_t *st)
1097 {
1098 	parse_all_attributes(&st->attr_list);
1099 
1100 	if (is_token(TOKEN_WHILE)) {
1101 		parse_while(st);
1102 		st->type = STATEMENT_WHILE;
1103 		return;
1104 	}
1105 
1106 	if (is_token(TOKEN_TABLE)) {
1107 		parse_table(&st->t.data);
1108 		st->type = STATEMENT_TABLE;
1109 		return;
1110 	}
1111 
1112 	if (is_token(TOKEN_STRUCT) || is_token(TOKEN_PRIVATE_STRUCT)) {
1113 		parse_struct(&st->s.data, 1);
1114 		st->type = STATEMENT_STRUCT;
1115 		return;
1116 	}
1117 
1118 	if (is_token(TOKEN_SWITCH)) {
1119 		parse_switch(&(st->sw.data));
1120 		st->type = STATEMENT_SWITCH;
1121 		return;
1122 	}
1123 
1124 	if (is_token(TOKEN_DYNAMIC_SWITCH)) {
1125 		parse_dynamic_switch(&(st->sw.data));
1126 		st->type = STATEMENT_DYNAMIC_SWITCH;
1127 		return;
1128 	}
1129 #if 1
1130 	if (is_token(TOKEN_SEMICOLON)) {
1131 		accept(TOKEN_SEMICOLON);
1132 		st->type = -3;
1133 		return;
1134 	}
1135 #endif
1136 
1137 	st->type = STATEMENT_FIELD;
1138 	st->f.t_id = accept_id();
1139 
1140 	if (is_token_accept(TOKEN_LPAREN)) {
1141 		parse_expression_list(&st->f.params);
1142 		accept(TOKEN_RPAREN);
1143 
1144 	} else
1145 		st->f.params = NULL;
1146 
1147 	st->f.id = accept_id();
1148 	if (is_token_accept(TOKEN_COLON))
1149 		st->f.bits = accept_int();
1150 
1151 	else if (is_token_accept(TOKEN_LBRACKET)) {
1152 		st->f.arr = xparse_expression();
1153 		accept(TOKEN_RBRACKET);
1154 	}
1155 
1156 	if (is_formatting())
1157 		st->f.format = xparse_formatting();
1158 
1159 	if (is_token_accept(TOKEN_LCURLY)) {
1160 		st->f.sts = xparse_statements();
1161 		accept(TOKEN_RCURLY);
1162 		is_token_accept(TOKEN_SEMICOLON);
1163 		return;
1164 	}
1165 
1166 	accept(TOKEN_SEMICOLON);
1167 }
1168 
1169 /* Protocol = "protocol", ID, [Params], [Formatting], "{", Statements, "}", ";" ; */
1170 static void
parse_protocol(npl_protocol_t * p)1171 parse_protocol(npl_protocol_t *p)
1172 {
1173 	accept(TOKEN_PROTOCOL);
1174 	p->id = accept_id();
1175 
1176 	if (is_params())
1177 		parse_params(&p->params);
1178 
1179 	if (is_formatting())
1180 		p->format = xparse_formatting();
1181 
1182 	accept(TOKEN_LCURLY);
1183 	p->sts = xparse_statements();
1184 	accept(TOKEN_RCURLY);
1185 	is_token_accept(TOKEN_SEMICOLON);
1186 }
1187 
1188 static void
parse_struct(npl_struct_t * s,int statement)1189 parse_struct(npl_struct_t *s, int statement)
1190 {
1191 	if (is_token_accept(TOKEN_STRUCT))
1192 		s->private = 0;
1193 	else if (is_token_accept(TOKEN_PRIVATE_STRUCT))
1194 		s->private = 1;
1195 	else
1196 		nomatch();
1197 
1198 	if (!statement || is_id())
1199 		s->id = accept_id();
1200 
1201 	if (is_params())
1202 		parse_params(&s->params);
1203 
1204 	if (statement) {
1205 		if (is_token_accept(TOKEN_LBRACKET)) {
1206 			s->count_expr = xparse_expression();
1207 			accept(TOKEN_RBRACKET);
1208 		}
1209 	}
1210 
1211 	if (is_formatting())
1212 		s->format = xparse_formatting();
1213 
1214 	accept(TOKEN_LCURLY);
1215 	s->sts = xparse_statements();
1216 	accept(TOKEN_RCURLY);
1217 	is_token_accept(TOKEN_SEMICOLON);
1218 }
1219 
1220 /* Table = "table", ID, [Params], "{", "switch", [ "(", Expr, ")" ], {TableCase}, [DefaultCase], "}", ";" ;
1221 
1222    DefaultCase = "default", ":", Expression", ";" ;
1223  */
1224 static void
parse_table(npl_table_t * t)1225 parse_table(npl_table_t *t)
1226 {
1227 	accept(TOKEN_TABLE);
1228 	t->id = accept_id();
1229 	if (is_params())
1230 		parse_params(&t->params);
1231 
1232 	accept(TOKEN_LCURLY);
1233 	{
1234 		struct npl_table_case **ptr;
1235 
1236 		accept(TOKEN_SWITCH);
1237 		if (is_token_accept(TOKEN_LPAREN)) {
1238 			t->switch_expr = xparse_expression();
1239 			accept(TOKEN_RPAREN);
1240 		}
1241 
1242 		accept(TOKEN_LCURLY);
1243 
1244 		ptr = &(t->cases);
1245 		while (is_token_accept(TOKEN_CASE)) {
1246 			struct npl_table_case *cur;
1247 
1248 			cur = *ptr = xnew(struct npl_table_case);
1249 			ptr = &(cur->next);
1250 
1251 			parse_expression(&(cur->e));
1252 			accept(TOKEN_COLON);
1253 
1254 			while (is_token_accept(TOKEN_CASE)) {
1255 				cur = *ptr = xnew(struct npl_table_case);
1256 				ptr = &(cur->next);
1257 
1258 				parse_expression(&(cur->e));
1259 				accept(TOKEN_COLON);
1260 			}
1261 			cur->return_expr = xparse_expression();
1262 			accept(TOKEN_SEMICOLON);
1263 		}
1264 		*ptr = NULL;
1265 
1266 		if (is_token_accept(TOKEN_DEFAULT)) {
1267 			accept(TOKEN_COLON);
1268 			t->default_expr = xparse_expression();
1269 			accept(TOKEN_SEMICOLON);
1270 		}
1271 		accept(TOKEN_RCURLY);
1272 
1273 	}
1274 	accept(TOKEN_RCURLY);
1275 	is_token_accept(TOKEN_SEMICOLON);
1276 }
1277 
1278 static int
is_type(void)1279 is_type(void)
1280 {
1281 	return
1282 		is_token(TOKEN_DECIMAL) ||
1283 		is_token(TOKEN_NUMBER) ||
1284 		is_token(TOKEN_TIME) ||
1285 		is_token(TOKEN_UNSIGNED_NUMBER);
1286 }
1287 
1288 /* Type = BasicType, ID, [Params], "{", {TypeAttr}, "}" ;
1289 
1290    BasicType = "Decimal" | "Number" | "Time" | "UnsignedNumber" ;
1291 
1292    TypeAttr = AttrName, "=", Expression ;
1293 
1294    AttrName = "ByteOrder" | "DisplayFormat" | "Size" ;
1295  */
1296 static void
parse_type(npl_type_t * t)1297 parse_type(npl_type_t *t)
1298 {
1299 	if (is_token_accept(TOKEN_DECIMAL))
1300 		t->type = FIELD_DECIMAL;
1301 	else if (is_token_accept(TOKEN_NUMBER))
1302 		t->type = FIELD_NUMBER;
1303 	else if (is_token_accept(TOKEN_TIME))
1304 		t->type = FIELD_TIME;
1305 	else if (is_token_accept(TOKEN_UNSIGNED_NUMBER))
1306 		t->type = FIELD_UNSIGNED_NUMBER;
1307 	else
1308 		nomatch();
1309 
1310 	t->id = accept_id();
1311 	if (is_params())
1312 		parse_params(&t->params);
1313 	accept(TOKEN_LCURLY);
1314 
1315 	while (!is_token(TOKEN_RCURLY)) {
1316 		npl_expression_t **ptr;
1317 
1318 		if (is_token_accept(TOKEN_BYTE_ORDER))
1319 			ptr = &t->byte_order;
1320 		else if (is_token_accept(TOKEN_DISPLAY_FORMAT))
1321 			ptr = &t->display_format;
1322 		else if (is_token_accept(TOKEN_SIZE))
1323 			ptr = &t->size;
1324 		else
1325 			nomatch();
1326 #if 0
1327 		if (*ptr)
1328 			fprintf(stdout, "already got %s attr!\n", str);
1329 #endif
1330 		accept(TOKEN_ASSIGN);
1331 		*ptr = xparse_expression();
1332 
1333 		if (is_token_accept(TOKEN_COMMA))
1334 			{ }
1335 		else if (is_token_accept(TOKEN_SEMICOLON))
1336 			{ }
1337 	}
1338 	accept(TOKEN_RCURLY);
1339 }
1340 
1341 /* Const = "const", ID, "=", Expression, ";" ; */
1342 static void
parse_const(npl_const_t * c)1343 parse_const(npl_const_t *c)
1344 {
1345 	accept(TOKEN_CONST);
1346 	c->id = accept_id();
1347 	accept(TOKEN_ASSIGN);
1348 	parse_expression(&c->expr);
1349 	accept(TOKEN_SEMICOLON);
1350 }
1351 
1352 /* Declaration = Attributes
1353                | Struct
1354                | Table
1355                | Const
1356                | Protocol
1357                | Type
1358                | ( "include", STR )
1359                ;
1360  */
1361 static void
parse_decl(npl_decl_t * d)1362 parse_decl(npl_decl_t *d)
1363 {
1364 	parse_all_attributes(&d->attr_list);
1365 
1366 	if (is_token(TOKEN_STRUCT)) {
1367 		d->type = DECL_STRUCT;
1368 		parse_struct(&d->s.data, 0);
1369 
1370 	} else if (is_token(TOKEN_TABLE)) {
1371 		d->type = DECL_TABLE;
1372 		parse_table(&d->t.data);
1373 
1374 	} else if (is_token(TOKEN_CONST)) {
1375 		d->type = DECL_CONST;
1376 		parse_const(&d->c.data);
1377 
1378 	} else if (is_token(TOKEN_PROTOCOL)) {
1379 		d->type = DECL_PROTOCOL;
1380 		parse_protocol(&d->p.data);
1381 
1382 	} else if (is_type()) {
1383 		d->type = DECL_TYPE;
1384 		parse_type(&d->ty.data);
1385 
1386 	} else if (is_token_accept(TOKEN_INCLUDE)) {
1387 		d->type = DECL_INCLUDE;
1388 		d->i.file = accept_str();	/* XXX, it's C-escaped */ /* XXX, unix / vs dos \\  */
1389 
1390 	} else
1391 		nomatch();
1392 }
1393 
1394 /* NPL = { Declaration } ; */
1395 static void
parse_npl(npl_code_t * code)1396 parse_npl(npl_code_t *code)
1397 {
1398 	struct _npl_decl_list **ptr = &(code->decls);
1399 
1400 	while (!is_token_accept(TOKEN_EOF)) {
1401 		struct _npl_decl_list *cur = xnew(struct _npl_decl_list);
1402 
1403 		*ptr = cur;
1404 		ptr = &(cur->next);
1405 
1406 		parse_decl(&cur->d);
1407 	}
1408 	*ptr = NULL;
1409 }
1410 
1411 int
npl_parse_file(npl_code_t * code,FILE * f,const char * filename)1412 npl_parse_file(npl_code_t *code, FILE *f, const char *filename)
1413 {
1414 	volatile int parse_ok = 0;
1415 
1416 	yyfilename = filename;
1417 	yyin = f;
1418 
1419 	if (!setjmp(parser_exception)) {
1420 		next_token();
1421 		parse_npl(code);
1422 		parse_ok = 1;
1423 	}
1424 
1425 	yylex_destroy();
1426 
1427 	return (parse_ok == 1);
1428 }
1429 
1430