Date:2012-05-20 19:16:16 (11 years 10 months ago)
Author:Werner Almesberger
Commit:fd14c5200acd9f60b755db6806fb37276f03809f
Message:b2/: add processing of substitution rules

Files: b2/Makefile (1 diff)
b2/subex.c (1 diff)
b2/subex.h (1 diff)

Change Details

b2/Makefile
1313
1414CFLAGS = -g -Wall $(shell pkg-config --cflags glib-2.0)
1515SLOPPY = -Wno-unused -Wno-implicit-function-declaration
16OBJS = boom.o chr.o comp.o db.o dump.o eval.o param.o subst.o util.o \
16OBJS = boom.o chr.o comp.o db.o dump.o eval.o param.o subex.o subst.o util.o \
1717       lex.yy.o y.tab.o
1818LDLIBS = -lfl $(shell pkg-config --libs glib-2.0)
1919
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 <sys/types.h>
17#include <regex.h>
18
19#include "util.h"
20#include "lang.h"
21#include "subst.h"
22#include "subex.h"
23
24
25#define FIELDS 10
26
27
28static const char *fn = NULL, *f[FIELDS];
29
30/* Jump target that can never be reached. */
31static struct subst jump_end;
32
33
34static void append_n(char **res, int *res_len, const char *s, int len)
35{
36    if (!len)
37        return;
38    *res = realloc(*res, *res_len+len+1);
39    if (!*res)
40        abort();
41    memcpy(*res+*res_len, s, len);
42    *res_len += len;
43    (*res)[*res_len] = 0;
44}
45
46
47static void append(char **res, int *res_len, const char *s)
48{
49    append_n(res, res_len, s, strlen(s));
50}
51
52
53#if 0
54static void append_char(char **res, int *res_len, char c)
55{
56    append_n(res, res_len, &c, 1);
57}
58#endif
59
60
61/*
62 * TODO: decide what to do with units
63 */
64
65static char *compose(const struct chunk *c,
66    const struct var *in, const struct var *out,
67    const char *s, const regmatch_t *match)
68{
69    char *res = stralloc("");
70    int res_len = 0;
71    const char *val;
72    int n;
73
74    while (c) {
75        switch (c->type) {
76        case ct_string:
77            append(&res, &res_len, c->u.s);
78            break;
79        case ct_var:
80            val = var_lookup(in, c->u.var);
81            if (!val)
82                val = var_lookup(out, c->u.var);
83            if (!val)
84                yyerrorf("unknown variable \"%s\"", c->u.var);
85            append(&res, &res_len, val);
86            break;
87        case ct_sub:
88            n = c->u.sub;
89            if (!s)
90                yyerrorf("$%c without prior match",
91                    n ? n+'0' : '$');
92            if (!n) {
93                append(&res, &res_len, s);
94                break;
95            }
96            if (match[n-1].rm_so == -1)
97                yyerrorf("substring $%d out of range", n);
98#if 0
99            len = match[n-1].rm_eo-match[n-1].rm_so);
100            tmp = alloc_size(len);
101            memcpy(tmp, s+match[n-1].rm_so, len);
102            tmp[len] = 0;
103            tmp2 = canonicalize(tmp, c->unit);
104            append(&res, &res_len, tmp2);
105#endif
106            append_n(&res, &res_len, s+match[n-1].rm_so,
107                match[n-1].rm_eo-match[n-1].rm_so);
108            break;
109        default:
110            abort();
111        }
112        c = c->next;
113    }
114    return res;
115}
116
117
118struct var *make_var(const char *name, const char *val)
119{
120    struct var *var;
121
122    var = alloc_type(struct var);
123    var->name = unique(name);
124    var->value = unique(val);
125    var->next = NULL;
126    return var;
127}
128
129
130static void do_assign(const char *name, struct var **out, const char *val)
131{
132    while (*out) {
133        if ((*out)->name == name)
134            break;
135        out = &(*out)->next;
136    }
137    if (*out) {
138        free((void *) (*out)->value);
139        (*out)->value = val;
140    } else {
141        *out = make_var(name, val);
142    }
143}
144
145
146static int do_match_1(const char *var, const regex_t *re,
147    const struct var *in, const struct var *out,
148    const char **val, regmatch_t *match)
149{
150    *val = var_lookup(out, var);
151    if (!*val)
152        *val = var_lookup(in, var);
153    if (!*val)
154        return -1;
155    return regexec(re, *val, 10, match, 0);
156}
157
158
159static int do_match(const char *var, const regex_t *re,
160    const struct var *in, const struct var *out,
161    const char **val, regmatch_t *match)
162{
163    int i;
164
165    if (var != fn)
166        return do_match_1(var, re, in, out, val, match);
167    for (i = 0; i != FIELDS; i++)
168        if (!do_match_1(f[i], re, in, out, val, match))
169            return 0;
170    return -1;
171}
172
173
174static const struct subst *recurse_sub(const struct subst *sub,
175    const struct var *in, const char *s, const regmatch_t *match,
176    struct var **out)
177{
178    const struct subst *jump;
179    regmatch_t m_tmp[10];
180    const char *val;
181    char *tmp;
182
183    while (sub) {
184        switch (sub->type) {
185        case st_match:
186            if (do_match(sub->u.match.src, &sub->u.match.re,
187                in, *out, &val, m_tmp))
188                break;
189            jump = recurse_sub(sub->u.match.block, in, val, m_tmp,
190                out);
191            if (jump && jump != sub)
192                return jump;
193            break;
194        case st_assign:
195            tmp = compose(sub->u.assign.pat, in, *out, s, match);
196            do_assign(sub->u.assign.dst, out, tmp);
197            break;
198        case st_end:
199            return &jump_end;
200        case st_break:
201            sub = sub->u.jump->next;
202            continue;
203        case st_again:
204            sub = sub->u.jump->u.match.block;
205            continue;
206        default:
207            abort();
208        }
209        sub = sub->next;
210    }
211    return NULL;
212}
213
214
215struct var *substitute(const struct subst *sub, const struct var *in)
216{
217    struct var *out = NULL;
218    int i;
219    char tmp[4];
220
221    if (!fn) {
222        fn = unique("FN");
223        for (i = 0; i != FIELDS; i++) {
224            sprintf(tmp, "F%d", i);
225            f[i] = unique(tmp);
226        }
227    }
228    recurse_sub(sub, in, NULL, NULL, &out);
229    return out;
230}
231
232
233const char *var_lookup(const struct var *vars, const char *name)
234{
235    while (vars) {
236        if (vars->name == name)
237            return vars->value;
238        vars = vars->next;
239    }
240    return NULL;
241}
242
243
244void free_vars(struct var *vars)
245{
246    struct var *next;
247
248    while (vars) {
249        next = vars->next;
250        free(vars);
251        vars = next;
252    }
253}
b2/subex.h
1/*
2 * subex.h - 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#ifndef SUBEX_H
14#define SUBEX_H
15
16#include "subst.h"
17
18
19struct var {
20    const char *name;
21    const char *value;
22    struct var *next;
23};
24
25
26struct var *substitute(const struct subst *sub, const struct var *in);
27struct var *make_var(const char *name, const char *val);
28const char *var_lookup(const struct var *vars, const char *name);
29void free_vars(struct var *vars);
30
31#endif /* !SUBEX_H */

Archive Download the corresponding diff file

Branches:
master



interactive