forked from DoctorWkt/acwj
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgen.c
144 lines (127 loc) · 3.47 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
#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 genIFAST(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 zero 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);
}
// 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 (genIFAST(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, 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)
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);
}