Date: | 2012-05-21 02:55:54 (11 years 10 months ago) |
---|---|
Author: | Werner Almesberger |
Commit: | 99e577744871520707c37cfc4e6fe5d491ab7dcc |
Message: | b2/: finish unit handling and move most of its processing to the
match side The ${foo#unit} syntax didn't really make sense because it created a large number of potential error conditions on the assignment side and didn't help with finding compatible fields. With all this moved to the match side, an invalid syntax simply causes a mismatch. |
Files: |
b2/SUBST (2 diffs) b2/subex.c (6 diffs) b2/subst.c (7 diffs) b2/subst.h (3 diffs) |
Change Details
b2/SUBST | ||
---|---|---|
1 | 1 | REF=R[0-9]* { |
2 | 2 | T=R |
3 | VAL=* { R=$$#R } | |
3 | VAL=(#R) { R=$1 } | |
4 | 4 | TOL = 5% |
5 | FN=*% { TOL=${$#%} } | |
5 | FN=*% { TOL=$$ } | |
6 | 6 | break REF |
7 | 7 | // end break again |
8 | 8 | } |
9 | 9 | |
10 | 10 | /* |
11 | pattern: () * ? . | |
11 | pattern: | |
12 | () | like in RE | |
13 | * ? like in glob | |
14 | (#U) expect a numeric value of unit U (use substring to get canonical value) | |
15 | ||
12 | 16 | subst: $1 ... $field |
13 | 17 | |
14 | 18 | substring: |
... | ... | |
17 | 21 | $foo, ... |
18 | 22 | with curly braces: |
19 | 23 | ${foo}, ... |
20 | unit conversion: | |
21 | $foo#V | |
22 | ${1#R} | |
23 | 24 | input variable: |
24 | 25 | $$ |
26 | ||
27 | Caveat: | |
28 | ||
29 | Wrong: FN=* { X=$FN } there is no variable called FN | |
30 | Right: FN=* { X=$$ } yields the Fn field selected by FN | |
31 | ||
32 | Wrong: VAL=(#R) { R=$VAL } yields literal value | |
33 | Wrong: VAL=(#R) { R=$$ } yields literal value | |
34 | Right: VAL=(#R) { R=$1 } yield canonicalized value | |
25 | 35 | */ |
b2/subex.c | ||
---|---|---|
13 | 13 | #include <stdlib.h> |
14 | 14 | #include <stdio.h> |
15 | 15 | #include <string.h> |
16 | #include <ctype.h> | |
16 | 17 | #include <sys/types.h> |
17 | 18 | #include <regex.h> |
19 | #include <assert.h> | |
18 | 20 | |
19 | 21 | #include "util.h" |
20 | 22 | #include "vstring.h" |
... | ... | |
32 | 34 | static struct subst jump_end; |
33 | 35 | |
34 | 36 | |
35 | /* | |
36 | * TODO: decide what to do with units | |
37 | */ | |
37 | ||
38 | static char *canonicalize(const char *s, char unit) | |
39 | { | |
40 | char *res; | |
41 | int res_len = 0; | |
42 | int seen_dot = 0; | |
43 | int seen_unit = 0; | |
44 | char mult = 0; | |
45 | ||
46 | if (!unit) | |
47 | return stralloc(s); | |
48 | res = stralloc(""); | |
49 | while (*s) { | |
50 | if (*s == unit) { | |
51 | assert(!seen_unit); | |
52 | if (!s[1]) | |
53 | break; | |
54 | if (!seen_dot) | |
55 | append_char(&res, &res_len, '.'); | |
56 | seen_unit = seen_dot = 1; | |
57 | s++; | |
58 | continue; | |
59 | } | |
60 | if (*s == '.') { | |
61 | assert(!seen_dot); | |
62 | append_char(&res, &res_len, '.'); | |
63 | seen_dot = 1; | |
64 | } else if (*s == '-' || isdigit(*s)) { | |
65 | append_char(&res, &res_len, *s); | |
66 | s++; | |
67 | continue; | |
68 | } else if (strchr(MULT_CHARS, *s)) { | |
69 | assert(!seen_unit); | |
70 | assert(!mult); | |
71 | mult = *s; | |
72 | if (!seen_dot) | |
73 | append_char(&res, &res_len, '.'); | |
74 | seen_dot = 1; | |
75 | } else { | |
76 | abort(); | |
77 | } | |
78 | s++; | |
79 | } | |
80 | if (res_len && res[res_len-1] == '.') | |
81 | res_len--; | |
82 | if (mult) | |
83 | append_char(&res, &res_len, mult); | |
84 | append_char(&res, &res_len, unit); | |
85 | return res; | |
86 | } | |
87 | ||
38 | 88 | |
39 | 89 | static char *compose(const struct chunk *c, |
40 | 90 | const struct var *in, const struct var *out, |
41 | const char *s, const regmatch_t *match) | |
91 | const char *s, const regmatch_t *match, const char *units) | |
42 | 92 | { |
43 | 93 | char *res = stralloc(""); |
44 | int res_len = 0; | |
94 | int res_len = 0, len; | |
45 | 95 | const char *val; |
96 | char *tmp, *tmp2; | |
46 | 97 | int n; |
47 | 98 | |
48 | 99 | while (c) { |
... | ... | |
69 | 120 | } |
70 | 121 | if (match[n-1].rm_so == -1) |
71 | 122 | yyerrorf("substring $%d out of range", n); |
72 | #if 0 | |
73 | len = match[n-1].rm_eo-match[n-1].rm_so); | |
123 | len = match[n-1].rm_eo-match[n-1].rm_so; | |
74 | 124 | tmp = alloc_size(len); |
75 | 125 | memcpy(tmp, s+match[n-1].rm_so, len); |
76 | 126 | tmp[len] = 0; |
77 | tmp2 = canonicalize(tmp, c->unit); | |
127 | tmp2 = canonicalize(tmp, units ? units[n-1] : 0); | |
78 | 128 | append(&res, &res_len, tmp2); |
79 | #endif | |
80 | append_n(&res, &res_len, s+match[n-1].rm_so, | |
81 | match[n-1].rm_eo-match[n-1].rm_so); | |
129 | free(tmp); | |
130 | free(tmp2); | |
82 | 131 | break; |
83 | 132 | default: |
84 | 133 | abort(); |
... | ... | |
147 | 196 | |
148 | 197 | static const struct subst *recurse_sub(const struct subst *sub, |
149 | 198 | const struct var *in, const char *s, const regmatch_t *match, |
150 | struct var **out) | |
199 | const char *units, struct var **out) | |
151 | 200 | { |
152 | 201 | const struct subst *jump; |
153 | 202 | regmatch_t m_tmp[10]; |
... | ... | |
161 | 210 | in, *out, &val, m_tmp)) |
162 | 211 | break; |
163 | 212 | jump = recurse_sub(sub->u.match.block, in, val, m_tmp, |
164 | out); | |
213 | sub->u.match.units, out); | |
165 | 214 | if (jump && jump != sub) |
166 | 215 | return jump; |
167 | 216 | break; |
168 | 217 | case st_assign: |
169 | tmp = compose(sub->u.assign.pat, in, *out, s, match); | |
218 | tmp = compose(sub->u.assign.pat, in, *out, s, match, | |
219 | units); | |
170 | 220 | do_assign(sub->u.assign.dst, out, tmp); |
171 | 221 | break; |
172 | 222 | case st_end: |
... | ... | |
199 | 249 | f[i] = unique(tmp); |
200 | 250 | } |
201 | 251 | } |
202 | recurse_sub(sub, in, NULL, NULL, &out); | |
252 | recurse_sub(sub, in, NULL, NULL, NULL, &out); | |
203 | 253 | return out; |
204 | 254 | } |
205 | 255 |
b2/subst.c | ||
---|---|---|
38 | 38 | } |
39 | 39 | |
40 | 40 | |
41 | static char *prepare_re(const char *re) | |
41 | /* | |
42 | * With M the SI multiplier prefixes and U the unit character, our regexp | |
43 | * is | |
44 | * | |
45 | * (-?[0-9]+\.?[[0-9]*M?U?|-?[0-9]+[UM][0-9]*) | |
46 | * | |
47 | * The first part is for things like 10, 1.2k, 3.3V, -2mA, etc. | |
48 | * The second part is for things like 1k20, 1R2, etc. | |
49 | */ | |
50 | ||
51 | static void unit_expr(char **res, int *res_len, char unit) | |
52 | { | |
53 | append(res, res_len, "(-?[0-9]+\\.?[0-9]*[" MULT_CHARS "]?"); | |
54 | append_char(res, res_len, unit); | |
55 | append(res, res_len, "?|-?[0-9]+["); | |
56 | append_char(res, res_len, unit); | |
57 | append(res, res_len, MULT_CHARS "][0-9]*)"); | |
58 | } | |
59 | ||
60 | ||
61 | static char *prepare_re(const char *re, int *parens, char *units) | |
42 | 62 | { |
43 | 63 | char *res = NULL; |
44 | 64 | int res_len = 0; |
45 | 65 | |
66 | *parens = 0; | |
67 | memset(units, 0, 10); | |
46 | 68 | append_char(&res, &res_len, '^'); |
47 | 69 | while (*re) { |
48 | 70 | switch (*re) { |
... | ... | |
61 | 83 | append_n(&res, &res_len, re, 2); |
62 | 84 | re++; |
63 | 85 | break; |
86 | case '(': | |
87 | (*parens)++; | |
88 | if (re[1] == '#' && re[2] && isalpha(re[2]) && | |
89 | re[3] == ')') { | |
90 | units[*parens-1] = re[2]; | |
91 | unit_expr(&res, &res_len, re[2]); | |
92 | re += 3; | |
93 | break; | |
94 | } | |
95 | /* fall through */ | |
64 | 96 | default: |
65 | 97 | append_char(&res, &res_len, *re); |
66 | 98 | } |
... | ... | |
77 | 109 | char error[1000]; |
78 | 110 | struct subst *sub; |
79 | 111 | char *tmp; |
80 | int err; | |
112 | int parens, err; | |
81 | 113 | |
82 | 114 | sub = alloc_subst(st_match); |
83 | 115 | sub->u.match.src = src; |
84 | tmp = prepare_re(re); | |
116 | tmp = prepare_re(re, &parens, sub->u.match.units); | |
85 | 117 | err = regcomp(&sub->u.match.re, tmp, REG_EXTENDED); |
86 | 118 | free(tmp); |
87 | 119 | if (err) { |
... | ... | |
102 | 134 | c = alloc_type(struct chunk); |
103 | 135 | c->type = ct_string; |
104 | 136 | c->u.s = stralloc_n(start, s-start);; |
105 | c->unit = NULL; | |
106 | 137 | c->next = NULL; |
107 | 138 | **last = c; |
108 | 139 | *last = &c->next; |
... | ... | |
154 | 185 | c->u.sub = 0; |
155 | 186 | } |
156 | 187 | |
157 | if (*t != '#') { | |
158 | if (braced) { | |
159 | assert(*t == '}'); | |
160 | t++; | |
161 | } | |
162 | return t; | |
163 | } | |
164 | ||
165 | s = ++t; | |
166 | while (*t) { | |
167 | if (braced && *t == '}') | |
168 | break; | |
169 | if (!braced && t != s) | |
170 | break; | |
171 | t++; | |
172 | } | |
173 | if (s == t) | |
174 | yyerror("invalid unit"); | |
175 | c->unit = stralloc_n(s, t-s); | |
176 | 188 | if (braced) { |
177 | if (!*t) | |
178 | yyerror("unterminated unit"); | |
189 | if (*t != '}') | |
190 | yyerror("invalid variable name"); | |
179 | 191 | t++; |
180 | 192 | } |
181 | 193 | return t; |
... | ... | |
204 | 216 | |
205 | 217 | end_chunk(&last, start, s); |
206 | 218 | c = alloc_type(struct chunk); |
207 | c->unit = NULL; | |
208 | 219 | c->next = NULL; |
209 | 220 | *last = c; |
210 | 221 | last = &c->next; |
... | ... | |
324 | 335 | break; |
325 | 336 | case ct_sub: |
326 | 337 | if (c->u.sub) |
327 | fprintf(file, "${%d", c->u.sub); | |
338 | fprintf(file, "$%d", c->u.sub); | |
328 | 339 | else |
329 | fprintf(file, "${$"); | |
340 | fprintf(file, "$$"); | |
330 | 341 | break; |
331 | 342 | default: |
332 | 343 | abort(); |
333 | 344 | } |
334 | if (c->type != ct_string) { | |
335 | if (c->unit) | |
336 | fprintf(file, "#%s", c->unit); | |
337 | fprintf(file, "}"); | |
338 | } | |
339 | 345 | c = c->next; |
340 | 346 | } |
341 | 347 | } |
b2/subst.h | ||
---|---|---|
31 | 31 | const char *var; |
32 | 32 | int sub; /* 0 if $$ */ |
33 | 33 | } u; |
34 | const char *unit; /* NULL if no conversion specified */ | |
35 | 34 | struct chunk *next; |
36 | 35 | }; |
37 | 36 | |
... | ... | |
50 | 49 | const char *src; |
51 | 50 | regex_t re; |
52 | 51 | struct subst *block; |
52 | char units[10]; | |
53 | 53 | } match; |
54 | 54 | struct { |
55 | 55 | const char *dst; |
... | ... | |
62 | 62 | }; |
63 | 63 | |
64 | 64 | |
65 | #define MULT_CHARS "GMkmunpf" | |
66 | ||
67 | ||
65 | 68 | struct subst *subst_match(const char *src, const char *re); |
66 | 69 | struct subst *subst_assign(const char *dst, const char *pat); |
67 | 70 | struct subst *subst_end(void); |
Branches:
master