forked from DoctorWkt/acwj
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgen.c
174 lines (152 loc) · 4.21 KB
/
gen.c
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#include "defs.h"
#include "data.h"
#include "decl.h"
// Generic code generator
// Copyright (c) 2019 Warren Toomey, GPL3
// Generate and return a new label number
static int label(void) {
static int id = 1;
return (id++);
}
// Generate the code for an IF statement
// and an optional ELSE clause
static int genIF(struct ASTnode *n) {
int Lfalse, Lend;
// Generate two labels: one for the
// false compound statement, and one
// for the end of the overall IF statement.
// When there is no ELSE clause, Lfalse _is_
// the ending label!
Lfalse = label();
if (n->right)
Lend = label();
// Generate the condition code followed
// by a jump to the false label.
// We cheat by sending the Lfalse label as a register.
genAST(n->left, Lfalse, n->op);
genfreeregs();
// Generate the true compound statement
genAST(n->mid, NOREG, n->op);
genfreeregs();
// If there is an optional ELSE clause,
// generate the jump to skip to the end
if (n->right)
cgjump(Lend);
// Now the false label
cglabel(Lfalse);
// Optional ELSE clause: generate the
// false compound statement and the
// end label
if (n->right) {
genAST(n->right, NOREG, n->op);
genfreeregs();
cglabel(Lend);
}
return (NOREG);
}
// Generate the code for a WHILE statement
// and an optional ELSE clause
static int genWHILE(struct ASTnode *n) {
int Lstart, Lend;
// Generate the start and end labels
// and output the start label
Lstart = label();
Lend = label();
cglabel(Lstart);
// Generate the condition code followed
// by a jump to the end label.
// We cheat by sending the Lfalse label as a register.
genAST(n->left, Lend, n->op);
genfreeregs();
// Generate the compound statement for the body
genAST(n->right, NOREG, n->op);
genfreeregs();
// Finally output the jump back to the condition,
// and the end label
cgjump(Lstart);
cglabel(Lend);
return (NOREG);
}
// Given an AST, the register (if any) that holds
// the previous rvalue, and the AST op of the parent,
// generate assembly code recursively.
// Return the register id with the tree's final value
int genAST(struct ASTnode *n, int reg, int parentASTop) {
int leftreg, rightreg;
// We now have specific AST node handling at the top
switch (n->op) {
case A_IF:
return (genIF(n));
case A_WHILE:
return (genWHILE(n));
case A_GLUE:
// Do each child statement, and free the
// registers after each child
genAST(n->left, NOREG, n->op);
genfreeregs();
genAST(n->right, NOREG, n->op);
genfreeregs();
return (NOREG);
}
// General AST node handling below
// Get the left and right sub-tree values
if (n->left)
leftreg = genAST(n->left, NOREG, n->op);
if (n->right)
rightreg = genAST(n->right, leftreg, n->op);
switch (n->op) {
case A_ADD:
return (cgadd(leftreg, rightreg));
case A_SUBTRACT:
return (cgsub(leftreg, rightreg));
case A_MULTIPLY:
return (cgmul(leftreg, rightreg));
case A_DIVIDE:
return (cgdiv(leftreg, rightreg));
case A_EQ:
case A_NE:
case A_LT:
case A_GT:
case A_LE:
case A_GE:
// If the parent AST node is an A_IF or A_WHILE, generate
// a compare followed by a jump. Otherwise, compare registers
// and set one to 1 or 0 based on the comparison.
if (parentASTop == A_IF || parentASTop == A_WHILE)
return (cgcompare_and_jump(n->op, leftreg, rightreg, reg));
else
return (cgcompare_and_set(n->op, leftreg, rightreg));
case A_INTLIT:
return (cgloadint(n->v.intvalue));
case A_IDENT:
return (cgloadglob(Gsym[n->v.id].name));
case A_LVIDENT:
return (cgstorglob(reg, Gsym[n->v.id].name));
case A_ASSIGN:
// The work has already been done, return the result
return (rightreg);
case A_PRINT:
// Print the left-child's value
// and return no register
genprintint(leftreg);
genfreeregs();
return (NOREG);
default:
fatald("Unknown AST operator", n->op);
}
}
void genpreamble() {
cgpreamble();
}
void genpostamble() {
cgpostamble();
}
void genfreeregs() {
freeall_registers();
}
void genprintint(int reg) {
cgprintint(reg);
}
void genglobsym(char *s) {
cgglobsym(s);
}