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_exitdo_statement(compile_ctx_t *ctx) { statement_ctx_t *iter; unsigned pop_cnt = 0; for(iter = ctx->stat_ctx; iter; iter = iter->next) { pop_cnt += iter->stack_use; if(iter->while_end_label) break; } if(!iter) { FIXME("Exit Do outside Do Loop\n"); return E_FAIL; } if(pop_cnt) { HRESULT hres; hres = push_instr_uint(ctx, OP_pop, pop_cnt); if(FAILED(hres)) return hres; } return push_instr_addr(ctx, OP_jmp, iter->while_end_label); }
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; }
static HRESULT compile_exitprop_statement(compile_ctx_t *ctx) { if(ctx->prop_end_label == -1) { FIXME("Exit Property outside Property?\n"); return E_FAIL; } return push_instr_addr(ctx, OP_jmp, ctx->prop_end_label); }
static HRESULT compile_exitfunc_statement(compile_ctx_t *ctx) { if(ctx->func_end_label == -1) { FIXME("Exit Function outside Function?\n"); return E_FAIL; } return push_instr_addr(ctx, OP_jmp, ctx->func_end_label); }
static HRESULT compile_exitsub_statement(compile_ctx_t *ctx) { if(ctx->sub_end_label == -1) { FIXME("Exit Sub outside Sub?\n"); return E_FAIL; } return push_instr_addr(ctx, OP_jmp, ctx->sub_end_label); }
static HRESULT compile_exitdo_statement(compile_ctx_t *ctx) { if(ctx->while_end_label == -1) { FIXME("Exit Do outside Do Loop\n"); return E_FAIL; } return push_instr_addr(ctx, OP_jmp, ctx->while_end_label); }
static HRESULT compile_exitfor_statement(compile_ctx_t *ctx) { if(!ctx->for_end_label) { FIXME("Exit For outside For Loop\n"); return E_FAIL; } return push_instr_addr(ctx, OP_jmp, ctx->for_end_label); }
static HRESULT exit_label(compile_ctx_t *ctx, unsigned jmp_label) { statement_ctx_t *iter; unsigned pop_cnt = 0; for(iter = ctx->stat_ctx; iter; iter = iter->next) pop_cnt += iter->stack_use; if(pop_cnt) { HRESULT hres; hres = push_instr_uint(ctx, OP_pop, pop_cnt); if(FAILED(hres)) return hres; } return push_instr_addr(ctx, OP_jmp, jmp_label); }
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; }
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_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; }