summaryrefslogtreecommitdiff
path: root/tools/npl
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
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')
-rw-r--r--tools/npl/ast.h367
-rw-r--r--tools/npl/npl.c674
-rw-r--r--tools/npl/parser.l1438
-rw-r--r--tools/npl/xmem.h20
4 files changed, 2499 insertions, 0 deletions
diff --git a/tools/npl/ast.h b/tools/npl/ast.h
new file mode 100644
index 0000000000..ed6792ea3c
--- /dev/null
+++ b/tools/npl/ast.h
@@ -0,0 +1,367 @@
+typedef enum {
+ OP1_INVALID = 0,
+ OP1_MINUS,
+ OP1_NOT,
+ OP1_NEG
+} npl_op1_t;
+
+typedef enum {
+ OP2_INVALID = 0,
+
+ OP2_ASSIGN,
+
+ OP2_PLUS,
+ OP2_MINUS,
+
+ OP2_MULTIPLY,
+ OP2_DIV,
+ OP2_MOD,
+
+ OP2_SHL,
+ OP2_SHR,
+
+ OP2_EQUAL,
+ OP2_NOTEQUAL,
+
+ OP2_LESS,
+ OP2_GREATER,
+ OP2_LEQUAL,
+ OP2_GEQUAL,
+
+ OP2_LOGIC_OR,
+ OP2_LOGIC_AND,
+
+ OP2_OR,
+ OP2_AND,
+ OP2_XOR,
+
+} npl_op2_t;
+
+#define NPL_PARAMS_MAX 20
+
+typedef struct {
+ char *args[NPL_PARAMS_MAX];
+ int count;
+
+} npl_params_t;
+
+typedef enum {
+ EXPRESSION_INVALID = 0,
+
+ EXPRESSION_ID,
+ EXPRESSION_INT,
+ EXPRESSION_STR,
+
+ EXPRESSION_INDEX,
+ EXPRESSION_FIELD,
+ EXPRESSION_CALL,
+
+ EXPRESSION_UNARY,
+ EXPRESSION_BINARY,
+ EXPRESSION_COND
+
+} npl_expression_type_t;
+
+typedef struct _npl_expression {
+union {
+ struct {
+ npl_expression_type_t type;
+ };
+
+ struct {
+ npl_expression_type_t type; /* EXPRESSION_ID */
+ char *id;
+ } id;
+
+ struct {
+ npl_expression_type_t type; /* EXPRESSION_INT */
+ unsigned int digit;
+ } num;
+
+ struct {
+ npl_expression_type_t type; /* EXPRESSION_STR */
+ char *str;
+ } str;
+
+ struct {
+ npl_expression_type_t type; /* EXPRESSION_INDEX */
+
+ struct _npl_expression *base;
+ struct _npl_expression *index;
+ } arr;
+
+ struct {
+ npl_expression_type_t type; /* EXPRESSION_FIELD */
+
+ struct _npl_expression *base;
+ struct _npl_expression *field;
+ } fld;
+
+ struct {
+ npl_expression_type_t type; /* EXPRESSION_UNARY */
+
+ npl_op1_t operator;
+ struct _npl_expression *operand;
+
+ } u;
+
+ struct {
+ npl_expression_type_t type; /* EXPRESSION_BINARY */
+
+ struct _npl_expression *operand1;
+ struct _npl_expression *operand2;
+ npl_op2_t operator;
+
+ } b;
+
+ struct {
+ npl_expression_type_t type; /* EXPRESSION_CALL */
+
+ struct _npl_expression *fn;
+
+ struct _npl_expression_list {
+ struct _npl_expression_list *next;
+
+ struct _npl_expression *expr;
+
+ } *args;
+
+ } call;
+
+ struct {
+ npl_expression_type_t type; /* EXPRESSION_COND */
+
+ struct _npl_expression *test_expr;
+ struct _npl_expression *true_expr;
+ struct _npl_expression *false_expr;
+ } c;
+
+
+};
+} npl_expression_t;
+
+struct _npl_statement;
+
+typedef struct {
+ char *id;
+ int private;
+ npl_params_t params;
+
+ npl_expression_t *format;
+ npl_expression_t *count_expr;
+ struct _npl_statements *sts;
+
+} npl_struct_t;
+
+typedef struct {
+ char *id;
+ npl_params_t params;
+
+ npl_expression_t *switch_expr;
+
+ struct npl_table_case {
+ struct npl_table_case *next;
+
+ npl_expression_t e;
+
+ npl_expression_t *return_expr;
+
+ } *cases;
+
+ npl_expression_t *default_expr;
+
+} npl_table_t;
+
+typedef struct {
+ char *id;
+ npl_expression_t expr;
+
+} npl_const_t;
+
+typedef enum {
+ STATEMENT_INVALID = 0,
+
+ STATEMENT_WHILE,
+ STATEMENT_TABLE,
+ STATEMENT_STRUCT,
+ STATEMENT_FIELD,
+ STATEMENT_SWITCH,
+ STATEMENT_DYNAMIC_SWITCH,
+
+} npl_statement_type_t;
+
+typedef struct {
+ npl_expression_t *switch_expr;
+
+ struct npl_switch_case {
+ struct npl_switch_case *next;
+
+ npl_expression_t e;
+
+ struct _npl_statement *st;
+
+ } *cases;
+
+ struct _npl_statement *default_st;
+
+} npl_switch_t;
+
+typedef struct _npl_statement {
+ union {
+ struct {
+ npl_statement_type_t type;
+ };
+
+ struct {
+ npl_statement_type_t type; /* STATEMENT_WHILE */
+
+ char *id;
+ npl_expression_t expr;
+
+ struct _npl_statements *sts;
+ } w;
+
+ struct {
+ npl_statement_type_t type; /* STATEMTN_TABLE */
+
+ npl_table_t data;
+ } t;
+
+ struct {
+ npl_statement_type_t type; /* STATEMENT_STRUCT */
+
+ npl_struct_t data;
+ } s;
+
+ struct {
+ npl_statement_type_t type; /* STATEMENT_SWITCH or STATEMENT_DYNAMIC_SWITCH */
+
+ npl_switch_t data;
+ } sw;
+
+ struct {
+ npl_statement_type_t type; /* STATEMENT_FIELD */
+
+ char *t_id;
+ char *id;
+
+ unsigned int bits;
+ npl_expression_t *arr;
+
+ npl_expression_t *format;
+ struct _npl_statements *sts;
+
+ struct hfinfo *hfi; /* set by code gen */
+ } f;
+
+ };
+} npl_statement_t;
+
+struct _npl_statements {
+ struct _npl_statements *next;
+
+ npl_statement_t st;
+};
+
+typedef struct {
+ char *id;
+ npl_params_t params;
+
+ npl_expression_t *format;
+ struct _npl_statements *sts;
+
+} npl_protocol_t;
+
+typedef enum {
+ FIELD_INVALID = 0,
+
+ FIELD_DECIMAL,
+ FIELD_NUMBER,
+ FIELD_TIME,
+ FIELD_UNSIGNED_NUMBER
+
+} npl_field_type_t;
+
+typedef struct {
+ npl_field_type_t type;
+
+ char *name;
+ npl_params_t params;
+
+ npl_expression_t *byte_order;
+ npl_expression_t *display_format;
+ npl_expression_t *size;
+
+} npl_type_t;
+
+typedef enum {
+ DECL_INVALID = 0,
+
+ DECL_ATTR,
+ DECL_STRUCT,
+ DECL_TABLE,
+ DECL_CONST,
+ DECL_PROTOCOL,
+ DECL_TYPE
+
+} npl_decl_type_t;
+
+typedef struct _npl_attr {
+ npl_expression_t expr;
+} npl_attr_t;
+
+typedef struct {
+ union {
+ struct {
+ npl_decl_type_t type;
+ };
+
+ struct {
+ npl_decl_type_t type; /* DECL_ATTR */
+
+ npl_attr_t data;
+ } a;
+
+ struct {
+ npl_decl_type_t type; /* DECL_STRUCT */
+
+ npl_struct_t data;
+ } s;
+
+ struct {
+ npl_decl_type_t type; /* DECL_TABLE */
+
+ npl_table_t data;
+ } t;
+
+ struct {
+ npl_decl_type_t type; /* DECL_PROTOCOL */
+
+ npl_protocol_t data;
+ } p;
+
+ struct {
+ npl_decl_type_t type; /* DECL_CONST */
+
+ npl_const_t data;
+ } c;
+
+ struct {
+ npl_decl_type_t type; /* DECL_TYPE */
+
+ npl_type_t data;
+ } ty;
+
+ };
+} npl_decl_t;
+
+typedef struct {
+ struct _npl_decl_list {
+ struct _npl_decl_list *next;
+ npl_decl_t d;
+
+ } *decls;
+
+ int parse_ok;
+
+} npl_code_t;
diff --git a/tools/npl/npl.c b/tools/npl/npl.c
new file mode 100644
index 0000000000..96124107a2
--- /dev/null
+++ b/tools/npl/npl.c
@@ -0,0 +1,674 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "ast.h"
+#include "xmem.h"
+
+void npl_parse_file(npl_code_t *code, FILE *f, const char *filename); /* parser.l */
+
+static void gen_expr(FILE *f, npl_expression_t *e);
+static void gen_statements(FILE *f, struct _npl_statements *sts);
+
+struct hfinfo {
+ struct hfinfo *next;
+ npl_statement_t *st;
+
+ unsigned int id;
+};
+
+struct hfinfo *hfs;
+
+
+static struct hfinfo *
+add_hfi(npl_statement_t *st)
+{
+ static unsigned int _hf_id = 0;
+
+ struct hfinfo *new = xnew(struct hfinfo);
+
+ new->st = st;
+ new->id = ++_hf_id;
+
+ new->next = hfs;
+ hfs = new;
+
+ return new;
+}
+
+static const char *
+hfi_name(const struct hfinfo *hfi)
+{
+ static char hf_name[64];
+
+ snprintf(hf_name, sizeof(hf_name), "hf_field_%u", hfi->id);
+
+ return hf_name;
+}
+
+
+#define gen_fprintf(f, args...) \
+ do { \
+ if (f) fprintf(f, args); \
+ } while (0)
+
+static const char *
+op1_to_str(npl_op1_t op)
+{
+ switch (op) {
+ case OP1_MINUS:
+ return "-";
+ case OP1_NOT:
+ return "!";
+ case OP1_NEG:
+ return "~";
+ }
+ fprintf(stderr, "XXXX op: %d\n", op);
+ return "";
+}
+
+static const char *
+op2_to_str(npl_op2_t op)
+{
+ switch (op) {
+ case OP2_PLUS:
+ return "+";
+ case OP2_MINUS:
+ return "-";
+ case OP2_SHL:
+ return "<<";
+ case OP2_SHR:
+ return ">>";
+ case OP2_EQUAL:
+ return "==";
+ case OP2_NOTEQUAL:
+ return "!=";
+ case OP2_LOGIC_OR:
+ return "||";
+ case OP2_LOGIC_AND:
+ return "&&";
+ case OP2_OR:
+ return "|";
+ case OP2_XOR:
+ return "^";
+ case OP2_AND:
+ return "&";
+ case OP2_GREATER:
+ return ">";
+ case OP2_GEQUAL:
+ return ">=";
+ case OP2_LESS:
+ return "<";
+ case OP2_LEQUAL:
+ return "<=";
+ }
+ fprintf(stderr, "XXXX op: %d\n", op);
+ return "";
+}
+
+static void
+gen_expr(FILE *f, npl_expression_t *e)
+{
+ switch (e->type) {
+ case EXPRESSION_ID:
+ gen_fprintf(f, " %s ", e->id.id);
+ return;
+
+ case EXPRESSION_INT:
+ gen_fprintf(f, " %d ", e->num.digit);
+ return;
+
+ case EXPRESSION_STR:
+ // XXX e->str.str is escaped, almost like C-string so just print it.
+ gen_fprintf(f, " \"%s\" ", e->str.str);
+ return;
+
+ case EXPRESSION_UNARY:
+ gen_fprintf(f, "(");
+ gen_fprintf(f, "%s", op1_to_str(e->u.operator));
+ gen_expr(f, e->u.operand);
+ gen_fprintf(f, ")");
+ return;
+
+ case EXPRESSION_BINARY:
+ gen_fprintf(f, "(");
+ gen_expr(f, e->b.operand1);
+ gen_fprintf(f, " %s ", op2_to_str(e->b.operator));
+ gen_expr(f, e->b.operand2);
+ gen_fprintf(f, ")");
+ return;
+
+ case EXPRESSION_CALL:
+ {
+ struct _npl_expression_list *arg;
+ char *ind = "";
+
+ gen_expr(f, e->call.fn);
+ gen_fprintf(f, "(");
+ for (arg = e->call.args; arg; arg = arg->next) {
+ gen_fprintf(f, "%s", ind);
+ gen_expr(f, arg->expr);
+ ind = ", ";
+ }
+ gen_fprintf(f, ")");
+ return;
+ }
+ }
+ fprintf(stderr, "XXXX expr->type: %d\n", e->type);
+}
+
+static void
+gen_table(FILE *f, npl_table_t *t)
+{
+ struct npl_table_case *c;
+
+ gen_fprintf(f,
+ "static const char *\n"
+ "format_table_%s", t->id);
+
+ gen_fprintf(f, "(");
+ if (t->params.count) {
+ int i;
+
+ for (i = 0; i < t->params.count; i++) {
+ if (i)
+ gen_fprintf(f, ", ");
+ gen_fprintf(f, "TYPE %s", t->params.args[i]);
+ }
+
+ } else {
+ /* default */
+ gen_fprintf(f, "TYPE value");
+ }
+ gen_fprintf(f, ")\n{\n");
+
+ if (t->switch_expr) {
+ gen_fprintf(f, "\tswitch (");
+ gen_expr(f, t->switch_expr);
+ gen_fprintf(f, ") {\n");
+
+ for (c = t->cases; c; c = c->next) {
+again1:
+ gen_fprintf(f, "\t\tcase ");
+ gen_expr(f, &c->e);
+ gen_fprintf(f, ": ");
+
+ if (!c->return_expr) {
+ c = c->next;
+ if (!c)
+ abort();
+ gen_fprintf(f, "\n");
+ goto again1;
+ } else {
+ gen_fprintf(f, "\n");
+ gen_fprintf(f, "\t\t\treturn ");
+ gen_expr(f, c->return_expr);
+ gen_fprintf(f, ";\n");
+ }
+ }
+
+ gen_fprintf(f, "\t}\n");
+ } else {
+ for (c = t->cases; c; c = c->next) {
+
+ if (c == t->cases)
+ gen_fprintf(f, "\tif (");
+ else
+ gen_fprintf(f, "\telse if (");
+
+again2:
+ gen_fprintf(f, "(");
+ gen_expr(f, &c->e);
+ gen_fprintf(f, ")");
+
+ if (!c->return_expr) {
+ gen_fprintf(f, " || ");
+ c = c->next;
+ if (!c)
+ abort();
+ goto again2;
+ } else {
+ gen_fprintf(f, ")\n");
+
+ gen_fprintf(f, "\t\treturn ");
+ gen_expr(f, c->return_expr);
+ gen_fprintf(f, ";\n");
+ }
+ }
+ }
+
+ if (t->default_expr) {
+ gen_fprintf(f, "\treturn ");
+ gen_expr(f, t->default_expr);
+ gen_fprintf(f, ";\n");
+ } else
+ gen_fprintf(f, "\treturn \"\";\n");
+
+ gen_fprintf(f, "}\n");
+ gen_fprintf(f, "\n");
+}
+
+static void
+gen_statement(FILE *f, npl_statement_t *st)
+{
+ switch (st->type) {
+ case STATEMENT_WHILE:
+ // XXX ->id
+ gen_fprintf(f, "\twhile (");
+ gen_expr(f, &st->w.expr);
+ gen_fprintf(f, ") {\n");
+
+ gen_statements(f, st->w.sts);
+
+ gen_fprintf(f, "\t}\n");
+ return;
+
+ case STATEMENT_STRUCT:
+ // XXX put st->s somewhere to create this proc.
+ gen_fprintf(f, "\toffset = dissect_struct_%s(tvb, tree, hf_costam, offset);\n", st->s.data.id);
+ return;
+
+ case STATEMENT_FIELD:
+ {
+ if (!st->f.hfi) {
+ st->f.hfi = add_hfi(st);
+ // asssert f == NULL
+ }
+
+ if (f) {
+ // XXX, search for st->f.t_id in table.
+ gen_fprintf(f, "\toffset = dissect_%s(tvb, tree, %s, offset);\n", st->f.t_id, hfi_name(st->f.hfi));
+ }
+ // XXX st->f.bits, st->f.arr, st->f.format, st->f.sts
+ return;
+ }
+
+ /* case STATEMENT_DYNAMIC_SWITCH: */
+ case STATEMENT_SWITCH:
+ {
+ struct npl_switch_case *c = st->sw.data.cases;
+
+ if (st->sw.data.switch_expr) {
+ gen_fprintf(f, "\tswitch (");
+ gen_expr(f, st->sw.data.switch_expr);
+ gen_fprintf(f, ") {\n");
+
+ while (c) {
+ gen_fprintf(f, "\t\tcase ");
+ gen_expr(f, &c->e);
+ gen_fprintf(f, ":\n");
+
+ if (c->st) {
+ gen_fprintf(f, "\t\t");
+ gen_statement(f, c->st);
+ gen_fprintf(f, "\t\t\tbreak;\n");
+ }
+ c = c->next;
+ }
+
+ if (st->sw.data.default_st) {
+ gen_fprintf(f, "\t\tdefault:\n");
+ gen_fprintf(f, "\t\t");
+ gen_statement(f, st->sw.data.default_st);
+ }
+
+ gen_fprintf(f, "\t}\n");
+ return;
+ }
+
+
+ if (c) {
+ npl_statement_t *default_st = st->sw.data.default_st;
+
+ gen_fprintf(f, "\t");
+ while (c) {
+ npl_statement_t *case_st;
+ gen_fprintf(f, "if (");
+
+ gen_fprintf(f, "(");
+ gen_expr(f, &c->e);
+ gen_fprintf(f, ")");
+
+ case_st = c->st;
+ c = c->next;
+
+ while (c && !case_st) {
+ case_st = c->st;
+
+ gen_fprintf(f, " || ");
+ gen_fprintf(f, "(");
+ gen_expr(f, &c->e);
+ gen_fprintf(f, ")");
+ c = c->next;
+ }
+
+ if (!case_st) {
+ gen_fprintf(f, " || 1");
+ case_st = default_st;
+ default_st = NULL;
+ }
+ gen_fprintf(f, ") {\n");
+ gen_fprintf(f, "\t");
+ gen_statement(f, case_st);
+ gen_fprintf(f, "\t} ");
+
+ if (c || default_st)
+ gen_fprintf(f, "else ");
+ }
+
+ if (default_st) {
+ gen_fprintf(f, "{\n");
+ gen_fprintf(f, "\t");
+ gen_statement(f, default_st);
+ gen_fprintf(f, "\t}\n");
+ }
+
+ } else {
+ if (st->sw.data.default_st)
+ gen_statement(f, st->sw.data.default_st);
+ }
+ return;
+ }
+ }
+ fprintf(stderr, "gen_statement: %d\n", st->type);
+}
+
+static void
+gen_statements(FILE *f, struct _npl_statements *sts)
+{
+ while (sts) {
+ gen_statement(f, &sts->st);
+
+ sts = sts->next;
+ }
+}
+
+static void
+gen_protocol(FILE *f, npl_protocol_t *p)
+{
+ gen_fprintf(f,
+ "static int\n"
+ "dissect_%s(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)\n", p->id);
+
+ gen_fprintf(f, "{\n");
+ gen_fprintf(f,
+ "\tint offset = 0;\n"
+ "\n"
+ );
+
+ if (p->format) {
+
+
+ }
+
+ gen_statements(f, p->sts);
+
+ gen_fprintf(f, "\tproto_item_set_len(ti, offset);\n");
+ gen_fprintf(f, "\treturn offset;\n");
+ gen_fprintf(f, "}\n");
+ gen_fprintf(f, "\n");
+}
+
+static void
+gen_struct(FILE *f, npl_struct_t *s)
+{
+ const char *tree_var;
+
+ if (!s->id) {
+ static unsigned int _id = 0;
+ char id[32];
+
+ snprintf(id, sizeof(id), "_noname%u", ++_id);
+ s->id = xstrdup(id);
+
+ if (f != NULL)
+ abort();
+ }
+
+ if (s->count_expr) {
+ /* TODO */
+ fprintf(stderr, "TODO: s->count_expr");
+ }
+
+ gen_fprintf(f,
+ "static int\n"
+ "dissect_struct_%s(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset)\n"
+ "{\n", s->id);
+
+ if (!s->private) {
+ gen_fprintf(f, "\tconst int org_offset = offset;\n");
+
+ gen_fprintf(f, "\tproto_tree *tree = NULL\n");
+ gen_fprintf(f, "\tproto_item *ti = NULL;\n");
+ } else
+ gen_fprintf(f, "\tproto_tree *tree = parent_tree\n");
+
+ gen_fprintf(f,"\n");
+
+ if (!s->private) {
+ static unsigned int _ett_id = 0;
+ char ett_name[64];
+/*
+ if (s->format) {
+ fprintf(stderr, "gen_struct() s->format: '");
+ gen_expr(stderr, s->format);
+ fprintf(stderr, "\n\n");
+ }
+ */
+ snprintf(ett_name, sizeof(ett_name), "ett_field_%u", ++_ett_id);
+
+ gen_fprintf(f,
+ "\tif (parent_tree) {\n"
+ "\t\tti = proto_tree_add_bytes_format(tree, hf_%s, tvb, offset, 0, NULL, \"%s\");\n"
+ "\t\ttree = proto_item_add_subtree(ti, %s);\n"
+ "\t}\n", "hf_name", "description", ett_name);
+
+ } else {
+ if (s->format)
+ fprintf(stderr, "s->private && s->format?\n");
+ }
+
+ gen_statements(f, s->sts);
+
+ if (!s->private)
+ gen_fprintf(f, "\tproto_item_set_len(ti, offset - org_offset);\n");
+ gen_fprintf(f, "\treturn offset;\n");
+ gen_fprintf(f, "}\n");
+ gen_fprintf(f, "\n");
+}
+
+static void
+gen_const(FILE *f, npl_const_t *c)
+{
+// TODO
+ fprintf(stderr, "gen_const() TODO\n");
+}
+
+static void
+gen_type(FILE *f, npl_type_t *t)
+{
+ gen_fprintf(f,
+ "static int\n"
+ "dissect_type_%s(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset)\n"
+ "{\n", t->name);
+
+#if 0
+ npl_params_t params;
+
+ npl_expression_t *byte_order;
+ npl_expression_t *display_format;
+ npl_expression_t *size;
+#endif
+
+ gen_fprintf(f, "\treturn offset;\n");
+ gen_fprintf(f, "}\n");
+ gen_fprintf(f, "\n");
+}
+
+static void
+gen_attr(FILE *f, npl_attr_t *a)
+{
+// TODO
+ fprintf(stderr, "gen_attr() TODO");
+}
+
+static void
+gen_decl(FILE *f, npl_decl_t *d)
+{
+ switch (d->type) {
+ case DECL_ATTR:
+ gen_attr(f, &d->a.data);
+ return;
+ case DECL_STRUCT:
+ gen_struct(f, &d->s.data);
+ return;
+ case DECL_TABLE:
+ gen_table(f, &d->t.data);
+ return;
+ case DECL_PROTOCOL:
+ gen_protocol(f, &d->p.data);
+ return;
+ case DECL_CONST:
+ gen_const(f, &d->c.data);
+ return;
+ case DECL_TYPE:
+ gen_type(f, &d->ty.data);
+ return;
+ }
+ fprintf(stderr, "gen_decl() type: %d\n", d->type);
+}
+
+static void
+gen_code(FILE *f, npl_code_t *c)
+{
+ struct _npl_decl_list *decl;
+
+ for (decl = c->decls; decl; decl = decl->next)
+ gen_decl(f, &decl->d);
+}
+
+static void
+gen_hf(FILE *f)
+{
+ struct hfinfo *hfi;
+
+ for (hfi = hfs; hfi; hfi = hfi->next)
+ gen_fprintf(f, "static int %s = -1;\n", hfi_name(hfi));
+}
+
+static const char proto_name[] = "foo"; /* TODO, hardcoded */
+
+static void
+gen_proto_register(FILE *f)
+{
+ struct hfinfo *hfi;
+
+ gen_fprintf(f,
+ "void\n"
+ "proto_register_%s(void)\n"
+ "{\n", proto_name);
+
+ /* hf array */
+ gen_fprintf(f, "\tstatic hf_register_info hf[] = {\n");
+ for (hfi = hfs; hfi; hfi = hfi->next) {
+ npl_statement_t *st = hfi->st;
+
+ gen_fprintf(f,
+ "\t\t{ &%s,\n"
+ "\t\t\t{ \"%s\", \"%s\", %s, %s, NULL, 0x%.2x, NULL, HFILL }\n"
+ "\t\t},\n", hfi_name(hfi), st->f.id, "filtr", "typ", "dec", 0x00 );
+ }
+ gen_fprintf(f, "\t}\n\n");
+
+ gen_fprintf(f, "\tstatic gint *ett[] = {\n");
+#if 0
+ &ett_foo,
+ &ett_foo_smth1
+#endif
+ gen_fprintf(f, "\t}\n\n");
+
+
+ gen_fprintf(f, "\tproto_%s = proto_register_protocol(\"foo1\", \"foo2\", \"%s\");\n\n", proto_name, proto_name);
+
+ gen_fprintf(f, "\tproto_register_field_array(proto_%s, hf, array_length(hf));\n", proto_name);
+ gen_fprintf(f, "\tproto_register_subtree_array(ett, array_length(ett));\n");
+
+ gen_fprintf(f, "}\n");
+}
+
+static void
+gen_proto_handoff(FILE *f)
+{
+ gen_fprintf(f,
+ "void\n"
+ "proto_reg_handoff_%s(void)\n"
+ "{", proto_name);
+
+ gen_fprintf(f, "dissector_handle_t %s_handle = new_create_dissector_handle(dissect_%s, proto_%s);\n", proto_name, proto_name, proto_name);
+
+#if 0
+ dissector_add_uint("REG", XXX, %s_handle);
+
+ xml_handle = find_dissector("xml");
+#endif
+ gen_fprintf(f, "}\n");
+}
+
+int main(int argc, char **argv) {
+ FILE *f;
+ npl_code_t code;
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s filename\n", argv[0]);
+ return 1;
+ }
+
+ if (!(f = fopen(argv[1], "rb"))) {
+ fprintf(stderr, "can't open: %s\n", argv[1]);
+ return 1;
+ }
+
+ memset(&code, 0, sizeof(code));
+ printf("%s:\n", argv[1]);
+ npl_parse_file(&code, f, argv[1]);
+
+ if (code.parse_ok) {
+ FILE *out;
+
+ gen_code(NULL, &code);
+
+ out = fopen("/tmp/npl.c", "w");
+
+ /* TODO declare ett_ */
+ gen_hf(out);
+
+ gen_fprintf(out, "\n\n");
+
+ gen_code(out, &code);
+
+ gen_proto_register(out);
+ gen_proto_handoff(out);
+ }
+ fclose(f);
+ return 0;
+}
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();
+}
+
diff --git a/tools/npl/xmem.h b/tools/npl/xmem.h
new file mode 100644
index 0000000000..d42065f040
--- /dev/null
+++ b/tools/npl/xmem.h
@@ -0,0 +1,20 @@
+#ifndef _X_MEM_H
+#define _X_MEM_H
+
+#include <stdlib.h>
+
+static void oom_killer(void) {
+ fprintf(stderr, "\n\n !!! Out of memory !!!\n\n");
+ exit(1);
+}
+
+static inline void *xmalloc(size_t s) { void *ptr = malloc(s); if (!ptr) oom_killer(); return memset(ptr, 0x00, s); }
+static inline void *xrealloc(void *p, size_t s) { void *ptr = realloc(p, s); if (!ptr) oom_killer(); return ptr; }
+
+static inline void *xmemdup(void *p, size_t s) { void *ptr = malloc(s); if (!ptr) oom_killer(); return memcpy(ptr, p, s); }
+static inline void *xstrdup(const char *s) { void *ptr = strdup(s); if (!ptr) oom_killer(); return ptr; }
+
+#define xnew(x) (x *) xmalloc(sizeof(x))
+#define xdup(x, y) (x *) xmemdup(y, sizeof(x))
+
+#endif