%{ /* * lang.y - BOOM grammar * * Copyright 2012 by Werner Almesberger * * 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. */ #include #include #include "util.h" #include "param.h" #include "chr.h" #include "db.h" #include "lang.h" #include "y.tab.h" static const struct field *hierarchy; static struct field_stack { const struct field *field; struct field_stack *next; } *field_stack = NULL; static void push_field(const struct field *field) { struct field_stack *entry; entry = alloc_type(struct field_stack); entry->field = field; entry->next = field_stack; field_stack = entry; } static void pop_field(void) { struct field_stack *entry; assert(field_stack); entry = field_stack; field_stack = entry->next; free(entry); } static const struct field *top_field(void) { return field_stack ? field_stack->field : NULL; } %} %union { const char *s; struct equiv *equiv; struct names *names; struct format *format; enum relop relop; struct field *field; struct selector *sel; struct condition *cond; struct action act; struct part *part; struct param *param; }; %token START_HIERARCHY START_CHAR %token TOK_LE TOK_GE TOK_NL %token WORD %type nameqs %type names nameq %type format %type relop opt_relop %type /*rules*/ opt_rule rule opt_fields fields field %type selectors %type conditions condition %type opt_wildcard action %type part %type param params %% all: START_HIERARCHY hierarchy | START_CHAR characteristics ; hierarchy: nameset hierarchy | rule { hierarchy = $1; field_dump(stderr, $1); } ; nameset: '<' WORD '>' '=' names ';' { register_nameset($2, $5); } ; names: nameq { $$ = $1; } | nameq '<' names { $$ = $1; $$->next = $3; } ; nameq: nameqs { $$ = alloc_type(struct names); $$->equiv = $1; $$->next = NULL; } ; nameqs: WORD { $$ = alloc_type(struct equiv); $$->name = $1; $$->next = NULL; } | WORD '=' nameqs { $$ = alloc_type(struct equiv); $$->name = $1; $$->next = $3; } ; /* * @@@ for now, we can't select on a collective of fields. maybe later, with * a syntax change. * rules: { $$ = NULL; } | rule rules { $$ = $1; $$->next = $2; } ; */ opt_rule: { $$ = NULL; } | rule { $$ = $1; } ; rule: field { $1->prev = top_field(); push_field($1); } '{' selectors opt_wildcard '}' { $$ = $1; $$->sel = $4; $$->any = $5; $$->next = NULL; field_finalize($$); pop_field(); } ; selectors: { $$ = NULL; } | conditions ':' action selectors { $$ = new_selector(); $$->cond = $1; $$->act = $3; $$->next = $4; } ; conditions: condition { $$ = $1; } | condition '|' conditions { $$ = $1; $$->next = $3; } ; condition: opt_relop WORD { $$ = new_condition($1, $2); } ; opt_wildcard: { $$.fields = NULL; $$.rules = NULL; } | '*' ':' action { $$ = $3; } ; action: { push_field(top_field()); } opt_fields opt_rule ';' { $$.fields = $2; $$.rules = $3; pop_field(); } ; opt_relop: { $$ = rel_eq; } | relop { $$ = $1; } ; relop: '=' { $$ = rel_eq; } | '<' { $$ = rel_le; } | '>' { $$ = rel_gt; } | TOK_LE { $$ = rel_le; } | TOK_GE { $$ = rel_ge; } ; opt_fields: { $$ = NULL; } | '{' fields '}' { $$ = $2; } ; fields: { $$ = NULL; } | field { push_field($1); } fields { $$ = $1; $$->next = $3; pop_field(); $$->prev = top_field(); if ($3) $3->prev = $1; } ; field: WORD '=' format { $$ = new_field($1, $3, top_field()); } ; format: '*' { $$ = alloc_type(struct format); $$->ops = ¶m_ops_name; } | '<' WORD '>' { $$ = alloc_type(struct format); $$->ops = ¶m_ops_set; $$->u.set = find_nameset($2); if (!$$->u.set) yyerrorf("unknown name set \"%s\"", $2); } | '#' WORD { $$ = alloc_type(struct format); $$->ops = ¶m_ops_abs; $$->u.abs = $2; } | '%' WORD { $$ = alloc_type(struct format); $$->ops = ¶m_ops_rel; $$->u.rel = field_find($2, top_field()); if (!$$->u.rel) yyerrorf("unknown field \"%s\"", $2); } ; characteristics: | TOK_NL | part characteristics { part_finalize($1, hierarchy); } ; part: WORD WORD params TOK_NL { $$ = part_lookup($1, $2); if (!$$) $$ = part_add($1, $2); if ($$->param) yyerror("parameters already defined"); $$->param = $3; } ; params: { $$ = NULL; } | param params { $$ = $1; $$->next = $2; } ; param: WORD '=' WORD { $$ = alloc_type(struct param); $$->u.name = $1; $$->value.u.name = $3; } ;