/* scivi - visualization plugin for XMMS * Copyright (C) 2003 Vitaly V. Bursov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "common.h" #include "dynam.h" #include "mathcompile.h" #include "mathparse.tab.h" #define MK_MATH_EXPR_AND_RET_IF_OOM(t) \ struct math_expr *t = (struct math_expr*)malloc(sizeof(struct math_expr)); \ if (t == NULL) { \ eprintf("Failed to allocate %d bytes\n", sizeof(struct math_expr)); \ return NULL; \ } \ memset(t, 0, sizeof(struct math_expr)); #define EXPR ((struct math_expr*)expr) #define EXPR1 ((struct math_expr*)expr1) #define EXPR2 ((struct math_expr*)expr2) void MATH(nop)(int line, void *p) { struct math_expr *t = (struct math_expr*)malloc(sizeof(struct math_expr)); if (t == NULL) { eprintf("Failed to allocate %d bytes\n", sizeof(struct math_expr)); return; } memset(t, 0, sizeof(struct math_expr)); t->op = NOP; MATH(end_of_statement)(line, p, t); } void *MATH(number)(int line, float num) { MK_MATH_EXPR_AND_RET_IF_OOM(t) d2printf("%f\n", num); t->op = FLOAT; t->p1.num = num; return t; } void *MATH(variable)(int line, char *str) { MK_MATH_EXPR_AND_RET_IF_OOM(t) d2printf("`%s'\n", str); t->op = VAR_GET; t->p1.str = str; return t; } void *MATH(stmt_if)(int line, void *p, void *expr) { struct math_expr *t; math_expr_cont *orig_cont; math_expr_cont *new_cont; d2printf("'if' start\n"); new_cont = malloc(sizeof(math_expr_cont)); if (new_cont == NULL){ eprintf("Failed to allocate %d bytes\n", sizeof(math_expr_cont)); return NULL; } memset(new_cont, 0, sizeof(math_expr_cont)); orig_cont = *(math_expr_cont**)p; new_cont->dyn_data = orig_cont->dyn_data; new_cont->parent = orig_cont; t = (struct math_expr*)malloc(sizeof(struct math_expr)); if (t == NULL) { eprintf("Failed to allocate %d bytes\n", sizeof(struct math_expr)); return NULL; } memset(t, 0, sizeof(struct math_expr)); if (orig_cont->first == NULL){ orig_cont -> first = t; orig_cont -> last = t; } else { orig_cont -> last -> next = t; orig_cont -> last = t; } *(math_expr_cont**)p = new_cont; t->op = STM_IF; t->e3 = EXPR; return t; } void *MATH(stmt_if_else)(int line, void *p) { struct math_expr *t; math_expr_cont *orig_cont; math_expr_cont *new_cont; d2printf("'else' start\n"); new_cont = *(math_expr_cont**)p; orig_cont = new_cont->parent; t = (struct math_expr*)orig_cont->last; t->p1.e1 = new_cont->first; new_cont->first = NULL; new_cont->last = NULL; return t; } void *MATH(stmt_if_end)(int line, void *p) { struct math_expr *t; math_expr_cont *orig_cont; math_expr_cont *new_cont; d2printf("'if'/'else' end\n"); new_cont = *(math_expr_cont**)p; orig_cont = new_cont->parent; t = (struct math_expr*)orig_cont->last; if (t->p1.e1) /* else-body mode */ t->e2 = new_cont->first; else t->p1.e1 = new_cont->first; *(math_expr_cont**)p = orig_cont; free(new_cont); return t; } void MATH(funct_start)(int line, void *p) { math_expr_cont *orig_cont; math_expr_cont *new_cont; d2printf("'funct call' start\n"); new_cont = malloc(sizeof(math_expr_cont)); if (new_cont == NULL){ eprintf("Failed to allocate %d bytes\n", sizeof(math_expr_cont)); return; } memset(new_cont, 0, sizeof(math_expr_cont)); orig_cont = *(math_expr_cont**)p; new_cont->dyn_data = orig_cont->dyn_data; new_cont->parent = orig_cont; *(math_expr_cont**)p = new_cont; } void *MATH(funct)(int line, void *p, char *fname) { math_expr_cont *orig_cont; math_expr_cont *new_cont; MK_MATH_EXPR_AND_RET_IF_OOM(t) d2printf("'funct call' end\n"); new_cont = *(math_expr_cont**)p; orig_cont = new_cont->parent; t->op = FUNC_CALL; t->p1.str = fname; t->e2 = new_cont->first; *(math_expr_cont**)p = orig_cont; free(new_cont); return t; } void MATH(stmt_loop_start)(int line, void *p) { struct math_expr *t; math_expr_cont *orig_cont; math_expr_cont *new_cont; d2printf("loop start\n"); new_cont = malloc(sizeof(math_expr_cont)); if (new_cont == NULL){ eprintf("Failed to allocate %d bytes\n", sizeof(math_expr_cont)); return; } memset(new_cont, 0, sizeof(math_expr_cont)); orig_cont = *(math_expr_cont**)p; new_cont->dyn_data = orig_cont->dyn_data; new_cont->parent = orig_cont; t = (struct math_expr*)malloc(sizeof(struct math_expr)); if (t == NULL) { eprintf("Failed to allocate %d bytes\n", sizeof(struct math_expr)); return; } memset(t, 0, sizeof(struct math_expr)); if (orig_cont->first == NULL){ orig_cont -> first = t; orig_cont -> last = t; } else { orig_cont -> last -> next = t; orig_cont -> last = t; } *(math_expr_cont**)p = new_cont; } static void *math_stmt_loop_end_common(void *p, void *expr) { struct math_expr *t; math_expr_cont *orig_cont; math_expr_cont *new_cont; new_cont = *(math_expr_cont**)p; orig_cont = new_cont->parent; t = (struct math_expr*)orig_cont->last; t->p1.e1 = EXPR; t->e2 = new_cont->first; *(math_expr_cont**)p = orig_cont; free(new_cont); return t; } void *MATH(stmt_while_end)(int line, void *p, void *expr) { struct math_expr *t; d2printf("'while' end\n"); t = (struct math_expr *)math_stmt_loop_end_common(p, expr); if (t) t->op = STM_WHILE; return t; } void *MATH(stmt_do_end)(int line, void *p, void *expr) { struct math_expr *t; d2printf("'do' end\n"); t = (struct math_expr *)math_stmt_loop_end_common(p, expr); if (t) t->op = STM_DO; return t; } void *MATH(stmt_for_end)(int line, void *p, void *expr1, void *expr2, void *expr3) { struct math_expr *t, *expr, *e1, *e2, *e3; #define TRANS(_a_, _b_)\ if ((_a_) == NULL){ \ (_b_) = (struct math_expr*)malloc(sizeof(struct math_expr)); \ if ((_b_) == NULL) { \ eprintf("Failed to allocate %d bytes\n", sizeof(struct math_expr)); \ return NULL; \ } \ memset((_b_), 0, sizeof(struct math_expr)); \ (_b_)->op = NOP;\ } else \ (_b_) = (_a_); TRANS(expr1, e1) TRANS(expr2, e2) TRANS(expr3, e3) #undef TRANS e1->next = e2; d2printf("'for' end\n"); t = (struct math_expr *)math_stmt_loop_end_common(p, e1); if (t){ t->op = STM_FOR; t->e3 = e3; } return t; } void MATH(sbreak)(int line, void *p) { struct math_expr *t = (struct math_expr*)malloc(sizeof(struct math_expr)); if (t == NULL) { eprintf("Failed to allocate %d bytes\n", sizeof(struct math_expr)); return; } memset(t, 0, sizeof(struct math_expr)); t->op = STM_BREAK; MATH(end_of_statement)(line, p, t); } void MATH(scontinue)(int line, void *p) { struct math_expr *t = (struct math_expr*)malloc(sizeof(struct math_expr)); if (t == NULL) { eprintf("Failed to allocate %d bytes\n", sizeof(struct math_expr)); return; } memset(t, 0, sizeof(struct math_expr)); t->op = STM_CONTINUE; MATH(end_of_statement)(line, p, t); } void MATH(array_start)(int line, void *p) { math_expr_cont *orig_cont; math_expr_cont *new_cont; d2printf("'array var' start\n"); new_cont = malloc(sizeof(math_expr_cont)); if (new_cont == NULL){ eprintf("Failed to allocate %d bytes\n", sizeof(math_expr_cont)); return; } memset(new_cont, 0, sizeof(math_expr_cont)); orig_cont = *(math_expr_cont**)p; new_cont->dyn_data = orig_cont->dyn_data; new_cont->parent = orig_cont; *(math_expr_cont**)p = new_cont; } void *MATH(array)(int line, void *p, char *aname) { math_expr_cont *orig_cont; math_expr_cont *new_cont; MK_MATH_EXPR_AND_RET_IF_OOM(t) d2printf("'array var' end\n"); new_cont = *(math_expr_cont**)p; orig_cont = new_cont->parent; t->op = VARRAY; t->p1.str = aname; t->e2 = new_cont->first; *(math_expr_cont**)p = orig_cont; free(new_cont); return t; } #define ASSIGN(__fn__, __op__)\ void *MATH(__fn__)(int line, void *p, char *vname, void *expr) \ { \ MK_MATH_EXPR_AND_RET_IF_OOM(t) \ d2printf("`%s'" #__op__ "\n", vname); \ t->op = __op__; \ t->p1.str = vname; \ t->e2 = EXPR; \ return t; \ } ASSIGN(var_assgn, VAR_SET) ASSIGN(var_assgn_plus, VAR_SET_PLUS) ASSIGN(var_assgn_min, VAR_SET_MIN) ASSIGN(var_assgn_div, VAR_SET_DIV) ASSIGN(var_assgn_mul, VAR_SET_MUL) #define ARRASSIGN(__fn__, __op__)\ void *MATH(__fn__)(int line, void *p, void *arr, void *expr) \ { \ MK_MATH_EXPR_AND_RET_IF_OOM(t) \ d2printf("`%s'" #__op__ "\n", arr); \ t->op = __op__; \ t->p1.e1 = arr; \ t->e2 = EXPR; \ return t; \ } ARRASSIGN(vararray_assgn, VARARR_SET) ARRASSIGN(vararray_assgn_plus, VARARR_SET_PLUS) ARRASSIGN(vararray_assgn_min, VARARR_SET_MIN) ARRASSIGN(vararray_assgn_div, VARARR_SET_DIV) ARRASSIGN(vararray_assgn_mul, VARARR_SET_MUL) #define UNARY(__fn__, __op__) \ void *MATH(__fn__)(int line, void *p, void *expr)\ { \ MK_MATH_EXPR_AND_RET_IF_OOM(t) \ d2printf("" #__op__ "\n"); \ t->op = __op__; \ t->p1.e1 = EXPR; \ return t; \ } UNARY(negate, NEGATE) UNARY(not, NOT) UNARY(lnot, LNOT) #define BINARY(__fn__, __op__) \ void *MATH(__fn__)(int line, void *p, void *expr1, void *expr2)\ { \ MK_MATH_EXPR_AND_RET_IF_OOM(t) \ d2printf("" #__op__ "\n"); \ t->op = __op__; \ t->p1.e1 = EXPR1; \ t->e2 = EXPR2; \ return t; \ } BINARY(plus, PLUS) BINARY(minus, MINUS) BINARY(divide, DIVIDE) BINARY(mod, MOD) BINARY(multiply, MULTIPLY) BINARY(or, OR) BINARY(and, AND) BINARY(xor, XOR) BINARY(oror, OROR) BINARY(andand, ANDAND) BINARY(gr, GREAT) BINARY(ls, LESS) BINARY(ge, GREAT_EQ) BINARY(le, LESS_EQ) BINARY(eq, EQUAL) BINARY(neq, NEQUAL) void MATH(end_of_statement)(int line, void *p, void *expr) { d2printf("expr end\n\n"); if ((p) == NULL){ dprintf("p is NULL\n"); } if (((math_expr_cont*)(p)) -> first == NULL){ ((math_expr_cont*)(p)) -> first = EXPR; ((math_expr_cont*)(p)) -> last = EXPR; } else { ((math_expr_cont*)(p)) -> last -> next = EXPR; ((math_expr_cont*)(p)) -> last = EXPR; } } int MATH(is_func_name)(math_expr_cont *p, const char *str) { int i; for (i=0;idyn_data->funcs_last_ind;i++) if (!strcmp(p->dyn_data->funcs[i].funcname, str)){ d2printf("`%s' is func name\n", str); return 1; } d2printf("`%s' is not func name\n", str); return 0; } void MATH(expr_free)(struct math_expr *p) { #if 0 if ((p->op == STM_IF) || (p->op == STM_FOR)){ if (p->p1.e1 != NULL){ math_expr_free(p->p1.e1); p->p1.e1 = NULL; } if (p->e3 != NULL){ math_expr_free(p->e3); p->e3 = NULL; } } else if ((p->op == VAR_SET) || (p->op == VAR_SET_PLUS) || (p->op == VAR_SET_MIN) || (p->op == VAR_SET_DIV) || (p->op == VAR_SET_MUL) || (p->op == FUNC_CALL) || (p->op == VARRAY) || (p->op == VAR_GET)){ if (p->p1.str){ free(p->p1.str); p->p1.str = NULL; } } else if ((p->op != FLOAT) && (p->p1.e1 != NULL)){ math_expr_free(p->p1.e1); p->p1.e1 = NULL; } if (p->e2 != NULL){ math_expr_free(p->e2); p->e2 = NULL; } #else if ((p->op == VAR_GET) || (p->op == VARRAY) || (p->op == VAR_SET) || (p->op == VAR_SET_PLUS) || (p->op == VAR_SET_MIN) || (p->op == VAR_SET_DIV) || (p->op == VAR_SET_MUL) || (p->op == FUNC_CALL)){ if (p->p1.str){ free(p->p1.str); p->p1.str = NULL; } } else if (p->op != FLOAT){ if (p->p1.e1 != NULL){ MATH(expr_free)(p->p1.e1); p->p1.e1 = NULL; } } if (p->e2 != NULL){ MATH(expr_free)(p->e2); p->e2 = NULL; } if (p->e3 != NULL){ MATH(expr_free)(p->e3); p->e3 = NULL; } #endif if (p->next != NULL){ MATH(expr_free)(p->next); p->next = NULL; } free(p); } void MATH(expr_cont_free)(math_expr_cont *p) { if (p->first != NULL){ MATH(expr_free)(p->first); p->first = NULL; } p->last = NULL; } static int _ensure_we_have_space(Code **code, int *csize, int cpos, int need) { if ((*csize) < (cpos + need)){ int to_add = *csize; int nsize; void *p; while (((*csize)-cpos+to_add) < need) to_add *= 2; nsize = *csize + to_add; dprintf("*** increasing buffer size from %d to %d Code's.\n", *csize, nsize); p = realloc(*code, nsize*sizeof(Code)); if (p == NULL){ eprintf("failed to realloc %d to %d bytes\n", *csize*sizeof(Code), nsize*sizeof(Code)); return 1; } *csize = nsize; *code = p; } return 0; } static int _find_var_opcode(DynamicsData *d, const char *var_prefix, const char *var) { int i; if (var_prefix != NULL){ int tmp = strlen(var_prefix); char *var_wpref; var_wpref = malloc(tmp+strlen(var)+1); if (var_wpref == NULL){ eprintf("failed to allocate %d bytes\n", tmp+strlen(var)+1); return VUSER; } memcpy(var_wpref,var_prefix,tmp); strcpy(var_wpref+tmp,var); for (i=0;iuser_vars_last_ind;i++) if (!strcmp(d->user_vars_desc[i].varname, var_wpref)){ free(var_wpref); return VUSER+i; } for (i=0;iintern_vars_last_ind;i++) if (!strcmp(d->intern_vars_desc[i].varname, var_wpref)){ free(var_wpref); return VINTVAR+i; } free(var_wpref); } for (i=0;iuser_vars_last_ind;i++) if (!strcmp(d->user_vars_desc[i].varname, var)){ return VUSER+i; } for (i=0;iintern_vars_last_ind;i++) if (!strcmp(d->intern_vars_desc[i].varname, var)){ return VINTVAR+i; } return -1; } static int _find_array_index(DynamicsData *d, const char *arr) { int i; for (i=0;iuser_arr_last_ind;i++) if (!strcmp(d->user_arr_desc[i].arrname, arr)){ return i; } return -1; } struct eto_state { DynamicsData *d; Code **code; int *codesize; const char *var_prefix; }; static int comp_expr_to_opcodes(struct eto_state *state, int codepos, struct math_expr *e); int MATH(expr_to_opcodes)(DynamicsData *d, Code **code, int *codesize, int codepos, struct math_expr *e, const char *var_prefix) { struct eto_state state; state.d = d; state.code = code; state.codesize = codesize; state.var_prefix = var_prefix; return comp_expr_to_opcodes(&state, codepos, e); } static int comp_expr_to_opcodes(struct eto_state *state, int codepos, struct math_expr *e) { int offs = 0; #define DYN (state->d) #define CODE (state->code) #define CODESIZE (state->codesize) #define VARPREF (state->var_prefix) #define WANT_MORE(d) \ if (_ensure_we_have_space(state->code, state->codesize, codepos, d)) { \ return 0; \ } if (!e){ WANT_MORE(1); (*CODE)[codepos+offs].i = NOP; offs++; return offs; } switch (e->op){ case NOP: WANT_MORE(1); (*CODE)[codepos+offs].i = e->op; offs += 1; break; /* unary operator */ case FLOAT: WANT_MORE(2); (*CODE)[codepos+offs].i = FLOAT; (*CODE)[codepos+offs+1].f = e->p1.num; offs += 2; break; /* unary operator */ case NOT: case LNOT: case NEGATE:{ int noffs; WANT_MORE(1); (*CODE)[codepos+offs].i = e->op; offs += 1; noffs = comp_expr_to_opcodes(state, codepos+offs, e->p1.e1); if (noffs == 0){ return 0; } offs += noffs; break; } case VAR_GET:{ int vo; WANT_MORE(1); vo = _find_var_opcode(DYN, VARPREF, e->p1.str); if (vo < 0){ (*CODE)[codepos+offs].i = NOP; eprintf("warning: variable '%s' is not found\n", e->p1.str); } else { (*CODE)[codepos+offs].i = vo; } offs += 1; break; } case VAR_SET: case VAR_SET_PLUS: case VAR_SET_MIN: case VAR_SET_DIV: case VAR_SET_MUL: { int noffs; int vo; WANT_MORE(2); vo = _find_var_opcode(DYN, VARPREF, e->p1.str); if (vo < 0) vo = scivi_dyn_declare_variable(DYN, e->p1.str); if (vo < 0){ /* variable allotion failed */ (*CODE)[codepos+offs].i = NOP; offs++; break; } (*CODE)[codepos+offs].i = e->op; (*CODE)[codepos+offs+1].i = vo; offs += 2; noffs = comp_expr_to_opcodes(state, codepos+offs, e->e2); if (noffs == 0){ return 0; } offs += noffs; break; } case VARARR_SET: case VARARR_SET_PLUS: case VARARR_SET_MIN: case VARARR_SET_DIV: case VARARR_SET_MUL:{ struct math_expr *arre, *t; int noffs; int arri; int arrdim; arre = e->p1.e1; if ((arre == NULL) || (arre->op != VARRAY)){ WANT_MORE(1); eprintf("ICE:array assignment not to array\n"); (*CODE)[codepos+offs].i = NOP; offs++; break; } arri = _find_array_index(DYN, arre->p1.str); if (arri < 0){ WANT_MORE(1); eprintf("array '%s' is not declared\n", arre->p1.str); (*CODE)[codepos+offs].i = NOP; offs++; break; } arrdim = 0; t = arre->e2; while (t){ arrdim++; t = t->next; } if (arrdim != DYN->user_arr_desc[arri].dcnt){ eprintf("invalid dimensions specified\n"); WANT_MORE(1); (*CODE)[codepos+offs].i = NOP; offs++; break; } WANT_MORE(2); (*CODE)[codepos+offs].i = e->op; (*CODE)[codepos+offs+1].i = arri; offs += 2; noffs = comp_expr_to_opcodes(state, codepos+offs, arre->e2); if (noffs == 0){ return 0; } offs += noffs; noffs = comp_expr_to_opcodes(state, codepos+offs, e->e2); if (noffs == 0){ return 0; } offs += noffs; break; } case VARRAY: { struct math_expr *t; int noffs; int arri; int arrdim; arri = _find_array_index(DYN, e->p1.str); if (arri < 0){ WANT_MORE(1); eprintf("array '%s' is not declared\n", e->p1.str); (*CODE)[codepos+offs].i = NOP; offs++; break; } arrdim = 0; t = e->e2; while (t){ arrdim++; t = t->next; } if (arrdim != DYN->user_arr_desc[arri].dcnt){ eprintf("invalid dimensions specified\n"); WANT_MORE(1); (*CODE)[codepos+offs].i = NOP; offs++; break; } WANT_MORE(2); (*CODE)[codepos+offs].i = e->op; (*CODE)[codepos+offs+1].i = arri; offs += 2; noffs = comp_expr_to_opcodes(state, codepos+offs, e->e2); if (noffs == 0){ return 0; } offs += noffs; break; } case FUNC_CALL:{ int i; int f = 0; int oldoffs = offs; if (!strcmp(e->p1.str, SETUP_ARRAY_FUNC_NAME)){ struct math_expr *el = NULL, *elt; char *aname = NULL; int *dims, dims_p; int i; int ok = 1; f = 1; if (e->e2){ if (e->e2->op == VAR_GET){ aname = e->e2->p1.str; el = e->e2->next; } else { eprintf( "invalid argumet to %s func. expected: array name\n", SETUP_ARRAY_FUNC_NAME); el = NULL; } dims_p = 0; if (el){ elt = el; do { dims_p++; elt = elt->next; } while (elt); dims = (int*)malloc(sizeof(int)*dims_p); if (dims == NULL){ eprintf("Failed to allocate %d bytes\n", sizeof(int)*dims_p); return 0; } i = 0; do { if ((el->op == FLOAT) || (el->p1.num >= 1.0f)){ dims[i] = (int)el->p1.num; i++; } else { eprintf( "invalid argumet to %s func. expected: number\n", SETUP_ARRAY_FUNC_NAME); ok=0; break; } el = el->next; } while(el); if (ok){ scivi_dyn_declare_array(DYN, aname, dims, dims_p); } } } } if (f == 1){ WANT_MORE(1); offs = oldoffs; (*CODE)[codepos+offs].i = NOP; offs += 1; } if (f == 0){ for (i=0;ifuncs_last_ind;i++){ if (!strcmp(DYN->funcs[i].funcname, e->p1.str)){ int fargs = 0; struct math_expr *ea = (void*)e->e2; int noffs; WANT_MORE(1); (*CODE)[codepos+offs].i = DYN->funcs[i].funcopcode; offs++; if (ea){ noffs = comp_expr_to_opcodes(state, codepos+offs, ea); if (noffs == 0){ return 0; } offs += noffs; do { fargs++; ea = ea->next; } while (ea); } if (fargs != DYN->funcs[i].argcount){ eprintf("warning: wrong argument number for " "function '%s' got %d but %d expected\n", e->p1.str, fargs, DYN->funcs[i].argcount); } else f = 1; break; } } } if (f == 0){ WANT_MORE(1); offs = oldoffs; (*CODE)[codepos+offs].i = NOP; offs += 1; eprintf("warning: function '%s' is not used/found\n", e->p1.str); } break; } case OROR: case ANDAND: { int noffs; int second_expr_len_offs; WANT_MORE(2); (*CODE)[codepos+offs].i = e->op; second_expr_len_offs = offs+1; offs += 2; noffs = comp_expr_to_opcodes(state, codepos+offs, e->p1.e1); if (noffs == 0){ return 0; } offs += noffs; noffs = comp_expr_to_opcodes(state, codepos+offs, e->e2); if (noffs == 0){ return 0; } (*CODE)[codepos+second_expr_len_offs].i = noffs; offs += noffs; break; } case STM_FOR: case STM_DO: case STM_WHILE:{ struct math_expr *expr; int noffs, loffs; int body_len_offs /* postl_len_offs */; #define postl_len_offs (body_len_offs+1) WANT_MORE(3); /* in case of 'for' or 'do' */ (*CODE)[codepos+offs].i = e->op; body_len_offs = offs+1; offs += 2; if ((e->op == STM_FOR) || (e->op == STM_DO)) offs += 1; if (e->op != STM_DO){ /* conditional expression */ noffs = comp_expr_to_opcodes(state, codepos+offs, e->p1.e1); if (noffs == 0){ return 0; } offs += noffs; } /* loop body */ expr = e->e2; loffs = 0; if (expr){ noffs = comp_expr_to_opcodes(state, codepos+offs+loffs, expr); if (noffs == 0){ return 0; } loffs += noffs; expr = expr->next; } (*CODE)[codepos+body_len_offs].i = loffs; offs += loffs; if (e->op == STM_DO){ /* conditional expression */ noffs = comp_expr_to_opcodes(state, codepos+offs, e->p1.e1); if (noffs == 0){ return 0; } (*CODE)[codepos+postl_len_offs].i = noffs; offs += noffs; } else if (e->op == STM_FOR){ noffs = comp_expr_to_opcodes(state, codepos+offs, e->e3); if (noffs == 0){ return 0; } (*CODE)[codepos+postl_len_offs].i = noffs; offs += noffs; } break; } case STM_BREAK: case STM_CONTINUE:{ WANT_MORE(1); (*CODE)[codepos+offs].i = e->op; offs += 1; break; } case STM_IF:{ struct math_expr *expr; int noffs, loffs; int second_true_len_offs; int second_false_len_offs; WANT_MORE(3); (*CODE)[codepos+offs].i = e->op; second_true_len_offs = offs+1; second_false_len_offs = offs+2; offs += 3; /* True/False Expression */ noffs = comp_expr_to_opcodes(state, codepos+offs, e->e3); if (noffs == 0){ return 0; } offs += noffs; /* True */ expr = e->p1.e1; loffs = 0; if (expr){ noffs = comp_expr_to_opcodes(state, codepos+offs+loffs, expr); if (noffs == 0){ return 0; } loffs += noffs; expr = expr->next; } (*CODE)[codepos+second_true_len_offs].i = loffs; offs += loffs; /* False */ expr = e->e2; loffs = 0; if (expr){ noffs = comp_expr_to_opcodes(state, codepos+offs+loffs, expr); if (noffs == 0){ return 0; } loffs += noffs; expr = expr->next; } (*CODE)[codepos+second_false_len_offs].i = loffs; offs += loffs; break; } default:{ int noffs; WANT_MORE(1); (*CODE)[codepos+offs].i = e->op; offs += 1; noffs = comp_expr_to_opcodes(state, codepos+offs, e->p1.e1); if (noffs == 0){ return 0; } offs += noffs; noffs = comp_expr_to_opcodes(state, codepos+offs, e->e2); if (noffs == 0){ return 0; } offs += noffs; } }; if (e->next){ int noffs; noffs = comp_expr_to_opcodes(state, codepos+offs, e->next); if (noffs == 0){ return 0; } offs += noffs; } #undef WANT_MORE return offs; }