project11 - template

This commit is contained in:
2025-11-09 14:17:18 -05:00
parent 713b916890
commit b1014cd561
12 changed files with 970 additions and 0 deletions

27
11/Average/Main.jack Normal file
View File

@@ -0,0 +1,27 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/11/Average/Main.jack
// Inputs some numbers and computes their average
class Main {
function void main() {
var Array a;
var int length;
var int i, sum;
let length = Keyboard.readInt("How many numbers? ");
let a = Array.new(length); // constructs the array
let i = 0;
while (i < length) {
let a[i] = Keyboard.readInt("Enter a number: ");
let sum = sum + a[i];
let i = i + 1;
}
do Output.printString("The average is ");
do Output.printInt(sum / length);
return;
}
}

View File

@@ -0,0 +1,69 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/11/ComplexArrays/Main.jack
/**
* Performs several complex array processing tests.
* For each test, the expected result is printed, along with the
* actual result. In each test, the two results should be equal.
*/
class Main {
function void main() {
var Array a, b, c;
let a = Array.new(10);
let b = Array.new(5);
let c = Array.new(1);
let a[3] = 2;
let a[4] = 8;
let a[5] = 4;
let b[a[3]] = a[3] + 3; // b[2] = 5
let a[b[a[3]]] = a[a[5]] * b[((7 - a[3]) - Main.double(2)) + 1]; // a[5] = 8 * 5 = 40
let c[0] = null;
let c = c[0];
do Output.printString("Test 1: expected result: 5; actual result: ");
do Output.printInt(b[2]);
do Output.println();
do Output.printString("Test 2: expected result: 40; actual result: ");
do Output.printInt(a[5]);
do Output.println();
do Output.printString("Test 3: expected result: 0; actual result: ");
do Output.printInt(c);
do Output.println();
let c = null;
if (c = null) {
do Main.fill(a, 10);
let c = a[3];
let c[1] = 33;
let c = a[7];
let c[1] = 77;
let b = a[3];
let b[1] = b[1] + c[1]; // b[1] = 33 + 77 = 110;
}
do Output.printString("Test 4: expected result: 77; actual result: ");
do Output.printInt(c[1]);
do Output.println();
do Output.printString("Test 5: expected result: 110; actual result: ");
do Output.printInt(b[1]);
do Output.println();
return;
}
function int double(int a) {
return a * 2;
}
function void fill(Array a, int size) {
while (size > 0) {
let size = size - 1;
let a[size] = Array.new(3);
}
return;
}
}

81
11/ConvertToBin/Main.jack Normal file
View File

@@ -0,0 +1,81 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/11/ConvertToBin/Main.jack
/**
* Unpacks a 16-bit number into its binary representation:
* Takes the 16-bit number stored in RAM[8000] and stores its individual
* bits in RAM[8001]..RAM[8016] (each location will contain 0 or 1).
* Before the conversion, RAM[8001]..RAM[8016] are initialized to -1.
*
* The program should be tested as follows:
* 1) Load the program into the supplied VM emulator
* 2) Put some value in RAM[8000]
* 3) Switch to "no animation"
* 4) Run the program (give it enough time to run)
* 5) Stop the program
* 6) Check that RAM[8001]..RAM[8016] contain the correct bits, and
* that none of these memory locations contains -1.
*/
class Main {
/**
* Initializes RAM[8001]..RAM[8016] to -1,
* and converts the value in RAM[8000] to binary.
*/
function void main() {
var int value;
do Main.fillMemory(8001, 16, -1); // sets RAM[8001]..RAM[8016] to -1
let value = Memory.peek(8000); // Uses an OS routine to read the input
do Main.convert(value); // performs the conversion
return;
}
/** Converts the given decimal value to binary, and puts
* the resulting bits in RAM[8001]..RAM[8016]. */
function void convert(int value) {
var int mask, position;
var boolean loop;
let loop = true;
while (loop) {
let position = position + 1;
let mask = Main.nextMask(mask);
if (~(position > 16)) {
if (~((value & mask) = 0)) {
do Memory.poke(8000 + position, 1);
}
else {
do Memory.poke(8000 + position, 0);
}
}
else {
let loop = false;
}
}
return;
}
/** Returns the next mask (the mask that should follow the given mask). */
function int nextMask(int mask) {
if (mask = 0) {
return 1;
}
else {
return mask * 2;
}
}
/** Fills 'length' consecutive memory locations with 'value',
* starting at 'address'. */
function void fillMemory(int address, int length, int value) {
while (length > 0) {
do Memory.poke(address, value);
let length = length - 1;
let address = address + 1;
}
return;
}
}

