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
|
package no.eliashaugsbakk.kompilator.asmGeneration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import no.eliashaugsbakk.kompilator.IRGeneration.Instructions.Alloc;
import no.eliashaugsbakk.kompilator.IRGeneration.Instructions.Assign;
import no.eliashaugsbakk.kompilator.IRGeneration.Instructions.Call;
import no.eliashaugsbakk.kompilator.IRGeneration.Instructions.Instruction;
public class AssemblyBuilder {
final Map<String, StringVar> stringVariables = new HashMap<>();
record StringVar(String value, boolean mutable) {
}
final StringBuilder finalAssembly;
final StringBuilder text;
final StringBuilder rodata;
final StringBuilder data;
final StringBuilder bss;
private final static String exit = """
mov rax, 60
xor rdi, rdi
syscall
""";
public AssemblyBuilder() {
this.finalAssembly = new StringBuilder(".intel_syntax noprefix\n.global _start\n");
// CPU instructions
this.text = new StringBuilder(".text\n_start:\n\n");
// Read only data
this.rodata = new StringBuilder("\n.section .rodata\n");
// Global initialized variables, Read - Write
this.data = new StringBuilder("\n.data\n");
// Global uninitialized variables, Read - Write
this.bss = new StringBuilder("\n.section .bss\n");
}
public String createAssembly(List<Instruction> IR) {
for (Instruction inst : IR) {
if (inst instanceof Alloc alloc) {
handleAlloc(alloc);
} else if (inst instanceof Assign assign) {
handleAssign(assign);
} else if (inst instanceof Call call) {
handleCall(call);
}
}
this.text.append(exit);
this.finalAssembly.append(text);
this.finalAssembly.append(rodata);
this.finalAssembly.append(data);
this.finalAssembly.append(bss);
return this.finalAssembly.toString();
}
private void handleAssign(Assign assign) {
String reassignLabel = assign.name() + "_reassign";
this.stringVariables.put(assign.name(), new StringVar(assign.value(), true));
this.rodata.append(String.format("""
%s: .ascii "%s"
""", reassignLabel, assign.value()));
this.text.append(String.format("""
lea rax, [rip + %s]
mov [rip + %s], rax
""", reassignLabel, assign.name()));
}
private void handleAlloc(Alloc alloc) {
this.stringVariables.put(alloc.name(), new StringVar(alloc.initializer(), alloc.mutable()));
if (alloc.mutable()) {
handleAllocMut(alloc);
} else {
handleAllocRO(alloc);
}
}
private void handleAllocMut(Alloc alloc) {
if (alloc.type() == null) {
this.bss.append(String.format("""
%s: .skip 8
""", alloc.name()));
} else if (alloc.type().equals("streng")) {
String pointer = alloc.name() + "_ptr";
this.rodata.append(String.format("""
%s: .ascii "%s"
""", pointer, alloc.initializer()));
this.data.append(String.format("""
%s: .quad %s
""", alloc.name(), pointer));
} else {
throw new AssemblyBuilderException("Typen støttes ikke");
}
}
private void handleAllocRO(Alloc alloc) {
if (alloc.type().equals("streng")) {
this.rodata.append(String.format("""
%s: .ascii "%s"
""", alloc.name(), alloc.initializer()));
} else {
throw new AssemblyBuilderException("Typen støttes ikke av skriv");
}
}
private void handleCall(Call call) {
if (call.fn().equals("skriv")) {
handlePrint(call);
} else {
throw new AssemblyBuilderException("Ukjent kalltype: " + call.fn());
}
}
void handlePrint(Call call) {
if (call.args().size() != 1) {
throw new AssemblyBuilderException("Utskrift støtter bare ett argument");
}
String variableName = call.args().getFirst();
StringVar var = this.stringVariables.get(variableName);
int stringLength = var.value().length();
if (var.mutable()) {
this.text.append(String.format("""
mov rsi, [rip + %s]
mov rax, 1
mov rdi, 1
mov rdx, %d
syscall
""", variableName, stringLength));
} else {
this.text.append(String.format("""
mov rax, 1
mov rdi, 1
lea rsi, %s
mov rdx, %d
syscall
""", variableName, stringLength));
}
}
}
|