summaryrefslogtreecommitdiff
path: root/tools/npl/parser.l
diff options
context:
space:
mode:
authorJakub Zawadzki <darkjames-ws@darkjames.pl>2013-03-03 11:59:14 +0000
committerJakub Zawadzki <darkjames-ws@darkjames.pl>2013-03-03 11:59:14 +0000
commite0d19cb73a2d9f827cdf254d46362d532af2b81a (patch)
treef26df0b7dd18fd0ba36a93fe627f64a1c050f6fe /tools/npl/parser.l
parent78fe8ac7e9e4deced1659f9d6c63888743ae382e (diff)
downloadwireshark-e0d19cb73a2d9f827cdf254d46362d532af2b81a.tar.gz
Publish initial version of mine npl (Network Parsing Language) generator sources.
Parser pass almost all npl files from Network Monitor Parsers 3.4.2774 package, but but not all data is stored in AST. Work on wireshark code enerator has been started, but it need much more work. Beware! It's ugly, putting it to wireshark repo, just to not lose sources :) (feel free to improve/review it). svn path=/trunk/; revision=48033
Diffstat (limited to 'tools/npl/parser.l')
-rw-r--r--tools/npl/parser.l1438
1 files changed, 1438 insertions, 0 deletions
diff --git a/tools/npl/parser.l b/tools/npl/parser.l
new file mode 100644
index 0000000000..85a7981539
--- /dev/null
+++ b/tools/npl/parser.l
@@ -0,0 +1,1438 @@
+/*
+ * Copyright 2012-2013, Jakub Zawadzki <darkjames-ws@darkjames.pl>
+ *
+ * $Id$
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+%option noyywrap
+%option nounput
+
+%option noyy_scan_buffer
+%option noyy_scan_bytes
+%option noyy_scan_string
+
+%option yylineno
+%option never-interactive
+
+%option case-insensitive
+
+%{
+#define YY_DECL static token_type_t yylex(void)
+
+#include <stdarg.h>
+#include "ast.h"
+#include "xmem.h"
+
+typedef enum {
+ TOKEN_ERROR = -1,
+ TOKEN_EOF = 0,
+
+ TOKEN_INCLUDE,
+ TOKEN_STRUCT,
+ TOKEN_PRIVATE_STRUCT,
+ TOKEN_CONST,
+
+ TOKEN_WHILE,
+
+ TOKEN_SWITCH,
+ TOKEN_DYNAMIC_SWITCH,
+ TOKEN_CASE,
+
+ TOKEN_ID,
+ TOKEN_STR,
+ TOKEN_CHAR,
+ TOKEN_DIGIT,
+ TOKEN_FLOAT,
+
+ TOKEN_LPAREN,
+ TOKEN_RPAREN,
+ TOKEN_LBRACKET,
+ TOKEN_RBRACKET,
+ TOKEN_LCURLY,
+ TOKEN_RCURLY,
+
+ TOKEN_EQUAL,
+ TOKEN_NOTEQUAL,
+ TOKEN_NOTEQUAL2,
+
+ TOKEN_LEQUAL,
+ TOKEN_GEQUAL,
+
+ TOKEN_ASSIGN,
+ TOKEN_PLUS,
+ TOKEN_MINUS,
+ TOKEN_MULTIPLY,
+ TOKEN_DIV,
+ TOKEN_LOGIC_OR,
+ TOKEN_OR,
+ TOKEN_LOGIC_AND,
+ TOKEN_AND,
+ TOKEN_NOT,
+ TOKEN_NEG,
+ TOKEN_XOR,
+
+ TOKEN_SHL,
+ TOKEN_SHR,
+
+ TOKEN_PERCENT,
+ TOKEN_DOLLAR,
+ TOKEN_COND,
+ TOKEN_COLON,
+
+ TOKEN_SEMICOLON,
+ TOKEN_DOT,
+ TOKEN_COMMA,
+
+ TOKEN_LESS,
+ TOKEN_GREATER,
+
+} token_type_t;
+
+%}
+
+%x cppcomment
+%x lch
+%x lstr
+%x lstrescape
+
+DIGIT10 [0-9]
+DIGIT16 [0-9a-fA-F]
+
+ID [_a-zA-Z][_a-zA-Z0-9]*
+
+%%
+
+include return TOKEN_INCLUDE;
+struct return TOKEN_STRUCT;
+_struct return TOKEN_PRIVATE_STRUCT;
+
+const return TOKEN_CONST;
+
+while return TOKEN_WHILE;
+
+switch return TOKEN_SWITCH;
+DynamicSwitch return TOKEN_DYNAMIC_SWITCH;
+case return TOKEN_CASE;
+
+"(" return TOKEN_LPAREN;
+")" return TOKEN_RPAREN;
+"[" return TOKEN_LBRACKET;
+"]" return TOKEN_RBRACKET;
+"{" return TOKEN_LCURLY;
+"}" return TOKEN_RCURLY;
+
+"==" return TOKEN_EQUAL;
+"!=" return TOKEN_NOTEQUAL;
+"<>" return TOKEN_NOTEQUAL2;
+
+">=" return TOKEN_GEQUAL;
+"<=" return TOKEN_LEQUAL;
+
+"=" return TOKEN_ASSIGN;
+"+" return TOKEN_PLUS;
+"-" return TOKEN_MINUS;
+"*" return TOKEN_MULTIPLY;
+"/" return TOKEN_DIV;
+"||" return TOKEN_LOGIC_OR;
+"|" return TOKEN_OR;
+"&&" return TOKEN_LOGIC_AND;
+"&" return TOKEN_AND;
+"!" return TOKEN_NOT;
+"~" return TOKEN_NEG;
+"^" return TOKEN_XOR;
+"<<" return TOKEN_SHL;
+">>" return TOKEN_SHR;
+"%" return TOKEN_PERCENT;
+"$" return TOKEN_DOLLAR;
+"?" return TOKEN_COND;
+
+";" return TOKEN_SEMICOLON;
+"." return TOKEN_DOT;
+"," return TOKEN_COMMA;
+":" return TOKEN_COLON;
+
+"<" return TOKEN_LESS;
+">" return TOKEN_GREATER;
+
+"'" yymore(); BEGIN(lch);
+<lch>{
+ "'" BEGIN(INITIAL); return TOKEN_CHAR;
+ "\n" return TOKEN_ERROR;
+ . yymore();
+}
+
+"\"" yymore(); BEGIN(lstr);
+<lstr>{
+ "\"" BEGIN(INITIAL); return TOKEN_STR;
+ "\\" yymore(); BEGIN(lstrescape);
+ "\n" return TOKEN_ERROR;
+ . yymore();
+}
+
+<lstrescape>{
+ "\n" return TOKEN_ERROR;
+ . yymore(); BEGIN(lstr);
+}
+
+"//" BEGIN(cppcomment);
+<cppcomment>{
+ "\n" BEGIN(INITIAL);
+ . ;
+}
+
+"/*" {
+ int nested = 1;
+ int ch, last_ch;
+
+ last_ch = '*';
+
+ /* XXX, can comments be nested? (can't be determinated by current example file set) */
+
+ do {
+ ch = input();
+
+ if (last_ch == '*' && ch == '/')
+ nested--;
+
+ if (last_ch == '/' && ch == '*')
+ nested++;
+
+ if (ch == EOF)
+ return TOKEN_ERROR;
+
+ last_ch = ch;
+
+ } while(nested);
+}
+
+{ID} return TOKEN_ID;
+{DIGIT10}+"."{DIGIT10}* return TOKEN_FLOAT;
+{DIGIT10}+ return TOKEN_DIGIT;
+"0x"{DIGIT16}+ return TOKEN_DIGIT;
+
+[[:space:]] ;
+
+. return TOKEN_ERROR;
+
+%%
+
+static const char *yyfilename;
+static int token;
+
+static const char *token_name(token_type_t tok) {
+ static char buf[64];
+
+ switch (tok) {
+ case TOKEN_EOF: return "<<eof>>";
+ case TOKEN_ERROR: return "<<error>>";
+
+ case TOKEN_ID:
+ return "<ID>";
+ case TOKEN_STR:
+ return "<STR>";
+ case TOKEN_CHAR:
+ return "<CHAR>";
+ case TOKEN_DIGIT:
+ return "<DIGIT>";
+ case TOKEN_FLOAT:
+ return "<FLOAT>";
+
+ case TOKEN_STRUCT:
+ return "struct";
+ case TOKEN_PRIVATE_STRUCT:
+ return "_struct";
+ case TOKEN_CONST:
+ return "const";
+ case TOKEN_WHILE:
+ return "while";
+ case TOKEN_SWITCH:
+ return "switch";
+ case TOKEN_DYNAMIC_SWITCH:
+ return "dynamic switch";
+ case TOKEN_CASE:
+ return "case";
+
+ /* ... */
+ default:
+ ;
+ }
+
+ snprintf(buf, sizeof(buf), "<token #%d>", tok);
+ return buf;
+}
+
+static void next_token(void) {
+ token = yylex();
+}
+
+static void _strange(int line) {
+ fprintf(stdout, "?!?!? %s:%d got: %d (%s) @%s:%d\n", __FILE__, line, token, yytext, yyfilename, yylineno);
+}
+#define strange() _strange(__LINE__)
+
+static void _nomatch(int line) {
+ fprintf(stdout, "!!!! %s:%d got: %d (%s) @%s:%d\n", __FILE__, line, token, yytext, yyfilename, yylineno);
+ abort();
+}
+#define nomatch() _nomatch(__LINE__)
+
+static void _accept(token_type_t tok, int line) {
+ if (tok != token) {
+ fprintf(stdout, "%s:%d got: %d (%s) expected %s @%s:%d\n", __FILE__, line, token, yytext, token_name(tok), yyfilename, yylineno);
+ abort();
+ }
+ next_token();
+}
+#define accept(tok) _accept(tok, __LINE__)
+
+static char *_accept_id(int line) {
+ char *id;
+
+ if (token != TOKEN_ID) {
+ fprintf(stdout, "%s:%d got: %d (%s) expected %s @%s:%d\n", __FILE__, line, token, yytext, token_name(TOKEN_ID), yyfilename, yylineno);
+ abort();
+ }
+
+ id = xstrdup(yytext);
+ next_token();
+
+ return id;
+}
+
+#define accept_id() _accept_id(__LINE__)
+
+static unsigned int _accept_int(int line) {
+ unsigned int num;
+
+ if (token != TOKEN_DIGIT) {
+ fprintf(stdout, "%s:%d got: %d (%s) expected %s @%s:%d\n", __FILE__, line, token, yytext, token_name(TOKEN_DIGIT), yyfilename, yylineno);
+ abort();
+ }
+
+ if (yytext[0] == '0' && yytext[1] == 'x')
+ num = strtol(yytext + 2, NULL, 16);
+ else
+ num = strtol(yytext, NULL, 10);
+
+ next_token();
+
+ return num;
+}
+
+#define accept_int() _accept_int(__LINE__)
+
+
+static char *_accept_str(int line) {
+ size_t len;
+ char *str;
+
+ if (token != TOKEN_STR) {
+ fprintf(stdout, "%s:%d got: %d (%s) expected %s @%s:%d\n", __FILE__, line, token, yytext, token_name(TOKEN_STR), yyfilename, yylineno);
+ abort();
+ }
+
+ len = strlen(yytext);
+
+ if (len < 2 || yytext[0] != '"' || yytext[len-1] != '"')
+ abort();
+#if 0
+ char *ptr;
+ size_t i;
+
+ ptr = str = xmalloc(len-2+1);
+ for (i = 1; i < len-1; i++) {
+ if (yytext[i] == '\\') {
+ i++;
+
+ if (yytext[i] == '0' && yytext[i+1] == 'x') {
+ i += 2;
+
+ // XXX
+ *ptr++ = yytext[i];
+ } else
+ switch (yytext[i]) {
+ case '0':
+ *ptr++ = '\0';
+ break;
+ case '\\':
+ *ptr++ = '\\';
+ break;
+ case 'r':
+ *ptr++ = '\r';
+ break;
+ case 'n':
+ *ptr++ = '\n';
+ break;
+ case 't':
+ *ptr++ = '\t';
+ break;
+
+ case '"':
+ *ptr++ = '"';
+ break;
+ case '\'':
+ *ptr++ = '\'';
+ break;
+
+ default:
+ fprintf(stderr, "unrecog: %c @ %d\n", yytext[i], yylineno);
+ *ptr++ = yytext[i];
+ }
+
+ } else
+ *ptr++ = yytext[i];
+ }
+
+ *ptr = '\0';
+#else
+ len -= 2;
+ /* escaping is done almost like in C so don't unescape (cause it'd require escaping later...) */
+ str = xmalloc(len + 1);
+ memcpy(str, yytext + 1, len);
+ str[len] = '\0';
+#endif
+
+ next_token();
+
+ return str;
+}
+#define accept_str() _accept_str(__LINE__)
+
+static inline int is_token(token_type_t tok) { return (token == tok); }
+
+static int is_token_accept(token_type_t tok) {
+ if (is_token(tok)) {
+ next_token();
+ return 1;
+ }
+ return 0;
+}
+
+/* Some NPL files use keyword as ID (sucks...) */
+static int is_keyword(const char *str) {
+ if (is_token(TOKEN_ID) && yytext)
+ return (strcasecmp(yytext, str) == 0);
+ return 0;
+}
+
+static int is_keyword_accept(const char *str) {
+ if (is_keyword(str)) {
+ next_token();
+ return 1;
+ }
+ return 0;
+}
+
+static int is_default(void) {
+ return is_keyword("default");
+}
+
+static void accept_default(void) {
+ if (!is_default())
+ nomatch();
+ next_token();
+}
+
+static int is_protocol(void) {
+ return is_keyword("protocol");
+}
+
+static void accept_protocol(void) {
+ if (!is_protocol())
+ nomatch();
+ next_token();
+}
+
+static int is_table(void) {
+ return is_keyword("table");
+}
+
+static void accept_table(void) {
+ if (!is_table())
+ nomatch();
+ next_token();
+}
+
+static int is_oror(void) {
+ return is_keyword("or");
+}
+
+static int is_oror_accept(void) {
+ if (is_oror()) {
+ next_token();
+ return 1;
+ }
+ return 0;
+}
+
+static int is_andand_accept(void) {
+ return is_keyword_accept("and");
+}
+
+static int is_params(void) { return is_token(TOKEN_LPAREN); }
+
+static void
+parse_params(npl_params_t *p)
+{
+ int i = 0;
+
+ accept(TOKEN_LPAREN);
+ do {
+ if (i == NPL_PARAMS_MAX)
+ abort();
+
+ p->args[i++] = accept_id();
+
+ } while (is_token_accept(TOKEN_COMMA));
+ accept(TOKEN_RPAREN);
+
+ p->count = i;
+}
+
+static void parse_expression(npl_expression_t *expr);
+static npl_expression_t *xparse_expression(void);
+static npl_expression_t g_e;
+
+static void
+parse_primary(npl_expression_t *expr)
+{
+ if (is_token(TOKEN_ID)) {
+ expr->type = EXPRESSION_ID;
+ expr->id.id = accept_id();
+ return;
+ }
+
+ if (is_token(TOKEN_DIGIT)) {
+ expr->type = EXPRESSION_INT;
+ expr->num.digit = accept_int();
+ return;
+ }
+
+ if (is_token(TOKEN_FLOAT)) {
+ // XXX ast
+ accept(TOKEN_FLOAT);
+ expr->type = 0;
+ return;
+ }
+
+ if (is_token(TOKEN_CHAR)) {
+ // XXX ast
+ accept(TOKEN_CHAR);
+ expr->type = 0;
+ return;
+ }
+
+ if (is_token(TOKEN_STR)) {
+ expr->type = EXPRESSION_STR;
+ expr->str.str = accept_str();
+ return;
+ }
+
+ if (is_token_accept(TOKEN_LPAREN)) {
+ parse_expression(expr);
+ accept(TOKEN_RPAREN);
+ return;
+ }
+
+ nomatch();
+}
+
+static void
+parse_expression1(npl_expression_t *expr)
+{
+ parse_primary(expr);
+
+ do {
+ if (is_token_accept(TOKEN_LPAREN)) { /* foo() */
+ npl_expression_t *fun = xdup(npl_expression_t, expr);
+ struct _npl_expression_list **ptr = &(expr->call.args);
+
+ if (!is_token(TOKEN_RPAREN)) {
+ do {
+ struct _npl_expression_list *cur = xnew(struct _npl_expression_list);
+
+ *ptr = cur;
+ ptr = &(cur->next);
+ cur->expr = xparse_expression();
+
+ } while (is_token_accept(TOKEN_COMMA));
+ }
+ *ptr = NULL;
+
+ accept(TOKEN_RPAREN);
+ expr->call.fn = fun;
+ expr->type = EXPRESSION_CALL;
+
+ } else if (is_token(TOKEN_DOLLAR) || is_token(TOKEN_LBRACKET)) { /* $arr[field1, field2, ...], arr[10] */
+ npl_expression_t *base = xdup(npl_expression_t, expr);
+ npl_expression_t *idx;
+ int aa;
+
+ aa = is_token_accept(TOKEN_DOLLAR);
+ accept(TOKEN_LBRACKET);
+
+ idx = xparse_expression();
+
+ if (aa) {
+ while (is_token_accept(TOKEN_COMMA)) {
+ // XXX ast
+
+ npl_expression_t *idx2;
+
+ idx2 = xparse_expression();
+ }
+ }
+
+ accept(TOKEN_RBRACKET);
+
+ expr->type = EXPRESSION_INDEX;
+ expr->arr.base = base;
+ expr->arr.index = idx;
+
+ } else if (is_token_accept(TOKEN_DOT)) {
+ npl_expression_t *base = xdup(npl_expression_t, expr);
+ npl_expression_t *field;
+
+ field = xnew(npl_expression_t);
+ parse_primary(field);
+
+ expr->type = EXPRESSION_FIELD;
+ expr->fld.base = base;
+ expr->fld.field = field;
+
+ } else
+ break;
+
+ } while (1);
+}
+
+static void
+parse_expression2(npl_expression_t *expr)
+{
+ npl_op1_t op;
+
+ do {
+ op =
+ (is_token_accept(TOKEN_MINUS)) ? OP1_MINUS :
+ (is_token_accept(TOKEN_NOT)) ? OP1_NOT :
+ (is_token_accept(TOKEN_NEG)) ? OP1_NEG :
+ OP1_INVALID;
+
+ if (op != OP1_INVALID) {
+ expr->type = EXPRESSION_UNARY;
+ expr->u.operator = op;
+
+ expr = expr->u.operand = xnew(npl_expression_t);
+ }
+ } while (op != OP1_INVALID);
+
+ parse_expression1(expr);
+}
+
+static void
+parse_expression3(npl_expression_t *expr)
+{
+ npl_op2_t op;
+
+ parse_expression2(expr);
+again:
+ op =
+ (is_token_accept(TOKEN_MULTIPLY)) ? OP2_MULTIPLY :
+ (is_token_accept(TOKEN_DIV)) ? OP2_DIV :
+ (is_token_accept(TOKEN_PERCENT)) ? OP2_MOD :
+ OP2_INVALID;
+
+ if (op != OP2_INVALID) {
+ npl_expression_t *operand = xdup(npl_expression_t, expr);
+ npl_expression_t *e;
+
+ expr->b.operand2 = e = xnew(npl_expression_t);
+ parse_expression3(e);
+
+ expr->b.operator = op;
+ expr->b.operand1 = operand;
+ expr->type = EXPRESSION_BINARY;
+ goto again;
+ }
+}
+
+static void
+parse_expression4(npl_expression_t *expr)
+{
+ npl_op2_t op;
+
+ parse_expression3(expr);
+again:
+ op =
+ (is_token_accept(TOKEN_PLUS)) ? OP2_PLUS :
+ (is_token_accept(TOKEN_MINUS)) ? OP2_MINUS :
+ OP2_INVALID;
+
+ if (op != OP2_INVALID) {
+ npl_expression_t *operand = xdup(npl_expression_t, expr);
+ npl_expression_t *e;
+
+ expr->b.operand2 = e = xnew(npl_expression_t);
+ parse_expression4(e);
+
+ expr->b.operator = op;
+ expr->b.operand1 = operand;
+ expr->type = EXPRESSION_BINARY;
+ goto again;
+ }
+}
+
+static void
+parse_expression5(npl_expression_t *expr)
+{
+ npl_op2_t op;
+
+ parse_expression4(expr);
+again:
+ op =
+ (is_token_accept(TOKEN_SHL)) ? OP2_SHL :
+ (is_token_accept(TOKEN_SHR)) ? OP2_SHR :
+ OP2_INVALID;
+
+ if (op != OP2_INVALID) {
+ npl_expression_t *operand = xdup(npl_expression_t, expr);
+ npl_expression_t *e;
+
+ expr->b.operand2 = e = xnew(npl_expression_t);
+ parse_expression5(e);
+
+ expr->b.operator = op;
+ expr->b.operand1 = operand;
+ expr->type = EXPRESSION_BINARY;
+ goto again;
+ }
+}
+
+static void
+parse_expression6(npl_expression_t *expr)
+{
+ npl_op2_t op;
+
+ parse_expression5(expr);
+again:
+ op =
+ (is_token_accept(TOKEN_LESS)) ? OP2_LESS :
+ (is_token_accept(TOKEN_GREATER)) ? OP2_GREATER :
+ (is_token_accept(TOKEN_LEQUAL)) ? OP2_LEQUAL :
+ (is_token_accept(TOKEN_GEQUAL)) ? OP2_GEQUAL :
+ OP2_INVALID;
+
+ if (op != OP2_INVALID) {
+ npl_expression_t *operand = xdup(npl_expression_t, expr);
+ npl_expression_t *e;
+
+ expr->b.operand2 = e = xnew(npl_expression_t);
+ parse_expression6(e);
+
+ expr->b.operator = op;
+ expr->b.operand1 = operand;
+ expr->type = EXPRESSION_BINARY;
+ goto again;
+ }
+}
+
+static void
+parse_expression7(npl_expression_t *expr)
+{
+ npl_op2_t op;
+
+ parse_expression6(expr);
+again:
+ op =
+ (is_token_accept(TOKEN_EQUAL)) ? OP2_EQUAL :
+ (is_token_accept(TOKEN_NOTEQUAL)) ? OP2_NOTEQUAL :
+ (is_token_accept(TOKEN_NOTEQUAL2)) ? OP2_NOTEQUAL :
+ OP2_INVALID;
+
+ if (op != OP2_INVALID) {
+ npl_expression_t *operand = xdup(npl_expression_t, expr);
+ npl_expression_t *e;
+
+ expr->b.operand2 = e = xnew(npl_expression_t);
+ parse_expression7(e);
+
+ expr->b.operator = op;
+ expr->b.operand1 = operand;
+ expr->type = EXPRESSION_BINARY;
+ goto again;
+ }
+}
+
+static void
+parse_expression8(npl_expression_t *expr)
+{
+ parse_expression7(expr);
+again:
+ if (is_token_accept(TOKEN_AND)) {
+ npl_expression_t *operand = xdup(npl_expression_t, expr);
+ npl_expression_t *e;
+
+ expr->b.operand2 = e = xnew(npl_expression_t);
+ parse_expression8(e);
+
+ expr->b.operator = OP2_AND;
+ expr->b.operand1 = operand;
+ expr->type = EXPRESSION_BINARY;
+ goto again;
+ }
+}
+
+static void
+parse_expression9(npl_expression_t *expr)
+{
+ parse_expression8(expr);
+again:
+ if (is_token_accept(TOKEN_XOR)) {
+ npl_expression_t *operand = xdup(npl_expression_t, expr);
+ npl_expression_t *e;
+
+ expr->b.operand2 = e = xnew(npl_expression_t);
+ parse_expression9(e);
+
+ expr->b.operator = OP2_XOR;
+ expr->b.operand1 = operand;
+ expr->type = EXPRESSION_BINARY;
+ goto again;
+ }
+}
+
+static void
+parse_expression10(npl_expression_t *expr)
+{
+ parse_expression9(expr);
+again:
+ if (is_token_accept(TOKEN_OR)) {
+ npl_expression_t *operand = xdup(npl_expression_t, expr);
+ npl_expression_t *e;
+
+ expr->b.operand2 = e = xnew(npl_expression_t);
+ parse_expression10(e);
+
+ expr->b.operator = OP2_OR;
+ expr->b.operand1 = operand;
+ expr->type = EXPRESSION_BINARY;
+ goto again;
+ }
+}
+
+static void
+parse_expression11(npl_expression_t *expr)
+{
+ npl_op2_t op;
+
+ parse_expression10(expr);
+again:
+ op =
+ (is_token_accept(TOKEN_LOGIC_AND)) ? OP2_LOGIC_AND :
+ (is_andand_accept()) ? OP2_LOGIC_AND :
+ OP2_INVALID;
+
+ if (op != OP2_INVALID) {
+ npl_expression_t *operand = xdup(npl_expression_t, expr);
+ npl_expression_t *e;
+
+ expr->b.operand2 = e = xnew(npl_expression_t);
+ parse_expression11(e);
+
+ expr->b.operator = op;
+ expr->b.operand1 = operand;
+ expr->type = EXPRESSION_BINARY;
+ goto again;
+ }
+}
+
+static void
+parse_expression12(npl_expression_t *expr)
+{
+ npl_op2_t op;
+
+ parse_expression11(expr);
+again:
+ op =
+ (is_token_accept(TOKEN_LOGIC_OR)) ? OP2_LOGIC_OR :
+ (is_oror_accept()) ? OP2_LOGIC_OR :
+ OP2_INVALID;
+
+ if (op != OP2_INVALID) {
+ npl_expression_t *operand = xdup(npl_expression_t, expr);
+ npl_expression_t *e;
+
+ expr->b.operand2 = e = xnew(npl_expression_t);
+ parse_expression12(e);
+
+ expr->b.operator = op;
+ expr->b.operand1 = operand;
+ expr->type = EXPRESSION_BINARY;
+ goto again;
+ }
+}
+
+static void
+parse_expression13(npl_expression_t *expr)
+{
+ parse_expression12(expr);
+
+ if (is_token_accept(TOKEN_COND)) {
+ npl_expression_t *operand = xdup(npl_expression_t, expr);
+ npl_expression_t *e;
+
+ expr->c.test_expr = operand;
+
+ e = xnew(npl_expression_t);
+// parse_expression13(e);
+ parse_expression(e);
+ expr->c.true_expr = e;
+ accept(TOKEN_COLON);
+
+ e = xnew(npl_expression_t);
+// parse_expression13(e);
+ parse_expression(e);
+ expr->c.false_expr = e;
+
+ expr->type = EXPRESSION_COND;
+ }
+}
+
+static npl_expression_t *
+xparse_expression(void)
+{
+ npl_expression_t *expr = xnew(npl_expression_t);
+
+ parse_expression(expr);
+ return expr;
+}
+
+static void
+parse_expression(npl_expression_t *expr)
+{
+ parse_expression13(expr);
+
+ if (is_token_accept(TOKEN_ASSIGN)) {
+ npl_expression_t *operand = xdup(npl_expression_t, expr);
+
+ expr->b.operand2 = xparse_expression();
+
+ expr->b.operator = OP2_ASSIGN;
+ expr->b.operand1 = operand;
+ expr->type = EXPRESSION_BINARY;
+ }
+}
+
+static int is_attribute(void) { return is_token(TOKEN_LBRACKET); }
+
+static void
+parse_attributes(npl_attr_t *attr)
+{
+ accept(TOKEN_LBRACKET);
+
+ do {
+ parse_expression(&attr->expr);
+
+ if (is_token_accept(TOKEN_SEMICOLON))
+ { }
+ else if (is_token_accept(TOKEN_COMMA))
+ { }
+
+ }
+ while (!is_token(TOKEN_RBRACKET));
+// while (is_token_accept(TOKEN_COMMA));
+
+ accept(TOKEN_RBRACKET);
+}
+
+static void parse_statement(npl_statement_t *st);
+
+static npl_statement_t *
+xparse_statement(void)
+{
+ npl_statement_t *st = xnew(npl_statement_t);
+
+ parse_statement(st);
+ return st;
+}
+
+static void
+parse_switch_body(npl_switch_t *sw)
+{
+ struct npl_switch_case **ptr = &sw->cases;
+
+ while (is_token(TOKEN_CASE)) {
+ struct npl_switch_case *cur = xnew(struct npl_switch_case);
+
+ *ptr = cur;
+
+ ptr = &(cur->next);
+
+ accept(TOKEN_CASE);
+ parse_expression(&cur->e);
+ accept(TOKEN_COLON);
+
+ if (!is_token(TOKEN_CASE) && !is_default()) {
+ cur->st = xparse_statement();
+ is_token_accept(TOKEN_SEMICOLON);
+ }
+ }
+ *ptr = NULL;
+
+ if (is_default()) {
+ accept_default();
+ accept(TOKEN_COLON);
+ sw->default_st = xparse_statement();
+ }
+}
+
+static void
+parse_switch(npl_switch_t *sw)
+{
+ accept(TOKEN_SWITCH);
+
+ if (is_token_accept(TOKEN_LPAREN)) {
+ sw->switch_expr = xparse_expression();
+ accept(TOKEN_RPAREN);
+ }
+
+ accept(TOKEN_LCURLY);
+ parse_switch_body(sw);
+ accept(TOKEN_RCURLY);
+ is_token_accept(TOKEN_SEMICOLON);
+}
+
+static void
+parse_dynamic_switch(npl_switch_t *sw)
+{
+ accept(TOKEN_DYNAMIC_SWITCH);
+
+ sw->switch_expr = xparse_expression();
+
+ accept(TOKEN_LCURLY);
+ parse_switch_body(sw);
+ accept(TOKEN_RCURLY);
+ is_token_accept(TOKEN_SEMICOLON);
+}
+
+static void parse_table(npl_table_t *);
+
+static int is_statement(void) {
+ return
+ is_token(TOKEN_WHILE) ||
+ is_table() ||
+ is_token(TOKEN_STRUCT) || is_token(TOKEN_PRIVATE_STRUCT) ||
+ is_token(TOKEN_SWITCH) || is_token(TOKEN_DYNAMIC_SWITCH) ||
+ is_token(TOKEN_ID) || is_attribute() ||
+#if 1
+ is_token(TOKEN_SEMICOLON) ||
+#endif
+ 0
+ ;
+}
+
+static struct _npl_statements *
+xparse_statements(void)
+{
+ struct _npl_statements *ret;
+ struct _npl_statements **ptr = &ret;
+
+ while (is_statement()) {
+ struct _npl_statements *cur = xnew(struct _npl_statements);
+
+ parse_statement(&cur->st);
+
+ *ptr = cur;
+ ptr = &(cur->next);
+ }
+ *ptr = NULL;
+
+ return ret;
+}
+
+static void
+parse_while(npl_statement_t *st)
+{
+ accept(TOKEN_WHILE);
+
+ if (is_token(TOKEN_ID))
+ st->w.id = accept_id();
+
+ accept(TOKEN_LBRACKET);
+ parse_expression(&st->w.expr);
+ accept(TOKEN_RBRACKET);
+
+ accept(TOKEN_LCURLY);
+ st->w.sts = xparse_statements();
+ accept(TOKEN_RCURLY);
+ is_token_accept(TOKEN_SEMICOLON);
+}
+
+static npl_expression_t *
+xparse_formatting(void)
+{
+ npl_expression_t *format;
+
+ accept(TOKEN_ASSIGN);
+
+ format = xnew(npl_expression_t);
+ parse_expression(format);
+ return format;
+}
+
+static void parse_struct(npl_struct_t *s, int statement);
+
+static void
+parse_statement(npl_statement_t *st)
+{
+ while (is_attribute()) {
+ // XXX ast
+ npl_attr_t a = { };
+ parse_attributes(&a);
+ }
+
+ if (is_token(TOKEN_WHILE)) {
+ parse_while(st);
+ st->type = STATEMENT_WHILE;
+ return;
+ }
+
+ if (is_table()) {
+ parse_table(&st->t.data);
+ st->type = STATEMENT_TABLE;
+ return;
+ }
+
+ if (is_token(TOKEN_STRUCT) || is_token(TOKEN_PRIVATE_STRUCT)) {
+ parse_struct(&st->s.data, 1);
+ st->type = STATEMENT_STRUCT;
+ return;
+ }
+
+ if (is_token(TOKEN_SWITCH)) {
+ parse_switch(&(st->sw.data));
+ st->type = STATEMENT_SWITCH;
+ return;
+ }
+
+ if (is_token(TOKEN_DYNAMIC_SWITCH)) {
+ parse_dynamic_switch(&(st->sw.data));
+ st->type = STATEMENT_DYNAMIC_SWITCH;
+ return;
+ }
+#if 1
+ if (is_token(TOKEN_SEMICOLON)) {
+ accept(TOKEN_SEMICOLON);
+ return;
+ }
+#endif
+
+ st->type = STATEMENT_FIELD;
+ st->f.t_id = accept_id();
+
+ if (is_token_accept(TOKEN_LPAREN)) {
+ /* XXX, WTF: StringTerm(Property.XMLEncoding, "<", true, false, false) Reason; */
+
+ do {
+ /* XXX, ast */
+ parse_expression(&g_e);
+ } while (is_token_accept(TOKEN_COMMA));
+ accept(TOKEN_RPAREN);
+ }
+
+ st->f.id = accept_id();
+ if (is_token_accept(TOKEN_COLON))
+ st->f.bits = accept_int();
+
+ else if (is_token_accept(TOKEN_LBRACKET)) {
+ st->f.arr = xparse_expression();
+ accept(TOKEN_RBRACKET);
+ }
+
+ if (is_token(TOKEN_ASSIGN))
+ st->f.format = xparse_formatting();
+
+ if (is_token_accept(TOKEN_LCURLY)) {
+ st->f.sts = xparse_statements();
+ accept(TOKEN_RCURLY);
+ is_token_accept(TOKEN_SEMICOLON);
+ return;
+ }
+
+ accept(TOKEN_SEMICOLON);
+}
+
+static void
+parse_protocol(npl_protocol_t *p)
+{
+ accept_protocol();
+ p->id = accept_id();
+
+ if (is_params())
+ parse_params(&p->params);
+
+ if (is_token(TOKEN_ASSIGN))
+ p->format = xparse_formatting();
+
+ accept(TOKEN_LCURLY);
+ p->sts = xparse_statements();
+ accept(TOKEN_RCURLY);
+ is_token_accept(TOKEN_SEMICOLON);
+}
+
+static void
+parse_struct(npl_struct_t *s, int statement)
+{
+ if (is_token_accept(TOKEN_STRUCT))
+ s->private = 0;
+ else if (is_token_accept(TOKEN_PRIVATE_STRUCT))
+ s->private = 1;
+ else
+ nomatch();
+
+ if (is_token(TOKEN_ID))
+ s->id = accept_id();
+
+ if (is_params())
+ parse_params(&s->params);
+
+ if (statement) {
+ if (is_token_accept(TOKEN_LBRACKET)) {
+ s->count_expr = xparse_expression();
+ accept(TOKEN_RBRACKET);
+ }
+ }
+
+ if (is_token(TOKEN_ASSIGN))
+ s->format = xparse_formatting();
+
+ accept(TOKEN_LCURLY);
+ s->sts = xparse_statements();
+ accept(TOKEN_RCURLY);
+ is_token_accept(TOKEN_SEMICOLON);
+}
+
+/* Table = "table", ID, [Params], "{", "switch", [ "(", Expr, ")" ], {TableCase}, [DefaultCase], "}", ";" ;
+
+ DefaultCase = "default", ":", Expression", ";" ;
+ */
+static void
+parse_table(npl_table_t *t)
+{
+ accept_table();
+ t->id = accept_id();
+ if (is_params())
+ parse_params(&t->params);
+
+ accept(TOKEN_LCURLY);
+ {
+ struct npl_table_case **ptr;
+
+ accept(TOKEN_SWITCH);
+ if (is_token_accept(TOKEN_LPAREN)) {
+ t->switch_expr = xparse_expression();
+ accept(TOKEN_RPAREN);
+ }
+
+ accept(TOKEN_LCURLY);
+
+ ptr = &(t->cases);
+ while (is_token_accept(TOKEN_CASE)) {
+ struct npl_table_case *cur;
+
+ cur = *ptr = xnew(struct npl_table_case);
+ ptr = &(cur->next);
+
+ parse_expression(&(cur->e));
+ accept(TOKEN_COLON);
+
+ while (is_token_accept(TOKEN_CASE)) {
+ cur = *ptr = xnew(struct npl_table_case);
+ ptr = &(cur->next);
+
+ parse_expression(&(cur->e));
+ accept(TOKEN_COLON);
+ }
+ cur->return_expr = xparse_expression();
+ accept(TOKEN_SEMICOLON);
+ }
+ *ptr = NULL;
+
+ if (is_default()) {
+ accept_default();
+ accept(TOKEN_COLON);
+ t->default_expr = xparse_expression();
+ accept(TOKEN_SEMICOLON);
+ }
+ accept(TOKEN_RCURLY);
+
+ }
+ accept(TOKEN_RCURLY);
+ is_token_accept(TOKEN_SEMICOLON);
+}
+
+static int
+is_type(void)
+{
+ return
+ is_keyword("Decimal") ||
+ is_keyword("Number") ||
+ is_keyword("Time") ||
+ is_keyword("UnsignedNumber");
+}
+
+/* Type = BasicType, ID, [Params], "{", {TypeAttr}, "}" ;
+
+ BasicType = "Decimal" | "Number" | "Time" | "UnsignedNumber" ;
+
+ TypeAttr = AttrName, "=", Expression ;
+
+ AttrName = "ByteOrder" | "DisplayFormat" | "Size" ;
+ */
+static void
+parse_type(npl_type_t *t)
+{
+ if (is_keyword_accept("Decimal"))
+ t->type = FIELD_DECIMAL;
+ else if (is_keyword_accept("Number"))
+ t->type = FIELD_NUMBER;
+ else if (is_keyword_accept("Time"))
+ t->type = FIELD_TIME;
+ else if (is_keyword_accept("UnsignedNumber"))
+ t->type = FIELD_UNSIGNED_NUMBER;
+ else
+ nomatch();
+
+ t->name = accept_id();
+
+ if (is_params())
+ parse_params(&t->params);
+
+ accept(TOKEN_LCURLY);
+
+ while (!is_token(TOKEN_RCURLY)) {
+ npl_expression_t **ptr;
+
+ if (is_keyword_accept("ByteOrder"))
+ ptr = &t->byte_order;
+ else if (is_keyword_accept("DisplayFormat"))
+ ptr = &t->display_format;
+ else if (is_keyword_accept("Size"))
+ ptr = &t->size;
+ else
+ nomatch();
+#if 0
+ if (*ptr)
+ fprintf(stderr, "already got %s attr!\n", str);
+#endif
+ accept(TOKEN_ASSIGN);
+ *ptr = xparse_expression();
+
+ if (is_token_accept(TOKEN_COMMA))
+ { }
+ else if (is_token_accept(TOKEN_SEMICOLON))
+ { }
+ }
+ accept(TOKEN_RCURLY);
+}
+
+/* Const = "const", ID, "=", Expression, ";" ; */
+static void
+parse_const(npl_const_t *c)
+{
+ accept(TOKEN_CONST);
+ c->id = accept_id();
+ accept(TOKEN_ASSIGN);
+ parse_expression(&c->expr);
+ accept(TOKEN_SEMICOLON);
+}
+
+/* Declaration = Attributes
+ | Struct
+ | Table
+ | Const
+ | Protocol
+ | Type
+ | ( "include", STR )
+ ;
+ */
+static void
+parse_decl(npl_decl_t *d)
+{
+ if (is_token(TOKEN_LBRACKET)) {
+ d->type = DECL_ATTR;
+ parse_attributes(&d->a.data);
+
+ } else if (is_token(TOKEN_STRUCT)) {
+ d->type = DECL_STRUCT;
+ parse_struct(&d->s.data, 0);
+
+ } else if (is_table()) {
+ d->type = DECL_TABLE;
+ parse_table(&d->t.data);
+
+ } else if (is_token(TOKEN_CONST)) {
+ d->type = DECL_CONST;
+ parse_const(&d->c.data);
+
+ } else if (is_protocol()) {
+ d->type = DECL_PROTOCOL;
+ parse_protocol(&d->p.data);
+
+ } else if (is_type()) {
+ parse_type(&d->ty.data);
+ d->type = DECL_TYPE;
+
+ } else if (is_token_accept(TOKEN_INCLUDE)) {
+ /* XXX, ast */
+ char *file = accept_str();
+ free(file);
+
+ } else
+ nomatch();
+}
+
+/* NPL = { DECL } ; */
+static void
+parse_npl(npl_code_t *code)
+{
+ struct _npl_decl_list **ptr = &(code->decls);
+
+ while (!is_token_accept(TOKEN_EOF)) {
+ struct _npl_decl_list *cur = xnew(struct _npl_decl_list);
+
+ *ptr = cur;
+ ptr = &(cur->next);
+
+ parse_decl(&cur->d);
+ }
+ *ptr = NULL;
+}
+
+void
+npl_parse_file(npl_code_t *code, FILE *f, const char *filename)
+{
+ yyfilename = filename;
+ yyin = f;
+
+ next_token();
+ parse_npl(code);
+ code->parse_ok = 1;
+
+ yylex_destroy();
+}
+