203
11/Pong/Ball.jack Normal file
View File

@@ -0,0 +1,203 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/11/Pong/Ball.jack
// (Same as projects/9/Pong/Ball.jack)
/**
* A graphical ball in a Pong game. Characterized by a screen location and
* distance of last destination. Has methods for drawing, erasing and moving
* on the screen. The ball is displayed as a filled, 6-by-6 pixles rectangle.
*/
class Ball {
field int x, y; // the ball's screen location (in pixels)
field int lengthx, lengthy; // distance of last destination (in pixels)
field int d, straightD, diagonalD; // used for straight line movement computation
field boolean invert, positivex, positivey; // (same)
field int leftWall, rightWall, topWall, bottomWall; // wall locations
field int wall; // last wall that the ball was bounced off of
/** Constructs a new ball with the given initial location and wall locations. */
constructor Ball new(int Ax, int Ay,
int AleftWall, int ArightWall, int AtopWall, int AbottomWall) {
let x = Ax;
let y = Ay;
let leftWall = AleftWall;
let rightWall = ArightWall - 6; // -6 for ball size
let topWall = AtopWall;
let bottomWall = AbottomWall - 6; // -6 for ball size
let wall = 0;
do show();
return this;
}
/** Deallocates the Ball's memory. */
method void dispose() {
do Memory.deAlloc(this);
return;
}
/** Shows the ball. */
method void show() {
do Screen.setColor(true);
do draw();
return;
}
/** Hides the ball. */
method void hide() {
do Screen.setColor(false);
do draw();
return;
}
/** Draws the ball. */
method void draw() {
do Screen.drawRectangle(x, y, x + 5, y + 5);
return;
}
/** Returns the ball's left edge. */
method int getLeft() {
return x;
}
/** Returns the ball's right edge. */
method int getRight() {
return x + 5;
}
/** Computes and sets the ball's destination. */
method void setDestination(int destx, int desty) {
var int dx, dy, temp;
let lengthx = destx - x;
let lengthy = desty - y;
let dx = Math.abs(lengthx);
let dy = Math.abs(lengthy);
let invert = (dx < dy);
if (invert) {
let temp = dx; // swap dx, dy
let dx = dy;
let dy = temp;
let positivex = (y < desty);
let positivey = (x < destx);
}
else {
let positivex = (x < destx);
let positivey = (y < desty);
}
let d = (2 * dy) - dx;
let straightD = 2 * dy;
let diagonalD = 2 * (dy - dx);
return;
}
/**
* Moves the ball one step towards its destination.
* If the ball has reached a wall, returns 0.
* Else, returns a value according to the wall:
* 1 (left wall), 2 (right wall), 3 (top wall), 4 (bottom wall).
*/
method int move() {
do hide();
if (d < 0) { let d = d + straightD; }
else {
let d = d + diagonalD;
if (positivey) {
if (invert) { let x = x + 4; }
else { let y = y + 4; }
}
else {
if (invert) { let x = x - 4; }
else { let y = y - 4; }
}
}
if (positivex) {
if (invert) { let y = y + 4; }
else { let x = x + 4; }
}
else {
if (invert) { let y = y - 4; }
else { let x = x - 4; }
}
if (~(x > leftWall)) {
let wall = 1;
let x = leftWall;
}
if (~(x < rightWall)) {
let wall = 2;
let x = rightWall;
}
if (~(y > topWall)) {
let wall = 3;
let y = topWall;
}
if (~(y < bottomWall)) {
let wall = 4;
let y = bottomWall;
}
do show();
return wall;
}
/**
* Bounces off the current wall: sets the new destination
* of the ball according to the ball's angle and the given
* bouncing direction (-1/0/1=left/center/right or up/center/down).
*/
method void bounce(int bouncingDirection) {
var int newx, newy, divLengthx, divLengthy, factor;
// Since results are too big, divides by 10
let divLengthx = lengthx / 10;
let divLengthy = lengthy / 10;
if (bouncingDirection = 0) { let factor = 10; }
else {
if (((~(lengthx < 0)) & (bouncingDirection = 1)) | ((lengthx < 0) & (bouncingDirection = (-1)))) {
let factor = 20; // bounce direction is in ball direction
}
else { let factor = 5; } // bounce direction is against ball direction
}
if (wall = 1) {
let newx = 506;
let newy = (divLengthy * (-50)) / divLengthx;
let newy = y + (newy * factor);
}
else {
if (wall = 2) {
let newx = 0;
let newy = (divLengthy * 50) / divLengthx;
let newy = y + (newy * factor);
}
else {
if (wall = 3) {
let newy = 250;
let newx = (divLengthx * (-25)) / divLengthy;
let newx = x + (newx * factor);
}
else { // assumes wall = 4
let newy = 0;
let newx = (divLengthx * 25) / divLengthy;
let newx = x + (newx * factor);
}
}
}
do setDestination(newx, newy);
return;
}
}

