add builtin functions
This commit is contained in:
parent
41a5dba208
commit
5dd15ce9f1
@ -1,4 +1,4 @@
|
|||||||
x := 1
|
/*x := 1
|
||||||
y := 1
|
y := 1
|
||||||
|
|
||||||
i := 60
|
i := 60
|
||||||
@ -6,6 +6,12 @@ while i {
|
|||||||
z := x + y
|
z := x + y
|
||||||
y = x
|
y = x
|
||||||
x = z
|
x = z
|
||||||
//print(z)
|
print(z)
|
||||||
i = i - 1
|
i = i - 1
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
f := 2.0
|
||||||
|
|
||||||
|
a := int(pow(f, 2.0)) + 1
|
||||||
|
|
||||||
|
print(a)
|
||||||
|
33
ir.c
33
ir.c
@ -10,9 +10,9 @@ const char *irinstr_str[IRInstrEnumSize] = {
|
|||||||
[IRSub] = "sub",
|
[IRSub] = "sub",
|
||||||
[IRMul] = "mul",
|
[IRMul] = "mul",
|
||||||
[IRDiv] = "div",
|
[IRDiv] = "div",
|
||||||
[IRPrint] = "print",
|
|
||||||
[IRJmp] = "jmp",
|
[IRJmp] = "jmp",
|
||||||
[IRJnz] = "jnz",
|
[IRJnz] = "jnz",
|
||||||
|
[IRCallInternal] = "calli",
|
||||||
};
|
};
|
||||||
|
|
||||||
#define IRTOKS_INIT_CAP_LONG 4096
|
#define IRTOKS_INIT_CAP_LONG 4096
|
||||||
@ -37,13 +37,8 @@ void irtoks_init_short(IRToks *v) {
|
|||||||
|
|
||||||
void irtoks_term(IRToks *v) {
|
void irtoks_term(IRToks *v) {
|
||||||
for (size_t i = 0; i < v->len; i++) {
|
for (size_t i = 0; i < v->len; i++) {
|
||||||
if (v->toks[i].instr == IRPrint) {
|
if (v->toks[i].instr == IRCallInternal)
|
||||||
for (IRArgs *a = v->toks[i].Print.args; a != NULL;) {
|
free(v->toks[i].CallI.args);
|
||||||
IRArgs *next = a->next;
|
|
||||||
free(a);
|
|
||||||
a = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
free(v->toks);
|
free(v->toks);
|
||||||
}
|
}
|
||||||
@ -86,31 +81,25 @@ static void print_irparam(const IRParam *p) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_ir(IRToks *v) {
|
void print_ir(IRToks *v, const BuiltinFunc *builtin_funcs) {
|
||||||
for (size_t i = 0; i < v->len; i++) {
|
for (size_t i = 0; i < v->len; i++) {
|
||||||
printf("%04zx ", i);
|
printf("%04zx ", i);
|
||||||
printf("%s", irinstr_str[v->toks[i].instr]);
|
printf("%s", irinstr_str[v->toks[i].instr]);
|
||||||
switch (v->toks[i].instr) {
|
switch (v->toks[i].instr) {
|
||||||
case IRSet:
|
case IRSet:
|
||||||
case IRNeg:
|
case IRNeg:
|
||||||
printf(" %%%zu ", v->toks[i].Unary.addr);
|
printf(" %%%zx ", v->toks[i].Unary.addr);
|
||||||
print_irparam(&v->toks[i].Unary.val);
|
print_irparam(&v->toks[i].Unary.val);
|
||||||
break;
|
break;
|
||||||
case IRAdd:
|
case IRAdd:
|
||||||
case IRSub:
|
case IRSub:
|
||||||
case IRDiv:
|
case IRDiv:
|
||||||
case IRMul:
|
case IRMul:
|
||||||
printf(" %%%zu ", v->toks[i].Arith.addr);
|
printf(" %%%zx ", v->toks[i].Arith.addr);
|
||||||
print_irparam(&v->toks[i].Arith.lhs);
|
print_irparam(&v->toks[i].Arith.lhs);
|
||||||
printf(" ");
|
printf(" ");
|
||||||
print_irparam(&v->toks[i].Arith.rhs);
|
print_irparam(&v->toks[i].Arith.rhs);
|
||||||
break;
|
break;
|
||||||
case IRPrint:
|
|
||||||
for (IRArgs *a = v->toks[i].Print.args; a != NULL; a = a->next) {
|
|
||||||
printf(" ");
|
|
||||||
print_irparam(&a->param);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case IRJmp:
|
case IRJmp:
|
||||||
printf(" %zx", v->toks[i].Jmp.iaddr);
|
printf(" %zx", v->toks[i].Jmp.iaddr);
|
||||||
break;
|
break;
|
||||||
@ -119,9 +108,17 @@ void print_ir(IRToks *v) {
|
|||||||
print_irparam(&v->toks[i].CJmp.condition);
|
print_irparam(&v->toks[i].CJmp.condition);
|
||||||
printf(" %zx", v->toks[i].CJmp.iaddr);
|
printf(" %zx", v->toks[i].CJmp.iaddr);
|
||||||
break;
|
break;
|
||||||
default:
|
case IRCallInternal: {
|
||||||
|
const BuiltinFunc *f = &builtin_funcs[v->toks[i].CallI.fid];
|
||||||
|
printf(" %s %%%zx", f->name, v->toks[i].CallI.ret_addr);
|
||||||
|
for (size_t j = 0; j < f->n_args; j++) {
|
||||||
|
printf(" ");
|
||||||
|
print_irparam(&v->toks[i].CallI.args[j]);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
default: ASSERT_UNREACHED(); break;
|
||||||
|
}
|
||||||
printf(" ; %zu:%zu", v->toks[i].ln, v->toks[i].col);
|
printf(" ; %zu:%zu", v->toks[i].ln, v->toks[i].col);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
18
ir.h
18
ir.h
@ -3,6 +3,14 @@
|
|||||||
|
|
||||||
#include "tok.h"
|
#include "tok.h"
|
||||||
|
|
||||||
|
typedef struct BuiltinFunc {
|
||||||
|
char *name;
|
||||||
|
bool side_effects : 1;
|
||||||
|
size_t n_args;
|
||||||
|
Value (*func)(Value *args);
|
||||||
|
size_t fid; /* function ID, assigned automatically */
|
||||||
|
} BuiltinFunc;
|
||||||
|
|
||||||
enum IRInstr {
|
enum IRInstr {
|
||||||
IRSet,
|
IRSet,
|
||||||
IRNeg,
|
IRNeg,
|
||||||
@ -10,9 +18,9 @@ enum IRInstr {
|
|||||||
IRSub,
|
IRSub,
|
||||||
IRMul,
|
IRMul,
|
||||||
IRDiv,
|
IRDiv,
|
||||||
IRPrint,
|
|
||||||
IRJmp,
|
IRJmp,
|
||||||
IRJnz,
|
IRJnz,
|
||||||
|
IRCallInternal,
|
||||||
IRInstrEnumSize,
|
IRInstrEnumSize,
|
||||||
};
|
};
|
||||||
typedef enum IRInstr IRInstr;
|
typedef enum IRInstr IRInstr;
|
||||||
@ -66,6 +74,12 @@ typedef struct IRTok {
|
|||||||
size_t iaddr;
|
size_t iaddr;
|
||||||
IRParam condition;
|
IRParam condition;
|
||||||
} CJmp;
|
} CJmp;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
size_t ret_addr;
|
||||||
|
size_t fid;
|
||||||
|
IRParam *args;
|
||||||
|
} CallI;
|
||||||
};
|
};
|
||||||
} IRTok;
|
} IRTok;
|
||||||
|
|
||||||
@ -80,6 +94,6 @@ void irtoks_term(IRToks *v);
|
|||||||
void irtoks_app(IRToks *v, IRTok t);
|
void irtoks_app(IRToks *v, IRTok t);
|
||||||
void irtoks_app_irtoks(IRToks *v, IRToks *other);
|
void irtoks_app_irtoks(IRToks *v, IRToks *other);
|
||||||
|
|
||||||
void print_ir(IRToks *v);
|
void print_ir(IRToks *v, const BuiltinFunc *builtin_funcs);
|
||||||
|
|
||||||
#endif /* IR_H */
|
#endif /* IR_H */
|
||||||
|
60
main.c
60
main.c
@ -32,6 +32,56 @@ static void die(const char *fmt, ...) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Value fn_print(Value *args) {
|
||||||
|
switch (args[0].type.kind) {
|
||||||
|
case TypeVoid: printf("(void)\n"); break;
|
||||||
|
case TypeFloat: printf("%f\n", args[0].Float); break;
|
||||||
|
case TypeInt: printf("%zd\n", args[0].Int); break;
|
||||||
|
default:
|
||||||
|
ASSERT_UNREACHED();
|
||||||
|
}
|
||||||
|
return (Value){0};
|
||||||
|
}
|
||||||
|
|
||||||
|
static Value fn_int(Value *args) {
|
||||||
|
Value ret = {
|
||||||
|
.type.kind = TypeInt,
|
||||||
|
.Int = 0,
|
||||||
|
};
|
||||||
|
switch (args[0].type.kind) {
|
||||||
|
case TypeVoid: break;
|
||||||
|
case TypeFloat: ret.Int = (ssize_t)args[0].Float; break;
|
||||||
|
case TypeInt: ret.Int = args[0].Int; break;
|
||||||
|
default: ASSERT_UNREACHED();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Value fn_float(Value *args) {
|
||||||
|
Value ret = {
|
||||||
|
.type.kind = TypeFloat,
|
||||||
|
.Float = 0.0,
|
||||||
|
};
|
||||||
|
switch (args[0].type.kind) {
|
||||||
|
case TypeVoid: break;
|
||||||
|
case TypeFloat: ret.Float = args[0].Float; break;
|
||||||
|
case TypeInt: ret.Float = (double)args[0].Int; break;
|
||||||
|
default: ASSERT_UNREACHED();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Value fn_pow(Value *args) {
|
||||||
|
if (!(args[0].type.kind == TypeFloat && args[1].type.kind == TypeFloat)) {
|
||||||
|
set_err("pow() requires arguments of type float");
|
||||||
|
return (Value){0};
|
||||||
|
}
|
||||||
|
return (Value) {
|
||||||
|
.type.kind = TypeFloat,
|
||||||
|
.Float = pow(args[0].Float, args[1].Float),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, const char **argv) {
|
int main(int argc, const char **argv) {
|
||||||
/* parse arguments */
|
/* parse arguments */
|
||||||
size_t nargs = argc - 1;
|
size_t nargs = argc - 1;
|
||||||
@ -88,7 +138,13 @@ int main(int argc, const char **argv) {
|
|||||||
if (opt_emit_tokens)
|
if (opt_emit_tokens)
|
||||||
print_toks(&tokens);
|
print_toks(&tokens);
|
||||||
/* parse tokens into IR code */
|
/* parse tokens into IR code */
|
||||||
IRToks ir = parse(&tokens);
|
BuiltinFunc funcs[] = {
|
||||||
|
{ .name = "print", .side_effects = true, .n_args = 1, .func = fn_print, },
|
||||||
|
{ .name = "int", .side_effects = false, .n_args = 1, .func = fn_int, },
|
||||||
|
{ .name = "float", .side_effects = false, .n_args = 1, .func = fn_float, },
|
||||||
|
{ .name = "pow", .side_effects = false, .n_args = 2, .func = fn_pow, },
|
||||||
|
};
|
||||||
|
IRToks ir = parse(&tokens, funcs, sizeof(funcs) / sizeof(funcs[0]));
|
||||||
if (err) {
|
if (err) {
|
||||||
irtoks_term(&ir);
|
irtoks_term(&ir);
|
||||||
toklist_term(&tokens);
|
toklist_term(&tokens);
|
||||||
@ -97,7 +153,7 @@ int main(int argc, const char **argv) {
|
|||||||
}
|
}
|
||||||
toklist_term(&tokens);
|
toklist_term(&tokens);
|
||||||
if (opt_emit_ir)
|
if (opt_emit_ir)
|
||||||
print_ir(&ir);
|
print_ir(&ir, funcs);
|
||||||
/* run the IR */
|
/* run the IR */
|
||||||
/* TODO... */
|
/* TODO... */
|
||||||
irtoks_term(&ir);
|
irtoks_term(&ir);
|
||||||
|
155
parse.c
155
parse.c
@ -30,8 +30,8 @@ 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 void expr(IRToks *out_ir, TokList *toks, Scope *parent_sc, TokListItem *t, ExprMode mode);
|
static void expr(IRToks *out_ir, TokList *toks, Map *funcs, Scope *parent_sc, TokListItem *t, ExprMode mode);
|
||||||
static void stmt(IRToks *out_ir, TokList *toks, Scope *sc, TokListItem *t);
|
static void stmt(IRToks *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;
|
||||||
@ -91,7 +91,7 @@ static void term_scope(Scope *sc) {
|
|||||||
map_term(&sc->ident_addrs);
|
map_term(&sc->ident_addrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void expr(IRToks *out_ir, TokList *toks, Scope *parent_sc, TokListItem *t, ExprMode mode) {
|
static void expr(IRToks *out_ir, TokList *toks, Map *funcs, Scope *parent_sc, TokListItem *t, ExprMode mode) {
|
||||||
/* A simplified example of how the operator precedence parsing works:
|
/* A simplified example of how the operator precedence parsing works:
|
||||||
* ________________________________
|
* ________________________________
|
||||||
* Where t points to (between l_op and r_op in each step)
|
* Where t points to (between l_op and r_op in each step)
|
||||||
@ -145,6 +145,111 @@ static void expr(IRToks *out_ir, TokList *toks, Scope *parent_sc, TokListItem *t
|
|||||||
if (mode.ignore_newln && t->next->tok.kind == TokOp && t->next->tok.Op == OpNewLn)
|
if (mode.ignore_newln && t->next->tok.kind == TokOp && t->next->tok.Op == OpNewLn)
|
||||||
toklist_del(toks, t->next, t->next);
|
toklist_del(toks, t->next, t->next);
|
||||||
|
|
||||||
|
/* Collapse function call. */
|
||||||
|
if (t->tok.kind == TokIdent && t->tok.Ident.kind == IdentName && t->next->tok.kind == TokOp && t->next->tok.Op == OpLParen) {
|
||||||
|
BuiltinFunc func;
|
||||||
|
bool exists = map_get(funcs, t->tok.Ident.Name, &func);
|
||||||
|
if (!exists) {
|
||||||
|
mark_err(&t->tok);
|
||||||
|
set_err("Unrecognized function: %s()", t->tok.Ident.Name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TokListItem *func_ident = t;
|
||||||
|
t = t->next->next;
|
||||||
|
toklist_del(toks, t->prev, t->prev);
|
||||||
|
|
||||||
|
size_t n_args = 0;
|
||||||
|
TokListItem *first_arg = t;
|
||||||
|
TokListItem *last_arg = NULL;
|
||||||
|
|
||||||
|
bool eval_func_in_place = !func.side_effects;
|
||||||
|
for (;;) {
|
||||||
|
n_args++;
|
||||||
|
TRY(expr(out_ir, toks, funcs, &sc, t, (ExprMode){ .kind = ExprModeJustCollapse, .ignore_newln = true }));
|
||||||
|
if (t->tok.kind == TokIdent)
|
||||||
|
eval_func_in_place = false;
|
||||||
|
if (t->next->tok.kind == TokOp) {
|
||||||
|
if (t->next->tok.Op == OpComma) {
|
||||||
|
toklist_del(toks, t->next, t->next);
|
||||||
|
t = t->next;
|
||||||
|
continue;
|
||||||
|
} else if (t->next->tok.Op == OpRParen) {
|
||||||
|
toklist_del(toks, t->next, t->next);
|
||||||
|
last_arg = t;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mark_err(&t->next->tok);
|
||||||
|
set_err("Expected ',' or ')' after function argument");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (func.n_args != n_args) {
|
||||||
|
mark_err(&func_ident->tok);
|
||||||
|
const char *plural = func.n_args == 1 ? "" : "s";
|
||||||
|
set_err("Function %s() takes %zu argument%s but got %zu", func.name, func.n_args, plural, n_args);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eval_func_in_place) {
|
||||||
|
Value *args = xmalloc(sizeof(Value) * n_args);
|
||||||
|
TokListItem *itm = first_arg;
|
||||||
|
for (size_t i = 0;; i++) {
|
||||||
|
args[i] = itm->tok.Val;
|
||||||
|
if (itm == last_arg)
|
||||||
|
break;
|
||||||
|
itm = itm->next;
|
||||||
|
}
|
||||||
|
func_ident->tok = (Tok) {
|
||||||
|
.kind = TokVal,
|
||||||
|
.Val = func.func(args),
|
||||||
|
};
|
||||||
|
free(args);
|
||||||
|
} else {
|
||||||
|
bool is_last_operation = func_ident == start && last_arg->next->tok.kind == TokOp && op_prec[last_arg->next->tok.Op] == PREC_DELIM;
|
||||||
|
|
||||||
|
IRParam *args = xmalloc(sizeof(IRParam) * n_args);
|
||||||
|
TokListItem *itm = first_arg;
|
||||||
|
for (size_t i = 0;; i++) {
|
||||||
|
TRY_ELSE(args[i] = tok_to_irparam(&sc, &itm->tok), free(args));
|
||||||
|
if (itm == last_arg)
|
||||||
|
break;
|
||||||
|
itm = itm->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t res_addr;
|
||||||
|
if (mode.kind == ExprModeStorageAddr && is_last_operation)
|
||||||
|
res_addr = mode.StorageAddr;
|
||||||
|
else
|
||||||
|
res_addr = sc.mem_addr++;
|
||||||
|
irtoks_app(out_ir, (IRTok){
|
||||||
|
.ln = func_ident->tok.ln,
|
||||||
|
.col = func_ident->tok.col,
|
||||||
|
.instr = IRCallInternal,
|
||||||
|
.CallI = {
|
||||||
|
.ret_addr = res_addr,
|
||||||
|
.fid = func.fid,
|
||||||
|
.args = args,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (mode.kind == ExprModeStorageAddr && is_last_operation) {
|
||||||
|
toklist_del(toks, func_ident, func_ident);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
func_ident->tok = (Tok) {
|
||||||
|
.kind = TokIdent,
|
||||||
|
.Ident = {
|
||||||
|
.kind = IdentAddr,
|
||||||
|
.Addr = res_addr,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t = func_ident;
|
||||||
|
toklist_del(toks, first_arg, last_arg);
|
||||||
|
}
|
||||||
|
|
||||||
/* Collapse negative factor. */
|
/* Collapse negative factor. */
|
||||||
if (negate) {
|
if (negate) {
|
||||||
bool is_last_operation = t->prev == start && t->next->tok.kind == TokOp && op_prec[t->next->tok.Op] == PREC_DELIM;
|
bool is_last_operation = t->prev == start && t->next->tok.kind == TokOp && op_prec[t->next->tok.Op] == PREC_DELIM;
|
||||||
@ -329,9 +434,9 @@ static void expr(IRToks *out_ir, TokList *toks, Scope *parent_sc, TokListItem *t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stmt(IRToks *out_ir, TokList *toks, Scope *sc, TokListItem *t) {
|
static void stmt(IRToks *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) {
|
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;
|
||||||
t = t->next;
|
t = t->next;
|
||||||
if (t->tok.kind == TokDeclare) {
|
if (t->tok.kind == TokDeclare) {
|
||||||
@ -343,13 +448,14 @@ static void stmt(IRToks *out_ir, TokList *toks, Scope *sc, TokListItem *t) {
|
|||||||
set_err("'%s' already declared in this scope", name);
|
set_err("'%s' already declared in this scope", name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
TRY(expr(out_ir, toks, sc, t, (ExprMode){ .kind = ExprModeStorageAddr, .ignore_newln = false, .StorageAddr = addr }));
|
TRY(expr(out_ir, toks, funcs, sc, t, (ExprMode){ .kind = ExprModeStorageAddr, .ignore_newln = false, .StorageAddr = addr }));
|
||||||
} else if (t->tok.kind == TokAssign) {
|
} else if (t->tok.kind == TokAssign) {
|
||||||
t = t->next;
|
t = t->next;
|
||||||
size_t addr;
|
size_t addr;
|
||||||
TRY(addr = get_ident_addr(sc, name, &start->tok));
|
TRY(addr = get_ident_addr(sc, name, &start->tok));
|
||||||
TRY(expr(out_ir, toks, sc, t, (ExprMode){ .kind = ExprModeStorageAddr, .ignore_newln = false, .StorageAddr = addr }));
|
TRY(expr(out_ir, toks, funcs, sc, t, (ExprMode){ .kind = ExprModeStorageAddr, .ignore_newln = false, .StorageAddr = addr }));
|
||||||
}
|
} else
|
||||||
|
ASSERT_UNREACHED();
|
||||||
} else if (t->tok.kind == TokOp && t->tok.Op == OpLCurl) {
|
} else if (t->tok.kind == TokOp && t->tok.Op == OpLCurl) {
|
||||||
Scope inner_sc = make_scope(sc, true);
|
Scope inner_sc = make_scope(sc, true);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@ -363,7 +469,7 @@ static void stmt(IRToks *out_ir, TokList *toks, Scope *sc, TokListItem *t) {
|
|||||||
if (t->next->tok.Op == OpRCurl)
|
if (t->next->tok.Op == OpRCurl)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
TRY_ELSE(stmt(out_ir, toks, &inner_sc, t->next), term_scope(&inner_sc));
|
TRY_ELSE(stmt(out_ir, toks, funcs, &inner_sc, t->next), term_scope(&inner_sc));
|
||||||
}
|
}
|
||||||
term_scope(&inner_sc);
|
term_scope(&inner_sc);
|
||||||
t = t->next;
|
t = t->next;
|
||||||
@ -392,7 +498,7 @@ static void stmt(IRToks *out_ir, TokList *toks, Scope *sc, TokListItem *t) {
|
|||||||
/* parse condition */
|
/* parse condition */
|
||||||
IRToks cond_ir;
|
IRToks cond_ir;
|
||||||
irtoks_init_short(&cond_ir);
|
irtoks_init_short(&cond_ir);
|
||||||
TRY_ELSE(expr(&cond_ir, toks, sc, t, (ExprMode){ .kind = ExprModeJustCollapse, .ignore_newln = false }), irtoks_term(&cond_ir));
|
TRY_ELSE(expr(&cond_ir, toks, funcs, sc, t, (ExprMode){ .kind = ExprModeJustCollapse, .ignore_newln = true }), irtoks_term(&cond_ir));
|
||||||
IRParam cond_irparam;
|
IRParam cond_irparam;
|
||||||
TRY_ELSE(cond_irparam = tok_to_irparam(sc, &t->tok), irtoks_term(&cond_ir));
|
TRY_ELSE(cond_irparam = tok_to_irparam(sc, &t->tok), irtoks_term(&cond_ir));
|
||||||
/* add conditional jump */
|
/* add conditional jump */
|
||||||
@ -406,10 +512,8 @@ static void stmt(IRToks *out_ir, TokList *toks, Scope *sc, TokListItem *t) {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
t = t->next;
|
|
||||||
|
|
||||||
/* parse loop body */
|
/* parse loop body */
|
||||||
TRY_ELSE(stmt(out_ir, toks, sc, t), irtoks_term(&cond_ir));
|
TRY_ELSE(stmt(out_ir, toks, funcs, sc, t->next), irtoks_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;
|
out_ir->toks[jmp_instr_iaddr].Jmp.iaddr = out_ir->len;
|
||||||
@ -417,19 +521,40 @@ static void stmt(IRToks *out_ir, TokList *toks, Scope *sc, TokListItem *t) {
|
|||||||
/* append condition IR to program IR, then terminate condition IR stream */
|
/* append condition IR to program IR, then terminate condition IR stream */
|
||||||
irtoks_app_irtoks(out_ir, &cond_ir);
|
irtoks_app_irtoks(out_ir, &cond_ir);
|
||||||
irtoks_term(&cond_ir);
|
irtoks_term(&cond_ir);
|
||||||
|
|
||||||
|
t = t->next;
|
||||||
|
} else if (t->tok.kind == TokOp && t->tok.Op == OpNewLn) {
|
||||||
|
} else {
|
||||||
|
/* assume expression */
|
||||||
|
TRY(expr(out_ir, toks, funcs, sc, t, (ExprMode){ .kind = ExprModeJustCollapse, .ignore_newln = false }));
|
||||||
}
|
}
|
||||||
toklist_del(toks, start, t);
|
toklist_del(toks, start, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
IRToks parse(TokList *toks) {
|
IRToks parse(TokList *toks, BuiltinFunc *builtin_funcs, size_t n_builtin_funcs) {
|
||||||
|
Map funcs;
|
||||||
|
map_init(&funcs, sizeof(BuiltinFunc));
|
||||||
|
for (size_t i = 0; i < n_builtin_funcs; i++) {
|
||||||
|
builtin_funcs[i].fid = i;
|
||||||
|
bool replaced = map_insert(&funcs, builtin_funcs[i].name, &builtin_funcs[i]);
|
||||||
|
if (replaced) {
|
||||||
|
err_ln = 0; err_col = 0;
|
||||||
|
set_err("Builtin function %s() declared more than once", builtin_funcs[i].name);
|
||||||
|
map_term(&funcs);
|
||||||
|
return (IRToks){0};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
IRToks ir;
|
IRToks ir;
|
||||||
irtoks_init_long(&ir);
|
irtoks_init_long(&ir);
|
||||||
Scope global_scope = make_scope(NULL, true);
|
Scope global_scope = make_scope(NULL, true);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (toks->begin->tok.kind == TokOp && toks->begin->tok.Op == OpEOF)
|
if (toks->begin->tok.kind == TokOp && toks->begin->tok.Op == OpEOF)
|
||||||
break;
|
break;
|
||||||
TRY_RET_ELSE(stmt(&ir, toks, &global_scope, toks->begin), ir, term_scope(&global_scope));
|
TRY_RET_ELSE(stmt(&ir, toks, &funcs, &global_scope, toks->begin), ir,
|
||||||
|
{ term_scope(&global_scope); map_term(&funcs); });
|
||||||
}
|
}
|
||||||
term_scope(&global_scope);
|
term_scope(&global_scope);
|
||||||
|
map_term(&funcs);
|
||||||
return ir;
|
return ir;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user