change IR stream to linked list
This commit is contained in:
parent
45feb3fe1d
commit
7773cc6c14
142
ir.c
142
ir.c
@ -23,55 +23,81 @@ const char *irinstr_str[IRInstrEnumSize] = {
|
|||||||
[IRAddrOf] = "addrof",
|
[IRAddrOf] = "addrof",
|
||||||
};
|
};
|
||||||
|
|
||||||
#define IRTOKS_INIT_CAP_LONG 4096
|
#define IRLIST_INIT_CAP_LONG 4096
|
||||||
#define IRTOKS_INIT_CAP_SHORT 16
|
#define IRLIST_INIT_CAP_SHORT 16
|
||||||
|
|
||||||
static void irtoks_init_with_cap(IRToks *v, size_t cap);
|
static void irlist_init_with_cap(IRList *v, size_t cap);
|
||||||
|
static IRItem *irlist_new_item(IRList *v);
|
||||||
|
|
||||||
static void irtoks_init_with_cap(IRToks *v, size_t cap) {
|
static void irlist_init_with_cap(IRList *v, size_t cap) {
|
||||||
v->toks = xmalloc(sizeof(IRTok) * cap);
|
v->begin = NULL;
|
||||||
|
v->end = NULL;
|
||||||
|
v->p = pool_new(sizeof(IRItem) * cap);
|
||||||
|
v->index = NULL;
|
||||||
v->len = 0;
|
v->len = 0;
|
||||||
v->cap = cap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void irtoks_init_long(IRToks *v) {
|
static IRItem *irlist_new_item(IRList *v) {
|
||||||
irtoks_init_with_cap(v, IRTOKS_INIT_CAP_LONG);
|
IRItem *ret = pool_alloc(v->p, sizeof(IRItem));
|
||||||
|
ret->next = NULL;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void irtoks_init_short(IRToks *v) {
|
void irlist_init_long(IRList *v) {
|
||||||
irtoks_init_with_cap(v, IRTOKS_INIT_CAP_SHORT);
|
irlist_init_with_cap(v, IRLIST_INIT_CAP_LONG);
|
||||||
}
|
}
|
||||||
|
|
||||||
void irtoks_term(IRToks *v) {
|
void irlist_init_short(IRList *v) {
|
||||||
for (size_t i = 0; i < v->len; i++) {
|
irlist_init_with_cap(v, IRLIST_INIT_CAP_SHORT);
|
||||||
if (v->toks[i].instr == IRCallInternal && v->toks[i].CallI.args)
|
|
||||||
free(v->toks[i].CallI.args);
|
|
||||||
}
|
|
||||||
free(v->toks);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void irtoks_app(IRToks *v, IRTok t) {
|
void irlist_term(IRList *v) {
|
||||||
if (v->len+1 > v->cap)
|
for (IRItem *i = v->begin; i; i = i->next) {
|
||||||
v->toks = xrealloc(v->toks, sizeof(IRTok) * (v->cap *= 2));
|
if (i->tok.instr == IRCallInternal && i->tok.CallI.args)
|
||||||
v->toks[v->len++] = t;
|
free(i->tok.CallI.args);
|
||||||
|
}
|
||||||
|
pool_term(v->p);
|
||||||
}
|
}
|
||||||
|
|
||||||
void irtoks_eat_irtoks(IRToks *v, IRToks *other, size_t jmp_offset) {
|
void irlist_app(IRList *v, IRTok t) {
|
||||||
if (v->len+other->len > v->cap)
|
v->index = NULL; /* invalidate index */
|
||||||
v->toks = xrealloc(v->toks, sizeof(IRTok) * (other->len + (v->cap *= 2)));
|
IRItem *itm = irlist_new_item(v);
|
||||||
for (size_t i = 0; i < other->len; i++) {
|
itm->tok = t;
|
||||||
|
|
||||||
|
if (!v->begin && !v->end)
|
||||||
|
v->begin = v->end = itm;
|
||||||
|
else {
|
||||||
|
v->end->next = itm;
|
||||||
|
v->end = itm;
|
||||||
|
}
|
||||||
|
|
||||||
|
v->len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void irlist_eat_irlist(IRList *v, IRList *other) {
|
||||||
|
v->index = NULL; /* invalidate index */
|
||||||
|
size_t jmp_offset = v->len-1;
|
||||||
|
for (IRItem *i = other->begin; i; i = i->next) {
|
||||||
/* correct for changed jump addresses */
|
/* correct for changed jump addresses */
|
||||||
if (other->toks[i].instr == IRJmp)
|
if (i->tok.instr == IRJmp)
|
||||||
other->toks[i].Jmp.iaddr += jmp_offset;
|
i->tok.Jmp.iaddr += jmp_offset;
|
||||||
else if (other->toks[i].instr == IRJnz)
|
else if (i->tok.instr == IRJnz)
|
||||||
other->toks[i].CJmp.iaddr += jmp_offset;
|
i->tok.CJmp.iaddr += jmp_offset;
|
||||||
|
|
||||||
v->toks[v->len++] = other->toks[i];
|
irlist_app(v, i->tok);
|
||||||
}
|
}
|
||||||
/* We're not calling irtoks_term() because we don't want associated items
|
/* We're not calling irlist_term() because we don't want associated items
|
||||||
* (for example function arguments) to get deallocated as well. */
|
* (for example function arguments) to get deallocated as well. */
|
||||||
free(other->toks);
|
pool_term(other->p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void irlist_update_index(IRList *v) {
|
||||||
|
if (v->index)
|
||||||
|
return;
|
||||||
|
v->index = pool_alloc(v->p, v->len);
|
||||||
|
size_t num_idx = 0;
|
||||||
|
for (IRItem *i = v->begin; i; i = i->next, num_idx++)
|
||||||
|
v->index[num_idx] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_irparam(const IRParam *p);
|
static void print_irparam(const IRParam *p);
|
||||||
@ -84,17 +110,18 @@ static void print_irparam(const IRParam *p) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_ir(IRToks *v, const BuiltinFunc *builtin_funcs) {
|
void print_ir(IRList *v, const BuiltinFunc *builtin_funcs) {
|
||||||
for (size_t i = 0; i < v->len; i++) {
|
size_t iaddr = 0;
|
||||||
printf("%04zx ", i);
|
for (IRItem *i = v->begin; i; i = i->next, iaddr++) {
|
||||||
printf("%s", irinstr_str[v->toks[i].instr]);
|
printf("%04zx ", iaddr);
|
||||||
switch (v->toks[i].instr) {
|
printf("%s", irinstr_str[i->tok.instr]);
|
||||||
|
switch (i->tok.instr) {
|
||||||
case IRSet:
|
case IRSet:
|
||||||
case IRNeg:
|
case IRNeg:
|
||||||
case IRNot:
|
case IRNot:
|
||||||
case IRAddrOf:
|
case IRAddrOf:
|
||||||
printf(" %%%zx ", v->toks[i].Unary.addr);
|
printf(" %%%zx ", i->tok.Unary.addr);
|
||||||
print_irparam(&v->toks[i].Unary.val);
|
print_irparam(&i->tok.Unary.val);
|
||||||
break;
|
break;
|
||||||
case IRAdd:
|
case IRAdd:
|
||||||
case IRSub:
|
case IRSub:
|
||||||
@ -106,46 +133,47 @@ void print_ir(IRToks *v, const BuiltinFunc *builtin_funcs) {
|
|||||||
case IRLe:
|
case IRLe:
|
||||||
case IRAnd:
|
case IRAnd:
|
||||||
case IROr:
|
case IROr:
|
||||||
printf(" %%%zx ", v->toks[i].Binary.addr);
|
printf(" %%%zx ", i->tok.Binary.addr);
|
||||||
print_irparam(&v->toks[i].Binary.lhs);
|
print_irparam(&i->tok.Binary.lhs);
|
||||||
printf(" ");
|
printf(" ");
|
||||||
print_irparam(&v->toks[i].Binary.rhs);
|
print_irparam(&i->tok.Binary.rhs);
|
||||||
break;
|
break;
|
||||||
case IRJmp:
|
case IRJmp:
|
||||||
printf(" %zx", v->toks[i].Jmp.iaddr);
|
printf(" %zx", i->tok.Jmp.iaddr);
|
||||||
break;
|
break;
|
||||||
case IRJnz:
|
case IRJnz:
|
||||||
printf(" ");
|
printf(" ");
|
||||||
print_irparam(&v->toks[i].CJmp.condition);
|
print_irparam(&i->tok.CJmp.condition);
|
||||||
printf(" %zx", v->toks[i].CJmp.iaddr);
|
printf(" %zx", i->tok.CJmp.iaddr);
|
||||||
break;
|
break;
|
||||||
case IRCallInternal: {
|
case IRCallInternal: {
|
||||||
const BuiltinFunc *f = &builtin_funcs[v->toks[i].CallI.fid];
|
const BuiltinFunc *f = &builtin_funcs[i->tok.CallI.fid];
|
||||||
if (f->returns)
|
if (f->returns)
|
||||||
printf(" %%%zx", v->toks[i].CallI.ret_addr);
|
printf(" %%%zx", i->tok.CallI.ret_addr);
|
||||||
printf(" %s", f->name);
|
printf(" %s", f->name);
|
||||||
for (size_t j = 0; j < v->toks[i].CallI.n_args; j++) {
|
for (size_t j = 0; j < i->tok.CallI.n_args; j++) {
|
||||||
printf(" ");
|
printf(" ");
|
||||||
print_irparam(&v->toks[i].CallI.args[j]);
|
print_irparam(&i->tok.CallI.args[j]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: ASSERT_UNREACHED();
|
default: ASSERT_UNREACHED();
|
||||||
}
|
}
|
||||||
printf(" ; %zu:%zu", v->toks[i].ln, v->toks[i].col);
|
printf(" ; %zu:%zu", i->tok.ln, i->tok.col);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void optimize_ir(IRToks *v) {
|
void optimize_ir(IRList *v) {
|
||||||
for (size_t i = 0; i < v->len; i++) {
|
irlist_update_index(v);
|
||||||
switch (v->toks[i].instr) {
|
for (IRItem *i = v->begin; i; i = i->next) {
|
||||||
|
switch (i->tok.instr) {
|
||||||
case IRJmp: {
|
case IRJmp: {
|
||||||
/* resolve jump chains (esp. produced by if-else-if... statements) */
|
/* resolve jump chains (esp. produced by if-else-if... statements) */
|
||||||
size_t ja = i;
|
size_t ja = i->tok.Jmp.iaddr;
|
||||||
while (ja < v->len && v->toks[ja].instr == IRJmp)
|
while (ja < v->len && v->index[ja]->tok.instr == IRJmp)
|
||||||
ja = v->toks[ja].Jmp.iaddr;
|
ja = v->index[ja]->tok.Jmp.iaddr;
|
||||||
v->toks[i].Jmp.iaddr = ja;
|
i->tok.Jmp.iaddr = ja;
|
||||||
}
|
}
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
30
ir.h
30
ir.h
@ -109,19 +109,27 @@ typedef struct IRTok {
|
|||||||
};
|
};
|
||||||
} IRTok;
|
} IRTok;
|
||||||
|
|
||||||
typedef struct IRToks {
|
typedef struct IRItem {
|
||||||
size_t len, cap;
|
struct IRItem *next;
|
||||||
IRTok *toks;
|
IRTok tok;
|
||||||
} IRToks;
|
} IRItem;
|
||||||
|
|
||||||
void irtoks_init_long(IRToks *v);
|
typedef struct IRList {
|
||||||
void irtoks_init_short(IRToks *v);
|
IRItem *begin, *end;
|
||||||
void irtoks_term(IRToks *v);
|
Pool *p;
|
||||||
void irtoks_app(IRToks *v, IRTok t);
|
IRItem **index; /* index to pointer, irlist_update_index() must be called before use */
|
||||||
void irtoks_eat_irtoks(IRToks *v, IRToks *other, size_t jmp_offset);
|
size_t len;
|
||||||
|
} IRList;
|
||||||
|
|
||||||
void print_ir(IRToks *v, const BuiltinFunc *builtin_funcs);
|
void irlist_init_long(IRList *v);
|
||||||
|
void irlist_init_short(IRList *v);
|
||||||
|
void irlist_term(IRList *v);
|
||||||
|
void irlist_app(IRList *v, IRTok t);
|
||||||
|
void irlist_eat_irlist(IRList *v, IRList *other);
|
||||||
|
void irlist_update_index(IRList *v); /* should be used very conservatively */
|
||||||
|
|
||||||
void optimize_ir(IRToks *v);
|
void print_ir(IRList *v, const BuiltinFunc *builtin_funcs);
|
||||||
|
|
||||||
|
void optimize_ir(IRList *v);
|
||||||
|
|
||||||
#endif /* IR_H */
|
#endif /* IR_H */
|
||||||
|
8
main.c
8
main.c
@ -244,9 +244,9 @@ int main(int argc, const char **argv) {
|
|||||||
{ .name = "sleep", .kind = FuncFixedArgs, .returns = false, .side_effects = true, .FixedArgs = { .n_args = 1, .NoRet.func = fn_sleep, }},
|
{ .name = "sleep", .kind = FuncFixedArgs, .returns = false, .side_effects = true, .FixedArgs = { .n_args = 1, .NoRet.func = fn_sleep, }},
|
||||||
{ .name = "getln", .kind = FuncFixedArgs, .returns = true, .side_effects = true, .FixedArgs = { .n_args = 0, .WithRet.func = fn_getln, }},
|
{ .name = "getln", .kind = FuncFixedArgs, .returns = true, .side_effects = true, .FixedArgs = { .n_args = 0, .WithRet.func = fn_getln, }},
|
||||||
};
|
};
|
||||||
IRToks ir = parse(&tokens, funcs, sizeof(funcs) / sizeof(funcs[0]));
|
IRList ir = parse(&tokens, funcs, sizeof(funcs) / sizeof(funcs[0]));
|
||||||
if (err) {
|
if (err) {
|
||||||
irtoks_term(&ir);
|
irlist_term(&ir);
|
||||||
toklist_term(&tokens);
|
toklist_term(&tokens);
|
||||||
pool_term(static_vars);
|
pool_term(static_vars);
|
||||||
fprintf(stderr, C_IRED "Parser error" C_RESET " in " C_CYAN "%s" C_RESET ":%zu:%zu: %s\n", filename, err_ln, err_col, errbuf);
|
fprintf(stderr, C_IRED "Parser error" C_RESET " in " C_CYAN "%s" C_RESET ":%zu:%zu: %s\n", filename, err_ln, err_col, errbuf);
|
||||||
@ -260,12 +260,12 @@ int main(int argc, const char **argv) {
|
|||||||
if (!opt_dry) {
|
if (!opt_dry) {
|
||||||
run(&ir, funcs);
|
run(&ir, funcs);
|
||||||
if (err) {
|
if (err) {
|
||||||
irtoks_term(&ir);
|
irlist_term(&ir);
|
||||||
pool_term(static_vars);
|
pool_term(static_vars);
|
||||||
fprintf(stderr, C_IRED "Runtime error" C_RESET " in " C_CYAN "%s" C_RESET ":%zu:%zu: %s\n", filename, err_ln, err_col, errbuf);
|
fprintf(stderr, C_IRED "Runtime error" C_RESET " in " C_CYAN "%s" C_RESET ":%zu:%zu: %s\n", filename, err_ln, err_col, errbuf);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
irtoks_term(&ir);
|
irlist_term(&ir);
|
||||||
pool_term(static_vars);
|
pool_term(static_vars);
|
||||||
}
|
}
|
||||||
|
81
parse.c
81
parse.c
@ -32,12 +32,12 @@ 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 bool expr_flush_ir_and_maybe_return(IRList *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(IRList *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(IRList *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(IRList *out_ir, TokList *toks, Map *funcs, Scope *parent_sc, TokListItem *t);
|
||||||
static void skip_newlns(TokList *toks, TokListItem *from);
|
static void skip_newlns(TokList *toks, TokListItem *from);
|
||||||
static void stmt(IRToks *out_ir, TokList *toks, Map *funcs, Scope *sc, TokListItem *t);
|
static void stmt(IRList *out_ir, TokList *toks, Map *funcs, Scope *sc, TokListItem *t);
|
||||||
|
|
||||||
static void mark_err(const Tok *t) {
|
static void mark_err(const Tok *t) {
|
||||||
err_ln = t->ln;
|
err_ln = t->ln;
|
||||||
@ -132,7 +132,7 @@ static void term_scope(Scope *sc) {
|
|||||||
* If ir_tok is not the expression's last instruction, ir_tok is written to
|
* 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.
|
* 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) {
|
static bool expr_flush_ir_and_maybe_return(IRList *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) {
|
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. */
|
/* ir_tok was the expression's last IR instruction. */
|
||||||
|
|
||||||
@ -149,7 +149,7 @@ static bool expr_flush_ir_and_maybe_return(IRToks *out_ir, TokList *toks, IRTok
|
|||||||
size_t dest_addr = expr_scope->mem_addr++;
|
size_t dest_addr = expr_scope->mem_addr++;
|
||||||
|
|
||||||
set_irtok_dest_addr(&ir_tok, dest_addr);
|
set_irtok_dest_addr(&ir_tok, dest_addr);
|
||||||
irtoks_app(out_ir, ir_tok);
|
irlist_app(out_ir, ir_tok);
|
||||||
|
|
||||||
t->tok = (Tok){
|
t->tok = (Tok){
|
||||||
.kind = TokIdent,
|
.kind = TokIdent,
|
||||||
@ -213,7 +213,7 @@ static bool expr_flush_ir_and_maybe_return(IRToks *out_ir, TokList *toks, IRTok
|
|||||||
* l_op r_op
|
* l_op r_op
|
||||||
* both l_op and r_op are delimiters (their precedence is PREC_DELIM) => done
|
* both l_op and r_op are delimiters (their precedence is PREC_DELIM) => done
|
||||||
*/
|
*/
|
||||||
static ExprRet expr(IRToks *out_ir, TokList *toks, Map *funcs, Scope *parent_sc, TokListItem *t) {
|
static ExprRet expr(IRList *out_ir, TokList *toks, Map *funcs, Scope *parent_sc, TokListItem *t) {
|
||||||
TokListItem *start = t;
|
TokListItem *start = t;
|
||||||
|
|
||||||
Scope sc = make_scope(parent_sc, false);
|
Scope sc = make_scope(parent_sc, false);
|
||||||
@ -253,7 +253,7 @@ static ExprRet expr(IRToks *out_ir, TokList *toks, Map *funcs, Scope *parent_sc,
|
|||||||
if (r.kind == ExprRetLastInstr) {
|
if (r.kind == ExprRetLastInstr) {
|
||||||
size_t res_addr = sc.mem_addr++;
|
size_t res_addr = sc.mem_addr++;
|
||||||
set_irtok_dest_addr(&r.LastInstr, res_addr);
|
set_irtok_dest_addr(&r.LastInstr, res_addr);
|
||||||
irtoks_app(out_ir, r.LastInstr);
|
irlist_app(out_ir, r.LastInstr);
|
||||||
t->tok = (Tok){
|
t->tok = (Tok){
|
||||||
.ln = t->tok.ln,
|
.ln = t->tok.ln,
|
||||||
.col = t->tok.col,
|
.col = t->tok.col,
|
||||||
@ -532,12 +532,12 @@ static ExprRet expr(IRToks *out_ir, TokList *toks, Map *funcs, Scope *parent_sc,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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(IRList *out_ir, TokList *toks, Map *funcs, Scope *parent_sc, TokListItem *t, size_t addr) {
|
||||||
ExprRet r;
|
ExprRet r;
|
||||||
TRY(r = expr(out_ir, toks, funcs, parent_sc, t));
|
TRY(r = expr(out_ir, toks, funcs, parent_sc, t));
|
||||||
if (r.kind == ExprRetLastInstr) {
|
if (r.kind == ExprRetLastInstr) {
|
||||||
set_irtok_dest_addr(&r.LastInstr, addr);
|
set_irtok_dest_addr(&r.LastInstr, addr);
|
||||||
irtoks_app(out_ir, r.LastInstr);
|
irlist_app(out_ir, r.LastInstr);
|
||||||
t->tok = (Tok){
|
t->tok = (Tok){
|
||||||
.ln = t->tok.ln,
|
.ln = t->tok.ln,
|
||||||
.col = t->tok.col,
|
.col = t->tok.col,
|
||||||
@ -550,7 +550,7 @@ static void expr_into_addr(IRToks *out_ir, TokList *toks, Map *funcs, Scope *par
|
|||||||
} else if (r.kind == ExprRetVal || r.kind == ExprRetIdent) {
|
} else if (r.kind == ExprRetVal || r.kind == ExprRetIdent) {
|
||||||
IRParam res;
|
IRParam res;
|
||||||
TRY(res = tok_to_irparam(parent_sc, &t->tok));
|
TRY(res = tok_to_irparam(parent_sc, &t->tok));
|
||||||
irtoks_app(out_ir, (IRTok){
|
irlist_app(out_ir, (IRTok){
|
||||||
.ln = t->tok.ln,
|
.ln = t->tok.ln,
|
||||||
.col = t->tok.col,
|
.col = t->tok.col,
|
||||||
.instr = IRSet,
|
.instr = IRSet,
|
||||||
@ -564,14 +564,14 @@ static void expr_into_addr(IRToks *out_ir, TokList *toks, Map *funcs, Scope *par
|
|||||||
ASSERT_UNREACHED();
|
ASSERT_UNREACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
static IRParam expr_into_irparam(IRToks *out_ir, TokList *toks, Map *funcs, Scope *parent_sc, TokListItem *t) {
|
static IRParam expr_into_irparam(IRList *out_ir, TokList *toks, Map *funcs, Scope *parent_sc, TokListItem *t) {
|
||||||
ExprRet r;
|
ExprRet r;
|
||||||
TRY_RET(r = expr(out_ir, toks, funcs, parent_sc, t), (IRParam){0});
|
TRY_RET(r = expr(out_ir, toks, funcs, parent_sc, t), (IRParam){0});
|
||||||
if (r.kind == ExprRetLastInstr) {
|
if (r.kind == ExprRetLastInstr) {
|
||||||
Scope sc = make_scope(parent_sc, false);
|
Scope sc = make_scope(parent_sc, false);
|
||||||
size_t addr = sc.mem_addr++;
|
size_t addr = sc.mem_addr++;
|
||||||
set_irtok_dest_addr(&r.LastInstr, addr);
|
set_irtok_dest_addr(&r.LastInstr, addr);
|
||||||
irtoks_app(out_ir, r.LastInstr);
|
irlist_app(out_ir, r.LastInstr);
|
||||||
return (IRParam){
|
return (IRParam){
|
||||||
.kind = IRParamAddr,
|
.kind = IRParamAddr,
|
||||||
.Addr = addr,
|
.Addr = addr,
|
||||||
@ -595,7 +595,7 @@ static void skip_newlns(TokList *toks, TokListItem *from) {
|
|||||||
toklist_del(toks, from, curr->prev);
|
toklist_del(toks, from, curr->prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stmt(IRToks *out_ir, TokList *toks, Map *funcs, Scope *sc, TokListItem *t) {
|
static void stmt(IRList *out_ir, TokList *toks, Map *funcs, Scope *sc, TokListItem *t) {
|
||||||
TokListItem *start = t;
|
TokListItem *start = t;
|
||||||
if (t->tok.kind == TokIdent && t->tok.Ident.kind == IdentName && (t->next->tok.kind == TokDeclare || t->next->tok.kind == TokAssign)) {
|
if (t->tok.kind == TokIdent && t->tok.Ident.kind == IdentName && (t->next->tok.kind == TokDeclare || t->next->tok.kind == TokAssign)) {
|
||||||
char *name = t->tok.Ident.Name;
|
char *name = t->tok.Ident.Name;
|
||||||
@ -643,8 +643,7 @@ static void stmt(IRToks *out_ir, TokList *toks, Map *funcs, Scope *sc, TokListIt
|
|||||||
* */
|
* */
|
||||||
|
|
||||||
/* add initial jmp instruction */
|
/* add initial jmp instruction */
|
||||||
size_t jmp_instr_iaddr = out_ir->len;
|
irlist_app(out_ir, (IRTok){
|
||||||
irtoks_app(out_ir, (IRTok){
|
|
||||||
.ln = t->tok.ln,
|
.ln = t->tok.ln,
|
||||||
.col = t->tok.col,
|
.col = t->tok.col,
|
||||||
.instr = IRJmp,
|
.instr = IRJmp,
|
||||||
@ -652,30 +651,32 @@ static void stmt(IRToks *out_ir, TokList *toks, Map *funcs, Scope *sc, TokListIt
|
|||||||
.iaddr = 0, /* unknown for now */
|
.iaddr = 0, /* unknown for now */
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
IRItem *jmp_instr = out_ir->end;
|
||||||
|
size_t body_iaddr = out_ir->len;
|
||||||
|
|
||||||
/* parse condition */
|
/* parse condition */
|
||||||
IRToks cond_ir;
|
IRList cond_ir;
|
||||||
irtoks_init_short(&cond_ir);
|
irlist_init_short(&cond_ir);
|
||||||
IRParam cond;
|
IRParam cond;
|
||||||
TRY_ELSE(cond = expr_into_irparam(&cond_ir, toks, funcs, sc, t->next), irtoks_term(&cond_ir));
|
TRY_ELSE(cond = expr_into_irparam(&cond_ir, toks, funcs, sc, t->next), irlist_term(&cond_ir));
|
||||||
|
|
||||||
/* parse loop body */
|
/* parse loop body */
|
||||||
skip_newlns(toks, t->next);
|
skip_newlns(toks, t->next);
|
||||||
TRY_ELSE(stmt(out_ir, toks, funcs, sc, t->next), irtoks_term(&cond_ir));
|
TRY_ELSE(stmt(out_ir, toks, funcs, sc, t->next), irlist_term(&cond_ir));
|
||||||
|
|
||||||
/* finally we know where the jmp from the beginning has to jump to */
|
/* finally we know where the jmp from the beginning has to jump to */
|
||||||
out_ir->toks[jmp_instr_iaddr].Jmp.iaddr = out_ir->len;
|
jmp_instr->tok.Jmp.iaddr = out_ir->len;
|
||||||
|
|
||||||
/* append condition IR to program IR, then terminate condition IR stream */
|
/* append condition IR to program IR, then terminate condition IR stream */
|
||||||
irtoks_eat_irtoks(out_ir, &cond_ir, out_ir->len-1);
|
irlist_eat_irlist(out_ir, &cond_ir);
|
||||||
|
|
||||||
/* add conditional jump */
|
/* add conditional jump */
|
||||||
irtoks_app(out_ir, (IRTok){
|
irlist_app(out_ir, (IRTok){
|
||||||
.ln = t->next->tok.ln,
|
.ln = t->next->tok.ln,
|
||||||
.col = t->next->tok.col,
|
.col = t->next->tok.col,
|
||||||
.instr = IRJnz,
|
.instr = IRJnz,
|
||||||
.CJmp = {
|
.CJmp = {
|
||||||
.iaddr = jmp_instr_iaddr + 1,
|
.iaddr = body_iaddr,
|
||||||
.condition = cond,
|
.condition = cond,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -695,8 +696,7 @@ static void stmt(IRToks *out_ir, TokList *toks, Map *funcs, Scope *sc, TokListIt
|
|||||||
TRY(cond = expr_into_irparam(out_ir, toks, funcs, sc, t->next));
|
TRY(cond = expr_into_irparam(out_ir, toks, funcs, sc, t->next));
|
||||||
|
|
||||||
/* add conditional jmp instruction */
|
/* add conditional jmp instruction */
|
||||||
size_t if_cjmp_instr_iaddr = out_ir->len;
|
irlist_app(out_ir, (IRTok){
|
||||||
irtoks_app(out_ir, (IRTok){
|
|
||||||
.ln = t->tok.ln,
|
.ln = t->tok.ln,
|
||||||
.col = t->tok.col,
|
.col = t->tok.col,
|
||||||
.instr = IRJnz,
|
.instr = IRJnz,
|
||||||
@ -705,12 +705,13 @@ static void stmt(IRToks *out_ir, TokList *toks, Map *funcs, Scope *sc, TokListIt
|
|||||||
.condition = cond,
|
.condition = cond,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
IRItem *if_cjmp_instr = out_ir->end;
|
||||||
|
|
||||||
/* parse if body */
|
/* parse if body */
|
||||||
skip_newlns(toks, t->next);
|
skip_newlns(toks, t->next);
|
||||||
IRToks if_body;
|
IRList if_body;
|
||||||
irtoks_init_short(&if_body);
|
irlist_init_short(&if_body);
|
||||||
TRY_ELSE(stmt(&if_body, toks, funcs, sc, t->next), irtoks_term(&if_body));
|
TRY_ELSE(stmt(&if_body, toks, funcs, sc, t->next), irlist_term(&if_body));
|
||||||
|
|
||||||
skip_newlns(toks, t->next);
|
skip_newlns(toks, t->next);
|
||||||
if (t->next->tok.kind == TokElse) {
|
if (t->next->tok.kind == TokElse) {
|
||||||
@ -718,12 +719,11 @@ static void stmt(IRToks *out_ir, TokList *toks, Map *funcs, Scope *sc, TokListIt
|
|||||||
|
|
||||||
/* parse and add else body */
|
/* parse and add else body */
|
||||||
skip_newlns(toks, t->next);
|
skip_newlns(toks, t->next);
|
||||||
TRY_ELSE(stmt(out_ir, toks, funcs, sc, t->next), irtoks_term(&if_body));
|
TRY_ELSE(stmt(out_ir, toks, funcs, sc, t->next), irlist_term(&if_body));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add jmp instruction to jump back to common code */
|
/* add jmp instruction to jump back to common code */
|
||||||
size_t else_jmp_instr_iaddr = out_ir->len;
|
irlist_app(out_ir, (IRTok){
|
||||||
irtoks_app(out_ir, (IRTok){
|
|
||||||
.ln = t->tok.ln,
|
.ln = t->tok.ln,
|
||||||
.col = t->tok.col,
|
.col = t->tok.col,
|
||||||
.instr = IRJmp,
|
.instr = IRJmp,
|
||||||
@ -731,15 +731,16 @@ static void stmt(IRToks *out_ir, TokList *toks, Map *funcs, Scope *sc, TokListIt
|
|||||||
.iaddr = 0, /* unknown for now */
|
.iaddr = 0, /* unknown for now */
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
IRItem *else_jmp_instr = out_ir->end;
|
||||||
|
|
||||||
/* set if condition jmp target */
|
/* set if condition jmp target */
|
||||||
out_ir->toks[if_cjmp_instr_iaddr].CJmp.iaddr = out_ir->len;
|
if_cjmp_instr->tok.CJmp.iaddr = out_ir->len;
|
||||||
|
|
||||||
/* add if body */
|
/* add if body */
|
||||||
irtoks_eat_irtoks(out_ir, &if_body, out_ir->len-1);
|
irlist_eat_irlist(out_ir, &if_body);
|
||||||
|
|
||||||
/* set else jmp target */
|
/* set else jmp target */
|
||||||
out_ir->toks[else_jmp_instr_iaddr].CJmp.iaddr = out_ir->len;
|
else_jmp_instr->tok.CJmp.iaddr = out_ir->len;
|
||||||
} else {
|
} else {
|
||||||
/* assume expression */
|
/* assume expression */
|
||||||
TRY(expr_into_irparam(out_ir, toks, funcs, sc, t));
|
TRY(expr_into_irparam(out_ir, toks, funcs, sc, t));
|
||||||
@ -748,7 +749,7 @@ static void stmt(IRToks *out_ir, TokList *toks, Map *funcs, Scope *sc, TokListIt
|
|||||||
toklist_del(toks, start, t);
|
toklist_del(toks, start, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
IRToks parse(TokList *toks, BuiltinFunc *builtin_funcs, size_t n_builtin_funcs) {
|
IRList parse(TokList *toks, BuiltinFunc *builtin_funcs, size_t n_builtin_funcs) {
|
||||||
bf = builtin_funcs;
|
bf = builtin_funcs;
|
||||||
|
|
||||||
Map funcs;
|
Map funcs;
|
||||||
@ -760,12 +761,12 @@ IRToks parse(TokList *toks, BuiltinFunc *builtin_funcs, size_t n_builtin_funcs)
|
|||||||
err_ln = 0; err_col = 0;
|
err_ln = 0; err_col = 0;
|
||||||
set_err("Builtin function %s() declared more than once", builtin_funcs[i].name);
|
set_err("Builtin function %s() declared more than once", builtin_funcs[i].name);
|
||||||
map_term(&funcs);
|
map_term(&funcs);
|
||||||
return (IRToks){0};
|
return (IRList){0};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IRToks ir;
|
IRList ir;
|
||||||
irtoks_init_long(&ir);
|
irlist_init_long(&ir);
|
||||||
Scope global_scope = make_scope(NULL, true);
|
Scope global_scope = make_scope(NULL, true);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
skip_newlns(toks, toks->begin);
|
skip_newlns(toks, toks->begin);
|
||||||
|
2
parse.h
2
parse.h
@ -5,6 +5,6 @@
|
|||||||
#include "tok.h"
|
#include "tok.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
IRToks parse(TokList *toks, BuiltinFunc *builtin_funcs, size_t n_builtin_funcs);
|
IRList parse(TokList *toks, BuiltinFunc *builtin_funcs, size_t n_builtin_funcs);
|
||||||
|
|
||||||
#endif /* PARSE_H */
|
#endif /* PARSE_H */
|
||||||
|
15
vm.c
15
vm.c
@ -42,14 +42,17 @@ static Value *irparam_to_val(Stack *s, IRParam *v) {
|
|||||||
ASSERT_UNREACHED();
|
ASSERT_UNREACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
void run(const IRToks *ir, const BuiltinFunc *builtin_funcs) {
|
void run(IRList *ir, const BuiltinFunc *builtin_funcs) {
|
||||||
/* so we don't have to call malloc on every function call */
|
/* so we don't have to call malloc on every function call */
|
||||||
size_t fn_args_cap = 16;
|
size_t fn_args_cap = 16;
|
||||||
Value *fn_args = xmalloc(sizeof(Value) * fn_args_cap);
|
Value *fn_args = xmalloc(sizeof(Value) * fn_args_cap);
|
||||||
|
|
||||||
|
/* so we can use index-based addressing */
|
||||||
|
irlist_update_index(ir);
|
||||||
|
|
||||||
Stack s = stack_make();
|
Stack s = stack_make();
|
||||||
for (size_t i = 0; i < ir->len;) {
|
for (IRItem *i = ir->begin; i;) {
|
||||||
IRTok *instr = &ir->toks[i];
|
IRTok *instr = &i->tok;
|
||||||
err_ln = instr->ln;
|
err_ln = instr->ln;
|
||||||
err_col = instr->col;
|
err_col = instr->col;
|
||||||
switch (instr->instr) {
|
switch (instr->instr) {
|
||||||
@ -91,11 +94,11 @@ void run(const IRToks *ir, const BuiltinFunc *builtin_funcs) {
|
|||||||
{free(fn_args); stack_term(&s);});
|
{free(fn_args); stack_term(&s);});
|
||||||
break;
|
break;
|
||||||
case IRJmp:
|
case IRJmp:
|
||||||
i = instr->Jmp.iaddr;
|
i = ir->index[instr->Jmp.iaddr];
|
||||||
continue;
|
continue;
|
||||||
case IRJnz:
|
case IRJnz:
|
||||||
if (is_nonzero(irparam_to_val(&s, &instr->CJmp.condition))) {
|
if (is_nonzero(irparam_to_val(&s, &instr->CJmp.condition))) {
|
||||||
i = instr->Jmp.iaddr;
|
i = ir->index[instr->Jmp.iaddr];
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -137,7 +140,7 @@ void run(const IRToks *ir, const BuiltinFunc *builtin_funcs) {
|
|||||||
ASSERT_UNREACHED();
|
ASSERT_UNREACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
i++;
|
i = i->next;
|
||||||
}
|
}
|
||||||
stack_term(&s);
|
stack_term(&s);
|
||||||
free(fn_args);
|
free(fn_args);
|
||||||
|
Loading…
Reference in New Issue
Block a user