104
11/Pong/Bat.jack Normal file
View File

@@ -0,0 +1,104 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/11/Pong/Bat.jack
// (Same as projects/9/Pong/Bat.jack)
/**
* A graphical bat in a Pong game.
* Displayed as a filled horizontal rectangle that has a screen location,
* a width and a height.
* Has methods for drawing, erasing, moving left and right, and changing
* its width (to make the hitting action more challenging).
* This class should have been called "Paddle", following the
* standard Pong terminology. Unaware of this terminology,
* we called it "bat", and the name stuck.
*/
class Bat {
field int x, y; // the bat's screen location
field int width, height; // the bat's width and height
field int direction; // direction of the bat's movement
// (1 = left, 2 = right)
/** Constructs a new bat with the given location and width. */
constructor Bat new(int Ax, int Ay, int Awidth, int Aheight) {
let x = Ax;
let y = Ay;
let width = Awidth;
let height = Aheight;
let direction = 2;
do show();
return this;
}
/** Deallocates the object's memory. */
method void dispose() {
do Memory.deAlloc(this);
return;
}
/** Shows the bat. */
method void show() {
do Screen.setColor(true);
do draw();
return;
}
/** Hides the bat. */
method void hide() {
do Screen.setColor(false);
do draw();
return;
}
/** Draws the bat. */
method void draw() {
do Screen.drawRectangle(x, y, x + width, y + height);
return;
}
/** Sets the bat's direction (0=stop, 1=left, 2=right). */
method void setDirection(int Adirection) {
let direction = Adirection;
return;
}
/** Returns the bat's left edge. */
method int getLeft() {
return x;
}
/** Returns the bat's right edge. */
method int getRight() {
return x + width;
}
/** Sets the bat's width. */
method void setWidth(int Awidth) {
do hide();
let width = Awidth;
do show();
return;
}
/** Moves the bat one step in the bat's direction. */
method void move() {
if (direction = 1) {
let x = x - 4;
if (x < 0) { let x = 0; }
do Screen.setColor(false);
do Screen.drawRectangle((x + width) + 1, y, (x + width) + 4, y + height);
do Screen.setColor(true);
do Screen.drawRectangle(x, y, x + 3, y + height);
}
else {
let x = x + 4;
if ((x + width) > 511) { let x = 511 - width; }
do Screen.setColor(false);
do Screen.drawRectangle(x - 4, y, x - 1, y + height);
do Screen.setColor(true);
do Screen.drawRectangle((x + width) - 3, y, x + width, y + height);
}
return;
}
}

