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
120
121
122
123
124
125
|
#include "ir.h"
static size_t reg_gen_id = 0;
static size_t lab_gen_id = 0;
Operand
emit_arith(ProgramBASM *program, Node *node, Operator op) {
LineInfo line = (LineInfo){
.line = node->line,
.col = node->col,
};
Operand reg_a = emit_basm(program, node->builtin.args[0]);
Operand reg_b;
for (size_t i = 1; i < array_size(node->builtin.args); ++i) {
Node *arg = node->builtin.args[i];
Operand reg_dst = NEW_REG();
reg_b = emit_basm(program, arg);
EMIT_2(program, line, op, reg_dst, reg_a, reg_b);
reg_a = reg_dst;
}
return reg_a;
}
Operand
emit_numcomp(ProgramBASM *program, Node *node, Operator op) {
LineInfo line = (LineInfo){
.line = node->line,
.col = node->col,
};
Operand label_false = NEW_LAB();
Operand label_end = NEW_LAB();
Operand reg_a = emit_basm(program, node->builtin.args[0]);
Operand reg_b;
for (size_t i = 1; i < array_size(node->builtin.args); ++i) {
Node *arg = node->builtin.args[i];
reg_b = emit_basm(program, arg);
EMIT_2(program, line, op, label_false, reg_a, reg_b);
reg_a = reg_b;
}
Operand reg_out = NEW_REG();
EMIT_1(program, line, OP_LD8, reg_out, NEW_S64(1));
EMIT_0(program, line, OP_JMP, label_end);
EMIT_0(program, line, OP_LABEL, label_false);
EMIT_1(program, line, OP_LD8, reg_out, NEW_S64(0));
EMIT_0(program, line, OP_LABEL, label_end);
return reg_out;
}
Operand
emit_builtin(ProgramBASM *program, Node *node) {
switch (node->builtin.type) {
case TOKEN_ADD: { return emit_arith(program, node, OP_ADD); } break;
case TOKEN_SUB: { return emit_arith(program, node, OP_SUB); } break;
case TOKEN_MUL: { return emit_arith(program, node, OP_MUL); } break;
case TOKEN_DIV: { return emit_arith(program, node, OP_DIV); } break;
case TOKEN_MOD: { return emit_arith(program, node, OP_MOD); } break;
case TOKEN_EQ: { return emit_numcomp(program, node, OP_JMP_NEQ); } break;
case TOKEN_LT: { return emit_numcomp(program, node, OP_JMP_GE); } break;
case TOKEN_GT: { return emit_numcomp(program, node, OP_JMP_LE); } break;
case TOKEN_LE: { return emit_numcomp(program, node, OP_JMP_GT); } break;
case TOKEN_GE: { return emit_numcomp(program, node, OP_JMP_LT); } break;
default: {
push_error(ERR_TYPE_BASM, ERR_UNIMPLEMENTED, node->line, node->col);
return (Operand){0};
} break;
}
}
Operand
emit_number(ProgramBASM *program, Node *node) {
// TODO: ldX depending on type of number.
LineInfo line = (LineInfo){.line = node->line, .col = node->col};
Operand reg_dst = NEW_REG();
Operand num = NEW_S64(node->number.integral);
EMIT_1(program, line, OP_LD64, reg_dst, num);
return reg_dst;
}
Operand
emit_bool(ProgramBASM *program, Node *node) {
LineInfo line = (LineInfo){.line = node->line, .col = node->col};
Operand reg_dst = NEW_REG();
Operand val;
if (node->boolean) {
val = NEW_S64(1);
} else {
val = NEW_S64(0);
}
EMIT_1(program, line, OP_LD8, reg_dst, val);
return reg_dst;
}
// TODO: emit_if
// TODO: emit_and
// TODO: emit_or
// TODO: emit_not
// TODO: emit_global
// TODO: emit_local
// TODO: emit_procedure
// TODO: emit_proc_call
Operand
emit_basm(ProgramBASM *program, Node *node) {
switch (node->type) {
case NODE_BOOL: { return emit_bool(program, node); } break;
case NODE_NUMBER: { return emit_number(program, node); } break;
case NODE_BUILTIN: { return emit_builtin(program, node); } break;
default: {
push_error(ERR_TYPE_BASM, ERR_UNIMPLEMENTED, node->line, node->col);
return (Operand){0};
} break;
}
}
ProgramBASM *
generate_basm(ParseTree *parse_tree) {
ProgramBASM *program = malloc(sizeof(ProgramBASM));
array_init(program->inst, 0);
array_init(program->lines, 0);
for (size_t i = 0; i < array_size(parse_tree->roots); ++i) {
Node *root = parse_tree->roots[i];
emit_basm(program, root);
}
return program;
}
|