1
0
mirror of git://projects.qi-hardware.com/eda-tools.git synced 2025-04-21 12:27:27 +03:00

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.
This commit is contained in:
Werner Almesberger
2012-05-20 21:55:54 -03:00
parent adecef8d4a
commit 99e5777448
4 changed files with 124 additions and 55 deletions

View File

@@ -38,11 +38,33 @@ static struct subst *alloc_subst(enum subst_type type)
}
static char *prepare_re(const char *re)
/*
* With M the SI multiplier prefixes and U the unit character, our regexp
* is
*
* (-?[0-9]+\.?[[0-9]*M?U?|-?[0-9]+[UM][0-9]*)
*
* The first part is for things like 10, 1.2k, 3.3V, -2mA, etc.
* The second part is for things like 1k20, 1R2, etc.
*/
static void unit_expr(char **res, int *res_len, char unit)
{
append(res, res_len, "(-?[0-9]+\\.?[0-9]*[" MULT_CHARS "]?");
append_char(res, res_len, unit);
append(res, res_len, "?|-?[0-9]+[");
append_char(res, res_len, unit);
append(res, res_len, MULT_CHARS "][0-9]*)");
}
static char *prepare_re(const char *re, int *parens, char *units)
{
char *res = NULL;
int res_len = 0;
*parens = 0;
memset(units, 0, 10);
append_char(&res, &res_len, '^');
while (*re) {
switch (*re) {
@@ -61,6 +83,16 @@ static char *prepare_re(const char *re)
append_n(&res, &res_len, re, 2);
re++;
break;
case '(':
(*parens)++;
if (re[1] == '#' && re[2] && isalpha(re[2]) &&
re[3] == ')') {
units[*parens-1] = re[2];
unit_expr(&res, &res_len, re[2]);
re += 3;
break;
}
/* fall through */
default:
append_char(&res, &res_len, *re);
}
@@ -77,11 +109,11 @@ struct subst *subst_match(const char *src, const char *re)
char error[1000];
struct subst *sub;
char *tmp;
int err;
int parens, err;
sub = alloc_subst(st_match);
sub->u.match.src = src;
tmp = prepare_re(re);
tmp = prepare_re(re, &parens, sub->u.match.units);
err = regcomp(&sub->u.match.re, tmp, REG_EXTENDED);
free(tmp);
if (err) {
@@ -102,7 +134,6 @@ static void end_chunk(struct chunk ***last, const char *start, const char *s)
c = alloc_type(struct chunk);
c->type = ct_string;
c->u.s = stralloc_n(start, s-start);;
c->unit = NULL;
c->next = NULL;
**last = c;
*last = &c->next;
@@ -154,28 +185,9 @@ static const char *parse_var(struct chunk *c, const char *s)
c->u.sub = 0;
}
if (*t != '#') {
if (braced) {
assert(*t == '}');
t++;
}
return t;
}
s = ++t;
while (*t) {
if (braced && *t == '}')
break;
if (!braced && t != s)
break;
t++;
}
if (s == t)
yyerror("invalid unit");
c->unit = stralloc_n(s, t-s);
if (braced) {
if (!*t)
yyerror("unterminated unit");
if (*t != '}')
yyerror("invalid variable name");
t++;
}
return t;
@@ -204,7 +216,6 @@ static struct chunk *parse_pattern(const char *s)
end_chunk(&last, start, s);
c = alloc_type(struct chunk);
c->unit = NULL;
c->next = NULL;
*last = c;
last = &c->next;
@@ -324,18 +335,13 @@ static void dump_chunks(FILE *file, const struct chunk *c)
break;
case ct_sub:
if (c->u.sub)
fprintf(file, "${%d", c->u.sub);
fprintf(file, "$%d", c->u.sub);
else
fprintf(file, "${$");
fprintf(file, "$$");
break;
default:
abort();
}
if (c->type != ct_string) {
if (c->unit)
fprintf(file, "#%s", c->unit);
fprintf(file, "}");
}
c = c->next;
}
}