Mercurial > repos > icfp2014
comparison code/gqc.tp @ 56:fde898a3cbbe
Mostly complete version of gqc. Biggest omission is if:else. Defining labels also needs work.
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 27 Jul 2014 19:52:30 -0700 |
parents | 194a1414e240 |
children | d35601d47db1 |
comparison
equal
deleted
inserted
replaced
55:194a1414e240 | 56:fde898a3cbbe |
---|---|
12 reg <- :_num { | 12 reg <- :_num { |
13 #{ | 13 #{ |
14 num <- { _num } | 14 num <- { _num } |
15 string <- { (#["a" "b" "c" "d" "e" "f" "g" "h" "pc"]) get: _num } | 15 string <- { (#["a" "b" "c" "d" "e" "f" "g" "h" "pc"]) get: _num } |
16 isReg? <- { true } | 16 isReg? <- { true } |
17 != <- :other { (reg?: other) && _num != (other num) } | 17 != <- :other { (not: (reg?: other)) || _num != (other num) } |
18 = <- :other { (reg?: other) && _num = (other num) } | 18 = <- :other { (reg?: other) && _num = (other num) } |
19 } | 19 } |
20 } | 20 } |
21 inst <- :_name _args { | 21 inst <- :_name _args { |
22 #{ | 22 #{ |
23 name <- _name | 23 name <- _name |
24 args <- _args | 24 args <- _args |
25 translateLabels <- :labelDict { | 25 translateLabels <- :labelDict { |
26 missing <- #[] | 26 missing <- #[] |
27 foreach: args :idx arg { | 27 args <- args map: :arg { |
28 if: (object does: arg understand?: "isString?") && (arg isString?) { | 28 if: (object does: arg understand?: "isString?") && (arg isString?) { |
29 labelDict ifget: arg :translated { | 29 labelDict get: arg else: { |
30 args set: idx translated | |
31 } else: { | |
32 missing append: arg | 30 missing append: arg |
31 arg | |
33 } | 32 } |
33 } else: { | |
34 arg | |
34 } | 35 } |
35 } | 36 } |
36 missing | 37 missing |
37 } | 38 } |
38 label <- "" | 39 label <- "" |
82 (file stderr) write: "Error - " . msg . "\n" | 83 (file stderr) write: "Error - " . msg . "\n" |
83 } | 84 } |
84 _nextVar <- 0 | 85 _nextVar <- 0 |
85 //a and b are reserved for int/return values | 86 //a and b are reserved for int/return values |
86 //h is reserved as a stack pointer | 87 //h is reserved as a stack pointer |
87 _tempRegs <- [ | 88 _allTemp <- [ |
88 reg: 2 | 89 reg: 2 |
89 reg: 3 | 90 reg: 3 |
90 reg: 4 | 91 reg: 4 |
91 reg: 5 | 92 reg: 5 |
92 reg: 6 | 93 reg: 6 |
93 ] | 94 ] |
95 _tempRegs <- _allTemp | |
94 | 96 |
95 _exprHandlers <- dict hash | 97 _exprHandlers <- dict hash |
96 | 98 |
97 compileExpr:syms <- :expr :syms { | 99 compileExpr:syms <- :expr :syms { |
98 _exprHandlers ifget: (expr nodeType) :handler { | 100 _exprHandlers ifget: (expr nodeType) :handler { |
168 v | 170 v |
169 ]) | 171 ]) |
170 dest | 172 dest |
171 } | 173 } |
172 | 174 |
173 _compileFun <- :name fun globsyms { | 175 _funHandlers <- dict hash |
176 //provide symbolic names for all the interupt routines | |
177 _funHandlers set: "debug" :args syms { | |
178 prog add: (inst: "INT" #[8]) | |
179 0 | |
180 } | |
181 _funHandlers set: "direction!" :args syms { | |
182 dir <- args value | |
183 startTempRegs <- _tempRegs | |
184 v <- compileExpr: dir syms: syms | |
185 _tempRegs <- startTempRegs | |
186 if: (reg: 0) != v { | |
187 prog add: (inst: "MOV" #[ | |
188 reg: 0 | |
189 v | |
190 ]) | |
191 } | |
192 prog add: (inst: "INT" #[0]) | |
193 0 | |
194 } | |
195 _funHandlers set: "lambdamanPos" :args syms { | |
196 prog add: (inst: "INT" #[1]) | |
197 reg: 0 | |
198 } | |
199 _funHandlers set: "lambdaman2Pos" :args syms { | |
200 prog add: (inst: "INT" #[2]) | |
201 reg: 0 | |
202 } | |
203 _funHandlers set: "me" :args syms { | |
204 prog add: (inst: "INT" #[3]) | |
205 reg: 0 | |
206 } | |
207 foreach: #["ghostStartPos" "ghostPos" "ghostStatus"] :idx name { | |
208 intNum <- idx + 4 | |
209 _funHandlers set: name :args syms { | |
210 ghostIdx <- args value | |
211 startTempRegs <- _tempRegs | |
212 v <- compileExpr: ghostIdx syms: syms | |
213 _tempRegs <- startTempRegs | |
214 if: (reg: 0) != v { | |
215 prog add: (inst: "MOV" #[ | |
216 reg: 0 | |
217 v | |
218 ]) | |
219 } | |
220 prog add: (inst: "INT" #[intNum]) | |
221 reg: 0 | |
222 } | |
223 } | |
224 _funHandlers set: "mapContentsAt" :args syms { | |
225 x <- args value | |
226 y <- (args tail) value | |
227 startTempRegs <- _tempRegs | |
228 x <- compileExpr: x syms: syms | |
229 y <- compileExpr: y syms: syms | |
230 _tempRegs <- startTempRegs | |
231 if: (reg: 0) != x { | |
232 prog add: (inst: "MOV" #[ | |
233 reg: 0 | |
234 x | |
235 ]) | |
236 } | |
237 if: (reg: 1) != y { | |
238 prog add: (inst: "MOV" #[ | |
239 reg: 1 | |
240 y | |
241 ]) | |
242 } | |
243 prog add: (inst: "INT" #[7]) | |
244 reg: 0 | |
245 } | |
246 | |
247 //allow access to raw instructions | |
248 foreach: #["MOV" "INC" "DEC" "ADD" "SUB" "MUL" "DIV" "AND" "OR" "XOR" "JLT" "JEQ" "JGT" "HLT"] :idx instName { | |
249 _funHandlers set: instName :args syms { | |
250 saveTempRegs <- _tempRegs | |
251 args <- args map: :arg { compileExpr: arg syms: syms } | |
252 prog add: (inst: instName args) | |
253 } | |
254 } | |
255 | |
256 _funHandlers set: "while:do" :args syms { | |
257 cond <- ((args value) expressions) value | |
258 body <- ((args tail) value) expressions | |
259 | |
260 if: (cond nodeType) = (ast binary) { | |
261 top <- prog makeLabel: "loop_top" | |
262 end <- prog makeLabel: "loop_end" | |
263 prog setLabel: top | |
264 | |
265 saveTempRegs <- _tempRegs | |
266 l <- compileExpr: (cond left) syms: syms | |
267 r <- compileExpr: (cond right) syms: syms | |
268 _tempRegs <- saveTempRegs | |
269 | |
270 ok <- true | |
271 //we need the inverse check in the instruction since a true condition | |
272 //means continue the loop, whereas we need a jump instruction that jumps | |
273 //only when it is time to exit | |
274 if: (cond op) = ">=" { | |
275 prog add: (inst: "JLT" #[ | |
276 end | |
277 l | |
278 r | |
279 ]) | |
280 } else: { | |
281 if: (cond op) = "<=" { | |
282 prog add: (inst: "JGT" #[ | |
283 end | |
284 l | |
285 r | |
286 ]) | |
287 } else: { | |
288 if: (cond op) = "!=" { | |
289 prog add: (inst: "JEQ" #[ | |
290 end | |
291 l | |
292 r | |
293 ]) | |
294 } else: { | |
295 if: (cond op) = ">" { | |
296 bodyLbl <- prog makeLabel: "loop_body" | |
297 prog add: (inst: "JGT" #[ | |
298 bodyLbl | |
299 l | |
300 r | |
301 ]) | |
302 prog add: (inst: "MOV" #[ | |
303 reg: 8 | |
304 end | |
305 ]) | |
306 prog setLabel: bodyLbl | |
307 } else: { | |
308 if: (cond op) = "<" { | |
309 bodyLbl <- prog makeLabel: "loop_body" | |
310 prog add: (inst: "JLT" #[ | |
311 bodyLbl | |
312 l | |
313 r | |
314 ]) | |
315 prog add: (inst: "MOV" #[ | |
316 reg: 8 | |
317 end | |
318 ]) | |
319 prog setLabel: bodyLbl | |
320 } else: { | |
321 bodyLbl <- prog makeLabel: "loop_body" | |
322 if: (cond op) = "=" { | |
323 prog add: (inst: "JEQ" #[ | |
324 bodyLbl | |
325 l | |
326 r | |
327 ]) | |
328 prog add: (inst: "MOV" #[ | |
329 reg: 8 | |
330 end | |
331 ]) | |
332 prog setLabel: bodyLbl | |
333 } else: { | |
334 ok <- false | |
335 } | |
336 } | |
337 } | |
338 } | |
339 } | |
340 } | |
341 if: ok { | |
342 //TODO: do 2 passes for labels to allow forward references | |
343 foreach: body :idx expr { | |
344 if: (expr nodeType) = (ast sym) { | |
345 //allow using bare symbols to define labels | |
346 lbl <- prog makeLabel: (expr name) | |
347 prog setLabel: lbl | |
348 syms define: (expr name) lbl | |
349 } else: { | |
350 saveTempRegsExpr <- _tempRegs | |
351 v <- compileExpr: expr syms: syms | |
352 _tempRegs <- saveTempRegsExpr | |
353 } | |
354 } | |
355 prog add: (inst: "MOV" #[ | |
356 reg: 8 | |
357 top | |
358 ]) | |
359 prog setLabel: end | |
360 } else: { | |
361 error: "Condition parameter to while:do must be a comparison operator expression" | |
362 } | |
363 } else: { | |
364 error: "Condition parameter to while:do must be a comparison operator expression" | |
365 } | |
366 } | |
367 | |
368 _exprHandlers set: (ast call) :expr syms { | |
369 tc <- (expr tocall) | |
370 if: (tc nodeType) = (ast sym) { | |
371 _funHandlers ifget: (tc name) :handler { | |
372 handler: (expr args) syms | |
373 } else: { | |
374 syms ifDefined: (tc name) :info { | |
375 saveTempRegs <- _tempRegs | |
376 funArgs <- (expr args) map: :arg { compileExpr: arg syms: syms} | |
377 _tempRegs <- saveTempRegs | |
378 | |
379 //save registers that need it | |
380 needSave <- _allTemp filter: :r { | |
381 not: (_tempRegs contains?: r) | |
382 } | |
383 foreach: needSave :idx r { | |
384 prog add: (inst: "DEC" #[(reg: 7)]) | |
385 prog add: (inst: "MOV" #[ | |
386 mem: (reg: 7) | |
387 r | |
388 ]) | |
389 } | |
390 after <- prog makeLabel: "after_call" | |
391 //save PC value after call | |
392 prog add: (inst: "DEC" #[(reg: 7)]) | |
393 prog add: (inst: "MOV" #[ | |
394 mem: (reg: 7) | |
395 after | |
396 ]) | |
397 //put arguments into the appropriate registers | |
398 passregs <- _allTemp | |
399 foreach: funArgs :idx arg { | |
400 passreg <- passregs value | |
401 passregs <- passregs tail | |
402 if: passreg != arg { | |
403 //there's a potential for clobbering argument temp regs | |
404 //but there's no time to figure out a good solution | |
405 prog add: (inst: "MOV" #[ | |
406 passreg | |
407 arg | |
408 ]) | |
409 } else: { | |
410 print: "Skipping MOV for argument: " . arg . "\n" | |
411 } | |
412 } | |
413 //jump to function | |
414 prog add: (inst: "MOV" #[ | |
415 reg: 8 | |
416 info def | |
417 ]) | |
418 prog setLabel: after | |
419 //adjust PC | |
420 prog add: (inst: "INC" #[(reg: 7)]) | |
421 | |
422 //restore registers that were saved earlier | |
423 foreach: (reverse: needSave) :idx r { | |
424 prog add: (inst: "MOV" #[ | |
425 r | |
426 mem: (reg: 7) | |
427 ]) | |
428 prog add: (inst: "INC" #[(reg: 7)]) | |
429 } | |
430 reg: 0 | |
431 } else: { | |
432 error: "Function " . (tc name) . " is not defined" | |
433 } | |
434 } | |
435 } else: { | |
436 error: "Calling expressions is not supported in" | |
437 } | |
438 } | |
439 | |
440 | |
441 _compileFun <- :fName fun globsyms { | |
174 syms <- symbols tableWithParent: globsyms | 442 syms <- symbols tableWithParent: globsyms |
175 | 443 |
176 saveTempRegs <- _tempRegs | 444 saveTempRegs <- _tempRegs |
177 foreach: (fun args) :idx arg { | 445 foreach: (fun args) :idx arg { |
178 argname <- (if: (arg startsWith?: ":") { arg from: 1 } else: { arg }) | 446 argname <- (if: (arg startsWith?: ":") { arg from: 1 } else: { arg }) |
179 reg <- _tempRegs value | 447 r <- _tempRegs value |
180 _tempRegs <- _tempRegs tail | 448 _tempRegs <- _tempRegs tail |
181 syms define: argname reg | 449 syms define: argname r |
182 } | 450 } |
183 | 451 |
184 lastexpr <- ((fun expressions) length) - 1 | 452 lastexpr <- ((fun expressions) length) - 1 |
185 | 453 |
454 //TODO: do 2 passes for labels to allow forward references | |
186 foreach: (fun expressions) :idx expr { | 455 foreach: (fun expressions) :idx expr { |
187 saveTempRegsExpr <- _tempRegs | 456 if: idx != lastexpr && (expr nodeType) = (ast sym) { |
188 v <- compileExpr: expr syms: syms | 457 //allow using bare symbols to define labels |
189 _tempRegs <- saveTempRegsExpr | 458 prog setLabel: (expr name) |
190 if: idx = lastexpr && (name != "main") { | 459 syms define: (expr name) (expr name) |
191 //move result to a register | 460 } else: { |
192 prog add: (inst: "MOV" #[ | 461 saveTempRegsExpr <- _tempRegs |
193 reg: 0 | 462 v <- compileExpr: expr syms: syms |
194 v | 463 _tempRegs <- saveTempRegsExpr |
195 ]) | 464 if: idx = lastexpr && (fName != "main") { |
196 //return instruction | 465 //move result to a register |
197 prog add: (inst: "MOV" #[ | 466 prog add: (inst: "MOV" #[ |
198 reg: 8 | 467 reg: 0 |
199 mem: (reg: 7) | 468 v |
200 ]) | 469 ]) |
470 //return instruction | |
471 prog add: (inst: "MOV" #[ | |
472 reg: 8 | |
473 mem: (reg: 7) | |
474 ]) | |
475 } | |
201 } | 476 } |
202 } | 477 } |
203 saveTempRegs <- _tempRegs | 478 saveTempRegs <- _tempRegs |
204 } | 479 } |
205 | 480 |
208 res <- parser top: code | 483 res <- parser top: code |
209 if: res { | 484 if: res { |
210 outer <- res yield | 485 outer <- res yield |
211 functions <- dict hash | 486 functions <- dict hash |
212 syms <- symbols table | 487 syms <- symbols table |
488 //define symbols for all registers | |
489 //for low level shenanigans | |
490 i <- 0 | |
491 while: { i < 9 } do: { | |
492 r <- reg: i | |
493 syms define: (string: r) r | |
494 i <- i + 1 | |
495 } | |
496 //define symbols for interrupt return values | |
497 syms define: "xCoord" (reg: 0) | |
498 syms define: "yCoord" (reg: 1) | |
499 syms define: "vitality" (reg: 0) | |
500 syms define: "direction" (reg: 1) | |
501 | |
502 //process top level assignments | |
213 foreach: (outer messages) :idx msg { | 503 foreach: (outer messages) :idx msg { |
214 if: (msg nodeType) = (ast assignment) { | 504 if: (msg nodeType) = (ast assignment) { |
215 def <- msg assign | 505 def <- msg assign |
216 sym <- (msg to) name | 506 sym <- (msg to) name |
217 | 507 |
235 prog add: (inst: "HLT" #[]) | 525 prog add: (inst: "HLT" #[]) |
236 | 526 |
237 foreach: functions :name def { | 527 foreach: functions :name def { |
238 if: name != "main" { | 528 if: name != "main" { |
239 prog setLabel: name | 529 prog setLabel: name |
240 _comipleFun: name def syms | 530 _compileFun: name def syms |
241 } | 531 } |
242 } | 532 } |
243 print: prog | 533 print: prog |
244 } | 534 } |
245 } | 535 } |