MSWSP: add two more Property Sets
[wireshark-wip.git] / tools / npl / parser.l
blob95fa159e97ddefa39126eab6ee4218afb90e4300
1 /* 
2  * Copyright 2012-2013, Jakub Zawadzki <darkjames-ws@darkjames.pl>
3  *
4  * $Id$
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
21 %option noyywrap 
22 %option nounput
24 %option noyy_scan_buffer
25 %option noyy_scan_bytes
26 %option noyy_scan_string
28 %option yylineno
29 %option never-interactive
31 %option case-insensitive
34 #define YY_DECL static token_type_t yylex(void)
36 #include <setjmp.h>
37 #include "ast.h"
38 #include "xmem.h"
40 typedef enum {
41         TOKEN_ERROR = -1,
42         TOKEN_EOF = 0,
44         TOKEN_INCLUDE,
45         TOKEN_STRUCT,
46         TOKEN_PRIVATE_STRUCT,
47         TOKEN_CONST,
48         TOKEN_PROTOCOL,
50         TOKEN_WHILE,
52         TOKEN_DYNAMIC_SWITCH,
53         TOKEN_SWITCH,
54         TOKEN_TABLE,
55         TOKEN_CASE,
56         TOKEN_DEFAULT,
58         TOKEN_ID,
59         TOKEN_STR,
60         TOKEN_CHAR,
61         TOKEN_DIGIT,
62         TOKEN_FLOAT,
64         TOKEN_LPAREN,
65         TOKEN_RPAREN,
66         TOKEN_LBRACKET,
67         TOKEN_RBRACKET,
68         TOKEN_LCURLY,
69         TOKEN_RCURLY,
71         TOKEN_ANDAND,
72         TOKEN_OROR,
74         TOKEN_EQUAL,
75         TOKEN_NOTEQUAL,
76         TOKEN_NOTEQUAL2,
78         TOKEN_LEQUAL,
79         TOKEN_GEQUAL,
81         TOKEN_ASSIGN,
82         TOKEN_ASSIGN_PLUS,
83         TOKEN_PLUS,
84         TOKEN_MINUS,
85         TOKEN_MULTIPLY,
86         TOKEN_DIV,
87         TOKEN_LOGIC_OR,
88         TOKEN_OR,
89         TOKEN_LOGIC_AND,
90         TOKEN_AND,
91         TOKEN_NOT,
92         TOKEN_NEG,
93         TOKEN_XOR,
95         TOKEN_SHL,
96         TOKEN_SHR,
98         TOKEN_PERCENT,
99         TOKEN_DOLLAR,
100         TOKEN_COND,
101         TOKEN_COLON,
103         TOKEN_SEMICOLON,
104         TOKEN_DOT,
105         TOKEN_COMMA,
107         TOKEN_LESS,
108         TOKEN_GREATER,
110         TOKEN_NUMBER,
111         TOKEN_UNSIGNED_NUMBER,
112         TOKEN_DECIMAL,
113         TOKEN_TIME,
114         TOKEN_BYTE_ORDER,
115         TOKEN_DISPLAY_FORMAT,
116         TOKEN_SIZE
118 } token_type_t;
122 %x cppcomment
123 %x lch
124 %x lstr
125 %x lstrescape
127 DIGIT10  [0-9]
128 DIGIT16  [0-9a-fA-F]
130 ID       [_a-zA-Z][_a-zA-Z0-9]*
134 include return TOKEN_INCLUDE;
135 struct return TOKEN_STRUCT;
136 _struct return TOKEN_PRIVATE_STRUCT;
138 const return TOKEN_CONST;
139 protocol return TOKEN_PROTOCOL;
141 while return TOKEN_WHILE;
143 DynamicSwitch return TOKEN_DYNAMIC_SWITCH;
144 switch return TOKEN_SWITCH;
145 table return TOKEN_TABLE;
146 case return TOKEN_CASE;
147 default return TOKEN_DEFAULT;
149 Number return TOKEN_NUMBER;
150 UnsignedNumber return TOKEN_UNSIGNED_NUMBER;
151 Decimal return TOKEN_DECIMAL;
152 Time return TOKEN_TIME;
153 ByteOrder return TOKEN_BYTE_ORDER;
154 DisplayFormat return TOKEN_DISPLAY_FORMAT;
155 Size return TOKEN_SIZE;
157 "(" return TOKEN_LPAREN;
158 ")" return TOKEN_RPAREN;
159 "[" return TOKEN_LBRACKET;
160 "]" return TOKEN_RBRACKET;
161 "{" return TOKEN_LCURLY;
162 "}" return TOKEN_RCURLY;
164 and  return TOKEN_ANDAND;
165 or   return TOKEN_OROR;
167 "==" return TOKEN_EQUAL;
168 "!=" return TOKEN_NOTEQUAL;
169 "<>" return TOKEN_NOTEQUAL2;
171 ">=" return TOKEN_GEQUAL;
172 "<=" return TOKEN_LEQUAL;
174 "+=" return TOKEN_ASSIGN_PLUS;
175 "=" return TOKEN_ASSIGN;
176 "+" return TOKEN_PLUS;
177 "-" return TOKEN_MINUS;
178 "*" return TOKEN_MULTIPLY;
179 "/" return TOKEN_DIV;
180 "||" return TOKEN_LOGIC_OR;
181 "|" return TOKEN_OR;
182 "&&" return TOKEN_LOGIC_AND;
183 "&" return TOKEN_AND;
184 "!" return TOKEN_NOT;
185 "~" return TOKEN_NEG;
186 "^" return TOKEN_XOR;
187 "<<" return TOKEN_SHL;
188 ">>" return TOKEN_SHR;
189 "%" return TOKEN_PERCENT;
190 "$" return TOKEN_DOLLAR;
191 "?" return TOKEN_COND;
193 ";" return TOKEN_SEMICOLON;
194 "." return TOKEN_DOT;
195 "," return TOKEN_COMMA;
196 ":" return TOKEN_COLON;
198 "<" return TOKEN_LESS;
199 ">" return TOKEN_GREATER;
201 "'" yymore(); BEGIN(lch);
202 <lch>{
203         "'" BEGIN(INITIAL); return TOKEN_CHAR;
204         "\n" return TOKEN_ERROR;
205         . yymore();
208 "\"" yymore(); BEGIN(lstr);
209 <lstr>{
210         "\"" BEGIN(INITIAL); return TOKEN_STR;
211         "\\" yymore(); BEGIN(lstrescape);
212         "\n" return TOKEN_ERROR;
213         . yymore();
216 <lstrescape>{
217         "\n" return TOKEN_ERROR;
218         . yymore(); BEGIN(lstr); 
221 "//" BEGIN(cppcomment);
222 <cppcomment>{
223         "\n" BEGIN(INITIAL);
224         . ;
227 "/*" {
228         int nested = 1;
229         int ch, last_ch;
231         last_ch = '*';
233         /* XXX, can comments be nested? (can't be determinated by current example file set) */
235         do {
236                 ch = input();
238                 if (last_ch == '*' && ch == '/')
239                         nested--;
241                 if (last_ch == '/' && ch == '*')
242                         nested++;
244                 if (ch == EOF)
245                         return TOKEN_ERROR;
247                 last_ch = ch;
249         } while(nested);
252 {ID} return TOKEN_ID;
253 {DIGIT10}+"."{DIGIT10}* return TOKEN_FLOAT;
254 {DIGIT10}+ return TOKEN_DIGIT;
255 "0x"{DIGIT16}+ return TOKEN_DIGIT;
257 [[:space:]] ;
259 .      return TOKEN_ERROR;
263 static const char *yyfilename;
264 static int token;
266 static const char *token_name(token_type_t tok) {
267         static char buf[64];
269         switch (tok) {
270                 case TOKEN_EOF: return "<<eof>>";
271                 case TOKEN_ERROR: return "<<error>>";
273                 case TOKEN_ID:
274                         return "<ID>";
275                 case TOKEN_STR:
276                         return "<STR>";
277                 case TOKEN_CHAR:
278                         return "<CHAR>";
279                 case TOKEN_DIGIT:
280                         return "<DIGIT>";
281                 case TOKEN_FLOAT:
282                         return "<FLOAT>";
284                 case TOKEN_STRUCT:
285                         return "struct";
286                 case TOKEN_PRIVATE_STRUCT:
287                         return "_struct";
288                 case TOKEN_CONST:
289                         return "const";
290                 case TOKEN_WHILE:
291                         return "while";
292                 case TOKEN_SWITCH:
293                         return "switch";
294                 case TOKEN_DYNAMIC_SWITCH:
295                         return "dynamic switch";
296                 case TOKEN_CASE:
297                         return "case";
299                 /* ... */
300                 default:
301                         ;
302         }
304         snprintf(buf, sizeof(buf), "<token #%d>", tok);
305         return buf;
308 static jmp_buf parser_exception;
310 static void xfail(void) { longjmp(parser_exception, 1); }
312 static void next_token(void) { token = yylex(); }
314 static inline int is_token(token_type_t tok) { return (token == tok); }
316 static void _strange(int line) {
317         fprintf(stdout, "?!?!? %s:%d got: %d (%s) @%s:%d\n", __FILE__, line, token, yytext, yyfilename, yylineno);
319 #define strange() _strange(__LINE__)
321 static void _nomatch(int line) {
322         fprintf(stdout, "!!!! %s:%d got: %d (%s) @%s:%d\n", __FILE__, line, token, yytext, yyfilename, yylineno);
323         xfail();
325 #define nomatch() _nomatch(__LINE__)
327 static void _accept(token_type_t tok, int line) {
328         if (tok != token) {
329                 fprintf(stdout, "%s:%d got: %d (%s) expected %s @%s:%d\n", __FILE__, line, token, yytext, token_name(tok), yyfilename, yylineno);
330                 xfail();
331         }
332         next_token();
334 #define accept(tok) _accept(tok, __LINE__)
336 static int is_id(void) {
337         /* Some NPL files use keyword as ID (sucks...) */
338         return
339                 is_token(TOKEN_PROTOCOL) ||
340                 is_token(TOKEN_SIZE) ||
341                 is_token(TOKEN_DEFAULT) ||
342                 is_token(TOKEN_NUMBER) ||
343                 is_token(TOKEN_DECIMAL) ||
344                 is_token(TOKEN_TIME) ||
345                 is_token(TOKEN_BYTE_ORDER) ||
346                 is_token(TOKEN_OROR) || is_token(TOKEN_ANDAND) ||
347                 is_token(TOKEN_STRUCT) || is_token(TOKEN_TABLE) ||
348                 is_token(TOKEN_ID);
351 static char *_accept_id(int line) {
352         char *id;
354         if (!is_id()) {
355                 fprintf(stdout, "%s:%d got: %d (%s) expected %s @%s:%d\n", __FILE__, line, token, yytext, token_name(TOKEN_ID), yyfilename, yylineno);
356                 xfail();
357         }
358         
359         id = xstrdup(yytext);
360         next_token();
362         return id;
365 #define accept_id() _accept_id(__LINE__)
367 static unsigned int _accept_int(int line) {
368         unsigned int num;
370         if (token != TOKEN_DIGIT) {
371                 fprintf(stdout, "%s:%d got: %d (%s) expected %s @%s:%d\n", __FILE__, line, token, yytext, token_name(TOKEN_DIGIT), yyfilename, yylineno);
372                 xfail();
373         }
375         if (yytext[0] == '0' && yytext[1] == 'x')
376                 num = strtol(yytext + 2, NULL, 16);
377         else
378                 num = strtol(yytext, NULL, 10);
380         next_token();
382         return num;
385 #define accept_int() _accept_int(__LINE__)
388 static char *_accept_str(int line) {
389         size_t len;
390         char *str;
392         if (token != TOKEN_STR) {
393                 fprintf(stdout, "%s:%d got: %d (%s) expected %s @%s:%d\n", __FILE__, line, token, yytext, token_name(TOKEN_STR), yyfilename, yylineno);
394                 xfail();
395         }
397         len = strlen(yytext);
399         if (len < 2 || yytext[0] != '"' || yytext[len-1] != '"')
400                 xfail();
401 #if 0
402         char *ptr;
403         size_t i;
405         ptr = str = xmalloc(len-2+1);
406         for (i = 1; i < len-1; i++) {
407                 if (yytext[i] == '\\') {
408                         i++;
410                         if (yytext[i] == '0' && yytext[i+1] == 'x') {
411                                 i += 2;
413                                 // XXX
414                                 *ptr++ = yytext[i];
415                         } else
416                                 switch (yytext[i]) {
417                                         case '0':
418                                                 *ptr++ = '\0';
419                                                 break;
420                                         case '\\':
421                                                 *ptr++ = '\\';
422                                                 break;
423                                         case 'r':
424                                                 *ptr++ = '\r';
425                                                 break;
426                                         case 'n':
427                                                 *ptr++ = '\n';
428                                                 break;
429                                         case 't':
430                                                 *ptr++ = '\t';
431                                                 break;
433                                         case '"':
434                                                 *ptr++ = '"';
435                                                 break;
436                                         case '\'':
437                                                 *ptr++ = '\'';
438                                                 break;
440                                         default:
441                                                 fprintf(stdout, "unrecog: %c @ %d\n", yytext[i], yylineno);
442                                                 *ptr++ = yytext[i];
443                                 }
445                 } else
446                         *ptr++ = yytext[i];
447         }
449         *ptr = '\0';
450 #else
451         len -= 2;
452         /* escaping is done almost like in C so don't unescape (cause it'd require escaping later...) */
453         str = xmalloc(len + 1);
454         memcpy(str, yytext + 1, len);
455         str[len] = '\0';
456 #endif
458         next_token();
460         return str;
462 #define accept_str() _accept_str(__LINE__)
464 static int is_token_accept(token_type_t tok) {
465         if (is_token(tok)) {
466                 next_token();
467                 return 1;
468         }
469         return 0;
472 static int is_params(void) { return is_token(TOKEN_LPAREN); }
474 static void
475 parse_params(npl_params_t *p)
477         int i = 0;
479         accept(TOKEN_LPAREN);
480         do {
481                 if (i == NPL_PARAMS_MAX) {
482                         fprintf(stdout, "i == NPL_PARAMS_MAX");
483                         xfail();
484                 }
486                 p->args[i++] = accept_id();
488         } while (is_token_accept(TOKEN_COMMA));
489         accept(TOKEN_RPAREN);
491         p->count = i;
494 static void parse_expression(npl_expression_t *expr);
495 static npl_expression_t *xparse_expression(void);
497 static void
498 parse_primary(npl_expression_t *expr)
500         if (is_id()) {
501                 expr->type = EXPRESSION_ID;
502                 expr->id.id = accept_id();
503                 return;
504         }
506         if (is_token(TOKEN_DIGIT)) {
507                 expr->type = EXPRESSION_INT;
508                 expr->num.digit = accept_int();
509                 return;
510         }
512         if (is_token(TOKEN_FLOAT)) {
513                 // XXX ast
514                 accept(TOKEN_FLOAT);
515                 expr->type = -1;
516                 return;
517         }
519         if (is_token(TOKEN_CHAR)) {
520                 // XXX ast
521                 accept(TOKEN_CHAR);
522                 expr->type = -2;
523                 return;
524         }
526         if (is_token(TOKEN_STR)) {
527                 expr->type = EXPRESSION_STR;
528                 expr->str.str = accept_str();
529                 return;
530         }
532         if (is_token_accept(TOKEN_LPAREN)) {
533                 parse_expression(expr);
534                 accept(TOKEN_RPAREN);
535                 return;
536         }
538         nomatch();
541 /* ExpressionList = Expression, { ",", Expression } ; */
542 static void
543 parse_expression_list(npl_expression_list_t **ptr)
545         do {
546                 npl_expression_list_t *cur = xnew(npl_expression_list_t);
548                 *ptr = cur;
549                 ptr = &(cur->next);
550                 cur->expr = xparse_expression();
552         } while (is_token_accept(TOKEN_COMMA));
554         *ptr = NULL;
557 static void
558 parse_expression1(npl_expression_t *expr)
560         parse_primary(expr);
562         do {
563                 if (is_token_accept(TOKEN_LPAREN)) {    /* foo() */
564                         npl_expression_t *fun = xdup(npl_expression_t, expr);
565                         npl_expression_list_t *args = NULL;
567                         if (!is_token(TOKEN_RPAREN))
568                                 parse_expression_list(&args);
569                         accept(TOKEN_RPAREN);
571                         expr->type = EXPRESSION_CALL;
572                         expr->call.fn = fun;
573                         expr->call.args = args;
575                 } else if (is_token_accept(TOKEN_DOLLAR)) { /* arr$[field1, field2, ...] */
576                         npl_expression_t *base = xdup(npl_expression_t, expr);
577                         npl_expression_list_t *indexes;
579                         accept(TOKEN_LBRACKET);
580                         parse_expression_list(&indexes);
581                         accept(TOKEN_RBRACKET);
583                         expr->type = EXPRESSION_MULTI_INDEX;
584                         expr->aarr.base = base;
585                         expr->aarr.indexes = indexes;
587                 } else if (is_token_accept(TOKEN_LBRACKET)) { /* arr[10] */
588                         npl_expression_t *base = xdup(npl_expression_t, expr);
589                         npl_expression_t *idx;
591                         idx = xparse_expression();
592                         accept(TOKEN_RBRACKET);
594                         expr->type = EXPRESSION_INDEX;
595                         expr->arr.base = base;
596                         expr->arr.index = idx;
598                 } else if (is_token_accept(TOKEN_DOT)) {
599                         npl_expression_t *base = xdup(npl_expression_t, expr);
600                         char *field;
602                         field = accept_id();
604                         expr->type = EXPRESSION_FIELD;
605                         expr->fld.base = base;
606                         expr->fld.field = field;
608                 } else
609                         break;
611         } while (1);
614 static void
615 parse_expression2(npl_expression_t *expr)
617         npl_op1_t op;
618         
619         do {
620                 op = 
621                         (is_token_accept(TOKEN_MINUS)) ? OP1_MINUS : 
622                         (is_token_accept(TOKEN_NOT)) ? OP1_NOT :
623                         (is_token_accept(TOKEN_NEG)) ? OP1_NEG :
624                         OP1_INVALID;
626                 if (op != OP1_INVALID) {
627                         expr->type = EXPRESSION_UNARY;
628                         expr->u.operator = op;
630                         expr = expr->u.operand = xnew(npl_expression_t);
631                 }
632         } while (op != OP1_INVALID);
634         parse_expression1(expr);
637 static void
638 parse_expression3(npl_expression_t *expr)
640         npl_op2_t op;
642         parse_expression2(expr);
643 again:
644         op = 
645                 (is_token_accept(TOKEN_MULTIPLY)) ? OP2_MULTIPLY :
646                 (is_token_accept(TOKEN_DIV)) ? OP2_DIV : 
647                 (is_token_accept(TOKEN_PERCENT)) ? OP2_MOD :
648                 OP2_INVALID;
650         if (op != OP2_INVALID) {
651                 npl_expression_t *operand = xdup(npl_expression_t, expr);
652                 npl_expression_t *e;
654                 expr->b.operand2 = e = xnew(npl_expression_t);
655                 parse_expression3(e);
657                 expr->b.operator = op;
658                 expr->b.operand1 = operand;
659                 expr->type = EXPRESSION_BINARY;
660                 goto again;
661         }
664 static void
665 parse_expression4(npl_expression_t *expr)
667         npl_op2_t op;
669         parse_expression3(expr);
670 again:
671         op = 
672                 (is_token_accept(TOKEN_PLUS)) ? OP2_PLUS :
673                 (is_token_accept(TOKEN_MINUS)) ? OP2_MINUS : 
674                 OP2_INVALID;
676         if (op != OP2_INVALID) {
677                 npl_expression_t *operand = xdup(npl_expression_t, expr);
678                 npl_expression_t *e;
680                 expr->b.operand2 = e = xnew(npl_expression_t);
681                 parse_expression4(e);
683                 expr->b.operator = op;
684                 expr->b.operand1 = operand;
685                 expr->type = EXPRESSION_BINARY;
686                 goto again;
687         }
690 static void
691 parse_expression5(npl_expression_t *expr)
693         npl_op2_t op;
695         parse_expression4(expr);
696 again:
697         op = 
698                 (is_token_accept(TOKEN_SHL)) ? OP2_SHL :
699                 (is_token_accept(TOKEN_SHR)) ? OP2_SHR : 
700                 OP2_INVALID;
702         if (op != OP2_INVALID) {
703                 npl_expression_t *operand = xdup(npl_expression_t, expr);
704                 npl_expression_t *e;
706                 expr->b.operand2 = e = xnew(npl_expression_t);
707                 parse_expression5(e);
709                 expr->b.operator = op;
710                 expr->b.operand1 = operand;
711                 expr->type = EXPRESSION_BINARY;
712                 goto again;
713         }
716 static void
717 parse_expression6(npl_expression_t *expr)
719         npl_op2_t op;
721         parse_expression5(expr);
722 again:
723         op = 
724                 (is_token_accept(TOKEN_LESS)) ? OP2_LESS :
725                 (is_token_accept(TOKEN_GREATER)) ? OP2_GREATER : 
726                 (is_token_accept(TOKEN_LEQUAL)) ? OP2_LEQUAL :
727                 (is_token_accept(TOKEN_GEQUAL)) ? OP2_GEQUAL : 
728                 OP2_INVALID;
730         if (op != OP2_INVALID) {
731                 npl_expression_t *operand = xdup(npl_expression_t, expr);
732                 npl_expression_t *e;
734                 expr->b.operand2 = e = xnew(npl_expression_t);
735                 parse_expression6(e);
737                 expr->b.operator = op;
738                 expr->b.operand1 = operand;
739                 expr->type = EXPRESSION_BINARY;
740                 goto again;
741         }
744 static void
745 parse_expression7(npl_expression_t *expr)
747         npl_op2_t op;
749         parse_expression6(expr);
750 again:
751         op = 
752                 (is_token_accept(TOKEN_EQUAL)) ? OP2_EQUAL :
753                 (is_token_accept(TOKEN_NOTEQUAL)) ? OP2_NOTEQUAL : 
754                 (is_token_accept(TOKEN_NOTEQUAL2)) ? OP2_NOTEQUAL : 
755                 OP2_INVALID;
757         if (op != OP2_INVALID) {
758                 npl_expression_t *operand = xdup(npl_expression_t, expr);
759                 npl_expression_t *e;
761                 expr->b.operand2 = e = xnew(npl_expression_t);
762                 parse_expression7(e);
764                 expr->b.operator = op;
765                 expr->b.operand1 = operand;
766                 expr->type = EXPRESSION_BINARY;
767                 goto again;
768         }
771 static void
772 parse_expression8(npl_expression_t *expr)
774         parse_expression7(expr);
775 again:
776         if (is_token_accept(TOKEN_AND)) {
777                 npl_expression_t *operand = xdup(npl_expression_t, expr);
778                 npl_expression_t *e;
780                 expr->b.operand2 = e = xnew(npl_expression_t);
781                 parse_expression8(e);
783                 expr->b.operator = OP2_AND;
784                 expr->b.operand1 = operand;
785                 expr->type = EXPRESSION_BINARY;
786                 goto again;
787         }
790 static void
791 parse_expression9(npl_expression_t *expr)
793         parse_expression8(expr);
794 again:
795         if (is_token_accept(TOKEN_XOR)) {
796                 npl_expression_t *operand = xdup(npl_expression_t, expr);
797                 npl_expression_t *e;
799                 expr->b.operand2 = e = xnew(npl_expression_t);
800                 parse_expression9(e);
802                 expr->b.operator = OP2_XOR;
803                 expr->b.operand1 = operand;
804                 expr->type = EXPRESSION_BINARY;
805                 goto again;
806         }
809 static void
810 parse_expression10(npl_expression_t *expr)
812         parse_expression9(expr);
813 again:
814         if (is_token_accept(TOKEN_OR)) {
815                 npl_expression_t *operand = xdup(npl_expression_t, expr);
816                 npl_expression_t *e;
818                 expr->b.operand2 = e = xnew(npl_expression_t);
819                 parse_expression10(e);
821                 expr->b.operator = OP2_OR;
822                 expr->b.operand1 = operand;
823                 expr->type = EXPRESSION_BINARY;
824                 goto again;
825         }
828 static void
829 parse_expression11(npl_expression_t *expr)
831         npl_op2_t op;
833         parse_expression10(expr);
834 again:
835         op = 
836                 (is_token_accept(TOKEN_LOGIC_AND)) ? OP2_LOGIC_AND :
837                 (is_token_accept(TOKEN_ANDAND)) ? OP2_LOGIC_AND : 
838                 OP2_INVALID;
840         if (op != OP2_INVALID) {
841                 npl_expression_t *operand = xdup(npl_expression_t, expr);
842                 npl_expression_t *e;
844                 expr->b.operand2 = e = xnew(npl_expression_t);
845                 parse_expression11(e);
847                 expr->b.operator = op;
848                 expr->b.operand1 = operand;
849                 expr->type = EXPRESSION_BINARY;
850                 goto again;
851         }
854 static void
855 parse_expression12(npl_expression_t *expr)
857         npl_op2_t op;
859         parse_expression11(expr);
860 again:
861         op = 
862                 (is_token_accept(TOKEN_LOGIC_OR)) ? OP2_LOGIC_OR :
863                 (is_token_accept(TOKEN_OROR)) ? OP2_LOGIC_OR : 
864                 OP2_INVALID;
866         if (op != OP2_INVALID) {
867                 npl_expression_t *operand = xdup(npl_expression_t, expr);
868                 npl_expression_t *e;
870                 expr->b.operand2 = e = xnew(npl_expression_t);
871                 parse_expression12(e);
873                 expr->b.operator = op;
874                 expr->b.operand1 = operand;
875                 expr->type = EXPRESSION_BINARY;
876                 goto again;
877         }
880 static void
881 parse_expression13(npl_expression_t *expr)
883         parse_expression12(expr);
885         if (is_token_accept(TOKEN_COND)) {
886                 npl_expression_t *operand = xdup(npl_expression_t, expr);
887                 npl_expression_t *e;
889                 expr->c.test_expr = operand;
891                 e = xnew(npl_expression_t);
892                 parse_expression(e);
893                 expr->c.true_expr = e;
894                 accept(TOKEN_COLON);
896                 e = xnew(npl_expression_t);
897                 parse_expression13(e);
898                 expr->c.false_expr = e;
900                 expr->type = EXPRESSION_COND;
901         }
904 static npl_expression_t *
905 xparse_expression(void)
907         npl_expression_t *expr = xnew(npl_expression_t);
909         parse_expression(expr);
910         return expr;
913 static void
914 parse_expression(npl_expression_t *expr)
916         npl_op2_t op;
918         parse_expression13(expr);
920         op = 
921                 (is_token_accept(TOKEN_ASSIGN)) ? OP2_ASSIGN :
922                 (is_token_accept(TOKEN_ASSIGN_PLUS)) ? OP2_ASSIGN_PLUS : 
923                 OP2_INVALID;
925         if (op != OP2_INVALID) {
926                 npl_expression_t *operand = xdup(npl_expression_t, expr);
928                 expr->b.operand2 = xparse_expression();
930                 expr->b.operator = op;
931                 expr->b.operand1 = operand;
932                 expr->type = EXPRESSION_BINARY;
933         }
936 static int is_attribute(void) { return is_token(TOKEN_LBRACKET); }
938 static npl_attribute_list_t **
939 pparse_attributes(npl_attribute_list_t **ptr)
941         accept(TOKEN_LBRACKET);
943         do {
944                 npl_attribute_list_t *cur = xnew(npl_attribute_list_t);
946                 *ptr = cur;
947                 ptr = &(cur->next);
948                 cur->expr = xparse_expression();
950                 if (is_token_accept(TOKEN_SEMICOLON))
951                         { }
952                 else if (is_token_accept(TOKEN_COMMA))
953                         { }
954         } 
955         while (!is_token(TOKEN_RBRACKET));
956 //      while (is_token_accept(TOKEN_COMMA));
958         accept(TOKEN_RBRACKET);
959         return ptr;
962 static void
963 parse_all_attributes(npl_attribute_list_t **attr_ptr)
965         while (is_attribute())
966                 attr_ptr = pparse_attributes(attr_ptr);
967         *attr_ptr = NULL;
970 static void parse_statement(npl_statement_t *st);
972 static npl_statement_t *
973 xparse_statement(void)
975         npl_statement_t *st = xnew(npl_statement_t);
977         parse_statement(st);
978         return st;
981 static void
982 parse_switch_body(npl_switch_t *sw)
984         struct npl_switch_case **ptr = &sw->cases;
986         while (is_token(TOKEN_CASE)) {
987                 struct npl_switch_case *cur = xnew(struct npl_switch_case);
989                 *ptr = cur;
991                 ptr = &(cur->next);
993                 accept(TOKEN_CASE);
994                 parse_expression(&cur->e);
995                 accept(TOKEN_COLON);
997                 if (!is_token(TOKEN_CASE) && !is_token(TOKEN_DEFAULT)) {
998                         cur->st = xparse_statement();
999                         is_token_accept(TOKEN_SEMICOLON);
1000                 }
1001         }
1002         *ptr = NULL;
1004         if (is_token_accept(TOKEN_DEFAULT)) {
1005                 accept(TOKEN_COLON);
1006                 sw->default_st = xparse_statement();
1007         }
1010 static void
1011 parse_switch(npl_switch_t *sw)
1013         accept(TOKEN_SWITCH);
1015         if (is_token_accept(TOKEN_LPAREN)) {
1016                 sw->switch_expr = xparse_expression();
1017                 accept(TOKEN_RPAREN);
1018         }
1020         accept(TOKEN_LCURLY);
1021         parse_switch_body(sw);
1022         accept(TOKEN_RCURLY);
1023         is_token_accept(TOKEN_SEMICOLON);
1026 static void
1027 parse_dynamic_switch(npl_switch_t *sw)
1029         accept(TOKEN_DYNAMIC_SWITCH);
1031         sw->switch_expr = xparse_expression();
1033         accept(TOKEN_LCURLY);
1034         parse_switch_body(sw);
1035         accept(TOKEN_RCURLY);
1036         is_token_accept(TOKEN_SEMICOLON);
1039 static int is_statement(void) {
1040         return 
1041                 is_token(TOKEN_WHILE) ||
1042                 is_token(TOKEN_TABLE) || 
1043                 is_token(TOKEN_STRUCT) || is_token(TOKEN_PRIVATE_STRUCT) ||
1044                 is_token(TOKEN_SWITCH) || is_token(TOKEN_DYNAMIC_SWITCH) ||
1045                 is_id() || is_attribute() ||
1046 #if 1
1047                 is_token(TOKEN_SEMICOLON) ||
1048 #endif
1049                 0
1050                 ;
1053 /* Statements = { Statement } ; */
1054 static struct _npl_statements *
1055 xparse_statements(void)
1057         struct _npl_statements *ret;
1058         struct _npl_statements **ptr = &ret;
1060         while (is_statement()) {
1061                 struct _npl_statements *cur = xnew(struct _npl_statements);
1063                 parse_statement(&cur->st);
1065                 *ptr = cur;
1066                 ptr = &(cur->next);
1067         }
1068         *ptr = NULL;
1070         return ret;
1073 static void
1074 parse_while(npl_statement_t *st)
1076         accept(TOKEN_WHILE);
1078         if (is_id())
1079                 st->w.id = accept_id();
1081         accept(TOKEN_LBRACKET);
1082         parse_expression(&st->w.expr);
1083         accept(TOKEN_RBRACKET);
1085         accept(TOKEN_LCURLY);
1086         st->w.sts = xparse_statements();
1087         accept(TOKEN_RCURLY);
1088         is_token_accept(TOKEN_SEMICOLON);
1091 static int is_formatting(void) { return is_token(TOKEN_ASSIGN); }
1093 /* Formatting = "=", Expression ; */
1094 static npl_expression_t *
1095 xparse_formatting(void)
1097         npl_expression_t *format;
1099         accept(TOKEN_ASSIGN);
1100         
1101         format = xnew(npl_expression_t);
1102         parse_expression(format);
1103         return format;
1106 static void parse_table(npl_table_t *);
1107 static void parse_struct(npl_struct_t *s, int statement);
1109 static void
1110 parse_statement(npl_statement_t *st)
1112         parse_all_attributes(&st->attr_list);
1114         if (is_token(TOKEN_WHILE)) {
1115                 parse_while(st);
1116                 st->type = STATEMENT_WHILE;
1117                 return;
1118         }
1120         if (is_token(TOKEN_TABLE)) {
1121                 parse_table(&st->t.data);
1122                 st->type = STATEMENT_TABLE;
1123                 return;
1124         }
1126         if (is_token(TOKEN_STRUCT) || is_token(TOKEN_PRIVATE_STRUCT)) {
1127                 parse_struct(&st->s.data, 1);
1128                 st->type = STATEMENT_STRUCT;
1129                 return;
1130         }
1132         if (is_token(TOKEN_SWITCH)) {
1133                 parse_switch(&(st->sw.data));
1134                 st->type = STATEMENT_SWITCH;
1135                 return;
1136         }
1138         if (is_token(TOKEN_DYNAMIC_SWITCH)) {
1139                 parse_dynamic_switch(&(st->sw.data));
1140                 st->type = STATEMENT_DYNAMIC_SWITCH;
1141                 return;
1142         }
1143 #if 1
1144         if (is_token(TOKEN_SEMICOLON)) {
1145                 accept(TOKEN_SEMICOLON);
1146                 st->type = -3;
1147                 return;
1148         }
1149 #endif
1151         st->type = STATEMENT_FIELD;
1152         st->f.t_id = accept_id();
1154         if (is_token_accept(TOKEN_LPAREN)) {
1155                 parse_expression_list(&st->f.params);
1156                 accept(TOKEN_RPAREN);
1158         } else
1159                 st->f.params = NULL;
1161         st->f.id = accept_id();
1162         if (is_token_accept(TOKEN_COLON))
1163                 st->f.bits = accept_int();
1165         else if (is_token_accept(TOKEN_LBRACKET)) {
1166                 st->f.arr = xparse_expression();
1167                 accept(TOKEN_RBRACKET);
1168         }
1170         if (is_formatting())
1171                 st->f.format = xparse_formatting();
1173         if (is_token_accept(TOKEN_LCURLY)) {
1174                 st->f.sts = xparse_statements();
1175                 accept(TOKEN_RCURLY);
1176                 is_token_accept(TOKEN_SEMICOLON);
1177                 return;
1178         }
1180         accept(TOKEN_SEMICOLON);
1183 /* Protocol = "protocol", ID, [Params], [Formatting], "{", Statements, "}", ";" ; */
1184 static void
1185 parse_protocol(npl_protocol_t *p)
1187         accept(TOKEN_PROTOCOL);
1188         p->id = accept_id();
1190         if (is_params())
1191                 parse_params(&p->params);
1193         if (is_formatting())
1194                 p->format = xparse_formatting();
1196         accept(TOKEN_LCURLY);
1197         p->sts = xparse_statements();
1198         accept(TOKEN_RCURLY);
1199         is_token_accept(TOKEN_SEMICOLON);
1202 static void
1203 parse_struct(npl_struct_t *s, int statement)
1205         if (is_token_accept(TOKEN_STRUCT))
1206                 s->private = 0;
1207         else if (is_token_accept(TOKEN_PRIVATE_STRUCT))
1208                 s->private = 1;
1209         else
1210                 nomatch();
1212         if (!statement || is_id())
1213                 s->id = accept_id();
1215         if (is_params())
1216                 parse_params(&s->params);
1218         if (statement) {
1219                 if (is_token_accept(TOKEN_LBRACKET)) {
1220                         s->count_expr = xparse_expression();
1221                         accept(TOKEN_RBRACKET);
1222                 }
1223         }
1225         if (is_formatting())
1226                 s->format = xparse_formatting();
1228         accept(TOKEN_LCURLY);
1229         s->sts = xparse_statements();
1230         accept(TOKEN_RCURLY);
1231         is_token_accept(TOKEN_SEMICOLON);
1234 /* Table = "table", ID, [Params], "{", "switch", [ "(", Expr, ")" ], {TableCase}, [DefaultCase], "}", ";" ;
1236    DefaultCase = "default", ":", Expression", ";" ;
1237  */
1238 static void
1239 parse_table(npl_table_t *t)
1241         accept(TOKEN_TABLE);
1242         t->id = accept_id();
1243         if (is_params())
1244                 parse_params(&t->params);
1246         accept(TOKEN_LCURLY);
1247         {
1248                 struct npl_table_case **ptr;
1250                 accept(TOKEN_SWITCH);
1251                 if (is_token_accept(TOKEN_LPAREN)) {
1252                         t->switch_expr = xparse_expression();
1253                         accept(TOKEN_RPAREN);
1254                 }
1256                 accept(TOKEN_LCURLY);
1258                 ptr = &(t->cases);
1259                 while (is_token_accept(TOKEN_CASE)) {
1260                         struct npl_table_case *cur;
1262                         cur = *ptr = xnew(struct npl_table_case);
1263                         ptr = &(cur->next);
1265                         parse_expression(&(cur->e));
1266                         accept(TOKEN_COLON);
1268                         while (is_token_accept(TOKEN_CASE)) {
1269                                 cur = *ptr = xnew(struct npl_table_case);
1270                                 ptr = &(cur->next);
1272                                 parse_expression(&(cur->e));
1273                                 accept(TOKEN_COLON);
1274                         }
1275                         cur->return_expr = xparse_expression();
1276                         accept(TOKEN_SEMICOLON);
1277                 }
1278                 *ptr = NULL;
1280                 if (is_token_accept(TOKEN_DEFAULT)) {
1281                         accept(TOKEN_COLON);
1282                         t->default_expr = xparse_expression();
1283                         accept(TOKEN_SEMICOLON);
1284                 }
1285                 accept(TOKEN_RCURLY);
1287         }
1288         accept(TOKEN_RCURLY);
1289         is_token_accept(TOKEN_SEMICOLON);
1292 static int
1293 is_type(void)
1295         return
1296                 is_token(TOKEN_DECIMAL) ||
1297                 is_token(TOKEN_NUMBER) ||
1298                 is_token(TOKEN_TIME) ||
1299                 is_token(TOKEN_UNSIGNED_NUMBER);
1302 /* Type = BasicType, ID, [Params], "{", {TypeAttr}, "}" ;
1304    BasicType = "Decimal" | "Number" | "Time" | "UnsignedNumber" ;
1306    TypeAttr = AttrName, "=", Expression ;
1308    AttrName = "ByteOrder" | "DisplayFormat" | "Size" ;
1309  */
1310 static void
1311 parse_type(npl_type_t *t)
1313         if (is_token_accept(TOKEN_DECIMAL))
1314                 t->type = FIELD_DECIMAL;
1315         else if (is_token_accept(TOKEN_NUMBER))
1316                 t->type = FIELD_NUMBER;
1317         else if (is_token_accept(TOKEN_TIME))
1318                 t->type = FIELD_TIME;
1319         else if (is_token_accept(TOKEN_UNSIGNED_NUMBER))
1320                 t->type = FIELD_UNSIGNED_NUMBER;
1321         else
1322                 nomatch();
1324         t->id = accept_id();
1325         if (is_params())
1326                 parse_params(&t->params);
1327         accept(TOKEN_LCURLY);
1329         while (!is_token(TOKEN_RCURLY)) {
1330                 npl_expression_t **ptr;
1332                 if (is_token_accept(TOKEN_BYTE_ORDER))
1333                         ptr = &t->byte_order;
1334                 else if (is_token_accept(TOKEN_DISPLAY_FORMAT))
1335                         ptr = &t->display_format;
1336                 else if (is_token_accept(TOKEN_SIZE))
1337                         ptr = &t->size;
1338                 else
1339                         nomatch();
1340 #if 0
1341                 if (*ptr)
1342                         fprintf(stdout, "already got %s attr!\n", str);
1343 #endif
1344                 accept(TOKEN_ASSIGN);
1345                 *ptr = xparse_expression();
1347                 if (is_token_accept(TOKEN_COMMA))
1348                         { }
1349                 else if (is_token_accept(TOKEN_SEMICOLON))
1350                         { }
1351         }
1352         accept(TOKEN_RCURLY);
1355 /* Const = "const", ID, "=", Expression, ";" ; */
1356 static void
1357 parse_const(npl_const_t *c)
1359         accept(TOKEN_CONST);
1360         c->id = accept_id();
1361         accept(TOKEN_ASSIGN);
1362         parse_expression(&c->expr);
1363         accept(TOKEN_SEMICOLON);
1366 /* Declaration = Attributes
1367                | Struct
1368                | Table
1369                | Const
1370                | Protocol
1371                | Type
1372                | ( "include", STR )
1373                ;
1374  */
1375 static void
1376 parse_decl(npl_decl_t *d)
1378         parse_all_attributes(&d->attr_list);
1380         if (is_token(TOKEN_STRUCT)) {
1381                 d->type = DECL_STRUCT;
1382                 parse_struct(&d->s.data, 0);
1384         } else if (is_token(TOKEN_TABLE)) {
1385                 d->type = DECL_TABLE;
1386                 parse_table(&d->t.data);
1388         } else if (is_token(TOKEN_CONST)) {
1389                 d->type = DECL_CONST;
1390                 parse_const(&d->c.data);
1392         } else if (is_token(TOKEN_PROTOCOL)) {
1393                 d->type = DECL_PROTOCOL;
1394                 parse_protocol(&d->p.data);
1396         } else if (is_type()) {
1397                 d->type = DECL_TYPE;
1398                 parse_type(&d->ty.data);
1400         } else if (is_token_accept(TOKEN_INCLUDE)) {
1401                 d->type = DECL_INCLUDE;
1402                 d->i.file = accept_str();       /* XXX, it's C-escaped */ /* XXX, unix / vs dos \\  */
1404         } else
1405                 nomatch();
1408 /* NPL = { Declaration } ; */
1409 static void
1410 parse_npl(npl_code_t *code)
1412         struct _npl_decl_list **ptr = &(code->decls);
1414         while (!is_token_accept(TOKEN_EOF)) {
1415                 struct _npl_decl_list *cur = xnew(struct _npl_decl_list);
1417                 *ptr = cur;
1418                 ptr = &(cur->next);
1420                 parse_decl(&cur->d);
1421         }
1422         *ptr = NULL;
1426 npl_parse_file(npl_code_t *code, FILE *f, const char *filename)
1428         volatile int parse_ok = 0;
1430         yyfilename = filename;
1431         yyin = f;
1433         if (!setjmp(parser_exception)) {
1434                 next_token();
1435                 parse_npl(code);
1436                 parse_ok = 1;
1437         }
1439         yylex_destroy();
1441         return (parse_ok == 1);