swissChili | ca107a0 | 2021-04-14 12:07:30 -0700 | [diff] [blame^] | 1 | #+TITLE: Lisp Notes |
| 2 | #+AUTHOR: swissChili |
| 3 | |
| 4 | * Compiler |
| 5 | |
| 6 | The compiler will using DynASM to generate code at runtime. It won’t |
| 7 | be a JIT (no interpreter), strictly a dynamic compiler. |
| 8 | |
| 9 | For now I won’t even have a register allocator, all variables and |
| 10 | temporaries will be stored on the stack. This makes more or less |
| 11 | sense considering they will need to be put on the stack anyway when |
| 12 | a function is called. |
| 13 | |
| 14 | An example assembly is in =scratch.s=. |
| 15 | |
| 16 | ** First Pass |
| 17 | |
| 18 | The first pass will involve finding all the local variables |
| 19 | (i.e. anything defined with =let=) and all the temporary values |
| 20 | necessary. Once a variable is out of scope, its stack space becomes |
| 21 | usable by other variables. Similarly, once a temporary is used, its |
| 22 | space becomes available. Variables are addressable by name but |
| 23 | temporaries are not. |
| 24 | |
| 25 | ** Second Pass |
| 26 | |
| 27 | The second pass will actually generate assembly. First enough space |
| 28 | will be reserved on the stack for the variables and temporaries, |
| 29 | then the AST will be walked as before to generate all the |
| 30 | appropriate function calls. |
| 31 | |
| 32 | When a function call is generated, first temporaries are allocated |
| 33 | for all its arguments. Then the sub-expressions are compiled left to |
| 34 | right given these temporary locations as the outputs. For now we |
| 35 | will assume that everything is either a variable or a function |
| 36 | call, there will be no literals yet. |