static void test_bool_ops() { Expr *e_not_t = expr_not(expr_true()); Expr *e_not_f = expr_not(expr_false()); Expr *e_and_tt = expr_and(expr_true(), expr_true()); Expr *e_and_tf = expr_and(expr_true(), expr_false()); Expr *e_or_tf = expr_or(expr_true(), expr_false()); Expr *e_or_ff = expr_or(expr_false(), expr_false()); if (expr_bool_val(e_not_t, NULL, NULL) != 0) fail(); if (expr_bool_val(e_not_f, NULL, NULL) == 0) fail(); if (expr_bool_val(e_and_tt, NULL, NULL) == 0) fail(); if (expr_bool_val(e_and_tf, NULL, NULL) != 0) fail(); if (expr_bool_val(e_or_tf, NULL, NULL) == 0) fail(); if (expr_bool_val(e_or_ff, NULL, NULL) != 0) fail(); expr_free(e_not_t); expr_free(e_not_f); expr_free(e_and_tt); expr_free(e_and_tf); expr_free(e_or_tf); expr_free(e_or_ff); }
/* L -> 'a' .. 'z' | 'A' .. 'Z' | '(' S ')' | '[' S ']' */ static inline node* expr_sym(expr *e) { node *a; uint8_t v; expr_eat_white(e); if (e->str[0]=='(') { e->str++; expr_eat_white(e); a=expr_or(e); expr_eat_white(e); if (e->str[0]==')') { e->str++; return a; } else { if ((int8_t)(e->str[0])>=32) { printf("parse error, closing round bracket expected, next char: '%c'\n",e->str[0]); } else { printf("parse error, closing round bracket expected, next code: 0x%02"PRIX8"\n",(uint8_t)(e->str[0])); } expr_rfree(a); e->erroroccured = 1; return NULL; } } if (e->str[0]=='[') { e->str++; expr_eat_white(e); a=expr_or(e); expr_eat_white(e); if (e->str[0]==']') { e->str++; return a; } else { if ((int8_t)(e->str[0])>=32) { printf("parse error, closing round bracket expected, next char: '%c'\n",e->str[0]); } else { printf("parse error, closing round bracket expected, next code: 0x%02"PRIX8"\n",(uint8_t)(e->str[0])); } expr_rfree(a); e->erroroccured = 1; return NULL; } } if (e->str[0]>='A' && e->str[0]<='Z') { v = e->str[0]-'A'; e->str++; return newnode(SYM,v,NULL,NULL); } if (e->str[0]>='a' && e->str[0]<='z') { v = e->str[0]-'a'; e->str++; return newnode(SYM,v,NULL,NULL); } if ((int8_t)(e->str[0])>=32) { printf("parse error, next char: '%c'\n",e->str[0]); } else { printf("parse error, next code: 0x%02"PRIX8"\n",(uint8_t)(e->str[0])); } e->erroroccured = 1; return NULL; }
/* * CNF transformation one-level down. */ static expr_t cnf_expr_nextlevel(expr_t e, context_t context) { if (expr_gettype(e) != EXPRTYPE_OP) return e; switch (expr_op(e)) { case EXPROP_NOT: case EXPROP_OR: { expr_t or = expr_bool(false), k, v; for (expritr_t i = expritr(e); expr_getpair(i, &k, &v); expr_next(i)) { k = cnf_arg(k, context); if (v == expr_bool(true)) k = expr_not(k); or = expr_or(k, or); } return or; } default: e = cnf_arg(e, context); return e; } }
/* E -> '*' | S */ static inline node* expr_first(expr *e) { expr_eat_white(e); if (e->str[0]=='*') { e->str++; return newnode(ANY,0,NULL,NULL); } return expr_or(e); }
/* * Eliminate <->s from an expression. */ static expr_t iffelim_expr(expr_t e, bool c) { if (expr_gettype(e) != EXPRTYPE_OP) return e; exprop_t op = expr_op(e); switch (op) { case EXPROP_NOT: case EXPROP_AND: case EXPROP_OR: { expr_t acc = (op == EXPROP_OR? expr_bool(false): expr_bool(true)); expr_t k, v; for (expritr_t i = expritr(e); expr_getpair(i, &k, &v); expr_next(i)) { bool d = (op != EXPROP_OR); d = (v == expr_bool(true)? !d: d); k = iffelim_expr(k, d); if (v == expr_bool(true)) k = expr_not(k); acc = (op == EXPROP_OR? expr_or(acc, k): expr_and(acc, k)); } return acc; } case EXPROP_IFF: { expr_t x = iffelim_expr(expr_arg(e, 0), c); expr_t y = iffelim_expr(expr_arg(e, 1), c); if (c) { expr_t c1 = expr_or(expr_not(x), y); expr_t c2 = expr_or(x, expr_not(y)); return expr_and(c1, c2); } else { expr_t c1 = expr_and(x, y); expr_t c2 = expr_and(expr_not(x), expr_not(y)); return expr_or(c1, c2); } } default: return e; } }
/* S -> S '+' M | S '|' M | S '||' M | M */ static inline node* expr_or(expr *e) { node *a; node *b; expr_eat_white(e); a = expr_and(e); expr_eat_white(e); if (e->str[0]=='|' && e->str[1]=='|') { e->str += 2; b = expr_or(e); return newnode(OR,0,a,b); } else if (e->str[0]=='|' || e->str[0]=='+') { e->str ++; b = expr_or(e); return newnode(OR,0,a,b); } else { return a; } }
static void test_select() { int a, b, c; Type ta, tb, tc; Rel *src = load("select_1"); head_attr(src->head, "b", &b, &tb); Expr *expr = expr_eq(expr_real(1.01), expr_attr(b, tb)); Rel *r = rel_select(src, expr); if (!equal(r, "select_1_res")) fail(); src = load("select_2"); head_attr(src->head, "a", &a, &ta); head_attr(src->head, "b", &b, &tb); head_attr(src->head, "c", &c, &tc); expr = expr_or(expr_gt(expr_attr(b, tb), expr_real(4.00)), expr_lt(expr_attr(a, ta), expr_int(2))); expr = expr_or(expr, expr_lt(expr_attr(c, tc), expr_str("aab"))); r = rel_select(src, expr); if (!equal(r, "select_2_res")) fail(); src = load("select_3"); head_attr(src->head, "a", &a, &ta); head_attr(src->head, "b", &b, &tb); expr = expr_and(expr_not(expr_attr(a, ta)), expr_not(expr_eq(expr_attr(b, tb), expr_real(1.01)))); r = rel_select(src, expr); if (!equal(r, "select_3_res")) fail(); }
Expr* expr_zbox(Expr* a, Expr* b) { Expr* za = expr_sub(a->zmax,a->zmin); Expr* zb = expr_sub(b->zmax,b->zmin); Expr* r = expr_mul(expr_lit(0.5),expr_add(za,zb)); auto tg = expr_or(expr_zmov(expr_sub(expr_neg(r),a->zmin),a), expr_zmov(expr_sub(expr_add(expr_neg(r),za),b->zmin),b)); tg->zmin = expr_neg(r); tg->zmax = r; tg->xmin = expr_min(a->xmin, b->xmin); tg->xmax = expr_max(a->xmax, b->xmax); tg->ymin = expr_min(a->ymin, b->ymin); tg->ymax = expr_max(a->ymax, b->ymax); return tg; }
static void test_compound() { char *names[] = {"a", "b", "c"}; Type types[] = {Int, Real, String}; int a, b, c; Type ta, tb, tc; Head *h = head_new(names, types, 3); head_attr(h, "a", &a, &ta); head_attr(h, "b", &b, &tb); head_attr(h, "c", &c, &tc); int v_int = 3; double v_real = 1.01; char *v_str = "bbb"; Value vals[3]; vals[0] = val_new_int(&v_int); vals[1] = val_new_real(&v_real); vals[2] = val_new_str(v_str); Tuple *t = tuple_new(vals, 3); Expr *expr = expr_or(expr_gt(expr_attr(b, Real), expr_real(4.00)), expr_lt(expr_attr(a, Int), expr_int(2))); expr = expr_or(expr, expr_lt(expr_attr(c, String), expr_str("aab"))); if (expr_bool_val(expr, t, NULL)) fail(); expr_free(expr); tuple_free(t); mem_free(h); }
Expr* expr_ybox(Expr* a, Expr* b) { Expr* ha = expr_sub(a->ymax,a->ymin); Expr* hb = expr_sub(b->ymax,b->ymin); Expr* r = expr_mul(expr_lit(0.5),expr_add(ha,hb)); auto tg = expr_or(expr_ymov(expr_sub(expr_neg(r),a->ymin),a),expr_ymov(expr_sub(expr_add(expr_neg(r),ha),b->ymin),b)); tg->ymin = expr_neg(r); tg->ymax = r; tg->xmin = expr_min(a->xmin, b->xmin); tg->xmax = expr_max(a->xmax, b->xmax); if (a->zmin != NULL && b->zmin != NULL) { tg->zmin = expr_min(a->zmin, b->zmin); tg->zmax = expr_max(a->zmax, b->zmax); } return tg; }
/* * CNF transformation on a Boolean argument. */ static expr_t cnf_arg(expr_t e, context_t context) { if (expr_gettype(e) != EXPRTYPE_OP) return e; expr_t b = cnf_new_var(context), nb = expr_not(b); switch (expr_op(e)) { case EXPROP_NOT: case EXPROP_AND: { expr_t clause = expr_bool(false), k, nk, v; for (expritr_t i = expritr(e); expr_getpair(i, &k, &v); expr_next(i)) { k = cnf_arg(k, context); nk = expr_not(k); if (v == expr_bool(true)) { expr_t tmp = k; k = nk; nk = tmp; } clause = expr_or(nk, clause); context_insertclause(context, expr_or(k, nb)); } clause = expr_or(b, clause); context_insertclause(context, clause); return b; } case EXPROP_OR: { expr_t clause = expr_bool(false), k, nk, v; for (expritr_t i = expritr(e); expr_getpair(i, &k, &v); expr_next(i)) { k = cnf_arg(k, context); nk = expr_not(k); if (v == expr_bool(true)) { expr_t tmp = k; k = nk; nk = tmp; } clause = expr_or(k, clause); context_insertclause(context, expr_or(nk, b)); } clause = expr_or(nb, clause); context_insertclause(context, clause); return b; } default: return context_insertiff(context, e, (expr_t)NULL); } }
int b_expr(int argc, char** argv, Shbltin_t* context) { State_t state; Node_t node; int n; cmdinit(argc, argv, context, ERROR_CATALOG, 0); state.standard = !!conformance(0, 0); #if 0 if (state.standard) state.arglist = argv+1; else #endif { while (n=optget(argv, usage)) { /* * NOTE: this loop ignores all but literal -- and -? * out of kindness for obsolescent usage * (and is ok with the standard) but strict * getopt conformance would give usage for all * unknown - options */ if(n=='?') error(ERROR_usage(2), "%s", opt_info.arg); if (opt_info.option[1] != '?') break; error(ERROR_usage(2), "%s", opt_info.arg); } if (error_info.errors) error(ERROR_usage(2),"%s",optusage((char*)0)); state.arglist = argv+opt_info.index; } if (expr_or(&state, &node)) error(ERROR_exit(2),"syntax error"); if (node.type&T_STR) { if (*node.str) sfprintf(sfstdout,"%s\n",node.str); } else sfprintf(sfstdout,"%d\n",node.num); return numeric(&node)?node.num==0:*node.str==0; }
Expr* polygonize (Nested<TV2> p) { Mesh mesh = triangulate(p); // printf("%d VERTICES %d INDICES\n", (int)mesh.vertices.size(), (int)mesh.indices.size()); Expr* res = expr_none(); Boxy box(vec( INFTY, INFTY, INFTY), vec(-INFTY, -INFTY, -INFTY)); for (auto tri : mesh.soup->elements) { Vec p0 = mesh.points[tri.x]; Vec p1 = mesh.points[tri.y]; Vec p2 = mesh.points[tri.z]; box = add(add(add(box, p0), p1), p2); res = expr_or(res, expr_triangle(expr_lit(p0.x), expr_lit(p0.y), expr_lit(p1.x), expr_lit(p1.y), expr_lit(p2.x), expr_lit(p2.y))); } res->xmin = expr_lit(box.lo.x); res->ymin = expr_lit(box.lo.y); res->zmin = expr_lit(box.lo.z); res->xmax = expr_lit(box.hi.x); res->ymax = expr_lit(box.hi.y); res->zmax = expr_lit(box.hi.z); return res; }
/* * Flattening transformation. */ static expr_t flatten(expr_t e, bool toplevel, context_t cxt) { if (expr_gettype(e) != EXPRTYPE_OP) return e; exprop_t op = expr_op(e); switch (op) { case EXPROP_EQ: { expr_t x, y; if (expr_view_x_eq_func(e, &x, &y)) { y = flatten(y, false, cxt); return flatten_eq_to_builtin(exprop_atom_make(ATOM_INT_EQ), x, y, toplevel, cxt); } // Fall-through: } case EXPROP_NEQ: case EXPROP_LT: case EXPROP_LEQ: case EXPROP_GT: case EXPROP_GEQ: { // Check if already a flattened comparison: exprop_t binop, cmp; expr_t x, y, z; if (expr_view_x_cmp_y(e, &x, &cmp, &y)) return flatten_x_cmp_y_to_builtin(x, cmp, y, cxt); if (expr_view_x_cmp_y_op_z(e, &x, &cmp, &y, &binop, &z)) { y = expr_make(binop, y, z); return flatten_eq_to_builtin(exprop_atom_make(ATOM_INT_EQ), x, y, toplevel, cxt); } e = expr_arg(e, 1); if (!expr_view_plus_sign_partition(e, &x, &y)) panic("failed to partition (+) expression"); if (op == EXPROP_EQ) { expr_t x0, x1; if (expr_view_plus_first_partition(x, &x0, &x1)) { x1 = flatten_to_primitive(x1, cxt); y = flatten_to_var(y, cxt); e = expr_make(EXPROP_ADD, x0, x1); return flatten_eq_to_builtin(exprop_atom_make(ATOM_INT_EQ), y, e, toplevel, cxt); } expr_t y0, y1; if (expr_view_plus_first_partition(y, &y0, &y1)) { y1 = flatten_to_primitive(y1, cxt); x = flatten_to_var(x, cxt); e = expr_make(EXPROP_ADD, y0, y1); return flatten_eq_to_builtin(exprop_atom_make(ATOM_INT_EQ), x, e, toplevel, cxt); } x = flatten_to_primitive(x, cxt); y = flatten_to_primitive(y, cxt); return flatten_eq_to_builtin(exprop_atom_make(ATOM_INT_EQ), x, y, toplevel, cxt); } else { x = flatten_to_primitive(x, cxt); y = flatten_to_primitive(y, cxt); if (expr_gettype(y) == EXPRTYPE_NUM) { num_t c = expr_getnum(y); y = expr_num(c - 1); e = flatten_x_cmp_y_to_builtin(x, cmp, y, cxt); return expr_not(e); } else return flatten_x_cmp_y_to_builtin(y, cmp, x, cxt); } } case EXPROP_NOT: { expr_t arg = expr_arg(e, 0); arg = flatten(arg, toplevel, cxt); return expr_not(arg); } case EXPROP_IFF: { expr_t arg0 = flatten(expr_arg(e, 0), false, cxt); expr_t arg1 = flatten(expr_arg(e, 1), false, cxt); return expr_iff(arg0, arg1); } case EXPROP_AND: { expr_t and = expr_bool(true), k, v; for (expritr_t i = expritr(e); expr_getpair(i, &k, &v); expr_next(i)) { k = flatten(k, toplevel, cxt); if (v == expr_bool(true)) k = expr_not(k); and = expr_and(k, and); } return and; } case EXPROP_OR: { expr_t or = expr_bool(false), k, v; for (expritr_t i = expritr(e); expr_getpair(i, &k, &v); expr_next(i)) { k = flatten(k, false, cxt); if (v == expr_bool(true)) k = expr_not(k); or = expr_or(k, or); } return or; } case EXPROP_ADD: case EXPROP_MUL: { size_t a = expr_arity(e); expr_t args[a]; expr_args(e, args); for (size_t i = 0; i < a; i++) args[i] = flatten_to_primitive(args[i], cxt); e = expr(op, args); return e; } case EXPROP_POW: { expr_t arg1 = expr_arg(e, 1); if (expr_gettype(arg1) != EXPRTYPE_NUM) { flatten_bad_pow: error("(%s: %zu) failed to flatten expression `!y%s!d'; " "exponent must be a positive constant, found `!y%s!d'", cxt->file, cxt->line, show(expr_term(e)), show(expr_term(arg1))); cxt->error = true; return e; } num_t c = expr_getnum(arg1); if (c <= 1) goto flatten_bad_pow; expr_t arg0 = flatten_to_primitive(expr_arg(e, 0), cxt); expr_t e = expr_pow(arg0, arg1); return e; } default: { atom_t atom = expr_sym(e); if (atom == ATOM_NIL_EQ || atom == ATOM_STR_EQ || atom == ATOM_ATOM_EQ || is_eq(atom)) { expr_t x = expr_arg(e, 0), y = expr_arg(e, 1); x = flatten(x, false, cxt); y = flatten(y, false, cxt); return flatten_eq_to_builtin(expr_op(e), x, y, toplevel, cxt); } size_t a = expr_arity(e); expr_t args[a]; expr_args(e, args); typesig_t sig = typeinst_get_decl((atom_t)op); for (size_t i = 0; i < a; i++) { typeinst_t t = typeinst_decl_arg(sig, i); if (t != typeinst_make_ground(t)) args[i] = flatten_to_var(args[i], cxt); else { // Note: type check does not check instances; we check // here. if (type(args[i]) == VAR || type(args[i]) == FUNC) { error("(%s: %zu) failed to flatten expression " "`!y%s!d'; cannot flatten %s argument " "`!y%s!d' to a ground term", cxt->file, cxt->line, show(expr_term(e)), (type(args[i]) == VAR? "variable": "function call"), show(expr_term(args[i]))); cxt->error = true; } } } e = expr(op, args); return e; } } }
static int getnode(State_t* state, Node_t *np) { register char* sp; register char* cp; register int i; register int j; register int k; register int tok; char* ep; if (!(cp = *state->arglist++)) error(ERROR_exit(2), "argument expected"); if (!state->standard) switch (cp[0]) { case 'i': if (cp[1] == 'n' && !strcmp(cp, "index")) { if (!(cp = *state->arglist++)) error(ERROR_exit(2), "string argument expected"); if (!(ep = *state->arglist++)) error(ERROR_exit(2), "chars argument expected"); np->num = (ep = strpbrk(cp, ep)) ? (ep - cp + 1) : 0; np->type = T_NUM; goto next; } break; case 'l': if (cp[1] == 'e' && !strcmp(cp, "length")) { if (!(cp = *state->arglist++)) error(ERROR_exit(2), "string argument expected"); np->num = strlen(cp); np->type = T_NUM; goto next; } break; case 'm': if (cp[1] == 'a' && !strcmp(cp, "match")) { if (!(np->str = *state->arglist++)) error(ERROR_exit(2), "pattern argument expected"); np->type = T_STR; return ':'; } break; case 'q': if (cp[1] == 'u' && !strcmp(cp, "quote") && !(cp = *state->arglist++)) error(ERROR_exit(2), "string argument expected"); break; case 's': if (cp[1] == 'u' && !strcmp(cp, "substr")) { if (!(sp = *state->arglist++)) error(ERROR_exit(2), "string argument expected"); if (!(cp = *state->arglist++)) error(ERROR_exit(2), "position argument expected"); i = strtol(cp, &ep, 10); if (*ep || --i < 0) i = -1; if (!(cp = *state->arglist++)) error(ERROR_exit(2), "length argument expected"); j = strtol(cp, &ep, 10); if (*ep) j = -1; k = strlen(sp); if (i < 0 || i >= k || j < 0) sp = ""; else { sp += i; k -= i; if (j < k) sp[j] = 0; } np->type = T_STR; np->str = sp; goto next; } break; } if (*cp=='(' && cp[1]==0) { tok = expr_or(state, np); if (tok != ')') error(ERROR_exit(2),"closing parenthesis missing"); } else { np->type = T_STR; np->str = cp; if (*cp) { np->num = strtol(np->str,&ep,10); if (!*ep) np->type |= T_NUM; } } next: if (!(cp = *state->arglist)) return 0; state->arglist++; for (i=0; i < sizeof(optable)/sizeof(*optable); i++) if (*cp==optable[i].opname[0] && cp[1]==optable[i].opname[1]) return optable[i].op; error(ERROR_exit(2),"%s: unknown operator argument",cp); return 0; }
Expr* expr_capsule(Expr* xyrad, Expr* zrad) { return expr_or(expr_cylinder(xyrad, zrad), expr_or(expr_zmov(expr_neg(zrad), expr_sphere(xyrad)), expr_zmov(zrad, expr_sphere(xyrad)))); }