20
11/Pong/Main.jack Normal file
View File

@@ -0,0 +1,20 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/11/Pong/Main.jack
// (Same as projects/9/Pong/Main.jack)
/**
* Main class of the Pong game.
*/
class Main {
/** Initializes a Pong game and starts running it. */
function void main() {
var PongGame game;
do PongGame.newInstance();
let game = PongGame.getInstance();
do game.run();
do game.dispose();
return;
}
}

137
11/Pong/PongGame.jack Normal file
View File

@@ -0,0 +1,137 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/11/Pong/PongGame.jack
// (Same as projects/9/Pong/PongGame.jack)
/**
* Represents a Pong game.
*/
class PongGame {
static PongGame instance; // A Pong game
field Bat bat; // bat
field Ball ball; // ball
field int wall; // current wall that the ball is bouncing off of
field boolean exit; // true when the game is over
field int score; // current score
field int lastWall; // last wall that the ball bounced off of
// The current width of the bat
field int batWidth;
/** Constructs a new Pong game. */
constructor PongGame new() {
do Screen.clearScreen();
let batWidth = 50; // initial bat size
let bat = Bat.new(230, 229, batWidth, 7);
let ball = Ball.new(253, 222, 0, 511, 0, 229);
do ball.setDestination(400,0);
do Screen.drawRectangle(0, 238, 511, 240);
do Output.moveCursor(22,0);
do Output.printString("Score: 0");
let exit = false;
let score = 0;
let wall = 0;
let lastWall = 0;
return this;
}
/** Deallocates the object's memory. */
method void dispose() {
do bat.dispose();
do ball.dispose();
do Memory.deAlloc(this);
return;
}
/** Creates an instance of a Pong game. */
function void newInstance() {
let instance = PongGame.new();
return;
}
/** Returns this Pong game. */
function PongGame getInstance() {
return instance;
}
/** Starts the game, and handles inputs from the user that control
* the bat's movement direction. */
method void run() {
var char key;
while (~exit) {
// waits for a key to be pressed.
while ((key = 0) & (~exit)) {
let key = Keyboard.keyPressed();
do bat.move();
do moveBall();
do Sys.wait(50);
}
if (key = 130) { do bat.setDirection(1); }
else {
if (key = 132) { do bat.setDirection(2); }
else {
if (key = 140) { let exit = true; }
}
}
// Waits for the key to be released.
while ((~(key = 0)) & (~exit)) {
let key = Keyboard.keyPressed();
do bat.move();
do moveBall();
do Sys.wait(50);
}
}
if (exit) {
do Output.moveCursor(10,27);
do Output.printString("Game Over");
}
return;
}
/**
* Handles ball movement, including bouncing.
* If the ball bounces off a wall, finds its new direction.
* If the ball bounces off the bat, increases the score by one
* and shrinks the bat's size, to make the game more challenging.
*/
method void moveBall() {
var int bouncingDirection, batLeft, batRight, ballLeft, ballRight;
let wall = ball.move();
if ((wall > 0) & (~(wall = lastWall))) {
let lastWall = wall;
let bouncingDirection = 0;
let batLeft = bat.getLeft();
let batRight = bat.getRight();
let ballLeft = ball.getLeft();
let ballRight = ball.getRight();
if (wall = 4) {
let exit = (batLeft > ballRight) | (batRight < ballLeft);
if (~exit) {
if (ballRight < (batLeft + 10)) { let bouncingDirection = -1; }
else {
if (ballLeft > (batRight - 10)) { let bouncingDirection = 1; }
}
let batWidth = batWidth - 2;
do bat.setWidth(batWidth);
let score = score + 1;
do Output.moveCursor(22,7);
do Output.printInt(score);
}
}
do ball.bounce(bouncingDirection);
}
return;
}
}

16
11/Seven/Main.jack Normal file
View File

@@ -0,0 +1,16 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/11/Seven/Main.jack
/**
* Computes the value of 1 + (2 * 3) and prints the result
* at the top-left of the screen.
*/
class Main {
function void main() {
do Output.printInt(1 + (2 * 3));
return;
}
}

