Finish readme and add pngs

This commit is contained in:
Felix Martin 2020-11-15 16:52:02 -05:00
parent 01e43dfba0
commit 143301f3d4
6 changed files with 177 additions and 0 deletions

View File

@ -91,4 +91,103 @@ translate individual asm-files and does not search a directory.
Load the resulting hack file into the CPU emulator to verify that the
assembler works correctly.
## Project 7/8: VM Translator
At this point, we have finished the hardware part of our computer and can
program it via the Hack assembly language. Of course, a higher-level programming
language is desirable to write programs more comfortably. Therefore, our goal
is to implement the high-level programming language *Jack* and compile it down
into Hack assembly.
We use a two-step compilation process. First, we translate the Jack code into VM
code, which we then translate further into Hack assembly. The goal of projects 7
and 8 is to implement the VM translator in a programming language of our choice.
Even though Python is my primary language, and I would have been faster using
it, I decided to opt for Rust, a language that I hadn't used before. Rust comes
with a flourishing eco-system and static typing that came in handy for this
project.
My VM translator ended up with just under 900 lines of code. A considerable part
of that is the template Hack assembly code that the translator fills with
registers and addresses. I would have opted for the Jinja2 templating language
in Python, but instead, I used in-code strings combined with "format!\". While
this looks ugly at times, it avoids external dependencies. The approach is okay
for this course, but a template engine would have been desirable for a
real-world project.
To run the VM translator, switch into the `./vm_translator directory` and
execute `cargo build`. You can then execute
`./vm_translator/target/debug/vm_translator` on one of the example projects in
`./projects/08`.
I was happy with my choice to learn Rust even though I spent too much time
figuring out trivial things like how to read a file.
## Project 9: High-Level Language
With the VM translator in place, it is now time to understand the high-level
Jack languaged by implementing a project. I decided to implement a 1D cellular
automation in `./projects/09/CellAutomaton1D`. To run the program first compile
the project by running `./tool/JackCompiler.sh ./projects/09/CellAutomaton1D`.
Then, start the Virtual Machine Emulator and open the project. Make sure to
select the directory `CellAutomaton1D` and not one of the VM files.
![A 1D cellular automaton on the Hack computer](gifs/automaton_drawing.png)
The program consists of two parts. First, you configure the initial population
using Vim key bindings, and then the program simulates the selected rule. You
have the option to pause and single step the simulation.
![The menu for the automaton](gifs/automaton_menu.png)
I have also implemented Vim syntax highlighting for the jack programming
language. The best thing is that Vim yells at you when you forgot one of
the keywords, like let or do. And you will forget them all the time.
Simple put [jack.vim](vim/jack.vim) into your Vim's syntax
directory, and you should be good to go.
![Jack syntax highlighting in Vim](gifs/vim_jack_syntax.png)
## Project 10/11: Compiler
With a solid understanding of the Jack programming language, we are now ready to
implement the compiler. I opted for Rust again and had a great time. The
directory `jack_analyzer` contains the tokenizer and parser, which outputs an
XML syntax tree. In project 11, we use the analyzer to generate VM code. The
resulting Rust project is in the directory `jack_compiler`. To compile the
project, change into the directory and execute `cargo build`.
You can now recompile the cellular automaton by running the following command:
~~~
./jack_compiler/target/debug/jack_compiler projects/09/CellAutomaton1D
~~~
I honestly was happy with my decision to opt for Rust again. While the project
would undoubtedly have been manageable in Python, static typing made it so much
easier to cover all cases for keywords and tokens. The compiler has a little
over 1000 lines of code. That sounds pretty decent.
![Number of source code lines for the compiler](gifs/compiler_loc.png)
## Project 12: The Operating System
With the compiler in place, the last step is implementing the OS functionality
that previously came from the Virtual Machine Emulator. In particular, there is
a library for string handling, memory management, array handling, math
(multiplication and division), and display routines to draw characters and
geometric forms.
I particularly enjoy seeing how much effort goes into simple routines like
multiplication and division. Of course, as a high-level programmer, you take
these operations for granted but getting into the details of how to implement
them is rewarding. I still learned a lot, even for this last project.
## Conclusion
Nand to Tetris is one of my favorite classes of all time. I highly recommend it
to everybody who works in computer science and feels like they only partially
understand how a computer works. I certainly got many new insights throughout
the course, and I learned a new programming language, Rust, which I should use
more often over Python.

BIN
gifs/automaton_drawing.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

BIN
gifs/automaton_menu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

BIN
gifs/compiler_loc.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
gifs/vim_jack_syntax.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

78
vim/jack.vim Normal file
View File

@ -0,0 +1,78 @@
if exists("b:current_syntax")
finish
endif
syntax match jackError "\v^\s*[A-Za-z_]+"
syntax match jackIdentifier "\v<Math>"
syntax match jackIdentifier "\v<String>"
syntax match jackIdentifier "\v<Array>"
syntax match jackIdentifier "\v<Output>"
syntax match jackIdentifier "\v<Screen>"
syntax match jackIdentifier "\v<Keyboard>"
syntax match jackIdentifier "\v<Memory>"
syntax match jackIdentifier "\v<Sys>"
syntax match jackKeyword "\v\s*<class>"
syntax match jackFunction "\v\s*<constructor>"
syntax match jackFunction "\v\s*<method>"
syntax match jackFunction "\v\s*<function>"
syntax match jackType "\v<int>"
syntax match jackType "\v<boolean>"
syntax match jackType "\v<char>"
syntax match jackType "\v<void>"
syntax match jackKeyword "\v\s*<var>"
syntax match jackKeyword "\v\s*<static>"
syntax match jackKeyword "\v\s*<field>"
syntax match jackConditional "\v\s*<let>"
syntax match jackConditional "\v\s*<do>"
syntax match jackConditional "\v\s*<if>"
syntax match jackConditional "\v\s*<else>"
syntax match jackConditional "\v\s*<while>"
syntax match jackConditional "\v\s*<return>"
syntax match jackConstant "\v<true>"
syntax match jackConstant "\v<false>"
syntax match jackConstant "\v<null>"
syntax match jackKeyword "\v<this>"
syntax match jackOperator "\v\+"
syntax match jackOperator "\v-"
syntax match jackOperator "\v\*"
syntax match jackOperator "\v/"
syntax match jackOperator "\v\&"
syntax match jackOperator "\v\|"
syntax match jackOperator "\v\~"
syntax match jackOperator "\v\<"
syntax match jackOperator "\v\>"
syntax match jackNumber "\v<([1-9][0-9]*|[0-9])>"
syntax region jackString start=/\v"/ skip=/\v\\./ end=/\v"/
syntax match jackTodo "\vTODO:?" contained
syntax match jackTodo "\vFIXME:?" contained
syntax match jackTodo "\vXXX:?" contained
syntax match jackComment "\v//.*$" contains=jackTodo
syntax region jackComment start="\v/\*\*" end="\v\*/" contains=jackTodo
syntax region jackComment start="\v/\*" end="\v\*/" contains=jackTodo
highlight link jackError Error
highlight link jackIdentifier Identifier
highlight link jackString String
highlight link jackComment Comment
highlight link jackTodo Todo
highlight link jackFunction Function
highlight link jackConditional Conditional
highlight link jackType Type
highlight link jackConstant Constant
highlight link jackOperator Operator
highlight link jackKeyword Keyword
highlight link jackString String
highlight link jackNumber Number
let b:current_syntax = "jack"