4
|
1 import unittest
|
8
|
2 import os
|
4
|
3
|
|
4 from compiler.compiler import Compiler
|
|
5 from compiler.errors import CompilerException, printError
|
|
6 from compiler import lexer
|
|
7 from compiler.parser import Parser
|
|
8 from compiler import assembler
|
|
9 from compiler.codegenerator import CodeGenerator
|
7
|
10 from project import Project
|
4
|
11
|
|
12 class CompilerTestCase(unittest.TestCase):
|
|
13 """ test methods start with 'test*' """
|
|
14 def testSource1(self):
|
|
15 source = """
|
|
16 module lcfos;
|
|
17 var
|
|
18 a : integer;
|
|
19
|
|
20 procedure putchar(num : integer);
|
|
21 begin
|
|
22 end putchar;
|
|
23
|
|
24 procedure WriteNum( num: integer);
|
|
25 var
|
|
26 d, base : integer;
|
|
27 dgt : integer;
|
|
28 begin
|
|
29 d := 1;
|
|
30 base := 10;
|
|
31 while num div d >= base do
|
|
32 d := d * base
|
|
33 end;
|
|
34 while d <> 0 do
|
|
35 dgt := num div d;
|
|
36 num := num mod d;
|
|
37 d := d div base;
|
|
38 putchar(48 + dgt)
|
|
39 end
|
|
40 end WriteNum;
|
|
41
|
|
42 begin
|
|
43 a := 1;
|
|
44 while a < 26
|
|
45 do
|
|
46 putchar(65+a);
|
|
47 a := a * 2
|
|
48 end;
|
|
49 end lcfos.
|
|
50 """
|
|
51 pc = Compiler()
|
|
52 pc.compilesource(source)
|
|
53 def testSource2(self):
|
|
54 source = """
|
|
55 module lcfos;
|
|
56 var
|
|
57 a, b : integer;
|
|
58 arr: array 30 of integer;
|
|
59 arr2: array 10, 12 of integer;
|
|
60 procedure t2*() : integer;
|
|
61 begin
|
|
62 a := 2;
|
|
63 while a < 5 do
|
|
64 b := arr[a-1] + arr[a-2];
|
|
65 arr2[a,2] := b;
|
|
66 arr2[a,3] := arr2[a,2] + arr2[a,2]*3 + b;
|
|
67 arr[a] := b;
|
|
68 a := a + 1;
|
|
69 end;
|
|
70 return b
|
|
71 end t2;
|
|
72 begin
|
|
73 b := 12;
|
|
74 arr[0] := 1;
|
|
75 arr[1] := 1;
|
|
76 end lcfos.
|
|
77 """
|
|
78 pc = Compiler()
|
|
79 mod = pc.compilesource(source)
|
|
80 def testSource5(self):
|
|
81 source = """
|
|
82 module lcfos;
|
|
83 procedure WriteLn() : integer;
|
|
84 const zzz = 13;
|
|
85 var
|
|
86 a, b, c: integer;
|
|
87 begin
|
|
88 a := 2;
|
|
89 b := 7;
|
|
90 c := 10 * a + b*10*a;
|
|
91 return c
|
|
92 end WriteLn;
|
|
93 begin end lcfos.
|
|
94 """
|
|
95 pc = Compiler()
|
|
96 pc.compilesource(source)
|
5
|
97 def tstForStatement(self):
|
4
|
98 source = """
|
|
99 module fortest;
|
|
100 var
|
|
101 a,b,c : integer;
|
|
102 begin
|
|
103 c := 0;
|
|
104 for a := 1 to 10 by 1 do
|
|
105 b := a + 15;
|
|
106 c := c + b * a;
|
|
107 end;
|
|
108 end fortest.
|
|
109 """
|
|
110 pc = Compiler()
|
|
111 pc.compilesource(source)
|
|
112 def testSourceIfAndWhilePattern(self):
|
|
113 source = """
|
|
114 module lcfos;
|
|
115 procedure WriteLn() : integer;
|
|
116 const zzz = 13;
|
|
117 var
|
|
118 a, b, c: integer;
|
|
119 begin
|
|
120 a := 1;
|
|
121 b := 2;
|
|
122 if a * 3 > b then
|
|
123 c := 10*a + b*10*a*a*a*b;
|
|
124 else
|
|
125 c := 13;
|
|
126 end;
|
|
127 while a < 101 do
|
|
128 a := a + 1;
|
|
129 c := c + 2;
|
|
130 end;
|
|
131 return c
|
|
132 end WriteLn;
|
|
133 begin end lcfos.
|
|
134 """
|
|
135 pc = Compiler()
|
|
136 pc.compilesource(source)
|
|
137
|
|
138 def testPattern1(self):
|
|
139 """ Test if expression can be compiled into byte code """
|
|
140 src = "12*13+33-12*2*3"
|
|
141 tokens = lexer.tokenize(src)
|
|
142 ast = Parser(tokens).parseExpression()
|
|
143 code = CodeGenerator().genexprcode(ast)
|
|
144
|
|
145 def testAssembler(self):
|
|
146 """ Check all kind of assembler cases """
|
|
147 assert(assembler.shortjump(5) == [0xeb, 0x5])
|
|
148 assert(assembler.shortjump(-2) == [0xeb, 0xfc])
|
|
149 assert(assembler.shortjump(10,'GE') == [0x7d, 0xa])
|
|
150 assert(assembler.nearjump(5) == [0xe9, 0x5,0x0,0x0,0x0])
|
|
151 assert(assembler.nearjump(-2) == [0xe9, 0xf9, 0xff,0xff,0xff])
|
|
152 assert(assembler.nearjump(10,'LE') == [0x0f, 0x8e, 0xa,0x0,0x0,0x0])
|
|
153
|
|
154 def testCall(self):
|
|
155 assert(assembler.call('r10') == [0x41, 0xff, 0xd2])
|
|
156 assert(assembler.call('rcx') == [0xff, 0xd1])
|
|
157 def testXOR(self):
|
|
158 assert(assembler.xorreg64('rax', 'rax') == [0x48, 0x31, 0xc0])
|
|
159 assert(assembler.xorreg64('r9', 'r8') == [0x4d, 0x31, 0xc1])
|
|
160 assert(assembler.xorreg64('rbx', 'r11') == [0x4c, 0x31, 0xdb])
|
|
161
|
|
162 def testINC(self):
|
|
163 assert(assembler.increg64('r11') == [0x49, 0xff, 0xc3])
|
|
164 assert(assembler.increg64('rcx') == [0x48, 0xff, 0xc1])
|
|
165
|
|
166 def testPush(self):
|
|
167 assert(assembler.push('rbp') == [0x55])
|
|
168 assert(assembler.push('rbx') == [0x53])
|
|
169 assert(assembler.push('r12') == [0x41, 0x54])
|
|
170 def testPop(self):
|
|
171 assert(assembler.pop('rbx') == [0x5b])
|
|
172 assert(assembler.pop('rbp') == [0x5d])
|
|
173 assert(assembler.pop('r12') == [0x41, 0x5c])
|
|
174
|
|
175 def testAsmLoads(self):
|
|
176 # TODO constant add testcases
|
|
177 assert(assembler.mov('rbx', 'r14') == [0x4c, 0x89, 0xf3])
|
|
178 assert(assembler.mov('r12', 'r8') == [0x4d, 0x89, 0xc4])
|
|
179 assert(assembler.mov('rdi', 'rsp') == [0x48, 0x89, 0xe7])
|
|
180
|
|
181 def testAsmMemLoads(self):
|
|
182 assert(assembler.mov('rax', ['r8','r15',0x11]) == [0x4b,0x8b,0x44,0x38,0x11])
|
|
183 assert(assembler.mov('r13', ['rbp','rcx',0x23]) == [0x4c,0x8b,0x6c,0xd,0x23])
|
|
184
|
|
185 assert(assembler.mov('r9', ['rbp',-0x33]) == [0x4c,0x8b,0x4d,0xcd])
|
|
186 #assert(assembler.movreg64('rbx', ['rax']) == [0x48, 0x8b,0x18])
|
|
187
|
|
188 assert(assembler.mov('rax', [0xb000]) == [0x48,0x8b,0x4,0x25,0x0,0xb0,0x0,0x0])
|
|
189 assert(assembler.mov('r11', [0xa0]) == [0x4c,0x8b,0x1c,0x25,0xa0,0x0,0x0,0x0])
|
|
190
|
|
191 assert(assembler.mov('r11', ['RIP', 0xf]) == [0x4c,0x8b,0x1d,0x0f,0x0,0x0,0x0])
|
|
192
|
|
193 def testAsmMemStores(self):
|
|
194 assert(assembler.mov(['rbp', 0x13],'rbx') == [0x48,0x89,0x5d,0x13])
|
|
195 assert(assembler.mov(['r12', 0x12],'r9') == [0x4d,0x89,0x4c,0x24,0x12])
|
|
196 assert(assembler.mov(['rcx', 0x11],'r14') == [0x4c,0x89,0x71,0x11])
|
|
197
|
|
198
|
|
199 assert(assembler.mov([0xab], 'rbx') == [0x48,0x89,0x1c,0x25,0xab,0x0,0x0,0x0])
|
|
200 assert(assembler.mov([0xcd], 'r13') == [0x4c,0x89,0x2c,0x25,0xcd,0x0,0x0,0x0])
|
|
201
|
|
202 assert(assembler.mov(['RIP', 0xf], 'r9') == [0x4c,0x89,0x0d,0x0f,0x0,0x0,0x0])
|
|
203
|
|
204 def testAsmMOV8(self):
|
|
205 assert(assembler.mov(['rbp', -8], 'al') == [0x88, 0x45, 0xf8])
|
|
206 assert(assembler.mov(['r11', 9], 'cl') == [0x41, 0x88, 0x4b, 0x09])
|
|
207
|
|
208 assert(assembler.mov(['rbx'], 'al') == [0x88, 0x03])
|
|
209 assert(assembler.mov(['r11'], 'dl') == [0x41, 0x88, 0x13])
|
|
210
|
|
211 def testAsmLea(self):
|
|
212 assert(assembler.leareg64('r11', ['RIP', 0xf]) == [0x4c,0x8d,0x1d,0x0f,0x0,0x0,0x0])
|
|
213 assert(assembler.leareg64('rsi', ['RIP', 0x7]) == [0x48,0x8d,0x35,0x07,0x0,0x0,0x0])
|
|
214
|
|
215 assert(assembler.leareg64('rcx', ['rbp', -8]) == [0x48,0x8d,0x4d,0xf8])
|
|
216
|
|
217 def testAssemblerCMP(self):
|
|
218 assert(assembler.cmpreg64('rdi', 'r13') == [0x4c, 0x39, 0xef])
|
|
219 assert(assembler.cmpreg64('rbx', 'r14') == [0x4c, 0x39, 0xf3])
|
|
220 assert(assembler.cmpreg64('r12', 'r9') == [0x4d, 0x39, 0xcc])
|
|
221
|
|
222 assert(assembler.cmpreg64('rdi', 1) == [0x48, 0x83, 0xff, 0x01])
|
|
223 assert(assembler.cmpreg64('r11', 2) == [0x49, 0x83, 0xfb, 0x02])
|
|
224 def testAssemblerADD(self):
|
|
225 assert(assembler.addreg64('rbx', 'r13') == [0x4c, 0x01, 0xeb])
|
|
226 assert(assembler.addreg64('rax', 'rbx') == [0x48, 0x01, 0xd8])
|
|
227 assert(assembler.addreg64('r12', 'r13') == [0x4d, 0x01, 0xec])
|
|
228
|
|
229 assert(assembler.addreg64('rbx', 0x13) == [0x48, 0x83, 0xc3, 0x13])
|
|
230 assert(assembler.addreg64('r11', 0x1234567) == [0x49, 0x81, 0xc3, 0x67, 0x45,0x23,0x1])
|
|
231 assert(assembler.addreg64('rsp', 0x33) == [0x48, 0x83, 0xc4, 0x33])
|
|
232
|
|
233 def testAssemblerSUB(self):
|
|
234 assert(assembler.subreg64('rdx', 'r14') == [0x4c, 0x29, 0xf2])
|
|
235 assert(assembler.subreg64('r15', 'rbx') == [0x49, 0x29, 0xdf])
|
|
236 assert(assembler.subreg64('r8', 'r9') == [0x4d, 0x29, 0xc8])
|
|
237
|
|
238 assert(assembler.subreg64('rsp', 0x123456) == [0x48, 0x81, 0xec, 0x56,0x34,0x12,0x0])
|
|
239 assert(assembler.subreg64('rsp', 0x12) == [0x48, 0x83, 0xec, 0x12])
|
|
240
|
|
241 def testAssemblerIDIV(self):
|
|
242 assert(assembler.idivreg64('r11') == [0x49, 0xf7, 0xfb])
|
|
243 assert(assembler.idivreg64('rcx') == [0x48, 0xf7, 0xf9])
|
|
244 assert(assembler.idivreg64('rsp') == [0x48, 0xf7, 0xfc])
|
|
245
|
|
246 def testAssemblerIMUL(self):
|
|
247 assert(assembler.imulreg64_rax('rdi') == [0x48, 0xf7, 0xef])
|
|
248 assert(assembler.imulreg64_rax('r10') == [0x49, 0xf7, 0xea])
|
|
249 assert(assembler.imulreg64_rax('rdx') == [0x48, 0xf7, 0xea])
|
|
250
|
|
251 assert(assembler.imulreg64('r11', 'rdi') == [0x4c, 0xf, 0xaf, 0xdf])
|
|
252 assert(assembler.imulreg64('r12', 'rbx') == [0x4c, 0xf, 0xaf, 0xe3])
|
|
253 # nasm generates this machine code: 0x4d, 0x6b, 0xff, 0xee
|
|
254 # This also works: 4D0FAFFE (another variant?? )
|
|
255 assert(assembler.imulreg64('r15', 'r14') == [0x4d, 0x0f, 0xaf, 0xfe])
|
7
|
256 def testProject(self):
|
15
|
257 p = Project('test.xml', isnew=True)
|
7
|
258 p.name = "Test project"
|
|
259 p.files.append('main.mod')
|
|
260 p.files.append('test.mod')
|
|
261 p.save('test.xml')
|
|
262
|
15
|
263 q = Project('test.xml')
|
7
|
264
|
|
265 assert(p.name == q.name)
|
|
266 assert(p.files == q.files)
|
|
267 # TODO: remove test.xml test file
|
8
|
268 os.remove('test.xml')
|
4
|
269
|
|
270 if __name__ == '__main__':
|
|
271 unittest.main()
|
|
272
|