15
11/Square/Main.jack Normal file
View File

@@ -0,0 +1,15 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/11/Square/Main.jack
/** Initializes a new Square game and starts running it. */
class Main {
function void main() {
var SquareGame game;
let game = SquareGame.new();
do game.run();
do game.dispose();
return;
}
}

113
11/Square/Square.jack Normal file
View File

@@ -0,0 +1,113 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/11/Square/Square.jack
/** Implements a graphical square.
The square has top-left x and y coordinates, and a size. */
class Square {
field int x, y; // screen location of the top-left corner of this square
field int size; // length of this square, in pixels
/** Constructs and draws a new square with a given location and size. */
constructor Square new(int ax, int ay, int asize) {
let x = ax;
let y = ay;
let size = asize;
do draw();
return this;
}
/** Disposes this square. */
method void dispose() {
do Memory.deAlloc(this);
return;
}
/** Draws this square in its current (x,y) location */
method void draw() {
// Draws the square using the color black
do Screen.setColor(true);
do Screen.drawRectangle(x, y, x + size, y + size);
return;
}
/** Erases this square. */
method void erase() {
// Draws the square using the color white (background color)
do Screen.setColor(false);
do Screen.drawRectangle(x, y, x + size, y + size);
return;
}
/** Increments the square size by 2 pixels (if possible). */
method void incSize() {
if (((y + size) < 254) & ((x + size) < 510)) {
do erase();
let size = size + 2;
do draw();
}
return;
}
/** Decrements the square size by 2 pixels (if possible). */
method void decSize() {
if (size > 2) {
do erase();
let size = size - 2;
do draw();
}
return;
}
/** Moves this square up by 2 pixels (if possible). */
method void moveUp() {
if (y > 1) {
// Erases the bottom two rows of this square in its current location
do Screen.setColor(false);
do Screen.drawRectangle(x, (y + size) - 1, x + size, y + size);
let y = y - 2;
// Draws the top two rows of this square in its new location
do Screen.setColor(true);
do Screen.drawRectangle(x, y, x + size, y + 1);
}
return;
}
/** Moves the square down by 2 pixels (if possible). */
method void moveDown() {
if ((y + size) < 254) {
do Screen.setColor(false);
do Screen.drawRectangle(x, y, x + size, y + 1);
let y = y + 2;
do Screen.setColor(true);
do Screen.drawRectangle(x, (y + size) - 1, x + size, y + size);
}
return;
}
/** Moves the square left by 2 pixels (if possible). */
method void moveLeft() {
if (x > 1) {
do Screen.setColor(false);
do Screen.drawRectangle((x + size) - 1, y, x + size, y + size);
let x = x - 2;
do Screen.setColor(true);
do Screen.drawRectangle(x, y, x + 1, y + size);
}
return;
}
/** Moves the square right by 2 pixels (if possible). */
method void moveRight() {
if ((x + size) < 510) {
do Screen.setColor(false);
do Screen.drawRectangle(x, y, x + 1, y + size);
let x = x + 2;
do Screen.setColor(true);
do Screen.drawRectangle((x + size) - 1, y, x + size, y + size);
}
return;
}
}

76
11/Square/SquareGame.jack Normal file
View File

