change IR stream to linked list
This commit is contained in:
		
							
								
								
									
										140
									
								
								ir.c
									
									
									
									
									
								
							
							
						
						
									
										140
									
								
								ir.c
									
									
									
									
									
								
							| @@ -23,55 +23,81 @@ const char *irinstr_str[IRInstrEnumSize] = { | ||||
| 	[IRAddrOf] = "addrof", | ||||
| }; | ||||
|  | ||||
| #define IRTOKS_INIT_CAP_LONG 4096 | ||||
| #define IRTOKS_INIT_CAP_SHORT 16 | ||||
| #define IRLIST_INIT_CAP_LONG 4096 | ||||
| #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) { | ||||
| 	v->toks = xmalloc(sizeof(IRTok) * cap); | ||||
| static void irlist_init_with_cap(IRList *v, size_t cap) { | ||||
| 	v->begin = NULL; | ||||
| 	v->end = NULL; | ||||
| 	v->p = pool_new(sizeof(IRItem) * cap); | ||||
| 	v->index = NULL; | ||||
| 	v->len = 0; | ||||
| 	v->cap = cap; | ||||
| } | ||||
|  | ||||
| void irtoks_init_long(IRToks *v) { | ||||
| 	irtoks_init_with_cap(v, IRTOKS_INIT_CAP_LONG); | ||||
|  | ||||
| static IRItem *irlist_new_item(IRList *v) { | ||||
| 	IRItem *ret = pool_alloc(v->p, sizeof(IRItem)); | ||||
| 	ret->next = NULL; | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| void irtoks_init_short(IRToks *v) { | ||||
| 	irtoks_init_with_cap(v, IRTOKS_INIT_CAP_SHORT); | ||||
| void irlist_init_long(IRList *v) { | ||||
| 	irlist_init_with_cap(v, IRLIST_INIT_CAP_LONG); | ||||
| } | ||||
|  | ||||
| void irtoks_term(IRToks *v) { | ||||
| 	for (size_t i = 0; i < v->len; i++) { | ||||
| 		if (v->toks[i].instr == IRCallInternal && v->toks[i].CallI.args) | ||||
| 			free(v->toks[i].CallI.args); | ||||
| void irlist_init_short(IRList *v) { | ||||
| 	irlist_init_with_cap(v, IRLIST_INIT_CAP_SHORT); | ||||
| } | ||||
|  | ||||
| void irlist_term(IRList *v) { | ||||
| 	for (IRItem *i = v->begin; i; i = i->next) { | ||||
| 		if (i->tok.instr == IRCallInternal && i->tok.CallI.args) | ||||
| 			free(i->tok.CallI.args); | ||||
| 	} | ||||
| 	free(v->toks); | ||||
| 	pool_term(v->p); | ||||
| } | ||||
|  | ||||
| void irtoks_app(IRToks *v, IRTok t) { | ||||
| 	if (v->len+1 > v->cap) | ||||
| 		v->toks = xrealloc(v->toks, sizeof(IRTok) * (v->cap *= 2)); | ||||
| 	v->toks[v->len++] = t; | ||||
| void irlist_app(IRList *v, IRTok t) { | ||||
| 	v->index = NULL; /* invalidate index */ | ||||
| 	IRItem *itm = irlist_new_item(v); | ||||
| 	itm->tok = t; | ||||
|  | ||||
| 	if (!v->begin && !v->end) | ||||
| 		v->begin = v->end = itm; | ||||
| 	else { | ||||
| 		v->end->next = itm; | ||||
| 		v->end = itm; | ||||
| 	} | ||||
|  | ||||
| 	v->len++; | ||||
| } | ||||
|  | ||||
| void irtoks_eat_irtoks(IRToks *v, IRToks *other, size_t jmp_offset) { | ||||
| 	if (v->len+other->len > v->cap) | ||||
| 		v->toks = xrealloc(v->toks, sizeof(IRTok) * (other->len + (v->cap *= 2))); | ||||
| 	for (size_t i = 0; i < other->len; i++) { | ||||
| 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 */ | ||||
| 		if (other->toks[i].instr == IRJmp) | ||||
| 			other->toks[i].Jmp.iaddr += jmp_offset; | ||||
| 		else if (other->toks[i].instr == IRJnz) | ||||
| 			other->toks[i].CJmp.iaddr += jmp_offset; | ||||
| 		if (i->tok.instr == IRJmp) | ||||
| 			i->tok.Jmp.iaddr += jmp_offset; | ||||
| 		else if (i->tok.instr == IRJnz) | ||||
| 			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. */ | ||||
| 	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); | ||||
| @@ -84,17 +110,18 @@ static void print_irparam(const IRParam *p) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void print_ir(IRToks *v, const BuiltinFunc *builtin_funcs) { | ||||
| 	for (size_t i = 0; i < v->len; i++) { | ||||
| 		printf("%04zx ", i); | ||||
| 		printf("%s", irinstr_str[v->toks[i].instr]); | ||||
| 		switch (v->toks[i].instr) { | ||||
| void print_ir(IRList *v, const BuiltinFunc *builtin_funcs) { | ||||
| 	size_t iaddr = 0; | ||||
| 	for (IRItem *i = v->begin; i; i = i->next, iaddr++) { | ||||
| 		printf("%04zx ", iaddr); | ||||
| 		printf("%s", irinstr_str[i->tok.instr]); | ||||
| 		switch (i->tok.instr) { | ||||
| 			case IRSet: | ||||
| 			case IRNeg: | ||||
| 			case IRNot: | ||||
| 			case IRAddrOf: | ||||
| 				printf(" %%%zx ", v->toks[i].Unary.addr); | ||||
| 				print_irparam(&v->toks[i].Unary.val); | ||||
| 				printf(" %%%zx ", i->tok.Unary.addr); | ||||
| 				print_irparam(&i->tok.Unary.val); | ||||
| 				break; | ||||
| 			case IRAdd: | ||||
| 			case IRSub: | ||||
| @@ -106,46 +133,47 @@ void print_ir(IRToks *v, const BuiltinFunc *builtin_funcs) { | ||||
| 			case IRLe: | ||||
| 			case IRAnd: | ||||
| 			case IROr: | ||||
| 				printf(" %%%zx ", v->toks[i].Binary.addr); | ||||
| 				print_irparam(&v->toks[i].Binary.lhs); | ||||
| 				printf(" %%%zx ", i->tok.Binary.addr); | ||||
| 				print_irparam(&i->tok.Binary.lhs); | ||||
| 				printf(" "); | ||||
| 				print_irparam(&v->toks[i].Binary.rhs); | ||||
| 				print_irparam(&i->tok.Binary.rhs); | ||||
| 				break; | ||||
| 			case IRJmp: | ||||
| 				printf(" %zx", v->toks[i].Jmp.iaddr); | ||||
| 				printf(" %zx", i->tok.Jmp.iaddr); | ||||
| 				break; | ||||
| 			case IRJnz: | ||||
| 				printf(" "); | ||||
| 				print_irparam(&v->toks[i].CJmp.condition); | ||||
| 				printf(" %zx", v->toks[i].CJmp.iaddr); | ||||
| 				print_irparam(&i->tok.CJmp.condition); | ||||
| 				printf(" %zx", i->tok.CJmp.iaddr); | ||||
| 				break; | ||||
| 			case IRCallInternal: { | ||||
| 				const BuiltinFunc *f = &builtin_funcs[v->toks[i].CallI.fid]; | ||||
| 				const BuiltinFunc *f = &builtin_funcs[i->tok.CallI.fid]; | ||||
| 				if (f->returns) | ||||
| 					printf(" %%%zx", v->toks[i].CallI.ret_addr); | ||||
| 					printf(" %%%zx", i->tok.CallI.ret_addr); | ||||
| 				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(" "); | ||||
| 					print_irparam(&v->toks[i].CallI.args[j]); | ||||
| 					print_irparam(&i->tok.CallI.args[j]); | ||||
| 				} | ||||
| 				break; | ||||
| 			} | ||||
| 			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"); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void optimize_ir(IRToks *v) { | ||||
| 	for (size_t i = 0; i < v->len; i++) { | ||||
| 		switch (v->toks[i].instr) { | ||||
| void optimize_ir(IRList *v) { | ||||
| 	irlist_update_index(v); | ||||
| 	for (IRItem *i = v->begin; i; i = i->next) { | ||||
| 		switch (i->tok.instr) { | ||||
| 			case IRJmp: { | ||||
| 				/* resolve jump chains (esp. produced by if-else-if... statements) */ | ||||
| 				size_t ja = i; | ||||
| 				while (ja < v->len && v->toks[ja].instr == IRJmp) | ||||
| 					ja = v->toks[ja].Jmp.iaddr; | ||||
| 				v->toks[i].Jmp.iaddr = ja; | ||||
| 				size_t ja = i->tok.Jmp.iaddr; | ||||
| 				while (ja < v->len && v->index[ja]->tok.instr == IRJmp) | ||||
| 					ja = v->index[ja]->tok.Jmp.iaddr; | ||||
| 				i->tok.Jmp.iaddr = ja; | ||||
| 			} | ||||
| 			default: break; | ||||
| 		} | ||||
|   | ||||
							
								
								
									
										30
									
								
								ir.h
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								ir.h
									
									
									
									
									
								
							| @@ -109,19 +109,27 @@ typedef struct IRTok { | ||||
| 	}; | ||||
| } IRTok; | ||||
|  | ||||
| typedef struct IRToks { | ||||
| 	size_t len, cap; | ||||
| 	IRTok *toks; | ||||
| } IRToks; | ||||
| typedef struct IRItem { | ||||
| 	struct IRItem *next; | ||||
| 	IRTok tok; | ||||
| } IRItem; | ||||
|  | ||||
| void irtoks_init_long(IRToks *v); | ||||
| void irtoks_init_short(IRToks *v); | ||||
| void irtoks_term(IRToks *v); | ||||
| void irtoks_app(IRToks *v, IRTok t); | ||||
| void irtoks_eat_irtoks(IRToks *v, IRToks *other, size_t jmp_offset); | ||||
| typedef struct IRList { | ||||
| 	IRItem *begin, *end; | ||||
| 	Pool *p; | ||||
| 	IRItem **index; /* index to pointer, irlist_update_index() must be called before use */ | ||||
| 	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 */ | ||||
|   | ||||
							
								
								
									
										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 = "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) { | ||||
| 		irtoks_term(&ir); | ||||
| 		irlist_term(&ir); | ||||
| 		toklist_term(&tokens); | ||||
| 		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); | ||||
| @@ -260,12 +260,12 @@ int main(int argc, const char **argv) { | ||||
| 	if (!opt_dry) { | ||||
| 		run(&ir, funcs); | ||||
| 		if (err) { | ||||
| 			irtoks_term(&ir); | ||||
| 			irlist_term(&ir); | ||||
| 			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); | ||||
| 			return 1; | ||||
| 		} | ||||
| 	} | ||||
| 	irtoks_term(&ir); | ||||
| 	irlist_term(&ir); | ||||
| 	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 Scope make_scope(Scope *parent, bool with_idents); | ||||
| 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 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 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(IRList *out_ir, TokList *toks, Map *funcs, Scope *parent_sc, TokListItem *t); | ||||
| 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(IRList *out_ir, TokList *toks, Map *funcs, Scope *parent_sc, TokListItem *t); | ||||
| 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) { | ||||
| 	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 | ||||
|  * 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) { | ||||
| 		/* 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++; | ||||
|  | ||||
| 		set_irtok_dest_addr(&ir_tok, dest_addr); | ||||
| 		irtoks_app(out_ir, ir_tok); | ||||
| 		irlist_app(out_ir, ir_tok); | ||||
|  | ||||
| 		t->tok = (Tok){ | ||||
| 			.kind = TokIdent, | ||||
| @@ -213,7 +213,7 @@ static bool expr_flush_ir_and_maybe_return(IRToks *out_ir, TokList *toks, IRTok | ||||
|  *  l_op  r_op | ||||
|  *  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; | ||||
|  | ||||
| 	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) { | ||||
| 				size_t res_addr = sc.mem_addr++; | ||||
| 				set_irtok_dest_addr(&r.LastInstr, res_addr); | ||||
| 				irtoks_app(out_ir, r.LastInstr); | ||||
| 				irlist_app(out_ir, r.LastInstr); | ||||
| 				t->tok = (Tok){ | ||||
| 					.ln = t->tok.ln, | ||||
| 					.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; | ||||
| 	TRY(r = expr(out_ir, toks, funcs, parent_sc, t)); | ||||
| 	if (r.kind == ExprRetLastInstr) { | ||||
| 		set_irtok_dest_addr(&r.LastInstr, addr); | ||||
| 		irtoks_app(out_ir, r.LastInstr); | ||||
| 		irlist_app(out_ir, r.LastInstr); | ||||
| 		t->tok = (Tok){ | ||||
| 			.ln = t->tok.ln, | ||||
| 			.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) { | ||||
| 		IRParam res; | ||||
| 		TRY(res = tok_to_irparam(parent_sc, &t->tok)); | ||||
| 		irtoks_app(out_ir, (IRTok){ | ||||
| 		irlist_app(out_ir, (IRTok){ | ||||
| 			.ln = t->tok.ln, | ||||
| 			.col = t->tok.col, | ||||
| 			.instr = IRSet, | ||||
| @@ -564,14 +564,14 @@ static void expr_into_addr(IRToks *out_ir, TokList *toks, Map *funcs, Scope *par | ||||
| 		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; | ||||
| 	TRY_RET(r = expr(out_ir, toks, funcs, parent_sc, t), (IRParam){0}); | ||||
| 	if (r.kind == ExprRetLastInstr) { | ||||
| 		Scope sc = make_scope(parent_sc, false); | ||||
| 		size_t addr = sc.mem_addr++; | ||||
| 		set_irtok_dest_addr(&r.LastInstr, addr); | ||||
| 		irtoks_app(out_ir, r.LastInstr); | ||||
| 		irlist_app(out_ir, r.LastInstr); | ||||
| 		return (IRParam){ | ||||
| 			.kind = IRParamAddr, | ||||
| 			.Addr = addr, | ||||
| @@ -595,7 +595,7 @@ static void skip_newlns(TokList *toks, TokListItem *from) { | ||||
| 		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; | ||||
| 	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; | ||||
| @@ -643,8 +643,7 @@ static void stmt(IRToks *out_ir, TokList *toks, Map *funcs, Scope *sc, TokListIt | ||||
| 		 * */ | ||||
|  | ||||
| 		/* add initial jmp instruction */ | ||||
| 		size_t jmp_instr_iaddr = out_ir->len; | ||||
| 		irtoks_app(out_ir, (IRTok){ | ||||
| 		irlist_app(out_ir, (IRTok){ | ||||
| 			.ln = t->tok.ln, | ||||
| 			.col = t->tok.col, | ||||
| 			.instr = IRJmp, | ||||
| @@ -652,30 +651,32 @@ static void stmt(IRToks *out_ir, TokList *toks, Map *funcs, Scope *sc, TokListIt | ||||
| 				.iaddr = 0, /* unknown for now */ | ||||
| 			}, | ||||
| 		}); | ||||
| 		IRItem *jmp_instr = out_ir->end; | ||||
| 		size_t body_iaddr = out_ir->len; | ||||
|  | ||||
| 		/* parse condition */ | ||||
| 		IRToks cond_ir; | ||||
| 		irtoks_init_short(&cond_ir); | ||||
| 		IRList cond_ir; | ||||
| 		irlist_init_short(&cond_ir); | ||||
| 		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 */ | ||||
| 		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 */ | ||||
| 		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 */ | ||||
| 		irtoks_eat_irtoks(out_ir, &cond_ir, out_ir->len-1); | ||||
| 		irlist_eat_irlist(out_ir, &cond_ir); | ||||
|  | ||||
| 		/* add conditional jump */ | ||||
| 		irtoks_app(out_ir, (IRTok){ | ||||
| 		irlist_app(out_ir, (IRTok){ | ||||
| 			.ln = t->next->tok.ln, | ||||
| 			.col = t->next->tok.col, | ||||
| 			.instr = IRJnz, | ||||
| 			.CJmp = { | ||||
| 				.iaddr = jmp_instr_iaddr + 1, | ||||
| 				.iaddr = body_iaddr, | ||||
| 				.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)); | ||||
|  | ||||
| 		/* add conditional jmp instruction */ | ||||
| 		size_t if_cjmp_instr_iaddr = out_ir->len; | ||||
| 		irtoks_app(out_ir, (IRTok){ | ||||
| 		irlist_app(out_ir, (IRTok){ | ||||
| 			.ln = t->tok.ln, | ||||
| 			.col = t->tok.col, | ||||
| 			.instr = IRJnz, | ||||
| @@ -705,12 +705,13 @@ static void stmt(IRToks *out_ir, TokList *toks, Map *funcs, Scope *sc, TokListIt | ||||
| 				.condition = cond, | ||||
| 			}, | ||||
| 		}); | ||||
| 		IRItem *if_cjmp_instr = out_ir->end; | ||||
|  | ||||
| 		/* parse if body */ | ||||
| 		skip_newlns(toks, t->next); | ||||
| 		IRToks if_body; | ||||
| 		irtoks_init_short(&if_body); | ||||
| 		TRY_ELSE(stmt(&if_body, toks, funcs, sc, t->next), irtoks_term(&if_body)); | ||||
| 		IRList if_body; | ||||
| 		irlist_init_short(&if_body); | ||||
| 		TRY_ELSE(stmt(&if_body, toks, funcs, sc, t->next), irlist_term(&if_body)); | ||||
|  | ||||
| 		skip_newlns(toks, t->next); | ||||
| 		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 */ | ||||
| 			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 */ | ||||
| 		size_t else_jmp_instr_iaddr = out_ir->len; | ||||
| 		irtoks_app(out_ir, (IRTok){ | ||||
| 		irlist_app(out_ir, (IRTok){ | ||||
| 			.ln = t->tok.ln, | ||||
| 			.col = t->tok.col, | ||||
| 			.instr = IRJmp, | ||||
| @@ -731,15 +731,16 @@ static void stmt(IRToks *out_ir, TokList *toks, Map *funcs, Scope *sc, TokListIt | ||||
| 				.iaddr = 0, /* unknown for now */ | ||||
| 			}, | ||||
| 		}); | ||||
| 		IRItem *else_jmp_instr = out_ir->end; | ||||
|  | ||||
| 		/* 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 */ | ||||
| 		irtoks_eat_irtoks(out_ir, &if_body, out_ir->len-1); | ||||
| 		irlist_eat_irlist(out_ir, &if_body); | ||||
|  | ||||
| 		/* 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 { | ||||
| 		/* assume expression */ | ||||
| 		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); | ||||
| } | ||||
|  | ||||
| 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; | ||||
|  | ||||
| 	Map funcs; | ||||
| @@ -760,12 +761,12 @@ IRToks parse(TokList *toks, BuiltinFunc *builtin_funcs, size_t n_builtin_funcs) | ||||
| 			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}; | ||||
| 			return (IRList){0}; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	IRToks ir; | ||||
| 	irtoks_init_long(&ir); | ||||
| 	IRList ir; | ||||
| 	irlist_init_long(&ir); | ||||
| 	Scope global_scope = make_scope(NULL, true); | ||||
| 	for (;;) { | ||||
| 		skip_newlns(toks, toks->begin); | ||||
|   | ||||
							
								
								
									
										2
									
								
								parse.h
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								parse.h
									
									
									
									
									
								
							| @@ -5,6 +5,6 @@ | ||||
| #include "tok.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 */ | ||||
|   | ||||
							
								
								
									
										15
									
								
								vm.c
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								vm.c
									
									
									
									
									
								
							| @@ -42,14 +42,17 @@ static Value *irparam_to_val(Stack *s, IRParam *v) { | ||||
| 		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 */ | ||||
| 	size_t fn_args_cap = 16; | ||||
| 	Value *fn_args = xmalloc(sizeof(Value) * fn_args_cap); | ||||
|  | ||||
| 	/* so we can use index-based addressing */ | ||||
| 	irlist_update_index(ir); | ||||
|  | ||||
| 	Stack s = stack_make(); | ||||
| 	for (size_t i = 0; i < ir->len;) { | ||||
| 		IRTok *instr = &ir->toks[i]; | ||||
| 	for (IRItem *i = ir->begin; i;) { | ||||
| 		IRTok *instr = &i->tok; | ||||
| 		err_ln = instr->ln; | ||||
| 		err_col = instr->col; | ||||
| 		switch (instr->instr) { | ||||
| @@ -91,11 +94,11 @@ void run(const IRToks *ir, const BuiltinFunc *builtin_funcs) { | ||||
| 					{free(fn_args); stack_term(&s);}); | ||||
| 				break; | ||||
| 			case IRJmp: | ||||
| 				i = instr->Jmp.iaddr; | ||||
| 				i = ir->index[instr->Jmp.iaddr]; | ||||
| 				continue; | ||||
| 			case IRJnz: | ||||
| 				if (is_nonzero(irparam_to_val(&s, &instr->CJmp.condition))) { | ||||
| 					i = instr->Jmp.iaddr; | ||||
| 					i = ir->index[instr->Jmp.iaddr]; | ||||
| 					continue; | ||||
| 				} | ||||
| 				break; | ||||
| @@ -137,7 +140,7 @@ void run(const IRToks *ir, const BuiltinFunc *builtin_funcs) { | ||||
| 				ASSERT_UNREACHED(); | ||||
| 		} | ||||
|  | ||||
| 		i++; | ||||
| 		i = i->next; | ||||
| 	} | ||||
| 	stack_term(&s); | ||||
| 	free(fn_args); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user