1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
#include <stdlib.h>
#include <string.h>
#include "codegen.h"
#include "common.h"
#include "preprocess.h"
typedef enum {
GenMode_lval,
GenMode_rval,
} GenMode;
typedef struct {
FILE* out;
int next_label;
int* loop_labels;
AstNode* current_func;
int switch_label;
} CodeGen;
static CodeGen* codegen_new(FILE* out) {
CodeGen* g = calloc(1, sizeof(CodeGen));
g->out = out;
g->next_label = 1;
g->loop_labels = calloc(1024, sizeof(int));
g->switch_label = -1;
return g;
}
static void codegen_expr(CodeGen* g, AstNode* ast, GenMode gen_mode);
static void codegen_stmt(CodeGen* g, AstNode* ast);
static void codegen_func_prologue(CodeGen* g, AstNode* ast) {
for (int i = 0; i < ast->node_params->node_len; ++i) {
fprintf(g->out, " (param $l_%s i32)", ast->node_params->node_items[i].name);
}
fprintf(g->out, " (result i32)\n");
}
static void codegen_func_epilogue(CodeGen* g, AstNode* ast) {
}
static void codegen_binary_expr(CodeGen* g, AstNode* ast, GenMode gen_mode) {
codegen_expr(g, ast->node_lhs, gen_mode);
codegen_expr(g, ast->node_rhs, gen_mode);
if (ast->node_op == TokenKind_plus) {
fprintf(g->out, "i32.add\n");
} else {
unreachable();
}
}
static void codegen_lvar(CodeGen* g, AstNode* ast, GenMode gen_mode) {
fprintf(g->out, " local.get $l_%s\n", ast->name);
}
static void codegen_expr(CodeGen* g, AstNode* ast, GenMode gen_mode) {
if (ast->kind == AstNodeKind_binary_expr) {
codegen_binary_expr(g, ast, gen_mode);
} else if (ast->kind == AstNodeKind_lvar) {
codegen_lvar(g, ast, gen_mode);
} else {
unreachable();
}
}
static void codegen_return_stmt(CodeGen* g, AstNode* ast) {
if (ast->node_expr) {
codegen_expr(g, ast->node_expr, GenMode_rval);
}
codegen_func_epilogue(g, ast);
}
static void codegen_nop(CodeGen* g, AstNode* ast) {
}
static void codegen_block_stmt(CodeGen* g, AstNode* ast) {
for (int i = 0; i < ast->node_len; ++i) {
AstNode* stmt = ast->node_items + i;
codegen_stmt(g, stmt);
}
}
static void codegen_stmt(CodeGen* g, AstNode* ast) {
if (ast->kind == AstNodeKind_list) {
codegen_block_stmt(g, ast);
} else if (ast->kind == AstNodeKind_return_stmt) {
codegen_return_stmt(g, ast);
} else if (ast->kind == AstNodeKind_nop) {
codegen_nop(g, ast);
} else {
unreachable();
}
}
static void codegen_func(CodeGen* g, AstNode* ast) {
g->current_func = ast;
fprintf(g->out, "(func (export \"%s\") \n", ast->name);
codegen_func_prologue(g, ast);
codegen_stmt(g, ast->node_body);
codegen_func_epilogue(g, ast);
fprintf(g->out, ")\n");
g->current_func = NULL;
}
void codegen_wasm(Program* prog, FILE* out) {
CodeGen* g = codegen_new(out);
fprintf(g->out, "(module\n");
for (int i = 0; i < prog->funcs->node_len; ++i) {
AstNode* func = prog->funcs->node_items + i;
codegen_func(g, func);
}
fprintf(g->out, ")\n");
}
|