From d3a0cc3a8ba6dfeb64d3faeffdeb6845b60e5840 Mon Sep 17 00:00:00 2001 From: Yuchen Pei Date: Sat, 20 Jan 2018 15:41:49 +0100 Subject: rearranged the dir for github - removed tools and pdfs - rearranged the projects dirs - added md files - other minor changes --- jackos/Array.jack | 26 +++++ jackos/Keyboard.jack | 97 ++++++++++++++++++ jackos/Math.jack | 158 +++++++++++++++++++++++++++++ jackos/Memory.jack | 72 +++++++++++++ jackos/Output.jack | 281 +++++++++++++++++++++++++++++++++++++++++++++++++++ jackos/Screen.jack | 138 +++++++++++++++++++++++++ jackos/String.jack | 176 ++++++++++++++++++++++++++++++++ jackos/Sys.jack | 51 ++++++++++ 8 files changed, 999 insertions(+) create mode 100644 jackos/Array.jack create mode 100644 jackos/Keyboard.jack create mode 100644 jackos/Math.jack create mode 100644 jackos/Memory.jack create mode 100644 jackos/Output.jack create mode 100644 jackos/Screen.jack create mode 100644 jackos/String.jack create mode 100644 jackos/Sys.jack (limited to 'jackos') diff --git a/jackos/Array.jack b/jackos/Array.jack new file mode 100644 index 0000000..343c25c --- /dev/null +++ b/jackos/Array.jack @@ -0,0 +1,26 @@ +// 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/12/Array.jack + +/** + * Represents an array. + * In the Jack language, arrays are instances of the Array class. + * Once declared, the array entries can be accessed using the usual + * syntax arr[i]. Each array entry can hold a primitive data type as + * well as any object type. Different array entries can have different + * data types. + */ +class Array { + + /** Constructs a new Array of the given size. */ + function Array new(int size) { + return Memory.alloc(size); + } + + /** Disposes this array. */ + method void dispose() { + do Memory.deAlloc(this); + return; + } +} diff --git a/jackos/Keyboard.jack b/jackos/Keyboard.jack new file mode 100644 index 0000000..a35704a --- /dev/null +++ b/jackos/Keyboard.jack @@ -0,0 +1,97 @@ +// 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/12/Keyboard.jack + +/** + * A library for handling user input from the keyboard. + */ +class Keyboard { + + /** Initializes the keyboard. */ + function void init() { + return; + } + + /** + * Returns the character of the currently pressed key on the keyboard; + * if no key is currently pressed, returns 0. + * + * Recognizes all ASCII characters, as well as the following keys: + * new line = 128 = String.newline() + * backspace = 129 = String.backspace() + * left arrow = 130 + * up arrow = 131 + * right arrow = 132 + * down arrow = 133 + * home = 134 + * End = 135 + * page up = 136 + * page down = 137 + * insert = 138 + * delete = 139 + * ESC = 140 + * F1 - F12 = 141 - 152 + */ + function char keyPressed() { + return Memory.peek(24576); + } + + /** + * Waits until a key is pressed on the keyboard and released, + * then echoes the key to the screen, and returns the character + * of the pressed key. + */ + function char readChar() { + var int key, key1; + let key = 0; + while (key = 0) { + let key = Memory.peek(24576); + } + let key1 = key; + while (key1 = key) { + let key1 = Memory.peek(24576); + } + if ((key > 31) & (key < 127) | (key = 128) | (key = 129)) { + do Output.printChar(key); + } + return key; + } + + /** + * Displays the message on the screen, reads from the keyboard the entered + * text until a newline character is detected, echoes the text to the screen, + * and returns its value. Also handles user backspaces. + */ + function String readLine(String message) { + var int c; + var String s; + let s = String.new(140); + do Output.printString(message); + let c = Keyboard.readChar(); + while (~(c = 128)) { + if (c = 129) { + if (s.length() > 0) { + do s.eraseLastChar(); + } + } else { + do s.appendChar(c); + } + let c = Keyboard.readChar(); + } + return s; + } + + /** + * Displays the message on the screen, reads from the keyboard the entered + * text until a newline character is detected, echoes the text to the screen, + * and returns its integer value (until the first non-digit character in the + * entered text is detected). Also handles user backspaces. + */ + function int readInt(String message) { + var String s; + do Output.printString(message); + let s = Keyboard.readLine(""); + return s.intValue(); + } +} diff --git a/jackos/Math.jack b/jackos/Math.jack new file mode 100644 index 0000000..01bce8f --- /dev/null +++ b/jackos/Math.jack @@ -0,0 +1,158 @@ +// 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/12/Math.jack + +/** + * A library of commonly used mathematical functions. + * Note: Jack compilers implement multiplication and division using OS method calls. + */ +class Math { + static Array twoToThe; + + /** Initializes the library. */ + function void init() { + var int i, x; + let x = 1; + let i = 0; + let twoToThe = Array.new(16); + while (i < 16){ + let twoToThe[i] = x; + let x = x + x; + let i = i + 1; + } + return; + } + + function boolean bit(int x, int i) { + return ~(x & twoToThe[i] = 0); + } + + function int sign(int x) { + if (x > 0) { + return 1; + } else { + if (x < 0) { + return -1; + } else { + return 0; + } + } + } + + /** Returns the absolute value of x. */ + function int abs(int x) { + if (x > 0){ + return x; + } else { + return -x; + } + } + + /** Returns the product of x and y. + * When a Jack compiler detects the multiplication operator '*' in the + * program's code, it handles it by invoking this method. In other words, + * the Jack expressions x*y and multiply(x,y) return the same value. + */ + function int multiply(int x, int y) { + var int res, shiftedX, i; + let shiftedX = x; + let i = 0; + let res = 0; + //while ((~(twoToThe[i] > y)) & (i < 16)) { + while (i < 16) { + if (Math.bit(y, i)){ + let res = res + shiftedX; + } + let shiftedX = shiftedX + shiftedX; + let i = i + 1; + } + return res; + } + + /** Returns the integer part of x/y. + * When a Jack compiler detects the multiplication operator '/' in the + * program's code, it handles it by invoking this method. In other words, + * the Jack expressions x/y and divide(x,y) return the same value. + */ + function int divide(int x, int y) { + var int ax, ay; + if (x > 0) { + if (y > 0) { + return Math.divide1(x, y); + } else { + return -Math.divide1(x, -y); + } + } else { + if (y > 0) { + return -Math.divide1(-x, y); + } else { + return Math.divide1(-x, -y); + } + } + } + + function int divide1(int x, int y) { + var int q; + if (y = 0) { + do Output.printString("Error: division by zero."); + do Sys.error(0); + } + if ((y > x) | (y < 0)) { + return 0; + } + let q = Math.divide1(x, y * 2); + if (x - (2 * q * y) < y) { + return 2 * q; + } else { + return 2 * q + 1; + } + } + + function int length(int x){ + var int n; + let n = 14; + while (twoToThe[n] > x){ + let n = n - 1; + } + return n; + } + + /** Returns the integer part of the square root of x. */ + function int sqrt(int x) { + var int y, k, z, w; + if (x < 0) { + do Output.printString("Error: square rooting a negative number."); + do Sys.error(0); + } + let k = Math.length(x) / 2; + let y = 0; + while (~(k < 0)) { + let z = y + twoToThe[k]; + let w = z * z; + if ((~(w > x)) & (w > 0)) { + let y = z; + } + let k = k - 1; + } + return y; + } + + /** Returns the greater number. */ + function int max(int a, int b) { + if (a > b) { + return a; + } else { + return b; + } + } + + /** Returns the smaller number. */ + function int min(int a, int b) { + if (a < b) { + return a; + } else { + return b; + } + } +} diff --git a/jackos/Memory.jack b/jackos/Memory.jack new file mode 100644 index 0000000..54e04aa --- /dev/null +++ b/jackos/Memory.jack @@ -0,0 +1,72 @@ +// 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/12/Memory.jack + +/** + * This library provides two services: direct access to the computer's main + * memory (RAM), and allocation and recycling of memory blocks. The Hack RAM + * consists of 32,768 words, each holding a 16-bit binary number. + */ +class Memory { + static Array memory; + static Array heap; + static int last; + + /** Initializes the class. */ + function void init() { + let memory = 0; + let heap = 2048; + let heap[0] = -1; + let heap[1] = 14334; + let last = 0; + return; + } + + /** Returns the RAM value at the given address. */ + function int peek(int address) { + return memory[address]; + } + + /** Sets the RAM value at the given address to the given value. */ + function void poke(int address, int value) { + let memory[address] = value; + return; + } + + /** Finds an available RAM block of the given size and returns + * a reference to its base address. */ + function int alloc(int size) { + var int current; + var int size2; + var int newLast; + let current = 0; + let size2 = size + 2; + while ((current > -1) & (heap[current + 1] < size2)) { + let current = heap[current]; + } + if (current = -1) { + do String.println("Insufficient space for allocation!"); + do Sys.error(1); + return -1; + } else { + let heap[current + 1] = heap[current + 1] - size2; + let newLast = current + heap[current + 1] + 2; + let heap[newLast] = heap[current]; + let heap[current] = newLast; + let heap[newLast + 1] = size; + return heap + newLast + 2; + } + } + + /** De-allocates the given object (cast as an array) by making + * it available for future allocations. */ + function void deAlloc(Array o) { + var int oBase; + let oBase = o - heap - 2; + let heap[oBase] = -1; + let heap[last] = oBase; + let last = oBase; + return; + } +} diff --git a/jackos/Output.jack b/jackos/Output.jack new file mode 100644 index 0000000..61b24de --- /dev/null +++ b/jackos/Output.jack @@ -0,0 +1,281 @@ +// 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/12/Output.jack + +/** + * A library of functions for writing text on the screen. + * The Hack physical screen consists of 512 rows of 256 pixels each. + * The library uses a fixed font, in which each character is displayed + * within a frame which is 11 pixels high (including 1 pixel for inter-line + * spacing) and 8 pixels wide (including 2 pixels for inter-character spacing). + * The resulting grid accommodates 23 rows (indexed 0..22, top to bottom) + * of 64 characters each (indexed 0..63, left to right). The top left + * character position on the screen is indexed (0,0). A cursor, implemented + * as a small filled square, indicates where the next character will be displayed. + */ +class Output { + + // Character map for displaying characters + static Array charMaps; + static int cursorI, cursorJ; + + /** Initializes the screen, and locates the cursor at the screen's top-left. */ + function void init() { + do Output.initMap(); + do Output.moveCursor(0, 0); + return; + } + + // Initializes the character map array + function void initMap() { + var int i; + + let charMaps = Array.new(127); + + // Black square, used for displaying non-printable characters. + do Output.create(0,63,63,63,63,63,63,63,63,63,0,0); + + // Assigns the bitmap for each character in the charachter set. + // The first parameter is the character index, the next 11 numbers + // are the values of each row in the frame that represents this character. + do Output.create(32,0,0,0,0,0,0,0,0,0,0,0); // + do Output.create(33,12,30,30,30,12,12,0,12,12,0,0); // ! + do Output.create(34,54,54,20,0,0,0,0,0,0,0,0); // " + do Output.create(35,0,18,18,63,18,18,63,18,18,0,0); // # + do Output.create(36,12,30,51,3,30,48,51,30,12,12,0); // $ + do Output.create(37,0,0,35,51,24,12,6,51,49,0,0); // % + do Output.create(38,12,30,30,12,54,27,27,27,54,0,0); // & + do Output.create(39,12,12,6,0,0,0,0,0,0,0,0); // ' + do Output.create(40,24,12,6,6,6,6,6,12,24,0,0); // ( + do Output.create(41,6,12,24,24,24,24,24,12,6,0,0); // ) + do Output.create(42,0,0,0,51,30,63,30,51,0,0,0); // * + do Output.create(43,0,0,0,12,12,63,12,12,0,0,0); // + + do Output.create(44,0,0,0,0,0,0,0,12,12,6,0); // , + do Output.create(45,0,0,0,0,0,63,0,0,0,0,0); // - + do Output.create(46,0,0,0,0,0,0,0,12,12,0,0); // . + do Output.create(47,0,0,32,48,24,12,6,3,1,0,0); // / + + do Output.create(48,12,30,51,51,51,51,51,30,12,0,0); // 0 + do Output.create(49,12,14,15,12,12,12,12,12,63,0,0); // 1 + do Output.create(50,30,51,48,24,12,6,3,51,63,0,0); // 2 + do Output.create(51,30,51,48,48,28,48,48,51,30,0,0); // 3 + do Output.create(52,16,24,28,26,25,63,24,24,60,0,0); // 4 + do Output.create(53,63,3,3,31,48,48,48,51,30,0,0); // 5 + do Output.create(54,28,6,3,3,31,51,51,51,30,0,0); // 6 + do Output.create(55,63,49,48,48,24,12,12,12,12,0,0); // 7 + do Output.create(56,30,51,51,51,30,51,51,51,30,0,0); // 8 + do Output.create(57,30,51,51,51,62,48,48,24,14,0,0); // 9 + + do Output.create(58,0,0,12,12,0,0,12,12,0,0,0); // : + do Output.create(59,0,0,12,12,0,0,12,12,6,0,0); // ; + do Output.create(60,0,0,24,12,6,3,6,12,24,0,0); // < + do Output.create(61,0,0,0,63,0,0,63,0,0,0,0); // = + do Output.create(62,0,0,3,6,12,24,12,6,3,0,0); // > + do Output.create(64,30,51,51,59,59,59,27,3,30,0,0); // @ + do Output.create(63,30,51,51,24,12,12,0,12,12,0,0); // ? + + do Output.create(65,12,12,30,30,51,51,63,51,51,0,0); // A + do Output.create(66,31,51,51,51,31,51,51,51,31,0,0); // B + do Output.create(67,28,54,35,3,3,3,35,54,28,0,0); // C + do Output.create(68,15,27,51,51,51,51,51,27,15,0,0); // D + do Output.create(69,63,51,35,11,15,11,35,51,63,0,0); // E + do Output.create(70,63,51,35,11,15,11,3,3,3,0,0); // F + do Output.create(71,28,54,35,3,59,51,51,54,44,0,0); // G + do Output.create(72,51,51,51,51,63,51,51,51,51,0,0); // H + do Output.create(73,30,12,12,12,12,12,12,12,30,0,0); // I + do Output.create(74,60,24,24,24,24,24,27,27,14,0,0); // J + do Output.create(75,51,51,51,27,15,27,51,51,51,0,0); // K + do Output.create(76,3,3,3,3,3,3,35,51,63,0,0); // L + do Output.create(77,33,51,63,63,51,51,51,51,51,0,0); // M + do Output.create(78,51,51,55,55,63,59,59,51,51,0,0); // N + do Output.create(79,30,51,51,51,51,51,51,51,30,0,0); // O + do Output.create(80,31,51,51,51,31,3,3,3,3,0,0); // P + do Output.create(81,30,51,51,51,51,51,63,59,30,48,0);// Q + do Output.create(82,31,51,51,51,31,27,51,51,51,0,0); // R + do Output.create(83,30,51,51,6,28,48,51,51,30,0,0); // S + do Output.create(84,63,63,45,12,12,12,12,12,30,0,0); // T + do Output.create(85,51,51,51,51,51,51,51,51,30,0,0); // U + do Output.create(86,51,51,51,51,51,30,30,12,12,0,0); // V + do Output.create(87,51,51,51,51,51,63,63,63,18,0,0); // W + do Output.create(88,51,51,30,30,12,30,30,51,51,0,0); // X + do Output.create(89,51,51,51,51,30,12,12,12,30,0,0); // Y + do Output.create(90,63,51,49,24,12,6,35,51,63,0,0); // Z + + do Output.create(91,30,6,6,6,6,6,6,6,30,0,0); // [ + do Output.create(92,0,0,1,3,6,12,24,48,32,0,0); // \ + do Output.create(93,30,24,24,24,24,24,24,24,30,0,0); // ] + do Output.create(94,8,28,54,0,0,0,0,0,0,0,0); // ^ + do Output.create(95,0,0,0,0,0,0,0,0,0,63,0); // _ + do Output.create(96,6,12,24,0,0,0,0,0,0,0,0); // ` + + do Output.create(97,0,0,0,14,24,30,27,27,54,0,0); // a + do Output.create(98,3,3,3,15,27,51,51,51,30,0,0); // b + do Output.create(99,0,0,0,30,51,3,3,51,30,0,0); // c + do Output.create(100,48,48,48,60,54,51,51,51,30,0,0); // d + do Output.create(101,0,0,0,30,51,63,3,51,30,0,0); // e + do Output.create(102,28,54,38,6,15,6,6,6,15,0,0); // f + do Output.create(103,0,0,30,51,51,51,62,48,51,30,0); // g + do Output.create(104,3,3,3,27,55,51,51,51,51,0,0); // h + do Output.create(105,12,12,0,14,12,12,12,12,30,0,0); // i + do Output.create(106,48,48,0,56,48,48,48,48,51,30,0); // j + do Output.create(107,3,3,3,51,27,15,15,27,51,0,0); // k + do Output.create(108,14,12,12,12,12,12,12,12,30,0,0); // l + do Output.create(109,0,0,0,29,63,43,43,43,43,0,0); // m + do Output.create(110,0,0,0,29,51,51,51,51,51,0,0); // n + do Output.create(111,0,0,0,30,51,51,51,51,30,0,0); // o + do Output.create(112,0,0,0,30,51,51,51,31,3,3,0); // p + do Output.create(113,0,0,0,30,51,51,51,62,48,48,0); // q + do Output.create(114,0,0,0,29,55,51,3,3,7,0,0); // r + do Output.create(115,0,0,0,30,51,6,24,51,30,0,0); // s + do Output.create(116,4,6,6,15,6,6,6,54,28,0,0); // t + do Output.create(117,0,0,0,27,27,27,27,27,54,0,0); // u + do Output.create(118,0,0,0,51,51,51,51,30,12,0,0); // v + do Output.create(119,0,0,0,51,51,51,63,63,18,0,0); // w + do Output.create(120,0,0,0,51,30,12,12,30,51,0,0); // x + do Output.create(121,0,0,0,51,51,51,62,48,24,15,0); // y + do Output.create(122,0,0,0,63,27,12,6,51,63,0,0); // z + + do Output.create(123,56,12,12,12,7,12,12,12,56,0,0); // { + do Output.create(124,12,12,12,12,12,12,12,12,12,0,0); // | + do Output.create(125,7,12,12,12,56,12,12,12,7,0,0); // } + do Output.create(126,38,45,25,0,0,0,0,0,0,0,0); // ~ + + return; + } + + // Creates the character map array of the given character index, using the given values. + function void create(int index, int a, int b, int c, int d, int e, + int f, int g, int h, int i, int j, int k) { + var Array map; + + let map = Array.new(11); + let charMaps[index] = map; + + let map[0] = a; + let map[1] = b; + let map[2] = c; + let map[3] = d; + let map[4] = e; + let map[5] = f; + let map[6] = g; + let map[7] = h; + let map[8] = i; + let map[9] = j; + let map[10] = k; + + return; + } + + // Returns the character map (array of size 11) of the given character. + // If the given character is invalid or non-printable, returns the + // character map of a black square. + function Array getMap(char c) { + if ((c < 32) | (c > 126)) { + let c = 0; + } + return charMaps[c]; + } + + /** Moves the cursor to the j-th column of the i-th row, + * and erases the character displayed there. */ + function void moveCursor(int i, int j) { + var int x, y; + let x = cursorJ * 8; + let y = cursorI * 11; + do Screen.setColor(false); + do Screen.drawRectangle(x, y, x + 7, y + 10); + let x = j * 8; + let y = i * 11; + do Screen.setColor(true); + do Screen.drawRectangle(x, y, x + 7, y + 10); + let cursorI = i; + let cursorJ = j; + return; + } + + /** Displays the given character at the cursor location, + * and advances the cursor one column forward. */ + function void printChar(char c) { + var int k, x, y, addr; + var Array cm; + if (c = 129) { + do Output.backSpace(); + return; + } + if (cursorI = 22) { + if (c = 128) { + return; + } + if (cursorJ = 63) { + return; + } + } + if (c = 128) { + do Output.println(); + return; + } + let k = 0; + let x = cursorJ / 2; + let y = cursorJ - (x * 2); // y = 0: lsb, y = 1: msb + let addr = cursorI * 352 + x + 16384; + let cm = Output.getMap(c); + if (cursorJ = 63) { + do Output.moveCursor(cursorI + 1, 0); + } else { + do Output.moveCursor(cursorI, cursorJ + 1); + } + while (k < 11) { + if (y = 0){ + do Memory.poke(addr, Memory.peek(addr) & (-128) + cm[k]); + } else { + do Memory.poke(addr, Memory.peek(addr) & 255 + (cm[k] * 256)); + } + let k = k + 1; + let addr = addr + 32; + } + return; + } + + /** displays the given string starting at the cursor location, + * and advances the cursor appropriately. */ + function void printString(String s) { + var int i; + var int n; + let i = 0; + let n = s.length(); + while (i < n) { + do Output.printChar(s.charAt(i)); + let i = i + 1; + } + return; + } + + /** Displays the given integer starting at the cursor location, + * and advances the cursor appropriately. */ + function void printInt(int i) { + var String s; + let s = String.new(6); + do s.setInt(i); + do Output.printString(s); + return; + } + + /** Advances the cursor to the beginning of the next line. */ + function void println() { + if (cursorI < 22) { + do Output.moveCursor(cursorI + 1, 0); + } + return; + } + + /** Moves the cursor one column back. */ + function void backSpace() { + if (cursorJ > 0) { + do Output.moveCursor(cursorI, cursorJ - 1); + } else { + do Output.moveCursor(cursorI - 1, 63); + } + return; + } +} diff --git a/jackos/Screen.jack b/jackos/Screen.jack new file mode 100644 index 0000000..a370ab9 --- /dev/null +++ b/jackos/Screen.jack @@ -0,0 +1,138 @@ +// 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/12/Screen.jack + +/** + * A library of functions for displaying graphics on the screen. + * The Hack physical screen consists of 512 rows (indexed 0..511, top to bottom) + * of 256 pixels each (indexed 0..255, left to right). The top left pixel on + * the screen is indexed (0,0). + */ +class Screen { + static Array twoToThe; + static Array screen; + static boolean color; + + /** Initializes the Screen. */ + function void init() { + var int i, x; + let x = 1; + let i = 0; + let twoToThe = Array.new(16); + while (i < 16){ + let twoToThe[i] = x; + let x = x + x; + let i = i + 1; + } + let screen = 16384; + let color = true; + return; + } + + /** Erases the entire screen. */ + function void clearScreen() { + var boolean c; + let c = color; + let color = false; + do Screen.drawRectangle(0, 0, 511, 255); + let color = c; + return; + } + + /** Sets the current color, to be used for all subsequent drawXXX commands. + * Black is represented by true, white by false. */ + function void setColor(boolean b) { + let color = b; + return; + } + + /** Draws the (x,y) pixel, using the current color. */ + function void drawPixel(int x, int y) { + var int addr, t; + if ((x < 0) | (y < 0) | (x > 511) | (y > 255)) { + //String.println("drawPixel: coordinates out of range!"); + //Sys.error(2); + return; + } + let t = x / 16; + let addr = 32 * y + t; + if (color) { + let screen[addr] = screen[addr] | twoToThe[x - (t * 16)]; + } else { + let screen[addr] = screen[addr] & (- (twoToThe[x - (t * 16)] + 1)); + } + return; + } + + /** Draws a line from pixel (x1,y1) to pixel (x2,y2), using the current color. */ + function void drawLine(int x1, int y1, int x2, int y2) { + var int dx, dy, x, y, a, b, diff; + let x = x1; + let y = y1; + do Screen.drawPixel(x, y); + if (x1 = x2) { + if (y1 = y2) { + return; + } else { + let diff = 1; + } + } else { + if (y1 = y2) { + let diff = -1; + } else { + let diff = 0; + } + } + let dx = x2 - x1; + let dy = y2 - y1; + let a = Math.sign(dx); + let b = Math.sign(dy); + let dx = Math.abs(dx); + let dy = Math.abs(dy); + while (~((x = x2) & (y = y2))) { + if (diff < 0){ + let x = x + a; + let diff = diff + dy; + } else { + let y = y + b; + let diff = diff - dx; + } + do Screen.drawPixel(x, y); + } + return; + } + + /** Draws a filled rectangle whose top left corner is (x1, y1) + * and bottom right corner is (x2,y2), using the current color. */ + function void drawRectangle(int x1, int y1, int x2, int y2) { + var int x; + if ((x1 > x2) | (y1 > y2)) { + return; + } + let x = x1; + while (~(x > x2)) { + do Screen.drawLine(x, y1, x, y2); + let x = x + 1; + } + return; + } + + /** Draws a filled circle of radius r<=181 around (x,y), using the current color. */ + function void drawCircle(int x, int y, int r) { + var int dx, dy, r2; + if (r > 181) { + do String.println("drawCircle: radius too big!"); + do Sys.error(2); + return; + } + let dy = -r; + let r2 = r * r; + while (~(dy > r)) { + let dx = Math.sqrt(r2 - (dy * dy)); + do Screen.drawLine(x - dx, y + dy, x + dx, y + dy); + let dy = dy + 1; + } + return; + } +} diff --git a/jackos/String.jack b/jackos/String.jack new file mode 100644 index 0000000..3ef40b2 --- /dev/null +++ b/jackos/String.jack @@ -0,0 +1,176 @@ +// 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/12/String.jack + +/** + * Represents character strings. In addition for constructing and disposing + * strings, the class features methods for getting and setting individual + * characters of the string, for erasing the string's last character, + * for appending a character to the string's end, and more typical + * string-oriented operations. + */ +class String { + field int maxLen; + field int len; + field Array s; + + /** constructs a new empty string with a maximum length of maxLength + * and initial length of 0. */ + constructor String new(int maxLength) { + if (maxLength > 0) { + let s = Array.new(maxLength); + } + let maxLen = maxLength; + let len = 0; + return this; + } + + /** Disposes this string. */ + method void dispose() { + if (maxLen > 0) { + do s.dispose(); + } + do Memory.deAlloc(this); + return; + } + + /** Returns the current length of this string. */ + method int length() { + return len; + } + + /** Returns the character at the j-th location of this string. */ + method char charAt(int j) { + if ((j < 0) | (j + 1 > len)){ + do Output.printString("String.charAt: index out of range!"); + do Sys.error(5); + } + return s[j]; + } + + /** Sets the character at the j-th location of this string to c. */ + method void setCharAt(int j, char c) { + if ((j < 0) | (j + 1 > len)){ + do Output.printString("String.setCharAt: index out of range!"); + do Sys.error(5); + } + let s[j] = c; + return; + } + + /** Appends c to this string's end and returns this string. */ + method String appendChar(char c) { + if (len = maxLen) { + do Output.printString("String.appendChar: reached max length!"); + do Sys.error(5); + } + let s[len] = c; + let len = len + 1; + return this; + } + + /** Erases the last character from this string. */ + method void eraseLastChar() { + if (len = 0){ + do Output.printString("String.eraseLastChar: string is already empty!"); + do Sys.error(5); + } + let len = len - 1; + return; + } + + /** Returns the integer value of this string, + * until a non-digit character is detected. */ + method int intValue() { + var int n, i; + var char c; + var boolean neg, done; + let n = 0; + if (s[0] = 45) { + let i = 1; + let neg = true; + } else { + let i = 0; + let neg = false; + } + let c = s[i]; + if ((c < 48) | (c > 57)) { + do Sys.error(3); + do Output.printString("String.intValue: the input data is not number!"); + } + let done = false; + while ((~done) & (i < len)) { + let c = s[i]; + if ((c > 47) & (c < 58)) { + let n = n * 10 + (c - 48); + } else { + let done = true; + } + let i = i + 1; + } + if (neg) { + return -n; + } else { + return n; + } + + } + + /** Sets this string to hold a representation of the given value. */ + method void setInt(int val) { //change Output.printInt after this + var int x, i, y; + var boolean neg; + if (val < 0) { + let neg = true; + let len = 2; + } else { + let neg = false; + let len = 1; + } + let x = Math.abs(val); + if (x > 9999) { + let len = len + 4; + } else { if (x > 999) { + let len = len + 3; + } else { if (x > 99) { + let len = len + 2; + } else { if (x > 9) { + let len = len + 1; + }}}} + if (len > maxLen) { + do Output.printString("String.setInt: val is too big for the string!"); + do Sys.error(5); + } + if (x = 0) { + do setCharAt(0, 48); + return; + } + if (neg) { + do setCharAt(0, 45); + } + let i = len - 1; + while (x > 0) { + let y = x / 10; + do setCharAt(i, x - (y * 10) + 48); + let x = y; + let i = i - 1; + } + return; + } + + /** Returns the new line character. */ + function char newLine() { + return 128; + } + + /** Returns the backspace character. */ + function char backSpace() { + return 129; + } + + /** Returns the double quote (") character. */ + function char doubleQuote() { + return 34; + } +} diff --git a/jackos/Sys.jack b/jackos/Sys.jack new file mode 100644 index 0000000..53c078c --- /dev/null +++ b/jackos/Sys.jack @@ -0,0 +1,51 @@ +// 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/12/Sys.jack + +/** + * A library that supports various program execution services. + */ +class Sys { + + /** Performs all the initializations required by the OS. */ + function void init() { + do Keyboard.init(); + do Math.init(); + do Memory.init(); + do Output.init(); + do Screen.init(); + do Main.main(); + do Sys.halt(); + return; + } + + /** Halts the program execution. */ + function void halt() { + while (true){ + } + return; + } + + /** Waits approximately duration milliseconds and returns. */ + function void wait(int duration) { + var int i, j; + let i = 0; + while (i < duration){ + let i = i + 1; + let j = 0; + while (j < 318){ + let j = j + 1; + } + } + return; + } + + /** Displays the given error code in the form "ERR", + * and halts the program's execution. */ + function void error(int errorCode) { + do Output.printString("ERR"); + do Output.printInt(errorCode); + return; + } +} -- cgit v1.2.3