remove expression parser code redundancy
This commit is contained in:
parent
18d6e7b7df
commit
46e7487cad
125
parse.c
125
parse.c
@ -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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user