static int getdyn(Node *n, int top) { NodeList *nl; Node *value; int mode; mode = 0; switch(n->op) { default: if(isliteral(n)) return MODECONST; return MODEDYNAM; case OARRAYLIT: if(!top && n->type->bound < 0) return MODEDYNAM; case OSTRUCTLIT: break; } for(nl=n->list; nl; nl=nl->next) { value = nl->n->right; mode |= getdyn(value, 0); if(mode == (MODEDYNAM|MODECONST)) break; } return mode; }
static void slicelit(int ctxt, Node *n, Node *var, NodeList **init) { Node *r, *a; NodeList *l; Type *t; Node *vstat, *vauto; Node *index, *value; int mode; // make an array type t = shallow(n->type); t->bound = mpgetfix(n->right->val.u.xval); t->width = 0; t->sym = nil; dowidth(t); if(ctxt != 0) { // put everything into static array vstat = staticname(t, ctxt); arraylit(ctxt, 1, n, vstat, init); arraylit(ctxt, 2, n, vstat, init); // copy static to slice a = nod(OSLICE, vstat, nod(OKEY, N, N)); a = nod(OAS, var, a); typecheck(&a, Etop); a->dodata = 2; *init = list(*init, a); return; } // recipe for var = []t{...} // 1. make a static array // var vstat [...]t // 2. assign (data statements) the constant part // vstat = constpart{} // 3. make an auto pointer to array and allocate heap to it // var vauto *[...]t = new([...]t) // 4. copy the static array to the auto array // *vauto = vstat // 5. assign slice of allocated heap to var // var = [0:]*auto // 6. for each dynamic part assign to the slice // var[i] = dynamic part // // an optimization is done if there is no constant part // 3. var vauto *[...]t = new([...]t) // 5. var = [0:]*auto // 6. var[i] = dynamic part // if the literal contains constants, // make static initialized array (1),(2) vstat = N; mode = getdyn(n, 1); if(mode & MODECONST) { vstat = staticname(t, ctxt); arraylit(ctxt, 1, n, vstat, init); } // make new auto *array (3 declare) vauto = nod(OXXX, N, N); tempname(vauto, ptrto(t)); // set auto to point at new heap (3 assign) a = nod(ONEW, N, N); a->list = list1(typenod(t)); a = nod(OAS, vauto, a); typecheck(&a, Etop); walkexpr(&a, init); *init = list(*init, a); if(vstat != N) { // copy static to heap (4) a = nod(OIND, vauto, N); a = nod(OAS, a, vstat); typecheck(&a, Etop); walkexpr(&a, init); *init = list(*init, a); } // make slice out of heap (5) a = nod(OAS, var, nod(OSLICE, vauto, nod(OKEY, N, N))); typecheck(&a, Etop); walkexpr(&a, init); *init = list(*init, a); // put dynamics into slice (6) for(l=n->list; l; l=l->next) { r = l->n; if(r->op != OKEY) fatal("slicelit: rhs not OKEY: %N", r); index = r->left; value = r->right; a = nod(OINDEX, var, index); a->etype = 1; // no bounds checking // TODO need to check bounds? switch(value->op) { case OARRAYLIT: if(value->type->bound < 0) break; arraylit(ctxt, 2, value, a, init); continue; case OSTRUCTLIT: structlit(ctxt, 2, value, a, init); continue; } if(isliteral(index) && isliteral(value)) continue; // build list of var[c] = expr a = nod(OAS, a, value); typecheck(&a, Etop); walkexpr(&a, init); *init = list(*init, a); } }
static Extype_t eval(Expr_t* ex, register Exnode_t* expr, void* env) { register Exnode_t* x; register Exnode_t* a; register Extype_t** t; register int n; Extype_t v; Extype_t r; Extype_t i; char* e; Exnode_t tmp; Exassoc_t* assoc; Extype_t args[FRAME+1]; Extype_t save[FRAME]; if (!expr || ex->loopcount) { v.integer = 1; return v; } x = expr->data.operand.left; switch (expr->op) { case BREAK: case CONTINUE: v = eval(ex, x, env); ex->loopcount = v.integer; ex->loopop = expr->op; return v; case CONSTANT: return expr->data.constant.value; case DEC: n = -1; add: if (x->op == DYNAMIC) r = getdyn(ex, x, env, &assoc); else { if (x->data.variable.index) i = eval(ex, x->data.variable.index, env); else i.integer = EX_SCALAR; r = (*ex->disc->getf)(ex, x, x->data.variable.symbol, x->data.variable.reference, env, (int)i.integer, ex->disc); } v = r; switch (x->type) { case FLOATING: v.floating += n; break; case INTEGER: case UNSIGNED: v.integer += n; break; default: goto huh; } set: if (x->op == DYNAMIC) { if (x->type == STRING) { v.string = vmstrdup(ex->vm, v.string); if (e = assoc ? assoc->value.string : x->data.variable.symbol->value->data.constant.value.string) vmfree(ex->vm, e); } if (assoc) assoc->value = v; else x->data.variable.symbol->value->data.constant.value = v; } else { if (x->data.variable.index) i = eval(ex, x->data.variable.index, env); else i.integer = EX_SCALAR; if ((*ex->disc->setf)(ex, x, x->data.variable.symbol, x->data.variable.reference, env, (int)i.integer, v, ex->disc) < 0) exerror("%s: cannot set value", x->data.variable.symbol->name); } if (expr->subop == PRE) r = v; return r; case DYNAMIC: return getdyn(ex, expr, env, &assoc); case EXIT: v = eval(ex, x, env); exit((int)v.integer); /*NOTREACHED*/ v.integer = -1; return v; case IF: v = eval(ex, x, env); if (v.integer) eval(ex, expr->data.operand.right->data.operand.left, env); else eval(ex, expr->data.operand.right->data.operand.right, env); v.integer = 1; return v; case FOR: case WHILE: expr = expr->data.operand.right; for (;;) { r = eval(ex, x, env); if (!r.integer) { v.integer = 1; return v; } if (expr->data.operand.right) { eval(ex, expr->data.operand.right, env); if (ex->loopcount > 0 && (--ex->loopcount > 0 || ex->loopop != CONTINUE)) { v.integer = 0; return v; } } if (expr->data.operand.left) eval(ex, expr->data.operand.left, env); } /*NOTREACHED*/ case SWITCH: v = eval(ex, x, env); i.integer = x->type; r.integer = 0; x = expr->data.operand.right; a = x->data.select.statement; n = 0; while (x = x->data.select.next) { if (!(t = x->data.select.constant)) n = 1; else for (; *t; t++) { switch ((int)i.integer) { case INTEGER: case UNSIGNED: if ((*t)->integer == v.integer) break; continue; case STRING: if ((ex->disc->version >= 19981111L && ex->disc->matchf) ? (*ex->disc->matchf)(ex, x, (*t)->string, expr->data.operand.left, v.string, env, ex->disc) : strmatch((*t)->string, v.string)) break; continue; case FLOATING: if ((*t)->floating == v.floating) break; continue; } n = 1; break; } if (n) { if (!x->data.select.statement) { r.integer = 1; break; } r = eval(ex, x->data.select.statement, env); if (ex->loopcount > 0) { ex->loopcount--; break; } } } if (!n && a) { r = eval(ex, a, env); if (ex->loopcount > 0) ex->loopcount--; } return r; case ITERATE: v.integer = 0; if (expr->data.generate.array->op == DYNAMIC) { n = expr->data.generate.index->type == STRING; for (assoc = (Exassoc_t*)dtfirst((Dt_t*)expr->data.generate.array->data.variable.symbol->local.pointer); assoc; assoc = (Exassoc_t*)dtnext((Dt_t*)expr->data.generate.array->data.variable.symbol->local.pointer, assoc)) { v.integer++; if (n) expr->data.generate.index->value->data.constant.value.string = assoc->name; else expr->data.generate.index->value->data.constant.value.integer = strtol(assoc->name, NiL, 0); eval(ex, expr->data.generate.statement, env); if (ex->loopcount > 0 && (--ex->loopcount > 0 || ex->loopop != CONTINUE)) { v.integer = 0; break; } } } else { r = (*ex->disc->getf)(ex, expr, expr->data.generate.array->data.variable.symbol, expr->data.generate.array->data.variable.reference, env, 0, ex->disc); for (v.integer = 0; v.integer < r.integer; v.integer++) { expr->data.generate.index->value->data.constant.value.integer = v.integer; eval(ex, expr->data.generate.statement, env); if (ex->loopcount > 0 && (--ex->loopcount > 0 || ex->loopop != CONTINUE)) { v.integer = 0; break; } } } return v; case CALL: x = expr->data.call.args; for (n = 0, a = expr->data.call.procedure->value->data.procedure.args; a && x; a = a->data.operand.right) { if (n < elementsof(args)) { save[n] = a->data.operand.left->data.variable.symbol->value->data.constant.value; args[n++] = eval(ex, x->data.operand.left, env); } else a->data.operand.left->data.variable.symbol->value->data.constant.value = eval(ex, x->data.operand.left, env); x = x->data.operand.right; } for (n = 0, a = expr->data.call.procedure->value->data.procedure.args; a && n < elementsof(save); a = a->data.operand.right) a->data.operand.left->data.variable.symbol->value->data.constant.value = args[n++]; if (x) exerror("too many actual args"); else if (a) exerror("not enough actual args"); v = exeval(ex, expr->data.call.procedure->value->data.procedure.body, env); for (n = 0, a = expr->data.call.procedure->value->data.procedure.args; a && n < elementsof(save); a = a->data.operand.right) a->data.operand.left->data.variable.symbol->value->data.constant.value = save[n++]; return v; case FUNCTION: n = 0; args[n++].string = (char*)env; for (x = expr->data.operand.right; x && n < elementsof(args); x = x->data.operand.right) args[n++] = eval(ex, x->data.operand.left, env); return (*ex->disc->getf)(ex, expr->data.operand.left, expr->data.operand.left->data.variable.symbol, expr->data.operand.left->data.variable.reference, args+1, EX_CALL, ex->disc); case ID: if (expr->data.variable.index) i = eval(ex, expr->data.variable.index, env); else i.integer = EX_SCALAR; return (*ex->disc->getf)(ex, expr, expr->data.variable.symbol, expr->data.variable.reference, env, (int)i.integer, ex->disc); case INC: n = 1; goto add; case PRINTF: v.integer = print(ex, expr, env, NiL); return v; case QUERY: print(ex, expr, env, sfstderr); v.integer = !astquery(2, ""); return v; case RETURN: ex->loopret = eval(ex, x, env); ex->loopcount = 32767; ex->loopop = expr->op; return ex->loopret; case SCANF: case SSCANF: v.integer = scan(ex, expr, env, NiL); return v; case SPRINTF: print(ex, expr, env, ex->tmp); v.string = exstash(ex->tmp, ex->ve); return v; case '=': v = eval(ex, expr->data.operand.right, env); if (expr->subop != '=') { r = v; if (x->op == DYNAMIC) v = getdyn(ex, x, env, &assoc); else { if (x->data.variable.index) v = eval(ex, x->data.variable.index, env); else v.integer = EX_SCALAR; v = (*ex->disc->getf)(ex, x, x->data.variable.symbol, x->data.variable.reference, env, (int)v.integer, ex->disc); } switch (x->type) { case FLOATING: switch (expr->subop) { case '+': v.floating += r.floating; break; case '-': v.floating -= r.floating; break; case '*': v.floating *= r.floating; break; case '/': if (r.floating == 0.0) exerror("floating divide by 0"); else v.floating /= r.floating; break; case '%': if ((r.integer = r.floating) == 0) exerror("floating 0 modulus"); else v.floating = ((Sflong_t)v.floating) % r.integer; break; case '&': v.floating = ((Sflong_t)v.floating) & ((Sflong_t)r.floating); break; case '|': v.floating = ((Sflong_t)v.floating) | ((Sflong_t)r.floating); break; case '^': v.floating = ((Sflong_t)v.floating) ^ ((Sflong_t)r.floating); break; case LS: v.floating = ((Sflong_t)v.floating) << ((Sflong_t)r.floating); break; case RS: #if _WIN32 v.floating = (Sflong_t)(((Sfulong_t)v.floating) >> ((Sflong_t)r.floating)); #else v.floating = ((Sfulong_t)v.floating) >> ((Sflong_t)r.floating); #endif break; default: goto huh; } break; case INTEGER: case UNSIGNED: switch (expr->subop) { case '+': v.integer += r.integer; break; case '-': v.integer -= r.integer; break; case '*': v.integer *= r.integer; break; case '/': if (r.integer == 0) exerror("integer divide by 0"); else v.integer /= r.integer; break; case '%': if (r.integer == 0) exerror("integer 0 modulus"); else v.integer %= r.integer; break; case '&': v.integer &= r.integer; break; case '|': v.integer |= r.integer; break; case '^': v.integer ^= r.integer; break; case LS: v.integer <<= r.integer; break; case RS: v.integer = (Sfulong_t)v.integer >> r.integer; break; default: goto huh; } break; case STRING: switch (expr->subop) { case '+': v.string = str_add(ex, v.string, r.string); break; case '|': v.string = str_ior(ex, v.string, r.string); break; case '&': v.string = str_and(ex, v.string, r.string); break; case '^': v.string = str_xor(ex, v.string, r.string); break; case '%': v.string = str_mod(ex, v.string, r.string); break; case '*': v.string = str_mpy(ex, v.string, r.string); break; default: goto huh; } break; default: goto huh; } } else if (x->op == DYNAMIC)