static struct expr * vcc_expr_edit(enum var_type fmt, const char *p, struct expr *e1, struct expr *e2) { struct expr *e; int nl = 1; e = vcc_new_expr(); while (*p != '\0') { if (*p == '\n') { if (!nl) VSB_putc(e->vsb, *p); nl = 1; p++; continue; } nl = 0; if (*p != '\v') { VSB_putc(e->vsb, *p); p++; continue; } assert(*p == '\v'); p++; switch(*p) { case '+': VSB_cat(e->vsb, "\v+"); break; case '-': VSB_cat(e->vsb, "\v-"); break; case '1': case '2': if (*p == '1') VSB_cat(e->vsb, VSB_data(e1->vsb)); else { AN(e2); VSB_cat(e->vsb, VSB_data(e2->vsb)); } break; default: assert(__LINE__ == 0); } p++; } AZ(VSB_finish(e->vsb)); if (e1 != NULL) e->t1 = e1->t1; else if (e2 != NULL) e->t1 = e2->t1; if (e2 != NULL) e->t2 = e2->t1; else if (e1 != NULL) e->t1 = e1->t1; if ((e1 == NULL || e1->constant) && (e2 == NULL || e2->constant)) e->constant = 1; vcc_delete_expr(e1); vcc_delete_expr(e2); e->fmt = fmt; return (e); }
static struct expr * vcc_mk_expr(enum var_type fmt, const char *str, ...) { va_list ap; struct expr *e; e = vcc_new_expr(); e->fmt = fmt; va_start(ap, str); VSB_vprintf(e->vsb, str, ap); va_end(ap); AZ(VSB_finish(e->vsb)); return (e); }
static struct expr * vcc_expr_edit(enum var_type fmt, const char *p, struct expr *e1, struct expr *e2) { struct expr *e; int nl = 1; AN(e1); e = vcc_new_expr(); while (*p != '\0') { if (*p != '\v') { if (*p != '\n' || !nl) VSB_putc(e->vsb, *p); nl = (*p == '\n'); p++; continue; } assert(*p == '\v'); switch(*++p) { case '+': VSB_cat(e->vsb, "\v+"); break; case '-': VSB_cat(e->vsb, "\v-"); break; case '1': VSB_cat(e->vsb, VSB_data(e1->vsb)); break; case '2': AN(e2); VSB_cat(e->vsb, VSB_data(e2->vsb)); break; default: WRONG("Illegal edit in VCC expression"); } p++; } AZ(VSB_finish(e->vsb)); e->t1 = e1->t1; e->t2 = e1->t2; if (e2 != NULL) e->t2 = e2->t2; vcc_delete_expr(e1); vcc_delete_expr(e2); e->fmt = fmt; return (e); }
static void vcc_expr4(struct vcc *tl, struct expr **e, enum var_type fmt) { struct expr *e1, *e2; const struct symbol *sym; double d; *e = NULL; if (tl->t->tok == '(') { SkipToken(tl, '('); vcc_expr0(tl, &e2, fmt); ERRCHK(tl); SkipToken(tl, ')'); *e = vcc_expr_edit(e2->fmt, "(\v1)", e2, NULL); return; } switch(tl->t->tok) { case ID: /* * XXX: what if var and func/proc had same name ? * XXX: look for SYM_VAR first for consistency ? */ sym = VCC_FindSymbol(tl, tl->t, SYM_NONE); if (sym == NULL || sym->eval == NULL) { VSB_printf(tl->sb, "Symbol not found: "); vcc_ErrToken(tl, tl->t); VSB_printf(tl->sb, " (expected type %s):\n", vcc_Type(fmt)); vcc_ErrWhere(tl, tl->t); return; } AN(sym); switch(sym->kind) { case SYM_VAR: case SYM_FUNC: case SYM_BACKEND: AN(sym->eval); AZ(*e); sym->eval(tl, e, sym); return; default: break; } VSB_printf(tl->sb, "Symbol type (%s) can not be used in expression.\n", VCC_SymKind(tl, sym)); vcc_ErrWhere(tl, tl->t); return; case CSTR: assert(fmt != VOID); e1 = vcc_new_expr(); EncToken(e1->vsb, tl->t); e1->fmt = STRING; e1->t1 = tl->t; e1->constant = 1; vcc_NextToken(tl); AZ(VSB_finish(e1->vsb)); *e = e1; break; case CNUM: /* * XXX: %g may not have enough decimals by default * XXX: but %a is ugly, isn't it ? */ assert(fmt != VOID); if (fmt == DURATION) { vcc_RTimeVal(tl, &d); ERRCHK(tl); e1 = vcc_mk_expr(DURATION, "%g", d); } else if (fmt == BYTES) { vcc_ByteVal(tl, &d); ERRCHK(tl); e1 = vcc_mk_expr(BYTES, "%.1f", d); ERRCHK(tl); } else if (fmt == REAL) { e1 = vcc_mk_expr(REAL, "%g", vcc_DoubleVal(tl)); ERRCHK(tl); } else { e1 = vcc_mk_expr(INT, "%.*s", PF(tl->t)); vcc_NextToken(tl); } e1->constant = 1; *e = e1; break; default: VSB_printf(tl->sb, "Unknown token "); vcc_ErrToken(tl, tl->t); VSB_printf(tl->sb, " when looking for %s\n\n", vcc_Type(fmt)); vcc_ErrWhere(tl, tl->t); break; } }