diff --git a/b2/subex.c b/b2/subex.c index c608674..b9589c6 100644 --- a/b2/subex.c +++ b/b2/subex.c @@ -20,7 +20,6 @@ #include "util.h" #include "vstring.h" -#include "lang.h" #include "relop.h" #include "subst.h" #include "subex.h" @@ -106,21 +105,18 @@ static char *compose(const struct chunk *c, val = var_lookup(in, c->u.var); if (!val) val = var_lookup(out, c->u.var); - if (!val) - yyerrorf("unknown variable \"%s\"", c->u.var); + assert(val); append(&res, &res_len, val); break; case ct_sub: n = c->u.sub; - if (!s) - yyerrorf("$%c without prior match", - n ? n+'0' : '$'); + assert(s); if (!n) { append(&res, &res_len, s); break; } if (match[n-1].rm_so == -1) - yyerrorf("substring $%d out of range", n); + break; len = match[n-1].rm_eo-match[n-1].rm_so; tmp = alloc_size(len); memcpy(tmp, s+match[n-1].rm_so, len); diff --git a/b2/subst.c b/b2/subst.c index 7415419..6cf2058 100644 --- a/b2/subst.c +++ b/b2/subst.c @@ -110,11 +110,11 @@ struct subst *subst_match(const char *src, const char *re) char error[1000]; struct subst *sub; char *tmp; - int parens, err; + int err; sub = alloc_subst(st_match); sub->u.match.src = src; - tmp = prepare_re(re, &parens, sub->u.match.units); + tmp = prepare_re(re, &sub->u.match.parens, sub->u.match.units); err = regcomp(&sub->u.match.re, tmp, REG_EXTENDED); free(tmp); if (err) { @@ -287,18 +287,74 @@ static const struct subst *resolve_jump(const char *name, } -static void recurse_fin(struct subst *sub, const struct parent *parent) +static int find_var_use(const char *var, const struct subst *sub) { - struct parent next = { - .sub = sub, - .parent = parent, - }; - while (sub) { switch (sub->type) { case st_match: - recurse_fin(sub->u.match.block, &next); + if (sub->u.match.src == var) + return 1; + break; case st_assign: + if (sub->u.assign.dst == var) + return 1; + break; + default: + break; + } + sub = sub->prev; + } + return 0; +} + + +static void check_chunks(const struct chunk *c, const struct parent *parent, + const struct subst *prev) +{ + int parens; + + while (c) { + switch (c->type) { + case ct_sub: + if (!parent) + yyerrorf("$%c without match", + c->u.sub ? c->u.sub+'0' : '$'); + parens = parent->sub->u.match.parens; + if (c->u.sub > parens) + yyerrorf("$%d but only %d parenthes%s", + c->u.sub, parens, + parens == 1 ? "is" : "es"); + break; + case ct_var: + if (!find_var_use(c->u.var, prev)) + yyerrorf("$%s may be undefined", c->u.var); + break; + default: + break; + } + c = c->next; + } +} + + +static void recurse_fin(struct subst *sub, const struct parent *parent) +{ + struct parent next = { + .parent = parent, + }; + const struct subst *prev; + + prev = parent ? parent->sub : NULL; + while (sub) { + sub->prev = prev; + switch (sub->type) { + case st_match: + next.sub = sub; + recurse_fin(sub->u.match.block, &next); + break; + case st_assign: + check_chunks(sub->u.assign.pat, parent, prev); + break; case st_end: break; case st_break: @@ -308,6 +364,7 @@ static void recurse_fin(struct subst *sub, const struct parent *parent) default: abort(); } + prev = sub; sub = sub->next; } } diff --git a/b2/subst.h b/b2/subst.h index f2ca3ad..bb68445 100644 --- a/b2/subst.h +++ b/b2/subst.h @@ -52,6 +52,7 @@ struct subst { regex_t re; struct subst *block; char units[10]; + int parens; /* number of parentheses */ } match; struct { const char *dst; @@ -61,6 +62,7 @@ struct subst { const struct subst *jump; const char *tmp; /* jump target name; for subst_finalize */ } u; + const struct subst *prev; /* for tracking availability of variables */ struct subst *next; };