/* * chr.h - Part characteristics * * 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 "util.h" #include "lang.h" #include "relop.h" #include "param.h" #include "chr.h" const struct format *field_find(const char *name, const struct field *tail) { while (tail) { if (tail->name == name) return tail->fmt; tail = tail->prev; } return NULL; } /* ----- Construction of the field hierarchy ------------------------------- */ struct field *new_field(const char *name, const struct format *fmt, const struct field *prev) { struct field *field; if (field_find(name, prev)) yyerrorf("duplicate field \"%s\"", name); field = alloc_type(struct field); field->name = name; field->fmt = fmt; field->sel = NULL; field->any.fields = NULL; field->any.rules = NULL; field->next = NULL; field->prev = NULL; return field; } struct selector *new_selector(void) { struct selector *sel; sel = alloc_type(struct selector); sel->cond = NULL; sel->act.fields = NULL; sel->act.rules = NULL; sel->next = NULL; return sel; } struct condition *new_condition(enum relop relop, const char *word) { struct condition *cond; cond = alloc_type(struct condition); cond->value.u.s = word; cond->relop = relop; cond->next = NULL; return cond; } static int comp(const void *a, enum relop op, const void *b, const void *user) { return compare(user, a, op, b); } static void check_unreachable(const struct field *f, const struct condition *c1, const struct condition *c2) { if (relop_unreachable(c1->relop, c2->relop, &c1->value, &c2->value, comp, f->fmt)) yywarn("unreachable condition"); } void field_finalize(struct field *field) { const struct selector *sel, *s2; struct condition *cond; const struct condition *c2; for (sel = field->sel; sel; sel = sel->next) for (cond = sel->cond; cond; cond = cond->next) if (!evaluate(field->fmt, cond->value.u.s, &cond->value)) yyerrorf("invalid value in selection"); /* @@@ indicate exact location */ for (sel = field->sel; sel; sel = sel->next) for (cond = sel->cond; cond; cond = cond->next) { for (c2 = cond->next; c2; c2 = c2->next) check_unreachable(field, cond, c2); for (s2 = sel->next; s2; s2 = s2->next) for (c2 = s2->cond; c2; c2 = c2->next) check_unreachable(field, cond, c2); } } /* ----- Dumping ----------------------------------------------------------- */ #define INDENT 8 static void dump_rules(FILE *file, const struct field *field, int level); static void dump_set_decl(FILE *file, const struct names *first_name) { const char *name; name = nameset_rev_lookup(first_name); assert(name); fprintf(file, "<%s>", name); } static void dump_field_decl(FILE *file, const struct field *field) { if (field->fmt->ops == ¶m_ops_name) fprintf(file, "*"); else if (field->fmt->ops == ¶m_ops_set) dump_set_decl(file, field->fmt->u.set); else if (field->fmt->ops == ¶m_ops_abs) fprintf(file, "#%s", field->fmt->u.abs ? field->fmt->u.abs : "#"); else if (field->fmt->ops == ¶m_ops_rel) fprintf(file, "%%%s", field->fmt->u.rel->u.abs ? field->fmt->u.rel->u.abs : "#"); else abort(); } static void dump_action(FILE *file, const struct action *act, int level) { if (act->fields) { fprintf(file, " "); fields_dump(file, act->fields); } fprintf(file, "\n"); dump_rules(file, act->rules, level+1); } static void dump_one_rule(FILE *file, const struct field *field, int level) { const struct selector *sel; const struct condition *cond; fprintf(file, "%*s%s=", level*INDENT, "", field->name); dump_field_decl(file, field); fprintf(file, " {\n"); for (sel = field->sel; sel; sel = sel->next) { fprintf(file, "%*s", level*INDENT+INDENT/2, ""); for (cond = sel->cond; cond; cond = cond->next) { if (cond != sel->cond) fprintf(file, "|"); if (cond->relop != rel_eq) dump_relop(file, cond->relop); dump(file, field->fmt, &cond->value); } fprintf(file, ":"); dump_action(file, &sel->act, level); } if (field->any.fields || field->any.rules) { fprintf(file, "%*s*:", level*INDENT+INDENT/2, ""); dump_action(file, &field->any, level); } fprintf(file, "%*s}\n", level*INDENT, ""); } void fields_dump(FILE *file, const struct field *fields) { const struct field *f; if (!fields) return; fprintf(file, "{ "); for (f = fields; f; f = f->next) { fprintf(file, "%s%s=", f == fields ? "" : " ", f->name); dump_field_decl(file, f); } fprintf(file, " }"); } static void dump_rules(FILE *file, const struct field *field, int level) { while (field) { dump_one_rule(file, field, level); field = field->next; } } void rules_dump(FILE *file, const struct field *field) { dump_rules(file, field, 0); }