IWKS 3300: NAND to Tetris Spring 2019 John K. Bennett High Level Language (Jack) Foundations of Global Networked Computing: Building a Modern Computer From First Principles This course is based upon the work of Noam Nisan and Shimon Schocken. More information can be found at (www.nand2tetris.org).
Where We Are You are here We are skipping Software over this for now Abstract design Human Hierarchy abstract interface Thought Chapters 9, 12 Compiler H.L. Language & abstract interface Chapters 10 - 11 Operating Sys. VM Translator Virtual abstract interface Machine Chapters 7 - 8 Assembly Language Assembler Chapter 6 abstract interface Computer Architecture Machine abstract interface Code Chapters 4 - 5 Gate Logic Hardware abstract interface Platform Chapters 1 - 3 Electrical Engineering Chips & Physics Logic Gates Hardware Hierarchy
Some Programming Language Taxonomy/History Programming languages have a rich history; a few high points: Machine code (hand translated binary code) Assembly language (low-level symbolic programming) Simple procedural languages, ( Fortran, Basic, Algol, PL1, Pascal, C) Simple Functional Languages (Lisp, Scheme) Simple object-based languages (with and w/o inheritance): ( Simula 67, Smalltalk 80, Ada, C++, Objective C, In terms of Visual Basic, JavaScript) Jack functionality, Jack goes here Modern object-oriented languages ( Squeak, Java, C# )
The Jack Programming Language Jack: a simple, object-based, high-level language with a Java-like syntax Some sample applications written in Jack: procedural programming Pong game Space Invaders Tetris
Hello World /** Hello World program. */ class Main { function void main () { // Prints some text using the standard library do Output.printString("Hello World"); do Output.println(); // New line return; } } Some observations: Java-like syntax Typical comments format Standard function library A few language-specific peculiarities
Representative Programming Tasks in Jack Jack can be used to develop most apps that come to mind, for example: Procedural programming : a program that computes 1 + 2 + ... + n Object-oriented programming : a class representing bank accounts Abstract data type representation : a class representing fractions Data structure representation : a class representing linked lists Etc. Let’s look at these examples…
Procedural Programming Example Jack program = a collection of class Main { one or more classes /** Sums up 1 + 2 + 3 + ... + n */ Jack class = a collection of function int sum (int n) { one or more subroutines Note use of “ ~ ” var int sum, i; Execution order: when we execute a let sum = 0; for logical negation let i = 1; Jack program, Main.main() starts (not “ ! ” ) while (~(i > n)) { running. let sum = sum + i; Jack subroutines: let i = i + 1; method } return sum; constructor } function (static method) function void main () { (the example on the left has var int n; functions only, as it is “object - less”) let n = Keyboard.readInt("Enter n: "); Standard library: a set of OS services do Output.printString("The result is: "); (methods and functions) organized in 8 do Output.printInt(sum(n)); supplied classes: Math , String . Array , return; } Output , Keyboard , Screen , Memory , } Sys (OS API in the book).
Object-Oriented Programming Example The BankAccount class (skeletal) /** Represents a bank account. A bank account has an owner, an id, and a balance. The id values start at 0 and increment by 1 each time a new account is created. */ class BankAccount { /** Constructs a new bank account with a 0 balance. */ constructor BankAccount new(String owner) /** Deposits the given amount in this account. */ method void deposit(int amount) /** Withdraws the given amount from this account. */ method void withdraw(int amount) /** Prints the data of this account. */ method void printInfo() /** Disposes this account. */ method void dispose() }
Object-oriented Programming Example (continued) // Code in any other class: /** Represents a bank account. */ var int x; var BankAccount b; class BankAccount { let b = BankAccount.new("joe"); 2 // class variable (one per class) static int newAcctId; //compiler inits to 0 return this 1 // Private instance variables (aka fields) The constructor returns the RAM base address of the field int id; memory block that stores the data of the newly field String owner; created BankAccount object field int balance; 2 b = BankAccount.new("joe") Calls the constructor (which creates a new /** Constructs a new bank account */ BankAccount object), then stores in variable b a pointer to the object ’ s base memory address constructor BankAccount new (String owner) { let id = newAcctId; Behind the scenes (after compilation): let newAcctId = newAcctId + 1; let this.owner = owner; // b = BankAccount.new( " joe " ) push "joe" let balance = 0; call BankAccount.new return this; 1 pop b } Explanation: the calling code pushes an argument and calls the constructor; the constructor ’ s code // More BankAccount methods. (not shown) creates a new object, pushes its base address onto the stack, and returns; } The calling code then pops the base address into a variable that will now point to the new object.
Object-oriented Programming Example (continued) ... class BankAccount { static int nAccounts; var BankAccount b1, b2; ... field int id; let b1 = BankAccount.new("joe"); field String owner; let b2 = BankAccount.new("jane"); field int balance; do b1.deposit(5000); do b1.withdraw(1000); // Constructor ... (omitted) ... /** Handles deposits */ do b1.deposit(5000) method void deposit (int amount) { In Jack, void methods are invoked let balance = balance + amount; using the keyword do (a compilation return; artifact) } /** Handles withdrawals */ The object-oriented method invocation method void withdraw (int amount){ style b1.deposit(5000) has the same if (~(amount > balance)) { procedural semantics as let balance = balance - amount; “ deposit(b1,5000) ” } return; } Behind the scenes (after compilation): // do b1.deposit(5000) // More BankAccount methods. push b1 push 5000 } call BankAccount.deposit
Object-oriented Programming Example (continued) class BankAccount { // Code in any other class: static int nAccounts; ... var int x; field int id; var BankAccount b; field String owner; field int balance; let b = BankAccount.new("joe"); // Manipulates b... // Constructor ... (omitted) do b.printInfo(); do b.dispose(); /** Prints information about this account. */ ... method void printInfo () { do Output.printInt(id); do b.dispose() do Output.printString(owner); Jack has no garbage collection; do Output.printInt(balance); The programmer is responsible for return; explicitly recycling memory resources } of objects that are no longer needed. /** Disposes of this account. */ method void dispose () { do Memory.deAlloc(this) do Memory.deAlloc(this); This is a call to an OS function that return; knows how to recycle the memory } block whose base-address is this . This function is part of the OS runtime // More BankAccount methods. library (Chapter 12). }
Abstract Data Type Example The Fraction class API (method signatures only) /** Represents a fraction data type. A fraction consists of a numerator and a denominator, both int values */ class Fraction { /** Constructs a fraction from the given data */ constructor Fraction new(int numerator, int denominator) /** Reduces this fraction, e.g. changes 20/100 to 1/5. */ method void reduce() /** Accessors method int getNumerator() method int getDenominator() /** Returns the sum of this fraction and the other one */ method Fraction plus(Fraction other) /** Returns the product of this fraction and the other one */ method Fraction product(Fraction other) /** Prints this fraction */ method void print() /** Disposes this fraction */ method void dispose() }
Abstract Data Type Example (continued) /** Represents a fraction data type. A fraction consists of a numerator and a denominator, both int values */ class Fraction { field int numerator, denominator; constructor Fraction new (int numerator, int denominator) { let this.numerator = numerator; let this.denominator = denominator; do reduce() // Reduces the new fraction return this } /** Reduces this fraction */ method void reduce () { // Code omitted } // A static method that computes the greatest common denominator of a and b. function int gcd (int a, int b) { // Code omitted // Code in any other class: } ... var Fraction a, b; method int getNumerator () { return numerator; let a = Fraction.new(2,5); } let b = Fraction.new(70,210); do b.print() // prints "1/3" method int getDenominator () { ... return denominator; } // (print method in next slide) // More Fraction methods follow.
Recommend
More recommend