remove expression parser code redundancy

This commit is contained in:
r4 2021-12-26 15:06:33 +01:00
parent 18d6e7b7df
commit 46e7487cad
1 changed files with 59 additions and 66 deletions

125
parse.c
View File

@ -32,6 +32,7 @@ static size_t get_ident_addr(const Scope *sc, const char *name, const Tok *errpo
static IRParam tok_to_irparam(Scope *sc, Tok *t); static IRParam tok_to_irparam(Scope *sc, Tok *t);
static Scope make_scope(Scope *parent, bool with_idents); static Scope make_scope(Scope *parent, bool with_idents);
static void term_scope(Scope *sc); static void term_scope(Scope *sc);
static bool expr_flush_ir_and_maybe_return(IRToks *out_ir, TokList *toks, IRTok instr, TokListItem *expr_start, Scope *expr_scope, TokListItem *t, ExprRet *out_ret);
static ExprRet expr(IRToks *out_ir, TokList *toks, Map *funcs, Scope *parent_sc, TokListItem *t); static ExprRet expr(IRToks *out_ir, TokList *toks, Map *funcs, Scope *parent_sc, TokListItem *t);
static void expr_into_addr(IRToks *out_ir, TokList *toks, Map *funcs, Scope *parent_sc, TokListItem *t, size_t addr); static void expr_into_addr(IRToks *out_ir, TokList *toks, Map *funcs, Scope *parent_sc, TokListItem *t, size_t addr);
static IRParam expr_into_irparam(IRToks *out_ir, TokList *toks, Map *funcs, Scope *parent_sc, TokListItem *t); static IRParam expr_into_irparam(IRToks *out_ir, TokList *toks, Map *funcs, Scope *parent_sc, TokListItem *t);
@ -122,6 +123,43 @@ static void term_scope(Scope *sc) {
map_term(&sc->ident_addrs); map_term(&sc->ident_addrs);
} }
/* If ir_tok is the underlying expr() call's last evaluation, this function
* deletes t from toks, sets *out_ret and tells the caller it can return
* *out_ret by returning true.
*
* If ir_tok is not the expression's last instruction, ir_tok is written to
* out_ir and t is replaced by a pointer to the result's memory address.
* */
static bool expr_flush_ir_and_maybe_return(IRToks *out_ir, TokList *toks, IRTok ir_tok, TokListItem *expr_start, Scope *expr_scope, TokListItem *t, ExprRet *out_ret) {
if (t == expr_start && t->next->tok.kind == TokOp && op_prec[t->next->tok.Op] == PREC_DELIM) {
/* ir_tok was the expression's last IR instruction. */
toklist_del(toks, t, t);
*out_ret = (ExprRet){
.kind = ExprRetLastInstr,
.LastInstr = ir_tok,
};
return true;
} else {
/* ir_tok was not the expression's last IR instruction. */
size_t dest_addr = expr_scope->mem_addr++;
set_irtok_dest_addr(&ir_tok, dest_addr);
irtoks_app(out_ir, ir_tok);
t->tok = (Tok){
.kind = TokIdent,
.Ident = {
.kind = IdentAddr,
.Addr = dest_addr,
},
};
return false;
}
}
/* The job of this function is to reduce the expression to the most simple form /* The job of this function is to reduce the expression to the most simple form
* writing the least IR instructions possible (without overanalyzing). * writing the least IR instructions possible (without overanalyzing).
* This means that the only IR instructions it will be writing are those for * This means that the only IR instructions it will be writing are those for
@ -226,6 +264,7 @@ static ExprRet expr(IRToks *out_ir, TokList *toks, Map *funcs, Scope *parent_sc,
ASSERT_UNREACHED(); ASSERT_UNREACHED();
toklist_del(toks, t->next, t->next); toklist_del(toks, t->next, t->next);
} }
/* Collapse function call. */ /* Collapse function call. */
else if (t->tok.kind == TokIdent && t->tok.Ident.kind == IdentName && t->next->tok.kind == TokOp && t->next->tok.Op == OpLParen) { else if (t->tok.kind == TokIdent && t->tok.Ident.kind == IdentName && t->next->tok.kind == TokOp && t->next->tok.Op == OpLParen) {
/* get function */ /* get function */
@ -303,39 +342,22 @@ static ExprRet expr(IRToks *out_ir, TokList *toks, Map *funcs, Scope *parent_sc,
if (args) if (args)
free(args); free(args);
} else { } else {
bool is_last_operation = t == start && t->next->tok.kind == TokOp && op_prec[t->next->tok.Op] == PREC_DELIM; /* function call IR instruction */
IRTok ir_tok = {
size_t res_addr = is_last_operation ? 0 : sc.mem_addr++;
/* function call instruction */
IRTok ir = {
.ln = func_ident->tok.ln, .ln = func_ident->tok.ln,
.col = func_ident->tok.col, .col = func_ident->tok.col,
.instr = IRCallInternal, .instr = IRCallInternal,
.CallI = { .CallI = {
.ret_addr = res_addr, .ret_addr = 0,
.fid = func.fid, .fid = func.fid,
.args = args, .args = args,
}, },
}; };
if (is_last_operation) { /* return if we've just evaluated the last instruction */
/* done */ ExprRet ret;
toklist_del(toks, t, t); if (expr_flush_ir_and_maybe_return(out_ir, toks, ir_tok, start, &sc, func_ident, &ret))
return (ExprRet){ .kind = ExprRetLastInstr, .LastInstr = ir }; return ret;
} else {
/* write IR instruction */
irtoks_app(out_ir, ir);
/* leave new memory address as result */
t->tok = (Tok){
.kind = TokIdent,
.Ident = {
.kind = IdentAddr,
.Addr = res_addr,
},
};
}
} }
} }
@ -345,44 +367,29 @@ static ExprRet expr(IRToks *out_ir, TokList *toks, Map *funcs, Scope *parent_sc,
t = t->prev; /* go back to the '-' sign */ t = t->prev; /* go back to the '-' sign */
toklist_del(toks, t->next, t->next); /* again, just removing the reference */ toklist_del(toks, t->next, t->next); /* again, just removing the reference */
bool is_last_operation = t == start && t->next->tok.kind == TokOp && op_prec[t->next->tok.Op] == PREC_DELIM;
if (v->kind == TokVal) { if (v->kind == TokVal) {
/* immediately perform operation */ /* immediately perform operation */
t->tok.kind = TokVal; t->tok.kind = TokVal;
mark_err(&t->tok); mark_err(&t->tok);
TRY_RET(t->tok.Val = eval_unary(unary_op, &v->Val), (ExprRet){0}); TRY_RET(t->tok.Val = eval_unary(unary_op, &v->Val), (ExprRet){0});
} else { } else {
size_t res_addr = is_last_operation ? 0 : sc.mem_addr++;
/* unary IR instruction */ /* unary IR instruction */
IRParam v_irparam; IRParam v_irparam;
TRY_RET(v_irparam = tok_to_irparam(&sc, v), (ExprRet){0}); TRY_RET(v_irparam = tok_to_irparam(&sc, v), (ExprRet){0});
IRTok ir = { IRTok ir_tok = {
.ln = t->tok.ln, .ln = t->tok.ln,
.col = t->tok.col, .col = t->tok.col,
.instr = unary_op, .instr = unary_op,
.Unary = { .Unary = {
.addr = res_addr, .addr = 0,
.val = v_irparam, .val = v_irparam,
}, },
}; };
if (is_last_operation) { /* return if we've just evaluated the last instruction */
/* done */ ExprRet ret;
toklist_del(toks, t, t); if (expr_flush_ir_and_maybe_return(out_ir, toks, ir_tok, start, &sc, t, &ret))
return (ExprRet){ .kind = ExprRetLastInstr, .LastInstr = ir }; return ret;
} else {
/* write IR instruction */
irtoks_app(out_ir, ir);
/* leave new memory address as result */
t->tok.kind = TokIdent;
t->tok.Ident = (Identifier){
.kind = IdentAddr,
.Addr = res_addr,
};
}
} }
} }
@ -479,40 +486,26 @@ static ExprRet expr(IRToks *out_ir, TokList *toks, Map *funcs, Scope *parent_sc,
mark_err(l_op); mark_err(l_op);
TRY_RET(lhs->Val = eval_binary(instr, lhs_val, rhs_val), (ExprRet){0}); TRY_RET(lhs->Val = eval_binary(instr, lhs_val, rhs_val), (ExprRet){0});
} else { } else {
bool is_last_operation = t == start && r_op_prec == PREC_DELIM;
IRParam lhs_irparam, rhs_irparam; IRParam lhs_irparam, rhs_irparam;
TRY_RET(lhs_irparam = tok_to_irparam(&sc, lhs), (ExprRet){0}); TRY_RET(lhs_irparam = tok_to_irparam(&sc, lhs), (ExprRet){0});
TRY_RET(rhs_irparam = tok_to_irparam(&sc, rhs), (ExprRet){0}); TRY_RET(rhs_irparam = tok_to_irparam(&sc, rhs), (ExprRet){0});
size_t res_addr = is_last_operation ? 0 : sc.mem_addr++; /* binary IR instruction */
IRTok ir_tok = {
IRTok ir = {
.ln = l_op->ln, .ln = l_op->ln,
.col = l_op->col, .col = l_op->col,
.instr = instr, .instr = instr,
.Binary = { .Binary = {
.addr = res_addr, .addr = 0,
.lhs = swap_operands ? rhs_irparam : lhs_irparam, .lhs = swap_operands ? rhs_irparam : lhs_irparam,
.rhs = swap_operands ? lhs_irparam : rhs_irparam, .rhs = swap_operands ? lhs_irparam : rhs_irparam,
}, },
}; };
if (is_last_operation) {
/* done */
toklist_del(toks, t, t);
return (ExprRet){ .kind = ExprRetLastInstr, .LastInstr = ir };
} else {
/* write IR instruction */
irtoks_app(out_ir, ir);
/* leave new memory address as result */ /* return if we've just evaluated the last instruction */
lhs->kind = TokIdent; ExprRet ret;
lhs->Ident = (Identifier){ if (expr_flush_ir_and_maybe_return(out_ir, toks, ir_tok, start, &sc, t, &ret))
.kind = IdentAddr, return ret;
.Addr = res_addr,
};
}
} }
} }
} }