/* ECMA-262 3rd Edition 12.6.2 */ static HRESULT compile_while_statement(compiler_ctx_t *ctx, while_statement_t *stat) { statement_ctx_t stat_ctx = {0, FALSE, FALSE}; unsigned jmp_off; HRESULT hres; stat_ctx.break_label = alloc_label(ctx); if(!stat_ctx.break_label) return E_OUTOFMEMORY; stat_ctx.continue_label = alloc_label(ctx); if(!stat_ctx.continue_label) return E_OUTOFMEMORY; if(!stat->do_while) { /* FIXME: avoid */ if(!push_instr(ctx, OP_undefined)) return E_OUTOFMEMORY; jmp_off = ctx->code_off; label_set_addr(ctx, stat_ctx.continue_label); hres = compile_expression(ctx, stat->expr); if(FAILED(hres)) return hres; hres = push_instr_uint(ctx, OP_jmp_z, stat_ctx.break_label); if(FAILED(hres)) return hres; if(!push_instr(ctx, OP_pop)) return E_OUTOFMEMORY; }else { jmp_off = ctx->code_off; } hres = compile_statement(ctx, &stat_ctx, stat->statement); if(FAILED(hres)) return hres; if(stat->do_while) { label_set_addr(ctx, stat_ctx.continue_label); hres = compile_expression(ctx, stat->expr); if(FAILED(hres)) return hres; hres = push_instr_uint(ctx, OP_jmp_z, stat_ctx.break_label); if(FAILED(hres)) return hres; if(!push_instr(ctx, OP_pop)) return E_OUTOFMEMORY; } hres = push_instr_uint(ctx, OP_jmp, jmp_off); if(FAILED(hres)) return hres; label_set_addr(ctx, stat_ctx.break_label); return S_OK; }
void gen_two_line (void) { init_effect ("two_line"); push_row_area (); add_row (16); alloc_label ("SPECIAL"); add_row (16); alloc_label ("WHEN LIT"); pop_area (); current_effect->duration = 2000; finish_effect (); }
static HRESULT compile_if_statement(compile_ctx_t *ctx, if_statement_t *stat) { unsigned cnd_jmp, endif_label = -1; elseif_decl_t *elseif_decl; HRESULT hres; hres = compile_expression(ctx, stat->expr); if(FAILED(hres)) return hres; cnd_jmp = push_instr(ctx, OP_jmp_false); if(cnd_jmp == -1) return E_OUTOFMEMORY; hres = compile_statement(ctx, stat->if_stat); if(FAILED(hres)) return hres; if(stat->else_stat || stat->elseifs) { endif_label = alloc_label(ctx); if(endif_label == -1) return E_OUTOFMEMORY; hres = push_instr_addr(ctx, OP_jmp, endif_label); if(FAILED(hres)) return hres; } for(elseif_decl = stat->elseifs; elseif_decl; elseif_decl = elseif_decl->next) { instr_ptr(ctx, cnd_jmp)->arg1.uint = ctx->instr_cnt; hres = compile_expression(ctx, elseif_decl->expr); if(FAILED(hres)) return hres; cnd_jmp = push_instr(ctx, OP_jmp_false); if(cnd_jmp == -1) return E_OUTOFMEMORY; hres = compile_statement(ctx, elseif_decl->stat); if(FAILED(hres)) return hres; hres = push_instr_addr(ctx, OP_jmp, endif_label); if(FAILED(hres)) return hres; } instr_ptr(ctx, cnd_jmp)->arg1.uint = ctx->instr_cnt; if(stat->else_stat) { hres = compile_statement(ctx, stat->else_stat); if(FAILED(hres)) return hres; } if(endif_label != -1) label_set_addr(ctx, endif_label); return S_OK; }
static HRESULT compile_dowhile_statement(compile_ctx_t *ctx, while_statement_t *stat) { unsigned start_addr, prev_label; HRESULT hres; start_addr = ctx->instr_cnt; prev_label = ctx->while_end_label; if((ctx->while_end_label = alloc_label(ctx)) == -1) return E_OUTOFMEMORY; hres = compile_statement(ctx, stat->body); if(FAILED(hres)) return hres; hres = compile_expression(ctx, stat->expr); if(FAILED(hres)) return hres; hres = push_instr_addr(ctx, stat->stat.type == STAT_DOUNTIL ? OP_jmp_false : OP_jmp_true, start_addr); if(FAILED(hres)) return hres; label_set_addr(ctx, ctx->while_end_label); ctx->while_end_label = prev_label; return S_OK; }
static HRESULT compile_foreach_statement(compile_ctx_t *ctx, foreach_statement_t *stat) { statement_ctx_t loop_ctx = {1}; unsigned loop_start; HRESULT hres; hres = compile_expression(ctx, stat->group_expr); if(FAILED(hres)) return hres; if(!push_instr(ctx, OP_newenum)) return E_OUTOFMEMORY; loop_start = ctx->instr_cnt; if(!(loop_ctx.for_end_label = alloc_label(ctx))) return E_OUTOFMEMORY; hres = push_instr_uint_bstr(ctx, OP_enumnext, loop_ctx.for_end_label, stat->identifier); if(FAILED(hres)) return hres; hres = compile_statement(ctx, &loop_ctx, stat->body); if(FAILED(hres)) return hres; hres = push_instr_addr(ctx, OP_jmp, loop_start); if(FAILED(hres)) return hres; label_set_addr(ctx, loop_ctx.for_end_label); return S_OK; }
static HRESULT compile_dowhile_statement(compile_ctx_t *ctx, while_statement_t *stat) { statement_ctx_t loop_ctx = {0}; unsigned start_addr; vbsop_t jmp_op; HRESULT hres; start_addr = ctx->instr_cnt; if(!(loop_ctx.while_end_label = alloc_label(ctx))) return E_OUTOFMEMORY; hres = compile_statement(ctx, &loop_ctx, stat->body); if(FAILED(hres)) return hres; if(stat->expr) { hres = compile_expression(ctx, stat->expr); if(FAILED(hres)) return hres; jmp_op = stat->stat.type == STAT_DOUNTIL ? OP_jmp_false : OP_jmp_true; }else { jmp_op = OP_jmp; } hres = push_instr_addr(ctx, jmp_op, start_addr); if(FAILED(hres)) return hres; label_set_addr(ctx, loop_ctx.while_end_label); return S_OK; }
void gen_simple_message (const char *name, const char *message, dcc_time duration) { init_effect (name); dcc_label *l = alloc_label (message); current_effect->duration = duration; finish_effect (); }
void gen_simple_blink (const char *name, const char *message, dcc_time duration, dcc_time blink_time) { init_effect (name); dcc_label *l = alloc_label (message); l->blink_time = blink_time; current_effect->duration = duration; current_effect->frame_time = blink_time; finish_effect (); }
/* * Allocate a new forward-reference label */ CTcCodeLabel *CTcCodeStream::new_label_fwd() { CTcCodeLabel *lbl; /* allocate a new label */ lbl = alloc_label(); /* the label's location is not yet known */ lbl->ofs = 0; lbl->is_known = FALSE; /* return the new label */ return lbl; }
/* * Allocate a new label at the current code offset */ CTcCodeLabel *CTcCodeStream::new_label_here() { CTcCodeLabel *lbl; /* allocate a new label */ lbl = alloc_label(); /* set the label's location to the current write position */ lbl->ofs = ofs_; lbl->is_known = TRUE; /* return the new label */ return lbl; }
static HRESULT compile_while_statement(compile_ctx_t *ctx, while_statement_t *stat) { statement_ctx_t stat_ctx = {0}, *loop_ctx; unsigned start_addr; unsigned jmp_end; HRESULT hres; start_addr = ctx->instr_cnt; hres = compile_expression(ctx, stat->expr); if(FAILED(hres)) return hres; jmp_end = push_instr(ctx, stat->stat.type == STAT_UNTIL ? OP_jmp_true : OP_jmp_false); if(!jmp_end) return E_OUTOFMEMORY; if(stat->stat.type == STAT_WHILE) { loop_ctx = NULL; }else { if(!(stat_ctx.while_end_label = alloc_label(ctx))) return E_OUTOFMEMORY; loop_ctx = &stat_ctx; } hres = compile_statement(ctx, loop_ctx, stat->body); if(FAILED(hres)) return hres; hres = push_instr_addr(ctx, OP_jmp, start_addr); if(FAILED(hres)) return hres; instr_ptr(ctx, jmp_end)->arg1.uint = ctx->instr_cnt; if(loop_ctx) label_set_addr(ctx, stat_ctx.while_end_label); return S_OK; }
/* reserve a new label identifier and return the identifier to the caller */ t_axe_label * newLabelID(t_axe_label_manager *lmanager) { t_axe_label *result; /* preconditions: lmanager must be different from NULL */ assert(lmanager != NULL); /* initialize a new label */ result = alloc_label(lmanager->current_label_ID); /* update the value of `current_label_ID' */ lmanager->current_label_ID++; /* tests if an out of memory occurred */ if (result == NULL) return NULL; /* add the new label to the list of labels */ lmanager->labels = addElement(lmanager->labels, result, -1); /* return the new label */ return result; }
static HRESULT compile_while_statement(compile_ctx_t *ctx, while_statement_t *stat) { unsigned start_addr, prev_label; unsigned jmp_end; HRESULT hres; start_addr = ctx->instr_cnt; hres = compile_expression(ctx, stat->expr); if(FAILED(hres)) return hres; jmp_end = push_instr(ctx, stat->stat.type == STAT_UNTIL ? OP_jmp_true : OP_jmp_false); if(jmp_end == -1) return E_OUTOFMEMORY; prev_label = ctx->while_end_label; if(stat->stat.type != STAT_WHILE && (ctx->while_end_label = alloc_label(ctx)) == -1) return E_OUTOFMEMORY; hres = compile_statement(ctx, stat->body); if(FAILED(hres)) return hres; hres = push_instr_addr(ctx, OP_jmp, start_addr); if(FAILED(hres)) return hres; instr_ptr(ctx, jmp_end)->arg1.uint = ctx->instr_cnt; if(stat->stat.type != STAT_WHILE) { label_set_addr(ctx, ctx->while_end_label); ctx->while_end_label = prev_label; } return S_OK; }
static HRESULT compile_func(compile_ctx_t *ctx, statement_t *stat, function_t *func) { HRESULT hres; func->code_off = ctx->instr_cnt; ctx->while_end_label = -1; ctx->sub_end_label = -1; ctx->func_end_label = -1; ctx->prop_end_label = -1; switch(func->type) { case FUNC_FUNCTION: ctx->func_end_label = alloc_label(ctx); if(ctx->func_end_label == -1) return E_OUTOFMEMORY; /* FIXME ! */ break; case FUNC_SUB: ctx->sub_end_label = alloc_label(ctx); if(ctx->sub_end_label == -1) return E_OUTOFMEMORY; break; case FUNC_PROPGET: case FUNC_PROPLET: case FUNC_PROPSET: case FUNC_DEFGET: ctx->prop_end_label = alloc_label(ctx); if(ctx->prop_end_label == -1) return E_OUTOFMEMORY; break; case FUNC_GLOBAL: break; } ctx->func = func; ctx->dim_decls = NULL; hres = compile_statement(ctx, stat); ctx->func = NULL; if(FAILED(hres)) return hres; assert(ctx->while_end_label == -1); if(ctx->sub_end_label != -1) label_set_addr(ctx, ctx->sub_end_label); if(ctx->func_end_label != -1) label_set_addr(ctx, ctx->func_end_label); if(ctx->prop_end_label != -1) label_set_addr(ctx, ctx->prop_end_label); if(push_instr(ctx, OP_ret) == -1) return E_OUTOFMEMORY; resolve_labels(ctx, func->code_off); if(func->var_cnt) { dim_decl_t *dim_decl; if(func->type == FUNC_GLOBAL) { dynamic_var_t *new_var; func->var_cnt = 0; for(dim_decl = ctx->dim_decls; dim_decl; dim_decl = dim_decl->next) { new_var = compiler_alloc(ctx->code, sizeof(*new_var)); if(!new_var) return E_OUTOFMEMORY; new_var->name = compiler_alloc_string(ctx->code, dim_decl->name); if(!new_var->name) return E_OUTOFMEMORY; V_VT(&new_var->v) = VT_EMPTY; new_var->next = ctx->global_vars; ctx->global_vars = new_var; } }else { unsigned i; func->vars = compiler_alloc(ctx->code, func->var_cnt * sizeof(var_desc_t)); if(!func->vars) return E_OUTOFMEMORY; for(dim_decl = ctx->dim_decls, i=0; dim_decl; dim_decl = dim_decl->next, i++) { func->vars[i].name = compiler_alloc_string(ctx->code, dim_decl->name); if(!func->vars[i].name) return E_OUTOFMEMORY; } assert(i == func->var_cnt); } } return S_OK; }
/* ECMA-262 3rd Edition 12.6.3 */ static HRESULT compile_for_statement(compiler_ctx_t *ctx, for_statement_t *stat) { statement_ctx_t stat_ctx = {0, FALSE, FALSE}; unsigned expr_off; HRESULT hres; if(stat->variable_list) { hres = compile_variable_list(ctx, stat->variable_list); if(FAILED(hres)) return hres; }else if(stat->begin_expr) { BOOL no_ret = FALSE; hres = compile_expression_noret(ctx, stat->begin_expr, &no_ret); if(FAILED(hres)) return hres; if(!no_ret && !push_instr(ctx, OP_pop)) return E_OUTOFMEMORY; } stat_ctx.break_label = alloc_label(ctx); if(!stat_ctx.break_label) return E_OUTOFMEMORY; stat_ctx.continue_label = alloc_label(ctx); if(!stat_ctx.continue_label) return E_OUTOFMEMORY; /* FIXME: avoid */ if(!push_instr(ctx, OP_undefined)) return E_OUTOFMEMORY; expr_off = ctx->code_off; if(stat->expr) { hres = compile_expression(ctx, stat->expr); if(FAILED(hres)) return hres; hres = push_instr_uint(ctx, OP_jmp_z, stat_ctx.break_label); if(FAILED(hres)) return hres; } if(!push_instr(ctx, OP_pop)) return E_OUTOFMEMORY; hres = compile_statement(ctx, &stat_ctx, stat->statement); if(FAILED(hres)) return hres; label_set_addr(ctx, stat_ctx.continue_label); if(stat->end_expr) { BOOL no_ret = FALSE; hres = compile_expression_noret(ctx, stat->end_expr, &no_ret); if(FAILED(hres)) return hres; if(!no_ret && !push_instr(ctx, OP_pop)) return E_OUTOFMEMORY; } hres = push_instr_uint(ctx, OP_jmp, expr_off); if(FAILED(hres)) return hres; label_set_addr(ctx, stat_ctx.break_label); return S_OK; }
static HRESULT compile_select_statement(compile_ctx_t *ctx, select_statement_t *stat) { unsigned end_label, case_cnt = 0, *case_labels = NULL, i; case_clausule_t *case_iter; expression_t *expr_iter; HRESULT hres; hres = compile_expression(ctx, stat->expr); if(FAILED(hres)) return hres; if(!push_instr(ctx, OP_val)) return E_OUTOFMEMORY; end_label = alloc_label(ctx); if(!end_label) return E_OUTOFMEMORY; for(case_iter = stat->case_clausules; case_iter; case_iter = case_iter->next) case_cnt++; if(case_cnt) { case_labels = heap_alloc(case_cnt*sizeof(*case_labels)); if(!case_labels) return E_OUTOFMEMORY; } for(case_iter = stat->case_clausules, i=0; case_iter; case_iter = case_iter->next, i++) { case_labels[i] = alloc_label(ctx); if(!case_labels[i]) { hres = E_OUTOFMEMORY; break; } if(!case_iter->expr) break; for(expr_iter = case_iter->expr; expr_iter; expr_iter = expr_iter->next) { hres = compile_expression(ctx, expr_iter); if(FAILED(hres)) break; hres = push_instr_addr(ctx, OP_case, case_labels[i]); if(FAILED(hres)) break; } } if(FAILED(hres)) { heap_free(case_labels); return hres; } hres = push_instr_uint(ctx, OP_pop, 1); if(FAILED(hres)) { heap_free(case_labels); return hres; } hres = push_instr_addr(ctx, OP_jmp, case_iter ? case_labels[i] : end_label); if(FAILED(hres)) { heap_free(case_labels); return hres; } for(case_iter = stat->case_clausules, i=0; case_iter; case_iter = case_iter->next, i++) { label_set_addr(ctx, case_labels[i]); hres = compile_statement(ctx, NULL, case_iter->stat); if(FAILED(hres)) break; if(!case_iter->next) break; hres = push_instr_addr(ctx, OP_jmp, end_label); if(FAILED(hres)) break; } heap_free(case_labels); if(FAILED(hres)) return hres; label_set_addr(ctx, end_label); return S_OK; }
static HRESULT compile_forto_statement(compile_ctx_t *ctx, forto_statement_t *stat) { statement_ctx_t loop_ctx = {2}; unsigned step_instr, instr; BSTR identifier; HRESULT hres; identifier = alloc_bstr_arg(ctx, stat->identifier); if(!identifier) return E_OUTOFMEMORY; hres = compile_expression(ctx, stat->from_expr); if(FAILED(hres)) return hres; instr = push_instr(ctx, OP_assign_ident); if(!instr) return E_OUTOFMEMORY; instr_ptr(ctx, instr)->arg1.bstr = identifier; instr_ptr(ctx, instr)->arg2.uint = 0; hres = compile_expression(ctx, stat->to_expr); if(FAILED(hres)) return hres; if(!push_instr(ctx, OP_val)) return E_OUTOFMEMORY; if(stat->step_expr) { hres = compile_expression(ctx, stat->step_expr); if(FAILED(hres)) return hres; if(!push_instr(ctx, OP_val)) return E_OUTOFMEMORY; }else { hres = push_instr_int(ctx, OP_short, 1); if(FAILED(hres)) return hres; } loop_ctx.for_end_label = alloc_label(ctx); if(!loop_ctx.for_end_label) return E_OUTOFMEMORY; step_instr = push_instr(ctx, OP_step); if(!step_instr) return E_OUTOFMEMORY; instr_ptr(ctx, step_instr)->arg2.bstr = identifier; instr_ptr(ctx, step_instr)->arg1.uint = loop_ctx.for_end_label; hres = compile_statement(ctx, &loop_ctx, stat->body); if(FAILED(hres)) return hres; instr = push_instr(ctx, OP_incc); if(!instr) return E_OUTOFMEMORY; instr_ptr(ctx, instr)->arg1.bstr = identifier; hres = push_instr_addr(ctx, OP_jmp, step_instr); if(FAILED(hres)) return hres; hres = push_instr_uint(ctx, OP_pop, 2); if(FAILED(hres)) return hres; label_set_addr(ctx, loop_ctx.for_end_label); return S_OK; }
/* ECMA-262 3rd Edition 12.6.4 */ static HRESULT compile_forin_statement(compiler_ctx_t *ctx, forin_statement_t *stat) { statement_ctx_t stat_ctx = {4, FALSE, FALSE}; HRESULT hres; if(stat->variable) { hres = compile_variable_list(ctx, stat->variable); if(FAILED(hres)) return hres; } stat_ctx.break_label = alloc_label(ctx); if(!stat_ctx.break_label) return E_OUTOFMEMORY; stat_ctx.continue_label = alloc_label(ctx); if(!stat_ctx.continue_label) return E_OUTOFMEMORY; hres = compile_expression(ctx, stat->in_expr); if(FAILED(hres)) return hres; if(stat->variable) { hres = push_instr_bstr_uint(ctx, OP_identid, stat->variable->identifier, fdexNameEnsure); if(FAILED(hres)) return hres; }else if(is_memberid_expr(stat->expr->type)) { hres = compile_memberid_expression(ctx, stat->expr, fdexNameEnsure); if(FAILED(hres)) return hres; }else { hres = push_instr_uint(ctx, OP_throw_ref, JS_E_ILLEGAL_ASSIGN); if(FAILED(hres)) return hres; /* FIXME: compile statement anyways when we depend on compiler to check errors */ return S_OK; } hres = push_instr_int(ctx, OP_int, DISPID_STARTENUM); if(FAILED(hres)) return hres; /* FIXME: avoid */ if(!push_instr(ctx, OP_undefined)) return E_OUTOFMEMORY; label_set_addr(ctx, stat_ctx.continue_label); hres = push_instr_uint(ctx, OP_forin, stat_ctx.break_label); if(FAILED(hres)) return E_OUTOFMEMORY; hres = compile_statement(ctx, &stat_ctx, stat->statement); if(FAILED(hres)) return hres; hres = push_instr_uint(ctx, OP_jmp, stat_ctx.continue_label); if(FAILED(hres)) return hres; label_set_addr(ctx, stat_ctx.break_label); return S_OK; }
/* ECMA-262 3rd Edition 12.13 */ static HRESULT compile_switch_statement(compiler_ctx_t *ctx, switch_statement_t *stat) { statement_ctx_t stat_ctx = {0, FALSE, FALSE}; unsigned case_cnt = 0, *case_jmps, i, default_jmp; BOOL have_default = FALSE; statement_t *stat_iter; case_clausule_t *iter; HRESULT hres; hres = compile_expression(ctx, stat->expr); if(FAILED(hres)) return hres; stat_ctx.break_label = alloc_label(ctx); if(!stat_ctx.break_label) return E_OUTOFMEMORY; for(iter = stat->case_list; iter; iter = iter->next) { if(iter->expr) case_cnt++; } case_jmps = heap_alloc(case_cnt * sizeof(*case_jmps)); if(!case_jmps) return E_OUTOFMEMORY; i = 0; for(iter = stat->case_list; iter; iter = iter->next) { if(!iter->expr) { have_default = TRUE; continue; } hres = compile_expression(ctx, iter->expr); if(FAILED(hres)) break; case_jmps[i] = push_instr(ctx, OP_case); if(!case_jmps[i]) { hres = E_OUTOFMEMORY; break; } i++; } if(SUCCEEDED(hres)) { if(push_instr(ctx, OP_pop)) { default_jmp = push_instr(ctx, OP_jmp); if(!default_jmp) hres = E_OUTOFMEMORY; }else { hres = E_OUTOFMEMORY; } } if(FAILED(hres)) { heap_free(case_jmps); return hres; } i = 0; for(iter = stat->case_list; iter; iter = iter->next) { while(iter->next && iter->next->stat == iter->stat) { instr_ptr(ctx, iter->expr ? case_jmps[i++] : default_jmp)->arg1.uint = ctx->code_off; iter = iter->next; } instr_ptr(ctx, iter->expr ? case_jmps[i++] : default_jmp)->arg1.uint = ctx->code_off; for(stat_iter = iter->stat; stat_iter && (!iter->next || iter->next->stat != stat_iter); stat_iter = stat_iter->next) { hres = compile_statement(ctx, &stat_ctx, stat_iter); if(FAILED(hres)) break; if(stat_iter->next && !push_instr(ctx, OP_pop)) { hres = E_OUTOFMEMORY; break; } } if(FAILED(hres)) break; } heap_free(case_jmps); if(FAILED(hres)) return hres; assert(i == case_cnt); if(!have_default) instr_ptr(ctx, default_jmp)->arg1.uint = ctx->code_off; label_set_addr(ctx, stat_ctx.break_label); return S_OK; }