@@ -0,0 +1,76 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/11/Square/SquareGame.jack
/**
* Implements the Square game.
* This simple game allows the user to move a black square around
* the screen, and change the square's size during the movement.
* When the game starts, a square of 30 by 30 pixels is shown at the
* top-left corner of the screen. The user controls the square as follows.
* The 4 arrow keys are used to move the square up, down, left, and right.
* The 'z' and 'x' keys are used, respectively, to decrement and increment
* the square's size. The 'q' key is used to quit the game.
*/
class SquareGame {
field Square square; // the square of this game
field int direction; // the square's current direction:
// 0=none, 1=up, 2=down, 3=left, 4=right
/** Constructs a new square game. */
constructor SquareGame new() {
// The initial square is located in (0,0), has size 30, and is not moving.
let square = Square.new(0, 0, 30);
let direction = 0;
return this;
}
/** Disposes this game. */
method void dispose() {
do square.dispose();
do Memory.deAlloc(this);
return;
}
/** Moves the square in the current direction. */
method void moveSquare() {
if (direction = 1) { do square.moveUp(); }
if (direction = 2) { do square.moveDown(); }
if (direction = 3) { do square.moveLeft(); }
if (direction = 4) { do square.moveRight(); }
do Sys.wait(5); // delays the next movement
return;
}
/** Runs the game: handles the user's inputs and moves the square accordingly */
method void run() {
var char key; // the key currently pressed by the user
var boolean exit;
let exit = false;
while (~exit) {
// waits for a key to be pressed
while (key = 0) {
let key = Keyboard.keyPressed();
do moveSquare();
}
if (key = 81) { let exit = true; } // q key
if (key = 90) { do square.decSize(); } // z key
if (key = 88) { do square.incSize(); } // x key
if (key = 131) { let direction = 1; } // up arrow
if (key = 133) { let direction = 2; } // down arrow
if (key = 130) { let direction = 3; } // left arrow
if (key = 132) { let direction = 4; } // right arrow
// waits for the key to be released
while (~(key = 0)) {
let key = Keyboard.keyPressed();
do moveSquare();
}
} // while
return;
}
}

109
11/readme.txt Normal file
View File

