Root/
| 1 | /* |
| 2 | * chr.h - Part characteristics |
| 3 | * |
| 4 | * Copyright 2012 by Werner Almesberger |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation; either version 2 of the License, or |
| 9 | * (at your option) any later version. |
| 10 | */ |
| 11 | |
| 12 | |
| 13 | #include <assert.h> |
| 14 | |
| 15 | #include "util.h" |
| 16 | #include "lang.h" |
| 17 | #include "relop.h" |
| 18 | #include "param.h" |
| 19 | #include "chr.h" |
| 20 | |
| 21 | |
| 22 | const struct format *field_find(const char *name, const struct field *tail) |
| 23 | { |
| 24 | while (tail) { |
| 25 | if (tail->name == name) |
| 26 | return tail->fmt; |
| 27 | tail = tail->prev; |
| 28 | } |
| 29 | return NULL; |
| 30 | } |
| 31 | |
| 32 | |
| 33 | /* ----- Construction of the field hierarchy ------------------------------- */ |
| 34 | |
| 35 | |
| 36 | struct field *new_field(const char *name, const struct format *fmt, |
| 37 | const struct field *prev) |
| 38 | { |
| 39 | struct field *field; |
| 40 | |
| 41 | if (field_find(name, prev)) |
| 42 | yyerrorf("duplicate field \"%s\"", name); |
| 43 | field = alloc_type(struct field); |
| 44 | field->name = name; |
| 45 | field->fmt = fmt; |
| 46 | field->sel = NULL; |
| 47 | field->any.fields = NULL; |
| 48 | field->any.rules = NULL; |
| 49 | field->next = NULL; |
| 50 | field->prev = NULL; |
| 51 | return field; |
| 52 | } |
| 53 | |
| 54 | |
| 55 | struct selector *new_selector(void) |
| 56 | { |
| 57 | struct selector *sel; |
| 58 | |
| 59 | sel = alloc_type(struct selector); |
| 60 | sel->cond = NULL; |
| 61 | sel->act.fields = NULL; |
| 62 | sel->act.rules = NULL; |
| 63 | sel->next = NULL; |
| 64 | return sel; |
| 65 | } |
| 66 | |
| 67 | |
| 68 | struct condition *new_condition(enum relop relop, const char *word) |
| 69 | { |
| 70 | struct condition *cond; |
| 71 | |
| 72 | cond = alloc_type(struct condition); |
| 73 | cond->value.u.s = word; |
| 74 | cond->relop = relop; |
| 75 | cond->next = NULL; |
| 76 | return cond; |
| 77 | } |
| 78 | |
| 79 | |
| 80 | static int comp(const void *a, enum relop op, const void *b, const void *user) |
| 81 | { |
| 82 | return compare(user, a, op, b); |
| 83 | } |
| 84 | |
| 85 | |
| 86 | static void check_unreachable(const struct field *f, |
| 87 | const struct condition *c1, const struct condition *c2) |
| 88 | { |
| 89 | if (relop_unreachable(c1->relop, c2->relop, &c1->value, &c2->value, |
| 90 | comp, f->fmt)) |
| 91 | yywarn("unreachable condition"); |
| 92 | } |
| 93 | |
| 94 | |
| 95 | void field_finalize(struct field *field) |
| 96 | { |
| 97 | const struct selector *sel, *s2; |
| 98 | struct condition *cond; |
| 99 | const struct condition *c2; |
| 100 | |
| 101 | for (sel = field->sel; sel; sel = sel->next) |
| 102 | for (cond = sel->cond; cond; cond = cond->next) |
| 103 | if (!evaluate(field->fmt, cond->value.u.s, |
| 104 | &cond->value)) |
| 105 | yyerrorf("invalid value in selection"); |
| 106 | /* @@@ indicate exact location */ |
| 107 | for (sel = field->sel; sel; sel = sel->next) |
| 108 | for (cond = sel->cond; cond; cond = cond->next) { |
| 109 | for (c2 = cond->next; c2; c2 = c2->next) |
| 110 | check_unreachable(field, cond, c2); |
| 111 | for (s2 = sel->next; s2; s2 = s2->next) |
| 112 | for (c2 = s2->cond; c2; c2 = c2->next) |
| 113 | check_unreachable(field, cond, c2); |
| 114 | } |
| 115 | } |
| 116 | |
| 117 | |
| 118 | /* ----- Dumping ----------------------------------------------------------- */ |
| 119 | |
| 120 | |
| 121 | #define INDENT 8 |
| 122 | |
| 123 | |
| 124 | static void dump_rules(FILE *file, const struct field *field, int level); |
| 125 | |
| 126 | |
| 127 | static void dump_set_decl(FILE *file, const struct names *first_name) |
| 128 | { |
| 129 | const char *name; |
| 130 | |
| 131 | name = nameset_rev_lookup(first_name); |
| 132 | assert(name); |
| 133 | fprintf(file, "<%s>", name); |
| 134 | } |
| 135 | |
| 136 | |
| 137 | static void dump_field_decl(FILE *file, const struct field *field) |
| 138 | { |
| 139 | if (field->fmt->ops == ¶m_ops_name) |
| 140 | fprintf(file, "*"); |
| 141 | else if (field->fmt->ops == ¶m_ops_set) |
| 142 | dump_set_decl(file, field->fmt->u.set); |
| 143 | else if (field->fmt->ops == ¶m_ops_abs) |
| 144 | fprintf(file, "#%s", |
| 145 | field->fmt->u.abs ? field->fmt->u.abs : "#"); |
| 146 | else if (field->fmt->ops == ¶m_ops_rel) |
| 147 | fprintf(file, "%%%s", |
| 148 | field->fmt->u.rel->u.abs ? field->fmt->u.rel->u.abs : "#"); |
| 149 | else |
| 150 | abort(); |
| 151 | } |
| 152 | |
| 153 | |
| 154 | static void dump_action(FILE *file, const struct action *act, int level) |
| 155 | { |
| 156 | if (act->fields) { |
| 157 | fprintf(file, " "); |
| 158 | fields_dump(file, act->fields); |
| 159 | } |
| 160 | fprintf(file, "\n"); |
| 161 | dump_rules(file, act->rules, level+1); |
| 162 | } |
| 163 | |
| 164 | |
| 165 | static void dump_one_rule(FILE *file, const struct field *field, int level) |
| 166 | { |
| 167 | const struct selector *sel; |
| 168 | const struct condition *cond; |
| 169 | |
| 170 | fprintf(file, "%*s%s=", level*INDENT, "", field->name); |
| 171 | dump_field_decl(file, field); |
| 172 | |
| 173 | fprintf(file, " {\n"); |
| 174 | |
| 175 | for (sel = field->sel; sel; sel = sel->next) { |
| 176 | fprintf(file, "%*s", level*INDENT+INDENT/2, ""); |
| 177 | for (cond = sel->cond; cond; cond = cond->next) { |
| 178 | if (cond != sel->cond) |
| 179 | fprintf(file, "|"); |
| 180 | if (cond->relop != rel_eq) |
| 181 | dump_relop(file, cond->relop); |
| 182 | dump_param(file, field->fmt, &cond->value); |
| 183 | } |
| 184 | fprintf(file, ":"); |
| 185 | dump_action(file, &sel->act, level); |
| 186 | } |
| 187 | if (field->any.fields || field->any.rules) { |
| 188 | fprintf(file, "%*s*:", level*INDENT+INDENT/2, ""); |
| 189 | dump_action(file, &field->any, level); |
| 190 | } |
| 191 | fprintf(file, "%*s}\n", level*INDENT, ""); |
| 192 | } |
| 193 | |
| 194 | |
| 195 | void fields_dump(FILE *file, const struct field *fields) |
| 196 | { |
| 197 | const struct field *f; |
| 198 | |
| 199 | if (!fields) |
| 200 | return; |
| 201 | fprintf(file, "{ "); |
| 202 | for (f = fields; f; f = f->next) { |
| 203 | fprintf(file, "%s%s=", f == fields ? "" : " ", f->name); |
| 204 | dump_field_decl(file, f); |
| 205 | } |
| 206 | fprintf(file, " }"); |
| 207 | } |
| 208 | |
| 209 | |
| 210 | static void dump_rules(FILE *file, const struct field *field, int level) |
| 211 | { |
| 212 | while (field) { |
| 213 | dump_one_rule(file, field, level); |
| 214 | field = field->next; |
| 215 | } |
| 216 | } |
| 217 | |
| 218 | |
| 219 | void rules_dump(FILE *file, const struct field *field) |
| 220 | { |
| 221 | dump_rules(file, field, 0); |
| 222 | } |
| 223 |
Branches:
master
