Root/b2/subex.c

1/*
2 * subex.c - Substitution (execution)
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 <stdlib.h>
14#include <stdio.h>
15#include <string.h>
16#include <ctype.h>
17#include <sys/types.h>
18#include <regex.h>
19#include <assert.h>
20
21#include "util.h"
22#include "vstring.h"
23#include "lang.h"
24#include "relop.h"
25#include "subst.h"
26#include "subex.h"
27
28
29#define FIELDS 10 /* fields in KiCad schematics */
30
31
32static const char *f[FIELDS];
33
34/* Jump targets that can never be reached. */
35static struct subst jump_end;
36static struct subst jump_ignore;
37
38
39static char *canonicalize(const char *s, char unit)
40{
41    char *res;
42    int res_len = 0;
43    int seen_dot = 0;
44    int seen_unit = 0;
45    char mult = 0;
46
47    if (!unit)
48        return stralloc(s);
49    res = stralloc("");
50    while (*s) {
51        if (*s == unit && unit != '#') {
52            assert(!seen_unit);
53            if (!s[1])
54                break;
55            if (!seen_dot)
56                append_char(&res, &res_len, '.');
57            seen_unit = seen_dot = 1;
58            s++;
59            continue;
60        }
61        if (*s == '.') {
62            assert(!seen_dot);
63            append_char(&res, &res_len, '.');
64            seen_dot = 1;
65        } else if (*s == '-' || isdigit(*s)) {
66            append_char(&res, &res_len, *s);
67            s++;
68            continue;
69        } else if (strchr(MULT_CHARS, *s)) {
70            assert(!seen_unit);
71            assert(!mult);
72            mult = *s;
73            if (!seen_dot)
74                append_char(&res, &res_len, '.');
75            seen_dot = 1;
76        } else {
77            abort();
78        }
79        s++;
80    }
81    if (res_len && res[res_len-1] == '.')
82        res_len--;
83    if (mult)
84        append_char(&res, &res_len, mult);
85    if (unit != '#')
86        append_char(&res, &res_len, unit);
87    return res;
88}
89
90
91static char *compose(const struct chunk *c,
92    const struct param *in, const struct param *out,
93    const char *s, const regmatch_t *match, const char *units)
94{
95    char *res = stralloc("");
96    int res_len = 0;
97    const char *val;
98    char *tmp, *tmp2;
99    int n;
100
101    while (c) {
102        switch (c->type) {
103        case ct_string:
104            append(&res, &res_len, c->u.s);
105            break;
106        case ct_var:
107            val = var_lookup(out, c->u.var);
108            if (!val)
109                val = var_lookup(in, c->u.var);
110            assert(val);
111            append(&res, &res_len, val);
112            break;
113        case ct_sub:
114            n = c->u.sub;
115            assert(s);
116            if (!n) {
117                append(&res, &res_len, s);
118                break;
119            }
120            if (match[n].rm_so == -1)
121                break;
122            tmp = stralloc_n(s+match[n].rm_so,
123                match[n].rm_eo-match[n].rm_so);
124            tmp2 = canonicalize(tmp, units ? units[n-1] : 0);
125            append(&res, &res_len, tmp2);
126            free(tmp);
127            free(tmp2);
128            break;
129        default:
130            abort();
131        }
132        c = c->next;
133    }
134    return res;
135}
136
137
138static void do_assign(const char *name, struct param **out, enum relop op,
139    const char *val)
140{
141    while (*out) {
142        if ((*out)->u.name == name)
143            break;
144        out = &(*out)->next;
145    }
146    if (*out)
147        (*out)->value.u.s = val;
148    else
149        *out = make_var(name, op, val);
150}
151
152
153static int do_match_1(const char *var, const regex_t *re,
154    const struct param *in, const struct param *out,
155    const char **val, regmatch_t *match)
156{
157    *val = var_lookup(out, var);
158    if (!*val)
159        *val = var_lookup(in, var);
160    if (!*val)
161        return -1;
162    return regexec(re, *val, NMATCH, match, 0);
163}
164
165
166static int do_match(const char **var, const regex_t *re,
167    const struct param *in, const struct param *out,
168    const char **val, regmatch_t *match)
169{
170    int i;
171
172    if (*var != fn)
173        return do_match_1(*var, re, in, out, val, match);
174    for (i = 0; i != FIELDS; i++)
175        if (!do_match_1(f[i], re, in, out, val, match)) {
176            *var = f[i];
177            return 0;
178        }
179    return -1;
180}
181
182
183static void do_print(const char *var,
184    const struct param *in, const struct param *out)
185{
186    const char *list = "out";
187    const char *val;
188
189    val = var_lookup(out, var);
190    if (!val) {
191        val = var_lookup(in, var);
192        list = "in";
193    }
194    if (val)
195        printf("%s(%s) = \"%s\"\n", var, list, val);
196    else
197        printf("%s = ?\n", var);
198}
199
200
201static const struct subst *recurse_sub(const struct subst *sub,
202    const struct param *in, const char *matched_var, const char *matched_val,
203    const regmatch_t *match, const char *units, struct param **out,
204    enum subst_type *cause)
205{
206    const struct subst *jump;
207    regmatch_t m_tmp[NMATCH];
208    const char *var, *val;
209    char *tmp;
210
211    while (sub) {
212        switch (sub->type) {
213        case st_match:
214            var = sub->u.match.src;
215            if (var == dollar)
216                var = matched_var;
217            if (do_match(&var, &sub->u.match.re,
218                in, *out, &val, m_tmp))
219                break;
220            jump = recurse_sub(sub->u.match.block, in,
221                var, val, m_tmp, sub->u.match.units, out, cause);
222            if (jump) {
223                if (jump != sub)
224                    return jump;
225                if (*cause == st_continue)
226                    continue;
227            }
228            break;
229        case st_assign:
230            tmp = compose(sub->u.assign.pat, in, *out, matched_val,
231               match, units);
232            var = sub->u.assign.dst;
233            if (var == dollar)
234                var = matched_var;
235            do_assign(var, out, sub->u.assign.op, tmp);
236            break;
237        case st_print:
238            var = sub->u.print;
239            if (var == dollar)
240                var = matched_var;
241            do_print(var, in, *out);
242            break;
243        case st_end:
244            return &jump_end;
245        case st_ignore:
246            return &jump_ignore;
247        case st_break:
248        case st_continue:
249            *cause = sub->type;
250            return sub->u.jump;
251        default:
252            abort();
253        }
254        sub = sub->next;
255    }
256    return NULL;
257}
258
259
260int substitute(const struct subst *sub, const struct param *in,
261    struct param **out)
262{
263    enum subst_type cause = 0;
264
265    *out = NULL;
266    return recurse_sub(sub, in, NULL, NULL, NULL, NULL, out, &cause)
267        != &jump_ignore;
268}
269
270
271void subex_init(void)
272{
273    int i;
274    char tmp[4];
275
276    for (i = 0; i != FIELDS; i++) {
277        sprintf(tmp, "F%d", i);
278        f[i] = unique(tmp);
279    }
280}
281

Archive Download this file

Branches:
master



interactive