@@ -0,0 +1,109 @@
Project 11
The compiler built in Nand to Tetris consists of two main modules: a Syntax Analyzer, built in
project 10, and a Code Generator, built in this project. The former module is the point of departure
for the latter module. In particular, in this project you will morph the Syntax Analyzer built in
project 10 into a full-scale Jack compiler. You will do it by gradually replacing the routines that
generate passive XML output with routines that generate executable VM code.
Objective
Extend the Syntax Analyzer built in chapter 10 into a full-scale Jack compiler. Apply your evolving
compiler to all the test programs described below. Execute each translated program, and make
sure that it operates according to its given documentation. This version of the compiler assumes
that the source Jack code is error-free.
Resources
The main tool that you need is the programming language in which you will implement the
compiler. You will also need the supplied VM emulator, for testing the VM code generated by your
compiler. Since the compiler is implemented by extending the syntax analyzer built in project 10,
you will also need the analyzer's source code.
Implementation Stages
We propose completing the compilers development in two main stages: Symbol Table, and Code
Generation.
Stage 0: Make a back-up copy of the syntax analyzer code developed in project 10.
Stage 1: Symbol Table: Start by building the compilers SymbolTable module, and use it for
extending the syntax analyzer built in Project 10, as follows. Presently, whenever an identifier is
encountered in the source code, say foo, the syntax analyzer outputs the XML line <identifier> foo
</identifier>. Extend your analyzer to output the following information about each identifier:
name;
category (field, static, local, arg, class, subroutine);
index: if the identifiers category is field, static, local, or arg,
the running index assigned to the identifier by the symbol table;
usage: whether the identifier is presently being declared (in a static / field / var variable declaration,
or in a parameter list), or used (in an expression).
Have your syntax analyzer output this information as part of its XML output, using markup tags of
your choice.
Test your new SymbolTable module and the new functionality just described by running your
extended syntax analyzer on the test Jack programs supplied in project 10. If your extended syntax
analyzer is capable of outputting the information described above, it means that you've developed
a complete executable capability to understand the semantics of Jack programs. At this stage you
www.nand2tetris.org / Copyright © Noam Nisan and Shimon Schocken
can make the switch to developing the full-scale compiler, and start generating VM code instead of
XML output. This can be done gradually, as we now turn to describe.
Stage 1.5: Make a back-up copy of the extended syntax analyzer code.
Stage 2: Code Generation: We provide six Jack programs, designed to gradually unit-test the code
generation capabilities of your compiler. We advise to develop, and test, your evolving compiler on
the test programs in the order given below. This way, you will be implicitly guided to build the
compilers code generation capabilities in sensible stages, according to the demands presented by
each test program.
Normally, when one compiles a high-level program and runs into some difficulties, one concludes
that the program is screwed up. In this project the setting is exactly the opposite. All the supplied
test programs are error-free. Therefore, if their compilation yields any errors, its the compiler that
you have to fix, not the programs. Specifically, for each test program, we recommend going
through the following routine:
1. Compile the program folder using the compiler that you are developing. This action should
generate one .vm file for each source .jack file in the given folder.
2. Inspect the generated VM files. If there are visible problems, fix your compiler and go to step 1.
Remember: All the supplied test programs are error-free.
3. Load the program folder into the emulator, and run the loaded code. Note that each one of the
six supplied test programs contains specific execution guidelines; test the compiled program
(translated VM code) according to these guidelines.
4. If the program behaves unexpectedly, or some error message is displayed by the VM emulator,
fix your compiler and go to step 1.
Test Programs
Seven: Tests how the compiler handles a simple program containing an arithmetic expression with
integer constants but without variables, a do statement, and a return statement. Specifically, the
program computes the expression 1 + (3 * 2) and prints its value at the top left of the screen. To
test that your compiler has translated the program correctly, run the translated code in the VM
emulator and verify that it displays 7 correctly.
ConvertToBin: Tests how the compiler handles all the procedural elements of the Jack language:
expressions (without arrays or method calls), functions, and the statements if, while, do, let and
return. The program does not test the handling of methods, constructors, arrays, strings, static
variables, and field variables. Specifically, the program gets a 16-bit decimal value from RAM[8000],
converts it to binary, and stores the individual bits in RAM[8001],...,RAM[8016] (each location will
contain 0 or 1). Before the conversion starts, the program initializes RAM[8001],...,RAM[8016] to
-1. To test that your compiler has translated the program correctly, load the translated code into
the VM emulator, and proceed as follows:
Enter (interactively, using the simulators GUI) some decimal value in RAM[8000];
www.nand2tetris.org / Copyright © Noam Nisan and Shimon Schocken
Run the program for a few seconds, then stop its execution;
Check (by visual inspection) that memory locations RAM[8001],...,RAM[8016] contain the correct
bits, and that none of them contains -1.
Square (same as projects/9/Square): Tests how the compiler handles the object-based features of
the Jack language: constructors, methods, fields, and expressions that include method calls. Does
not test the handling of static variables. Specifically, the program launches a simple interactive
"game" that enables moving a black square around the screen, using the keyboards four arrow
keys. While moving, the size of the square can be increased and decreased anytime by pressing the
'z' and 'x' keys, respectively. To quit the game, press the 'q' key. To test that your compiler has
translated the program correctly, run the translated code in the VM emulator and verify that the
game unfolds as expected (to play the game, select “no animation” and set the speed slider as
needed).
Average (same as projects/9/Average and projects/10/ArrayTest): : Tests how the compiler handles
arrays, and strings. This is done by computing the average of a user-supplied sequence of integers.
To test that your compiler has translated the program correctly, run the translated code in the VM
emulator and follow the instructions displayed on the screen.
Pong: A complete test of how the compiler handles an object-based application, including the
handling of objects and static variables. In the classical Pong game, a ball is moving randomly,
bouncing off the screen "walls." The user tries to hit the ball with a small paddle which can be
moved by pressing the keyboards left and right arrow keys. Each time the paddle hits the ball, the
user scores a point and the paddle shrinks a little, making the game increasingly more challenging.
If the user misses and the ball hits the “floor”, the game is over. To test that your compiler has
translated this program correctly, run the translated code in the VM emulator and play the game.
Make sure to score some points, to test the part of the program that displays the score on the
screen (to play the game, select “no animation” and set the speed slider as needed).
ComplexArrays: Tests how the compiler handles complex array references, and expressions. To
that end, the program performs five complex calculations using arrays. For each such calculation,
the program prints on the screen the expected result, along with the actual result, as performed by
the compiled program. To test that your compiler has translated the program correctly, run the
translated code in the VM emulator and make sure that the expected and actual results are
identical.