CO5570: The Assembler David Barnes Chapter 6 Slides support chapter 6 of the book The Elements of Computing Systems By Noam Nisan and Shimon Schocken MIT Press Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 1 CO5570: Computer Systems: assessments Some Java features to brush up on: • Java packages: writing and running code within a package. • Java enumerated types (enum). • Running Java programs from the command line. Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 2 2 Nand to Tetris: the big picture human thought write a program software hierarchy abstraction compiler high-level language abstraction OS VM translator VM code abstraction machine language assembler abstraction digital design computer architecture p4 hardware platform abstraction p5 p6 CPU, RAM, chipset comb. and seq. Logic abstraction p2 p3 elementary logic gates combinational logic p1 Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Nand Slide 3 Assembly process Assembly Language Machine Language @i M=1 // i = 1 @sum M=0 // sum = 0 (LOOP) @i // if i>RAM[0] D=M // GOTP WRITE @R0 D=D-M @WRITE D;JGT ... // Etc. 0000000000010000 1110111111001000 0000000000010001 1110101010001000 0000000000010000 1111110000010000 0000000000000000 1111010011010000 0000000000010010 1110001100000001 0000000000010000 1111110000010000 0000000000010001 ... assembler run assemble mario.asm into mario.bin Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 4 Assembler: lecture plan • The assembly process • The Hack assembly language • The assembly process: instructions • The assembly process: symbols • Developing an assembler • Project 6 overview Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 5 The translator’s challenge (overview) Hack assembly code (source language) // Computes RAM[1]=1+...+RAM[0] @i M=1 // i = 1 @sum M=0 // sum = 0 (LOOP) @i // if i>RAM[0] goto STOP D=M @R0 D=D-M @STOP D;JGT @i // sum += i D=M @sum M=D+M @i // i++ M=M+1 @LOOP // goto LOOP 0;JMP ... Hack binary code (source language) Assembler What are the rules of the game? 0000000000010000 1110111111001000 0000000000010001 1110101010001000 0000000000010000 1111110000010000 0000000000000000 1111010011010000 0000000000010010 1110001100000001 0000000000010000 1111110000010000 0000000000010001 1111000010001000 0000000000010000 1111110111001000 0000000000000100 1110101010000111 ... Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 6 The translator’s challenge (overview) Hack assembly code (source language) // Computes RAM[1]=1+...+RAM[0] @i M=1 // i = 1 @sum M=0 // sum = 0 (LOOP) @i // if i>RAM[0] goto STOP D=M @R0 D=D-M @STOP D;JGT @i // sum += i D=M @sum M=D+M @i // i++ M=M+1 @LOOP // goto LOOP 0;JMP ... Hack binary code (source language) Assembler Based on the syntax rules of: • The source language • The target language 0000000000010000 1110111111001000 0000000000010001 1110101010001000 0000000000010000 1111110000010000 0000000000000000 1111010011010000 0000000000010010 1110001100000001 0000000000010000 1111110000010000 0000000000010001 1111000010001000 0000000000010000 1111110111001000 0000000000000100 1110101010000111 ... Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 7 Hack language specification: A-instruction Symbolic syntax: @ value Examples: @21 @foo Where value is either • a non-negative decimal constant or • a symbol referring to such a constant Binary syntax: 0 valueInBinary Example: 0000000000010101 Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 8 Hack language specification: C-instruction Symbolic syntax: dest = comp ; jump Binary syntax: 1 1 1 a c1 c2 c3 c4 c5 c6 d1 d2 d3 j1 j2 j3 Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 9 Hack language specification: C-instruction Symbolic syntax: dest = comp ; jump Binary syntax: 1 1 1 a c1 c2 c3 c4 c5 c6 d1 d2 d3 j1 j2 j3 comp 0 1 -1 D A !D !A -D -A D+1 A+1 D-1 A-1 D+A D-A A-D D&A D|A a=0 c1 c2 c3 c4 c5 c6 M !M -M M+1 M-1 D+M D-M M-D D&M D|M a=1 1 1 1 0 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 1 1 0 1 0 1 0 1 1 1 0 1 0 1 0 0 1 1 1 1 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 1 1 1 0 0 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 0 1 dest null M D MD A AM AD AMD d1 d2 d3 effect: the value is stored in: 0 0 0 The value is not stored 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 RAM[A] D register RAM[A] and D register A register A register and RAM[A] A register and D register A register, RAM[A], and D register jump j1 j2 j3 effect: null 0 0 0 no jump JGT JEQ JGE JLT JNE JLE JMP 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 if out > 0 jump if out = 0 jump if out ≥ 0 jump if out < 0 jump if out ≠ 0 jump if out ≤ 0 jump Unconditional jump Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 10 Hack language specification: symbols Pre-defined symbols: symbol value symbol value R0 R1 R2 ... R15 0 1 2 ... 15 SP LCL ARG THIS THAT 0 1 2 3 4 SCREEN 16384 KBD 24576 Label declaration: (label) Variable declaration: @variableName Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 11 The Hack language: a translator’s perspective Assembly program // Computes RAM[1] = 1 + ... + RAM[0] @i M=1 // i = 1 @sum M=0 // sum = 0 (LOOP) @i // if i>RAM[0] goto STOP D=M @R0 D=D-M @STOP D;JGT @i // sum += i D=M @sum M=D+M @i // i++ M=M+1 @LOOP // goto LOOP 0;JMP (STOP) @sum D=M @R1 M=D // RAM[1] = the sum (END) @END 0;JMP Assembly program elements: • White space Empty lines / indentation q Line comments q In-line comments q • Instructions A-instructions q C-instructions q • Symbols References q Label declarations q Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 12 The Hack language: a translator’s perspective Assembly program // Computes RAM[1] = 1 + ... + RAM[0] @i M=1 // i = 1 @sum M=0 // sum = 0 (LOOP) @i // if i>RAM[0] goto STOP D=M @R0 D=D-M @STOP D;JGT @i // sum += i D=M @sum M=D+M @i // i++ M=M+1 @LOOP // goto LOOP 0;JMP (STOP) @sum D=M @R1 M=D // RAM[1] = the sum (END) @END 0;JMP Hack machine code Assembler Tasks: Handling… • White space • Instructions • Symbols 0000000000010000 1110111111001000 0000000000010001 1110101010001000 0000000000010000 1111110000010000 0000000000000000 1111010011010000 0000000000010010 1110001100000001 0000000000010000 1111110000010000 0000000000010001 1111000010001000 0000000000010000 1111110111001000 0000000000000100 1110101010000111 0000000000010001 1111110000010000 0000000000000001 1110001100001000 0000000000010110 1110101010000111 Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 13 Symbols Program with symbols // Computes RAM[1] = 1 + ... + RAM[0] @i M=1 // i = 1 @sum M=0 // sum = 0 (LOOP) @i // if i>RAM[0] goto STOP D=M @R0 D=D-M @STOP D;JGT @i // sum += i D=M @sum M=D+M @i // i++ M=M+1 @LOOP // goto LOOP 0;JMP (STOP) @sum D=M @R1 M=D // RAM[1] = the sum (END) @END 0;JMP Tasks: Handling… • White space • Instructions • Symbols Simplifying assumption: Let’s deal with symbols later. Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 14 Handling programs without symbols Hack machine code Assembly program (without symbols) // Computes RAM[1] = 1 + ... + RAM[0] @16 M=1 // i = 1 @17 M=0 // sum = 0 @16 // if i>RAM[0] goto STOP D=M @0 D=D-M @18 D;JGT @16 // sum += i D=M @17 M=D+M @16 // i++ M=M+1 @4 // goto LOOP 0;JMP @17 D=M @1 M=D // RAM[1] = the sum @22 0;JMP Assembler for symbol-less Hack programs Tasks: Handling… • White space • Instructions 0000000000010000 1110111111001000 0000000000010001 1110101010001000 0000000000010000 1111110000010000 0000000000000000 1111010011010000 0000000000010010 1110001100000001 0000000000010000 1111110000010000 0000000000010001 1111000010001000 0000000000010000 1111110111001000 0000000000000100 1110101010000111 0000000000010001 1111110000010000 0000000000000001 1110001100001000 0000000000010110 1110101010000111 Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 15 Handling white space Hack machine code Assembly program (without symbols) // Computes RAM[1] = 1 + ... + RAM[0] @16 M=1 // i = 1 @17 M=0 // sum = 0 @16 // if i>RAM[0] goto STOP D=M @0 D=D-M @18 D;JGT @16 // sum += i D=M @17 M=D+M @16 // i++ M=M+1 @4 // goto LOOP 0;JMP @17 D=M @1 M=D // RAM[1] = the sum @22 0;JMP Assembler for symbol-less Hack programs Tasks: Handling… • White space • Instructions 0000000000010000 1110111111001000 0000000000010001 1110101010001000 0000000000010000 1111110000010000 0000000000000000 1111010011010000 0000000000010010 1110001100000001 0000000000010000 1111110000010000 0000000000010001 1111000010001000 0000000000010000 1111110111001000 0000000000000100 1110101010000111 0000000000010001 1111110000010000 0000000000000001 1110001100001000 0000000000010110 1110101010000111 Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 16 Handling white space Hack machine code Assembly program (without symbols) // Computes RAM[1] = 1 + ... + RAM[0] @16 M=1 // i = 1 @17 M=0 // sum = 0 @16 // if i>RAM[0] goto STOP D=M @0 D=D-M @18 D;JGT @16 // sum += i D=M @17 M=D+M @16 // i++ M=M+1 @4 // goto LOOP 0;JMP @17 D=M @1 M=D // RAM[1] = the sum @22 0;JMP Assembler for symbol-less Hack programs Tasks: Handling… • White space • Instructions Handling white space: Ignore it! Possible because it isn’t used as a separator. 0000000000010000 1110111111001000 0000000000010001 1110101010001000 0000000000010000 1111110000010000 0000000000000000 1111010011010000 0000000000010010 1110001100000001 0000000000010000 1111110000010000 0000000000010001 1111000010001000 0000000000010000 1111110111001000 0000000000000100 1110101010000111 0000000000010001 1111110000010000 0000000000000001 1110001100001000 0000000000010110 1110101010000111 Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 17 Handling instructions Hack machine code Assembly program (without symbols) @16 M=1 @17 M=0 @16 D=M @0 D=D-M @18 D;JGT @16 D=M @17 M=D+M @16 M=M+1 @4 0;JMP @17 D=M @1 M=D @22 0;JMP Assembler for symbol-less Hack programs Tasks: Handling… ü White space • Instructions 0000000000010000 1110111111001000 0000000000010001 1110101010001000 0000000000010000 1111110000010000 0000000000000000 1111010011010000 0000000000010010 1110001100000001 0000000000010000 1111110000010000 0000000000010001 1111000010001000 0000000000010000 1111110111001000 0000000000000100 1110101010000111 0000000000010001 1111110000010000 0000000000000001 1110001100001000 0000000000010110 1110101010000111 Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 18 Translating A-instructions Symbolic syntax: @ value Examples: @21 @foo Where value is either • a non-negative decimal constant or • a symbol referring to such a constant (later) Binary syntax: 0 valueInBinary if(line.charAt(0) == '@') { value = line.substring(1); } Example: 0000000000010101 Translation to binary: • If value is a decimal constant, generate the equivalent binary constant • If value is a symbol, later. Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 19 Translating C-instructions Symbolic syntax: dest = comp ; jump Binary syntax: 1 1 1 a c1 c2 c3 c4 c5 c6 d1 d2 d3 j1 j2 j3 comp 0 1 -1 D A !D !A -D -A D+1 A+1 D-1 A-1 D+A D-A A-D D&A D|A a=0 M !M -M M+1 M-1 D+M D-M M-D D&M D|M a=1 1 1 1 0 1 0 1 0 1 0 1 0 1 0 0 0 0 0 1 1 assign 1 1 1 M 0 0 1 RAM[A] int = line.indexOf('='); 1 1 0 1 0 D 0 1 0 D register int 0 1 semi 1 0 0 = line.indexOf(';'); MD 0 1 1 RAM[A] and D register 1 0 Extract 0 0 0 // substrings … A 1 0(simplified!) 0 A register 0 1 1 = 0 line.substring(0, 1 A register and RAM[A] AM 1 0 1 assign); dest 1 0 0 0 1 AD 1 1 0 A register and D register comp semi); 0 1 1 = 1 line.substring(assign+1, 1 AMD 1 1 1 A register, RAM[A], and D register 1 0 0 = 1 line.substring(semi+1); 1 jump 1 1 1 1 1 jump j1 j2 j3 effect: 1 0 1 0 1 0 0 1 Symbolic: Example: dest d1 d2 d3 effect: the value is stored in: // C-instruction. 0 1 Decompose 0 1 0 null 0 0 0 The value is not stored c1 c2 c3 c4 c5 c6 0 1 0 0 0 0 0 0 1 1 0 0 0 1 0 1 1 1 1 1 1 1 0 0 1 0 0 0 1 1 0 1 null 0 0 0 no jump JGT JEQ JGE JLT JNE JLE JMP 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 if out > 0 jump if out = 0 jump if out ≥ 0 jump if out < 0 jump if out ≠ 0 jump if out ≤ 0 jump Map<String, String> comps; comps.put("0", "0101010"); … comps.put("D+1", "0011111"); … Unconditional jump Binary: MD=D+1 Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 20 Translating C-instructions Symbolic syntax: dest = comp ; jump Binary syntax: 1 1 1 a c1 c2 c3 c4 c5 c6 d1 d2 d3 j1 j2 j3 comp 0 1 -1 D A !D !A -D -A D+1 A+1 D-1 A-1 D+A D-A A-D D&A D|A a=0 c1 c2 c3 c4 c5 c6 M !M -M M+1 M-1 D+M D-M M-D D&M D|M a=1 1 1 1 0 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 1 1 0 1 0 1 0 1 1 1 0 1 0 1 0 0 1 Symbolic: Example: 1 1 1 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 1 1 1 0 0 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 0 1 dest null M D MD A AM AD AMD d1 d2 d3 effect: the value is stored in: 0 0 0 The value is not stored 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 RAM[A] D register RAM[A] and D register A register A register and RAM[A] A register and D register A register, RAM[A], and D register jump j1 j2 j3 effect: null 0 0 0 no jump JGT JEQ JGE JLT JNE JLE JMP 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 if out > 0 jump if out = 0 jump if out ≥ 0 jump if out < 0 jump if out ≠ 0 jump if out ≤ 0 jump Unconditional jump Binary: MD=D+1 Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 21 Translating C-instructions Symbolic syntax: dest = comp ; jump Binary syntax: 1 1 1 a c1 c2 c3 c4 c5 c6 d1 d2 d3 j1 j2 j3 comp 0 1 -1 D A !D !A -D -A D+1 A+1 D-1 A-1 D+A D-A A-D D&A D|A a=0 Example: c1 c2 c3 c4 c5 c6 M !M -M M+1 M-1 D+M D-M M-D D&M D|M a=1 1 1 1 0 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 1 1 0 1 0 1 0 1 1 1 0 1 0 1 0 0 1 1 1 1 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 1 1 1 0 0 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 0 1 dest null M D MD A AM AD AMD d1 d2 d3 effect: the value is stored in: 0 0 0 The value is not stored 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 RAM[A] D register RAM[A] and D register A register A register and RAM[A] A register and D register A register, RAM[A], and D register jump j1 j2 j3 effect: null 0 0 0 no jump JGT JEQ JGE JLT JNE JLE JMP 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 if out > 0 jump if out = 0 jump if out ≥ 0 jump if out < 0 jump if out ≠ 0 jump if out ≤ 0 jump Symbolic: Binary: MD=D+1 111 Unconditional jump Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 22 Translating C-instructions Symbolic syntax: dest = comp ; jump Binary syntax: 1 1 1 a c1 c2 c3 c4 c5 c6 d1 d2 d3 j1 j2 j3 comp 0 1 -1 D A !D !A -D -A D+1 A+1 D-1 A-1 D+A D-A A-D D&A D|A a=0 Example: c1 c2 c3 c4 c5 c6 M !M -M M+1 M-1 D+M D-M M-D D&M D|M a=1 1 1 1 0 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 1 1 0 1 0 1 0 1 1 1 0 1 0 1 0 0 1 1 1 1 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 1 1 1 0 0 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 0 1 dest null M D MD A AM AD AMD d1 d2 d3 effect: the value is stored in: 0 0 0 The value is not stored 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 RAM[A] D register RAM[A] and D register A register A register and RAM[A] A register and D register A register, RAM[A], and D register jump j1 j2 j3 effect: null 0 0 0 no jump JGT JEQ JGE JLT JNE JLE JMP 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 if out > 0 jump if out = 0 jump if out ≥ 0 jump if out < 0 jump if out ≠ 0 jump if out ≤ 0 jump Symbolic: Binary: MD=D+1 111 Unconditional jump Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 23 Translating C-instructions Symbolic syntax: dest = comp ; jump Binary syntax: 1 1 1 a c1 c2 c3 c4 c5 c6 d1 d2 d3 j1 j2 j3 comp 0 1 -1 D A !D !A -D -A D+1 A+1 D-1 A-1 D+A D-A A-D D&A D|A a=0 Example: c1 c2 c3 c4 c5 c6 M !M -M M+1 M-1 D+M D-M M-D D&M D|M a=1 1 1 1 0 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 1 1 0 1 0 1 0 1 1 1 0 1 0 1 0 0 1 1 1 1 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 1 1 1 0 0 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 0 1 dest null M D MD A AM AD AMD d1 d2 d3 effect: the value is stored in: 0 0 0 The value is not stored 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 RAM[A] D register RAM[A] and D register A register A register and RAM[A] A register and D register A register, RAM[A], and D register jump j1 j2 j3 effect: null 0 0 0 no jump JGT JEQ JGE JLT JNE JLE JMP 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 if out > 0 jump if out = 0 jump if out ≥ 0 jump if out < 0 jump if out ≠ 0 jump if out ≤ 0 jump Symbolic: Binary: MD=D+1 111 Unconditional jump Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 24 Translating C-instructions Symbolic syntax: dest = comp ; jump Binary syntax: 1 1 1 a c1 c2 c3 c4 c5 c6 d1 d2 d3 j1 j2 j3 comp 0 1 -1 D A !D !A -D -A D+1 A+1 D-1 A-1 D+A D-A A-D D&A D|A a=0 Example: c1 c2 c3 c4 c5 c6 M !M -M M+1 M-1 D+M D-M M-D D&M D|M a=1 1 1 1 0 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 1 1 0 1 0 1 0 1 1 1 0 1 0 1 0 0 1 1 1 1 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 1 1 1 0 0 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 0 1 dest null M D MD A AM AD AMD d1 d2 d3 effect: the value is stored in: 0 0 0 The value is not stored 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 RAM[A] D register RAM[A] and D register A register A register and RAM[A] A register and D register A register, RAM[A], and D register jump j1 j2 j3 effect: null 0 0 0 no jump JGT JEQ JGE JLT JNE JLE JMP 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 if out > 0 jump if out = 0 jump if out ≥ 0 jump if out < 0 jump if out ≠ 0 jump if out ≤ 0 jump Symbolic: Binary: MD=D+1 111 Unconditional jump Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 25 Translating C-instructions Symbolic syntax: dest = comp ; jump Binary syntax: 1 1 1 a c1 c2 c3 c4 c5 c6 d1 d2 d3 j1 j2 j3 comp 0 1 -1 D A !D !A -D -A D+1 A+1 D-1 A-1 D+A D-A A-D D&A D|A a=0 Example: c1 c2 c3 c4 c5 c6 M !M -M M+1 M-1 D+M D-M M-D D&M D|M a=1 1 1 1 0 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 1 1 0 1 0 1 0 1 1 1 0 1 0 1 0 0 1 1 1 1 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 1 1 1 0 0 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 0 1 dest null M D MD A AM AD AMD d1 d2 d3 effect: the value is stored in: 0 0 0 The value is not stored 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 RAM[A] D register RAM[A] and D register A register A register and RAM[A] A register and D register A register, RAM[A], and D register jump j1 j2 j3 effect: null 0 0 0 no jump JGT JEQ JGE JLT JNE JLE JMP 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 if out > 0 jump if out = 0 jump if out ≥ 0 jump if out < 0 jump if out ≠ 0 jump if out ≤ 0 jump Symbolic: Binary: MD=D+1 1110011111 Unconditional jump Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken bits = comps.get(comp); instr += bits; Slide 26 Translating C-instructions Symbolic syntax: dest = comp ; jump Binary syntax: 1 1 1 a c1 c2 c3 c4 c5 c6 d1 d2 d3 j1 j2 j3 comp 0 1 -1 D A !D !A -D -A D+1 A+1 D-1 A-1 D+A D-A A-D D&A D|A a=0 Example: c1 c2 c3 c4 c5 c6 M !M -M M+1 M-1 D+M D-M M-D D&M D|M a=1 1 1 1 0 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 1 1 0 1 0 1 0 1 1 1 0 1 0 1 0 0 1 1 1 1 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 1 1 1 0 0 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 0 1 dest null M D MD A AM AD AMD d1 d2 d3 effect: the value is stored in: 0 0 0 The value is not stored 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 RAM[A] D register RAM[A] and D register A register A register and RAM[A] A register and D register A register, RAM[A], and D register jump j1 j2 j3 effect: null 0 0 0 no jump JGT JEQ JGE JLT JNE JLE JMP 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 if out > 0 jump if out = 0 jump if out ≥ 0 jump if out < 0 jump if out ≠ 0 jump if out ≤ 0 jump Symbolic: Binary: MD=D+1 1110011111 Unconditional jump Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 27 Translating C-instructions Symbolic syntax: dest = comp ; jump Binary syntax: 1 1 1 a c1 c2 c3 c4 c5 c6 d1 d2 d3 j1 j2 j3 comp 0 1 -1 D A !D !A -D -A D+1 A+1 D-1 A-1 D+A D-A A-D D&A D|A a=0 Example: c1 c2 c3 c4 c5 c6 M !M -M M+1 M-1 D+M D-M M-D D&M D|M a=1 1 1 1 0 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 1 1 0 1 0 1 0 1 1 1 0 1 0 1 0 0 1 1 1 1 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 1 1 1 0 0 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 0 1 dest null M D MD A AM AD AMD d1 d2 d3 effect: the value is stored in: 0 0 0 The value is not stored 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 RAM[A] D register RAM[A] and D register A register A register and RAM[A] A register and D register A register, RAM[A], and D register jump j1 j2 j3 effect: null 0 0 0 no jump JGT JEQ JGE JLT JNE JLE JMP 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 if out > 0 jump if out = 0 jump if out ≥ 0 jump if out < 0 jump if out ≠ 0 jump if out ≤ 0 jump Symbolic: Binary: MD=D+1 1110011111 Unconditional jump Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 28 Translating C-instructions Symbolic syntax: dest = comp ; jump Binary syntax: 1 1 1 a c1 c2 c3 c4 c5 c6 d1 d2 d3 j1 j2 j3 comp 0 1 -1 D A !D !A -D -A D+1 A+1 D-1 A-1 D+A D-A A-D D&A D|A a=0 Example: c1 c2 c3 c4 c5 c6 M !M -M M+1 M-1 D+M D-M M-D D&M D|M a=1 1 1 1 0 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 1 1 0 1 0 1 0 1 1 1 0 1 0 1 0 0 1 1 1 1 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 1 1 1 0 0 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 0 1 dest null M D MD A AM AD AMD d1 d2 d3 effect: the value is stored in: 0 0 0 The value is not stored 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 RAM[A] D register RAM[A] and D register A register A register and RAM[A] A register and D register A register, RAM[A], and D register jump j1 j2 j3 effect: null 0 0 0 no jump JGT JEQ JGE JLT JNE JLE JMP 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 if out > 0 jump if out = 0 jump if out ≥ 0 jump if out < 0 jump if out ≠ 0 jump if out ≤ 0 jump Symbolic: Binary: MD=D+1 1110011111 Unconditional jump Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 29 Translating C-instructions Symbolic syntax: dest = comp ; jump Binary syntax: 1 1 1 a c1 c2 c3 c4 c5 c6 d1 d2 d3 j1 j2 j3 comp 0 1 -1 D A !D !A -D -A D+1 A+1 D-1 A-1 D+A D-A A-D D&A D|A a=0 Example: c1 c2 c3 c4 c5 c6 M !M -M M+1 M-1 D+M D-M M-D D&M D|M a=1 1 1 1 0 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 1 1 0 1 0 1 0 1 1 1 0 1 0 1 0 0 1 1 1 1 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 1 1 1 0 0 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 0 1 dest null M D MD A AM AD AMD d1 d2 d3 effect: the value is stored in: 0 0 0 The value is not stored 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 RAM[A] D register RAM[A] and D register A register A register and RAM[A] A register and D register A register, RAM[A], and D register jump j1 j2 j3 effect: null 0 0 0 no jump JGT JEQ JGE JLT JNE JLE JMP 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 if out > 0 jump if out = 0 jump if out ≥ 0 jump if out < 0 jump if out ≠ 0 jump if out ≤ 0 jump Unconditional jump Symbolic: Binary: MD=D+1 1110011111011 Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken bits = dests.get(dest); instr += bits; Slide 30 Translating C-instructions Symbolic syntax: dest = comp ; jump Binary syntax: 1 1 1 a c1 c2 c3 c4 c5 c6 d1 d2 d3 j1 j2 j3 comp 0 1 -1 D A !D !A -D -A D+1 A+1 D-1 A-1 D+A D-A A-D D&A D|A a=0 Example: c1 c2 c3 c4 c5 c6 M !M -M M+1 M-1 D+M D-M M-D D&M D|M a=1 1 1 1 0 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 1 1 0 1 0 1 0 1 1 1 0 1 0 1 0 0 1 1 1 1 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 1 1 1 0 0 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 0 1 dest null M D MD A AM AD AMD d1 d2 d3 effect: the value is stored in: 0 0 0 The value is not stored 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 RAM[A] D register RAM[A] and D register A register A register and RAM[A] A register and D register A register, RAM[A], and D register jump j1 j2 j3 effect: null 0 0 0 no jump JGT JEQ JGE JLT JNE JLE JMP 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 if out > 0 jump if out = 0 jump if out ≥ 0 jump if out < 0 jump if out ≠ 0 jump if out ≤ 0 jump Unconditional jump Symbolic: Binary: MD=D+1 1110011111011 Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 31 Translating C-instructions Symbolic syntax: dest = comp ; jump Binary syntax: 1 1 1 a c1 c2 c3 c4 c5 c6 d1 d2 d3 j1 j2 j3 comp 0 1 -1 D A !D !A -D -A D+1 A+1 D-1 A-1 D+A D-A A-D D&A D|A a=0 Example: c1 c2 c3 c4 c5 c6 M !M -M M+1 M-1 D+M D-M M-D D&M D|M a=1 1 1 1 0 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 1 1 0 1 0 1 0 1 1 1 0 1 0 1 0 0 1 1 1 1 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 1 1 1 0 0 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 0 1 dest null M D MD A AM AD AMD d1 d2 d3 effect: the value is stored in: 0 0 0 The value is not stored 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 RAM[A] D register RAM[A] and D register A register A register and RAM[A] A register and D register A register, RAM[A], and D register jump j1 j2 j3 effect: null 0 0 0 no jump JGT JEQ JGE JLT JNE JLE JMP 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 if out > 0 jump if out = 0 jump if out ≥ 0 jump if out < 0 jump if out ≠ 0 jump if out ≤ 0 jump Unconditional jump Symbolic: Binary: MD=D+1 1110011111011 Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 32 Translating C-instructions Symbolic syntax: dest = comp ; jump Binary syntax: 1 1 1 a c1 c2 c3 c4 c5 c6 d1 d2 d3 j1 j2 j3 comp 0 1 -1 D A !D !A -D -A D+1 A+1 D-1 A-1 D+A D-A A-D D&A D|A a=0 Example: c1 c2 c3 c4 c5 c6 M !M -M M+1 M-1 D+M D-M M-D D&M D|M a=1 1 1 1 0 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 1 1 0 1 0 1 0 1 1 1 0 1 0 1 0 0 1 1 1 1 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 1 1 1 0 0 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 0 1 dest null M D MD A AM AD AMD d1 d2 d3 effect: the value is stored in: 0 0 0 The value is not stored 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 RAM[A] D register RAM[A] and D register A register A register and RAM[A] A register and D register A register, RAM[A], and D register jump j1 j2 j3 effect: null 0 0 0 no jump JGT JEQ JGE JLT JNE JLE JMP 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 if out > 0 jump if out = 0 jump if out ≥ 0 jump if out < 0 jump if out ≠ 0 jump if out ≤ 0 jump Unconditional jump Symbolic: Binary: MD=D+1 1110011111011 Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 33 Translating C-instructions Symbolic syntax: dest = comp ; jump Binary syntax: 1 1 1 a c1 c2 c3 c4 c5 c6 d1 d2 d3 j1 j2 j3 comp 0 1 -1 D A !D !A -D -A D+1 A+1 D-1 A-1 D+A D-A A-D D&A D|A a=0 Example: c1 c2 c3 c4 c5 c6 M !M -M M+1 M-1 D+M D-M M-D D&M D|M a=1 1 1 1 0 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 1 1 0 1 0 1 0 1 1 1 0 1 0 1 0 0 1 1 1 1 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 1 1 1 0 0 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 0 1 dest null M D MD A AM AD AMD d1 d2 d3 effect: the value is stored in: 0 0 0 The value is not stored 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 RAM[A] D register RAM[A] and D register A register A register and RAM[A] A register and D register A register, RAM[A], and D register jump j1 j2 j3 effect: null 0 0 0 no jump JGT JEQ JGE JLT JNE JLE JMP 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 if out > 0 jump if out = 0 jump if out ≥ 0 jump if out < 0 jump if out ≠ 0 jump if out ≤ 0 jump Unconditional jump Symbolic: Binary: MD=D+1 1110011111011000 Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken bits = jumps.get(jump); instr += bits; Slide 34 Translating C-instructions Symbolic syntax: dest = comp ; jump Binary syntax: 1 1 1 a c1 c2 c3 c4 c5 c6 d1 d2 d3 j1 j2 j3 comp 0 1 -1 D A !D !A -D -A D+1 A+1 D-1 A-1 D+A D-A A-D D&A D|A a=0 Example: c1 c2 c3 c4 c5 c6 M !M -M M+1 M-1 D+M D-M M-D D&M D|M a=1 1 1 1 0 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 1 1 0 1 0 1 0 1 1 1 0 1 0 1 0 0 1 1 1 1 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 1 1 1 0 0 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 0 1 dest null M D MD A AM AD AMD d1 d2 d3 effect: the value is stored in: 0 0 0 The value is not stored 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 RAM[A] D register RAM[A] and D register A register A register and RAM[A] A register and D register A register, RAM[A], and D register jump j1 j2 j3 effect: null 0 0 0 no jump JGT JEQ JGE JLT JNE JLE JMP 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 if out > 0 jump if out = 0 jump if out ≥ 0 jump if out < 0 jump if out ≠ 0 jump if out ≤ 0 jump Unconditional jump Symbolic: Binary: MD=D+1 1110011111011000 Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 35 The overall assembly logic Assembly program @16 M=1 @17 M=0 @16 D=M @0 D=D-M @18 D;JGT @16 D=M @17 M=D+M @16 M=M+1 @4 0;JMP @17 D=M @1 M=D @22 0;JMP For each instruction • Parse the instruction: break it into its underlying fields • A-instruction: translate the decimal value into a binary value • C-instruction: for each field in the instruction, generate the corresponding binary code; • Assemble the translated binary codes into a complete 16-bit machine instruction • Write the 16-bit instruction to the output file. Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 36 The overall assembly logic Assembly program Hack machine code @16 M=1 @17 M=0 @16 D=M @0 D=D-M @18 D;JGT @16 D=M @17 M=D+M @16 M=M+1 @4 0;JMP @17 D=M @1 M=D @22 0;JMP 0000000000010000 1110111111001000 0000000000010001 1110101010001000 0000000000010000 1111110000010000 0000000000000000 1111010011010000 0000000000010010 1110001100000001 0000000000010000 1111110000010000 0000000000010001 1111000010001000 0000000000010000 1111110111001000 0000000000000100 1110101010000111 0000000000010001 1111110000010000 0000000000000001 1110001100001000 0000000000010110 1110101010000111 Resulting code: Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 37 The overall assembly logic Assembly program Hack machine code @16 M=1 @17 M=0 @16 D=M @0 D=D-M @18 D;JGT @16 D=M @17 M=D+M @16 M=M+1 @4 0;JMP @17 D=M @1 M=D @22 0;JMP 0000000000010000 1110111111001000 0000000000010001 1110101010001000 0000000000010000 1111110000010000 0000000000000000 1111010011010000 0000000000010010 1110001100000001 0000000000010000 1111110000010000 0000000000010001 1111000010001000 0000000000010000 1111110111001000 0000000000000100 1110101010000111 0000000000010001 1111110000010000 0000000000000001 1110001100001000 0000000000010110 1110101010000111 Resulting code: Disclaimer The source code contains no symbols Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 38 Assembler: lecture plan • Assembler logic (basic) • The Hack assembly language • The assembly process: instructions • The assembly process: symbols • Developing an assembler • Project 6 overview Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 39 Hack Assembler Assembly program Hack machine code // Computes RAM[1] = 1 + ... + RAM[0] @i M=1 // i = 1 @sum M=0 // sum = 0 (LOOP) @i // if i>RAM[0] goto STOP D=M @R0 D=D-M @STOP D;JGT @i // sum += i D=M @sum M=D+M @i // i++ M=M+1 @LOOP // goto LOOP 0;JMP (STOP) @sum D=M @R1 M=D // RAM[1] = the sum (END) @END 0;JMP Assembler Tasks: Handling… • White space • Instructions • Symbols 0000000000010000 1110111111001000 0000000000010001 1110101010001000 0000000000010000 1111110000010000 0000000000000000 1111010011010000 0000000000010010 1110001100000001 0000000000010000 1111110000010000 0000000000010001 1111000010001000 0000000000010000 1111110111001000 0000000000000100 1110101010000111 0000000000010001 1111110000010000 0000000000000001 1110001100001000 0000000000010110 1110101010000111 Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 40 Hack Assembler Assembly program Hack machine code // Computes RAM[1] = 1 + ... + RAM[0] @i M=1 // i = 1 @sum M=0 // sum = 0 (LOOP) @i // if i>RAM[0] goto STOP D=M @R0 D=D-M @STOP D;JGT @i // sum += i D=M @sum M=D+M @i // i++ M=M+1 @LOOP // goto LOOP 0;JMP (STOP) @sum D=M @R1 M=D // RAM[1] = the sum (END) @END 0;JMP Assembler Tasks: Handling… ü White space ü Instructions • Symbols 0000000000010000 1110111111001000 0000000000010001 1110101010001000 0000000000010000 1111110000010000 0000000000000000 1111010011010000 0000000000010010 1110001100000001 0000000000010000 1111110000010000 0000000000010001 1111000010001000 0000000000010000 1111110111001000 0000000000000100 1110101010000111 0000000000010001 1111110000010000 0000000000000001 1110001100001000 0000000000010110 1110101010000111 Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 41 Handling symbols Assembly program // Computes RAM[1] = 1 + ... + RAM[0] @i M=1 // i = 1 @sum M=0 // sum = 0 (LOOP) @i // if i>RAM[0] goto STOP D=M @R0 D=D-M @STOP D;JGT @i // sum += i D=M @sum M=D+M @i // i++ M=M+1 @LOOP // goto LOOP 0;JMP (STOP) @sum D=M @R1 M=D // RAM[1] = the sum (END) @END 0;JMP Pre-defined symbols: • represent special memory locations label symbols: • represent destinations of goto instructions variable symbols: • represent memory locations where the programmer wants to maintain values Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 42 Handling pre-defined symbols Assembly program // Computes RAM[1] = 1 + ... + RAM[0] @i M=1 // i = 1 @sum M=0 // sum = 0 (LOOP) @i // if i>RAM[0] goto STOP D=M @R0 D=D-M @STOP D;JGT @i // sum += i D=M @sum M=D+M @i // i++ M=M+1 @LOOP // goto LOOP 0;JMP (STOP) @sum D=M @R1 M=D // RAM[1] = the sum (END) @END 0;JMP The Hack language specification describes 23 pre-defined symbols: symbol value symbol value R0 R1 R2 ... R15 SCREEN KBD 0 1 2 ... 15 16384 24576 SP LCL ARG THIS THAT 0 1 2 3 4 Translating @preDefinedSymbol : Replace preDefinedSymbol with its value. Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 43 Handling symbols that denote labels Assembly program 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 // Computes RAM[1] = 1 + ... + RAM[0] @i M=1 // i = 1 @sum M=0 // sum = 0 (LOOP) @i // if i>RAM[0] goto STOP D=M @R0 D=D-M @STOP D;JGT @i // sum += i D=M @sum M=D+M @i // i++ M=M+1 @LOOP // goto LOOP 0;JMP (STOP) @sum D=M @R1 M=D // RAM[1] = the sum (END) @END 0;JMP Label symbols • Used to label destinations of goto commands • Declared by the pseudo-command (XXX) • This directive defines the symbol XXX to refer to the memory location holding the next instruction in the program if(line.charAt(0) == '(') { label = line.substring(1, line.length() – 1); value label into symbol table for the symbol // Insert LOOPnext instruction 4 // address. STOP 18 … END 22 } Translating @labelSymbol : Replace labelSymbol with its value Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 44 Handling symbols that denote variables Assembly program // Computes RAM[1] = 1 + ... + RAM[0] @i M=1 // i = 1 @sum M=0 // sum = 0 (LOOP) @i // if i>RAM[0] goto STOP D=M @R0 D=D-M @STOP D;JGT @i // sum += i D=M @sum M=D+M @i // i++ M=M+1 @LOOP // goto LOOP 0;JMP (STOP) @sum D=M @R1 M=D // RAM[1] = the sum (END) @END 0;JMP Variable symbols • Any symbol XXX appearing in an assembly program which is not predefined and is not defined elsewhere using the (XXX) directive is treated as a variable • Each variable is assigned a unique memory address, starting at 16 symbol value i sum 16 17 Translating @variableSymbol : • If seen for the first time, assign a unique memory address • Replace variableSymbol with this address Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 45 Symbol table Assembly program // Computes RAM[1] = 1 + ... + RAM[0] @i M=1 // i = 1 @sum M=0 // sum = 0 (LOOP) @i // if i>RAM[0] goto STOP D=M @R0 D=D-M @STOP D;JGT @i // sum += i D=M @sum M=D+M @i // i++ M=M+1 @LOOP // goto LOOP 0;JMP (STOP) @sum D=M @R1 M=D // RAM[1] = the sum (END) @END 0;JMP Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 46 Symbol table Assembly program // Computes RAM[1] = 1 + ... + RAM[0] @i M=1 // i = 1 @sum M=0 // sum = 0 Symbol table symbol value (LOOP) @i // if i>RAM[0] goto STOP D=M @R0 D=D-M @STOP D;JGT @i // sum += i D=M @sum M=D+M @i // i++ M=M+1 @LOOP // goto LOOP 0;JMP (STOP) @sum D=M @R1 M=D // RAM[1] = the sum (END) @END 0;JMP Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 47 Symbol table Assembly program // Computes RAM[1] = 1 + ... + RAM[0] @i M=1 // i = 1 @sum M=0 // sum = 0 (LOOP) @i // if i>RAM[0] goto STOP D=M @R0 D=D-M @STOP D;JGT @i // sum += i D=M @sum M=D+M @i // i++ M=M+1 @LOOP // goto LOOP 0;JMP (STOP) @sum D=M @R1 M=D // RAM[1] = the sum (END) @END 0;JMP Symbol table symbol value R0 0 R1 R2 ... R15 SCREEN KBD SP LCL ARG THIS THAT 1 2 ... 15 16384 24576 0 1 2 3 4 Initialization: Add the pre-defined symbols Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 48 Symbol table Assembly program 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 // Computes RAM[1] = 1 + ... + RAM[0] @i M=1 // i = 1 @sum M=0 // sum = 0 (LOOP) @i // if i>RAM[0] goto STOP D=M @R0 D=D-M @STOP D;JGT @i // sum += i D=M @sum M=D+M @i // i++ M=M+1 @LOOP // goto LOOP 0;JMP (STOP) @sum D=M @R1 M=D // RAM[1] = the sum (END) @END 0;JMP Symbol table symbol value R0 0 R1 R2 ... R15 SCREEN KBD SP LCL ARG THIS THAT 1 2 ... 15 16384 24576 0 1 2 3 4 Initialization: Add the pre-defined symbols Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 49 Symbol table Assembly program 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 // Computes RAM[1] = 1 + ... + RAM[0] @i M=1 // i = 1 @sum M=0 // sum = 0 (LOOP) @i // if i>RAM[0] goto STOP D=M @R0 D=D-M @STOP D;JGT @i // sum += i D=M @sum M=D+M @i // i++ M=M+1 @LOOP // goto LOOP 0;JMP (STOP) @sum D=M @R1 M=D // RAM[1] = the sum (END) @END 0;JMP Symbol table symbol value R0 0 R1 R2 ... R15 SCREEN KBD SP LCL ARG THIS THAT LOOP STOP END 1 2 ... 15 16384 24576 0 1 2 3 4 4 18 22 Initialization: Add the pre-defined symbols First pass: Add the label symbols Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 50 Symbol table Assembly program // Computes RAM[1] = 1 + ... + RAM[0] @i M=1 // i = 1 @sum M=0 // sum = 0 (LOOP) @i // if i>RAM[0] goto STOP D=M @R0 D=D-M @STOP D;JGT @i // sum += i D=M @sum M=D+M @i // i++ M=M+1 @LOOP // goto LOOP 0;JMP (STOP) @sum D=M @R1 M=D // RAM[1] = the sum (END) @END 0;JMP Symbol table symbol value R0 0 R1 R2 ... R15 SCREEN KBD SP LCL ARG THIS THAT LOOP STOP END 1 2 ... 15 16384 24576 0 1 2 3 4 4 18 22 Initialization: Add the pre-defined symbols First pass: Add the label symbols Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 51 Symbol table Assembly program // Computes RAM[1] = 1 + ... + RAM[0] @i M=1 // i = 1 @sum M=0 // sum = 0 (LOOP) @i // if i>RAM[0] goto STOP D=M @R0 D=D-M @STOP D;JGT @i // sum += i D=M @sum M=D+M @i // i++ M=M+1 @LOOP // goto LOOP 0;JMP (STOP) @sum D=M @R1 M=D // RAM[1] = the sum (END) @END 0;JMP Symbol table symbol value R0 0 R1 R2 ... R15 SCREEN KBD SP LCL ARG THIS THAT LOOP STOP END i sum 1 2 ... 15 16384 24576 0 1 2 3 4 4 18 22 16 17 Initialization: Add the pre-defined symbols First pass: Add the label symbols Second pass: Add the var. symbols Usage: To resolve a symbol, look up its value in the symbol table Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 52 The assembly process Initialization: q q Construct an empty symbol table Add the pre-defined symbols to the symbol table First pass: Scan the entire program; For each “instruction” of the form (xxx): q Add the pair (xxx, address) to the symbol table, where address is the number of the instruction following (xxx) Second pass: Set n to 16 Scan the entire program again; for each instruction: q If the instruction is @symbol, look up symbol in the symbol table; • If (symbol, value) is found, use value to complete the instruction’s translation; • If not found: o Add (symbol, n) to the symbol table, o Use n to complete the instruction’s translation, o n++ q If the instruction is a C-instruction, complete the instruction’s translation q Write the translated instruction to the output file. Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 53 Hack Assembler Assembly program // Computes RAM[1] = 1 + ... + RAM[0] @i M=1 // i = 1 @sum M=0 // sum = 0 (LOOP) @i // if i>RAM[0] goto STOP D=M @R0 D=D-M @STOP D;JGT @i // sum += i D=M @sum M=D+M @i // i++ M=M+1 @LOOP // goto LOOP 0;JMP (STOP) @sum D=M @R1 M=D // RAM[1] = the sum (END) @END 0;JMP Hack machine code Assembler Challenges: Handling… ü White space ü Instructions ü Symbols 0000000000010000 1110111111001000 0000000000010001 1110101010001000 0000000000010000 1111110000010000 0000000000000000 1111010011010000 0000000000010010 1110001100000001 0000000000010000 1111110000010000 0000000000010001 1111000010001000 0000000000010000 1111110111001000 0000000000000100 1110101010000111 0000000000010001 1111110000010000 0000000000000001 1110001100001000 0000000000010110 1110101010000111 Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 54 Assembler: lecture plan • Assembler logic (basic) • The Hack assembly language • The assembly process: instructions • The assembly process: symbols • Developing an assembler • Project 6 overview The assessment will be related to the task of writing an assembler but will be different. The remaining slides have been left in place for consistency with the course text book but we will not be covering them directly in the course. Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 55 Sub-tasks that need to be done • Reading and parsing commands • Converting mnemonics à code • Handling symbols Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 56 Reading and Parsing Commands No need to understand the meaning of anything Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 57 Reading and Parsing Commands • Start reading a file with a given name Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 58 Reading and Parsing Commands • Start reading a file with a given name q q E.g. Constructor for a Parser object that accepts a string specifying a file name. Need to know how to read text files Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 59 Reading and Parsing Commands • Start reading a file with a given name • Move to the next command in the file Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 60 Reading and Parsing Commands • Start reading a file with a given name • Move to the next command in the file q Are we finished? q Get the next command: void advance() q Need to read one line at a time q Need to skip whitespace including comments boolean hasMoreCommands() Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 61 Reading and Parsing Commands • Start reading a file with a given name • Move to the next command in the file • Get the fields of the current command Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 62 Reading and Parsing Commands • Start reading a file with a given name • Move to the next command in the file • Get the fields of the current command q Type of current command (A-Command, C-Command, or Label) Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 63 Reading and Parsing Commands • Start reading a file with a given name • Move to the next command in the file • Get the fields of the current command q Type of current command (A-Command, C-Command, or Label) q Easy access to the fields: D=M+1; JGT D M + 1 @sum J G T s u Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken m Slide 64 Reading and Parsing Commands • Start reading a file with a given name • Move to the next command in the file • Get the fields of the current command q Type of current command (A-Command, C-Command, or Label) q Easy access to the fields: D=M+1; JGT D String dest(); M + 1 String comp(); @sum J G T String jump(); s u m String label(); Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 65 Translating Mnemonic to Code: overview Symbolic syntax: dest = comp ; jump Binary syntax: 1 1 1 a c1 c2 c3 c4 c5 c6 d1 d2 d3 j1 j2 j3 Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 66 Translating Mnemonic to Code: overview No need to worry about how the mnemonic fields were obtained Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 67 Translating Mnemonic to Code: destination Symbolic syntax: dest = comp ; jump Binary syntax: 1 1 1 a c1 c2 c3 c4 c5 c6 d1 d2 d3 j1 j2 j3 dest d1 d2 d3 null M D MD A AM AD AMD 0 0 0 0 1 1 1 1 Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken 0 0 1 1 0 0 1 1 0 1 0 1 0 1 0 1 Slide 68 Translating Mnemonic to Code: jump Symbolic syntax: dest = comp ; jump Binary syntax: 1 1 1 a c1 c2 c3 c4 c5 c6 d1 d2 d3 j1 j2 j3 jump j1 j2 j3 Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken null 0 0 0 JGT JEQ JGE JLT JNE JLE JMP 0 0 0 1 1 1 1 0 1 1 0 0 1 1 1 0 1 0 1 0 1 Slide 69 Translating Mnemonic to Code: computation Symbolic syntax: dest = comp ; jump Binary syntax: 1 1 1 a c1 c2 c3 c4 c5 c6 d1 d2 d3 j1 j2 j3 comp 0 1 -1 D A !D !A -D -A D+1 A+1 D-1 A-1 D+A D-A A-D D&A D|A a=0 c1 c2 c3 c4 c5 c6 M !M -M M+1 M-1 D+M D-M M-D D&M D|M a=1 1 1 1 0 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 1 1 0 1 0 1 0 1 1 1 0 1 0 1 0 0 1 1 1 1 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 1 1 1 0 0 0 1 0 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 0 0 0 1 1 1 1 1 1 0 0 0 1 1 0 1 Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 70 Recap: Parsing + Translating Symbolic syntax: dest = comp ; jump Binary syntax: 1 1 1 a c1 c2 c3 c4 c5 c6 d1 d2 d3 j1 j2 j3 // Assume that current command is // D = M+1; JGT String c=parser.comp(); String d=parser.dest(); String j=parser.jump(); // “M+1” // “D” // “JGT” String cc = Code.comp(c); String dd = Code.dest(d); String jj = Code.jump(j); // “1110111” // “010” // “001” String out = “111” + cc + dd + jj; Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 71 The Symbol Table Symbol Address loop 73 sum 12 No need to worry about what these symbols mean Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 72 The Symbol Table Symbol Address loop 73 sum 12 • Create an new empty table • Add a (symbol , address) pair to the table • Does the table contain a given symbol? • What is the address associated with a given symbol? Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 73 Using the Symbol Table • Create a new empty table • Add all the pre-defined symbols to the table • While reading the input, add labels and new variables to the table • Whenever you see a “@xxx” command, where xxx is not a number, consult the table to replace the symbol xxx with its address. Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 74 Using the Symbol Table: adding symbols • … • … • While reading the input, add labels and new variables to the table q q Labels: when you see a “(xxx)” command, add the symbol xxx and the address of the next machine language command • Comment 1: this requires maintaining this running address • Comment 2: this may need to be done in a first pass Variables: when you see an “@xxx” command, where xxx is not a number and not already in the table, add the symbol xxx and the next free address for variable allocation Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 75 Overall logic • Initialization q Of Parser q Of Symbol Table • First Pass: Read all commands, only paying attention to labels and updating the symbol table • Restart reading and translating commands • Main Loop: q Get the next Assembly Language Command and parse it q For A-commands: Translate symbols to binary addresses q For C-commands: get code for each part and put them together q Output the resulting machine language command Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 76 Parser module: proposed API Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 77 Code module: proposed API Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 78 SymbolTable module: proposed API Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 79 Assembler: lecture plan • The assembly process • The Hack assembly language • The assembly process: instructions • The assembly process: symbols • Developing an assembler • Project 6 overview Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 80 Developing a Hack Assembler Contract • Develop an assembler that translates Hack assembly programs into executable Hack binary code • The source program is supplied in a text file named Xxx.asm • The generated code is written into a text file named Xxx.hack • Assumption: Xxx.asm is error-free Usage prompt> java HackAssembler Xxx.asm This command should create a new Xxx.hack file that can be executed as-is on the Hack computer. Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 81 Proposed design The assembler can be implemented in any high-level language Proposed software design q Parser: unpacks each instruction into its underlying fields q Code: translates each field into its corresponding binary value q SymbolTable: manages the symbol table q Main: initializes I/O files and drives the process. Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 82 Proposed Implementation Staged development • Develop a basic assembler that can translate assembly programs without symbols • Develop an ability to handle symbols • Morph the basic assembler into an assembler that can translate any assembly program Supplied test programs Add.asm Max.asm MaxL.asm Rectangle.asm RectangleL.asm Pong.asm PongL.asm Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 83 Test program: Add Add.asm // Computes RAM[0] = 2 + 3 @2 D=A @3 D=D+A @0 M=D Basic test of handling: • White space • Instructions Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 84 Test program: Max Max.asm // Computes RAM[2] = max(RAM[0],RAM[1]) @R0 D=M @R1 D=D-M @OUTPUT_RAM0 D;JGT // D = RAM[0] MaxL.asm // Symbol-less version // D = RAM[0] - RAM[1] @0 D=M // D = RAM[0] // if D>0 goto output RAM[0] @1 D=D-M // D = RAM[0] - RAM[1] // Output RAM[1] @12 @R1 D;JGT // if D>0 goto output RAM[0] D=M @R2 // Output RAM[1] M=D // RAM[2] = RAM[1] @1 @END D=M 0;JMP @2 M=D // RAM[2] = RAM[1] (OUTPUT_RAM0) @16 @R0 0;JMP D=M @R2 @0 M=D // RAM[2] = RAM[0] D=M @2 (END) M=D // RAM[2] = RAM[0] @END 0;JMP @16 0;JMP with labels without labels Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 85 Test program: Rectangle Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 86 Test program: Rectangle Rectangle.asm // Rectangle.asm @R0 D=M @n M=D // n = RAM[0] @i M=0 // i = 0 RectangleL.asm // Symbol-less version @SCREEN D=A @address M=D // base address of the Hack screen (LOOP) @i D=M @n D=D-M @END D;JGT ... with symbols // if i>n goto END @0 D=M @16 M=D // n = RAM[0] @17 M=0 // i = 0 @16384 D=A @18 M=D // base address of the Hack screen @17 D=M @16 D=D-M @27 D;JGT ... without symbols // if i>n goto END Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 87 Test program: Pong CPU Emulator Pong Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 88 Test program: Pong Pong.asm // Pong.asm @256 D=A @SP M=D @133 0;JMP @R15 M=D @SP AM=M-1 D=M A=A-1 D=M-D M=0 @END_EQ D;JNE @SP A=M-1 M=-1 (END_EQ) @R15 A=M 0;JMP @R15 M=D ... Observations: • Source code originally written in the Jack language • The Hack code was generated by the Jack compiler and the Hack assembler • The resulting code is 28,374 instructions long • (includes the Jack OS) Machine generated code: • No white space • “Strange” addresses • “Strange” labels • “Strange” pre-defined symbols Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 89 Testing options Use your assembler to translate Xxx.asm, generating the executable file Xxx.hack Hardware simulator: load Xxx.hack into the Hack Computer chip, then execute it CPU Emulator: load Xxx.hack into the supplied CPUEmulator, then execute it Assembler: use the supplied Assembler to translate Xxx.asm; Compare the resulting code to the binary code generated by your assembler. Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 90 Testing your assembler using the supplied assembler Xxx.hack file, translated by the supplied assembler Xxx.hack file, translated by your assembler Source Xxx.asm file Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 91 Project 6 Resources All the necessary project 6 files are available in: nand2tetris / projects / 06 Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 92 More resources • Supplied Assembler • Supplied CPU emulator • Assembler Tutorial • Proposed Assembler API • nand2tetris Q&A forum All available in: www.nand2tetris.org Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 93 Assembler: lecture plan • The assembly process • The Hack assembly language • The assembly process: instructions • The assembly process: symbols • Developing an assembler • Project 6 overview Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 94 Chapter 6 Assembler Slides support chapter 6 of the book The Elements of Computing Systems By Noam Nisan and Shimon Schocken MIT Press Nand to Tetris / www.nand2tetris.org / Chapter 6 / Copyright © Noam Nisan and Shimon Schocken Slide 95 COMP5570: The Virtual Machine, Part I David Barnes Chapter 7 Design of the VM These slides support chapter 7 of the book The Elements of Computing Systems By Noam Nisan and Shimon Schocken MIT Press Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The overall task • Bridging the gap between the low-level, primitive operations we have at machine level … • … and the high-level way we would like to be able to express the problems we wish to solve. • The role of a compiler. • In this lecture we will introduce the concept of a virtual machine as an intermediate step in the compilation process. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The big picture High-level program written in Jack. /** Demo: working with Point objects */ class Main { function void main() { var Point p1, p2, p3; let p1 = Point.new(1,2); let p2 = Point.new(3,4); let p3 = p1.plus(p2); do p3.print(); // prints (4,6) do Output.println(); do Output.printInt(p1.distance(p3)); return; } } /** Represents a Point */ class Point { field int x, y; static int pointCount; /** Constructs a new point */ constructor Point new(int ax, int ay) { let x = ax; let y = ay; let pointCount = pointCount + 1; return this; } ... } (4,6) 5 Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The big picture Low-level code High-level program /** Demo: working with Point objects */ class Main { function void main() { var Point p1, p2, p3; let p1 = Point.new(1,2); let p2 = Point.new(3,4); let p3 = p1.plus(p2); do p3.print(); // prints (4,6) do Output.println(); do Output.printInt(p1.distance(p3)); return; } } /** Represents a Point */ class Point { field int x, y; static int pointCount; /** Constructs a new point */ constructor Point new(int ax, int ay) { let x = ax; let y = ay; let pointCount = pointCount + 1; return this; } ... } Compiler 0000000000010000 1110111111001000 0000000000010001 1110101010001000 0000000000010000 1111110000010000 0000000000000000 1111010011010000 0000000000010010 1110001100000001 0000000000010000 1111110000010000 0000000000010001 0000000000010000 1110111111001000 0000000000010001 1110101010001000 0000000000010000 1111110000010000 0000000000000000 1111010011010000 0000000000010010 1110001100000001 0000000000010000 1111110000010000 0000000000010001 1111110000010000 ... Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Program compilation: 1-tier Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Program compilation: 1-tier that Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Program compilation: 1-tier that Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Program compilation: 1-tier Depending on the degree of coupling between ‘front end’ source parsing and ‘back end’ code generation, there might be some scope for shared elements. that Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Program compilation: 2-tier that Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Program compilation: 2-tier abstraction that Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Program compilation: 2-tier abstraction that Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Program compilation: 2-tier Only a single front-end is required for all target architectures. abstraction that Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Jack compilation Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Jack compilation Front end: projects 10,11 Back end: projects 7,8 Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Jack compilation Both emulation and full translation of VM code are options. virtual machine ‘Just-in-time’ (JIT) compilation offers a hybrid approach. JIT actually pioneered at Kent by Peter Brown: ‘throw-away compiling’ for BASIC in the 1970s. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The big picture Human Thought Write a program Abstraction High Level Language Compiler OS Abstraction VM Code VM translator Abstraction p7 p8 machine language Virtual Machine (chapters 7-8) • Understanding the VM abstraction • Building a VM implementation Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The big picture Stack machine abstraction • Architecture • Commands Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Stack top Stack operations: • push: add an element at the stack’s top • pop: remove the top element Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Stack NB: the stack here grows downwards, so the ‘top’ of the stack appears visually to move down as items are pushed and up as items are popped. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Stack NB: the stack here grows downwards, so the ‘top’ of the stack appears visually to move down as items are pushed and up as items are popped. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Stack NB: the stack here grows downwards, so the ‘top’ of the stack appears visually to move down as items are pushed and up as items are popped. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Stack arithmetic Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Stack arithmetic Applying a function f on the stack: • pops the argument(s) from the stack • Computes f on the arguments • Pushes the result onto the stack. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Stack arithmetic Applying a function f on the stack: • pops the argument(s) from the stack • Computes f on the arguments • Pushes the result onto the stack. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Stack arithmetic Applying a function f on the stack: • pops the argument(s) from the stack • Computes f on the arguments • Pushes the result onto the stack. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Stack arithmetic Applying a function f on the stack: • pops the argument(s) from the stack • Computes f on the arguments • Pushes the result onto the stack. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Stack arithmetic Applying a function f on the stack: • pops the argument(s) from the stack • Computes f on the arguments • Pushes the result onto the stack. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken NB: The function’s arguments are always removed from the stack before the operation is performed. The operation is never performed directly on a value in the stack. Stack arithmetic Applying a function f on the stack: • pops the argument(s) from the stack • Computes f on the arguments • Pushes the result onto the stack. NB: The function’s arguments are always removed from the stack before the operation is performed. The operation is never performed directly on a value in the stack. At least, that’s the specification view, but practical implementations might behave differently! Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Stack arithmetic Applying a function f on the stack: • pops the argument(s) from the stack • Computes f on the arguments • Pushes the result onto the stack. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Stack arithmetic Applying a function f on the stack: • pops the argument(s) from the stack • Computes f on the arguments • Pushes the result onto the stack. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Stack arithmetic Applying a function f on the stack: • pops the argument(s) from the stack • Computes f on the arguments • Pushes the result onto the stack. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Stack arithmetic Applying a function f on the stack: • pops the argument(s) from the stack • Computes f on the arguments • Pushes the result onto the stack. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Stack arithmetic Applying a function f on the stack: • pops the argument(s) from the stack • Computes f on the arguments • Pushes the result onto the stack. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Stack arithmetic (big picture) high-level x = 17 + 19 lower-level compile push 17 push 19 add pop x Abstraction / implementation • The high-level language is an abstraction; • It can be implemented by a stack machine. • The stack machine is also an abstraction; • It can implemented by... Stay tuned. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The stack machine model Stack machine, manipulated by: • Arithmetic / logical commands • Memory segment commands • Branching commands • Function commands Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Arithmetic commands VM code // d=(2-x)+(y+9) Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Arithmetic commands VM code // d=(2-x)+(y+9) push 2 push x sub push y push 9 add add pop d Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Arithmetic commands VM code // d=(2-x)+(y+9) push 2 For the time being, we are not concerned with how the translation from Jack to VM is achieved. push x sub We focus now on the VM execution model. push y push 9 add add pop d Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Arithmetic commands VM code // d=(2-x)+(y+9) push 2 push x sub push y push 9 add add pop d Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Arithmetic commands VM code // d=(2-x)+(y+9) push 2 push x sub push y push 9 add add pop d Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Arithmetic commands VM code // d=(2-x)+(y+9) push 2 push x sub push y push 9 add add pop d Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Arithmetic commands VM code // d=(2-x)+(y+9) push 2 push x sub push y push 9 add add pop d Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Arithmetic commands VM code // d=(2-x)+(y+9) push 2 push x sub push y push 9 add add pop d Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Arithmetic commands VM code // d=(2-x)+(y+9) push 2 push x sub push y push 9 add add pop d Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Arithmetic commands VM code // d=(2-x)+(y+9) push 2 push x sub push y push 9 add add pop d Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Arithmetic commands VM code // d=(2-x)+(y+9) push 2 push x sub push y push 9 add add pop d Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Arithmetic commands VM code // d=(2-x)+(y+9) push 2 push x sub push y push 9 add add pop d Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Arithmetic commands VM code // d=(2-x)+(y+9) push 2 push x sub push y push 9 add add pop d Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Arithmetic commands VM code // d=(2-x)+(y+9) push 2 push x sub push y push 9 add add pop d Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Arithmetic commands VM code // d=(2-x)+(y+9) push 2 push x sub push y push 9 add add pop d Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Arithmetic commands VM code // d=(2-x)+(y+9) push 2 push x sub push y push 9 add add pop d 21 Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Arithmetic commands VM code // d=(2-x)+(y+9) push 2 push x sub push y push 9 add add pop d 21 Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Arithmetic commands VM code // d=(2-x)+(y+9) push 2 push x sub push y push 9 add add pop d 21 Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Arithmetic commands VM code // d=(2-x)+(y+9) push 2 push x sub push y push 9 add add pop d 21 Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Arithmetic commands VM code // d=(2-x)+(y+9) push 2 push x sub push y push 9 add add pop d 21 Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Arithmetic commands VM code // d=(2-x)+(y+9) push 2 push x sub push y push 9 add add pop d 21 Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Logical commands VM code // (x<7) or (y==8) Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Logical commands VM code // (x<7) or (y==8) push x push 7 lt push y push 8 eq or NB: ‘or’ here is a fully-evaluating operator, in contrast to Java’s short-circuit operator: || Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Logical commands VM code // (x<7) or (y==8) push x push 7 lt push y push 8 eq or NB: ‘or’ here is a fully-evaluating operator, in contrast to Java’s short-circuit operator: || Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Arithmetic / Logical commands Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Arithmetic / Logical commands Command Return value Return value add x+y integer sub x-y integer neg -y integer eq x==0 boolean gt x>y boolean lt x<y boolean and x and y boolean or x or y boolean not not x boolean x y Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Arithmetic / Logical commands Command Return value Return value add x+y integer sub x-y integer neg -y integer eq x == y boolean gt x>y boolean lt x<y boolean and x and y boolean or x or y boolean not not x boolean x y NB: <= and >= are missing. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Arithmetic / Logical commands Command Return value Return value add x+y integer sub x-y integer neg -y integer eq x == y boolean gt x>y boolean lt x<y boolean and x and y boolean or x or y boolean not not x boolean x y NB: <= and >= are missing. NB: Both and and or are fully evaluating. Observation: Any arithmetic or logical expression can be expressed and evaluated by applying some sequence of the above operations on a stack. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The stack machine model Stack machine, manipulated by: • Arithmetic / logical commands • Memory segment commands • Branching commands • Function commands Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The big picture Compiled VM code Source code (Jack) class Foo { ... ... static int s1, s2; function int bar (int x, int y) { var int a, b, c; ... let c = s1 + y; ... } } compile ... ... ... ... ... ... ... ... Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The big picture Compiled VM code Source code (Jack) class Foo { ... ... static int s1, s2; function int bar (int x, int y) { var int a, b, c; ... let c = s1 + y; ... } } compile ... ... push s1 push y add pop c ... ... Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The big picture Compiled VM code Source code (Jack) class Foo { ... ... static int s1, s2; function int bar (int x, int y) { var int a, b, c; ... let c = s1 + y; ... } } compile ... ... push s1 push y add pop c ... ... Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Variable kinds Compiled VM code Source code (Jack) class Foo { ... ... static int s1, s2; function int bar (int x, int y) { var int a, b, c; ... let c = s1 + y; compile ... } ... ... push s1 push y add pop c ... ... } Variable kinds • Argument variables • Local variables • Static variables • (More kinds later) Each kind of variable arises in a different context: • Arguments are provided by the caller. • Locals are local to the callee. • Statics come into existence at program startup and persist. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Variable kinds and memory segments Compiled VM code Source code (Jack) class Foo { ... ... static int s1, s2; function int bar (int x, int y) { var int a, b, c; ... compile let c = s1 + y; ... } ... ... push s1 push y add pop c ... ... } Virtual memory segments: x y a b c s1 s2 NB: It is not uncommon for arguments and locals to be stored on a single runtime stack but that makes stack management more complex than this approach. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Variable kinds and memory segments Compiled VM code Source code (Jack) class Foo { ... ... static int s1, s2; function int bar (int x, int y) { var int a, b, c; ... compile let c = s1 + y; ... } ... ... push static 0 push y add pop c ... ... } Virtual memory segments: x y a b c s1 s2 Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Variable kinds and memory segments Compiled VM code Source code (Jack) class Foo { ... ... static int s1, s2; function int bar (int x, int y) { var int a, b, c; ... compile let c = s1 + y; ... } ... ... push static 0 push argument 1 add pop c ... ... } Virtual memory segments: x y a b c s1 s2 Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Variable kinds and memory segments Compiled VM code Source code (Jack) class Foo { ... ... static int s1, s2; function int bar (int x, int y) { var int a, b, c; ... compile let c = s1 + y; ... } ... ... push static 0 push argument 1 add pop local 2 ... ... } Virtual memory segments: x y a b c s1 s2 Following compilation, all the symbolic references are replaced with references to virtual memory segments Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Memory segments Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Memory segments The constant segment doesn’t necessarily exist in memory like the others. Syntax: push / pop segment i Examples: • push constant 17 • pop local 2 • pop static 5 • push argument 3 • ... Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Memory segments memory memory segments segment 0 1 2 3 ... local argument this . .... . ... ... . .... . ... ... ... Syntax: push segment i Where segment is: argument, local, static, constant, this, that, pointer, or temp and i is a non-negative integer. Syntax: pop segment i Where segment is: argument, local, static, this, that, pointer, or temp and i is a non-negative integer. that constant static pointer temp Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Quiz: write the missing code let static 2 = argument 1 ? Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The stack machine model VM language: • Arithmetic / logical commands • Memory segment commands • Branching commands • Function commands We will look at the branching and function commands in Chapter 8. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Review • We have seen that compiling high-level source to an intermediate form has the potential to reduce the cost of implementing a language on a new architecture. • Compiling different high-level languages to a common intermediate form means a new language can be introduced relatively quickly. • A stack-based ‘virtual machine’ provides a good abstraction to serve as the intermediate step in compilation of procedural and object-oriented languages. • The next step will be to look at translating VM instructions to Hack assembly code. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken COMP5570: The Virtual Machine, Part I David Barnes Chapter 7 Translation to Hack Asm These slides support chapter 7 of the book The Elements of Computing Systems By Noam Nisan and Shimon Schocken MIT Press Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Virtual machine Overview VM implementation platforms ü The road ahead • VM emulator ü Program compilation • VM translator VM abstraction The VM translator ü the stack • Proposed implementation ü memory segments • Building it (project 7) VM implementation • the stack • memory segments Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Memory segments memory memory segments segment 0 1 2 3 ... local argument this that . .... . ... ... . .... . ... ... ... constant static pointer temp Syntax: push segment i Where segment is: argument, local, static, constant, this, that, pointer, or temp and i is a non-negative integer. Syntax: pop segment i Where segment is: argument, local, static, this, that, pointer, or temp and i is a non-negative integer. NB: No pop constant. (Why not?) Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The VM abstraction let static 2 = argument 1 push argument 1 pop static 2 Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The VM stack architecture • All of the arithmetic and logical operations depend on the existence of a stack. Operands pushed prior to evaluation. q Operands popped in order to apply the operation. q Result pushed to the stack. q • Function/method calling (Chapter 8) will require the use of a stack to store return addresses. • However! The Hack architecture does not have a stack. • Supporting the stack abstraction will be a major part of the translation/implementation effort. • Limited registers (A and D) mean this requires considerable thought. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Standard VM mapping on the Hack platform Hack RAM Looking ahead The Hack architecture has a single linear RAM, so the separate segments must be realised using that. Each segment is simulated by having a dedicated RAM location that stores its base (LCL (RAM[1]), ARG (RAM[2]), etc.). Segment offsets are added to the base address; e.g, push local 2 would be translated to push RAM[RAM[LCL] + 2] LCL, ARG, etc. act as ‘pointers’. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Pointer manipulation Not present in Java but common in languages like C. Variables containing addresses are called pointers. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Pointer manipulation Pseudo assembly code Not present in Java but common in languages like C. D = *p Variables containing addresses are called pointers. In C, * is a ‘dereferencing operator’. *p means, access the memory location for which p stores the address. Notation: *p // the memory location that p points at Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken ‘Follow the pointer.’ Pointer manipulation Pseudo assembly code D = *p // D becomes 23 In Hack: Variables containing addresses are called pointers. @p A=M D=M Recall that M means RAM[A] Notation: *p Not present in Java but common in languages like C. // the memory location that p points at Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken In C, * is a ‘dereferencing operator’. *p means, access the memory location for which p stores the address. ‘Follow the pointer.’ Pointer manipulation Pseudo assembly code D = *p // D becomes 23 p-D = *p Not present in Java but common in languages like C. Variables containing addresses are called pointers. In C, * is a ‘dereferencing operator’. *p means, access the memory location for which p stores the address. Notation: *p // the memory location that p points at p++ // increment: p = p + 1 p-- // decrement: p = p - 1 Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken ‘Follow the pointer.’ Pointer manipulation Pseudo assembly code D = *p // D becomes 23 p-D = *p // RAM[0] becomes 256 // D becomes 19 Not present in Java but common in languages like C. Variables containing addresses are called pointers. In C, * is a ‘dereferencing operator’. *p means, access the memory location for which p stores the address. Notation: *p // the memory location that p points at p++ // increment: p = p + 1 p-- // decrement: p = p - 1 Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken ‘Follow the pointer.’ Pointer manipulation Pseudo assembly code D = *p // D becomes 23 p-D = *p // RAM[0] becomes 256 // D becomes 19 *q = 9 q++ Not present in Java but common in languages like C. Variables containing addresses are called pointers. In C, * is a ‘dereferencing operator’. *p means, access the memory location for which p stores the address. Notation: *p // the memory location that p points at p++ // increment: p = p + 1 p-- // decrement: p = p - 1 Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken ‘Follow the pointer.’ Pointer manipulation Pseudo assembly code D = *p // D becomes 23 p-D = *p // RAM[0] becomes 256 // D becomes 19 *q = 9 q++ // RAM[1024] becomes 9 // RAM[1] becomes 1025 Notation: *p // the memory location that p points at p++ // increment: p = p + 1 p-- // decrement: p = p - 1 Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Not present in Java but common in languages like C. Variables containing addresses are called pointers. In C, * is a ‘dereferencing operator’. *p means, access the memory location for which p stores the address. ‘Follow the pointer.’ Stack implementation Abstraction: Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Stack implementation Abstraction: Implementation: Assumptions: • SP stored in RAM[0] • Stack base addr = 256 Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Stack implementation Abstraction: Logic: *SP = 17 Implementation: Assumptions: SP++ Hack assembly: • SP stored in RAM[0] • Stack base addr = 256 Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Stack implementation Abstraction: Logic: *SP = 17 Implementation: Assumptions: SP++ Hack assembly: • SP stored in RAM[0] @17 • Stack base addr = 256 D=A @SP // D=17 // *SP=D A=M M=D @SP // SP++ M=M+1 Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken How to implement push D. Stack implementation VM code: push constant i Assembly pseudo code: VM translator *SP = i , SP++ VM Translator • A program that translates VM commands into lower-level commands of some host platform (like the Hack computer) • Each VM command generates one or more low-level commands • The low-level commands end up realizing the stack and the memory segments on the host platform. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Virtual machine: lecture plan Overview VM implementation platforms ü The road ahead • VM emulator ü Program compilation • VM translator VM abstraction The VM translator ü the stack • Proposed implementation ü memory segments • Building it (project 7) VM implementation ü the stack • memory segments Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Memory segments (abstraction) memory segment Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Memory segments (abstraction) memory segments 0 1 2 3 ... Syntax: push/pop segment i Examples: • push constant 17 • pop local 2 • pop static 5 • push argument 3 • pop this 2 • ... local argument this ... ... ... ... ... ... ... ... ... that constant static pointer temp Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Implementing push/pop local i memory segments 0 1 2 3 ... Syntax: push/pop local i local argument this ... ... ... ... ... ... ... ... ... that constant static pointer temp Why do we need a local segment? When the compiler translates high-level code into VM code... • high-level operations on local variables are translated into VM operations on the entries of the segment local • We now turn to describe how the local segment can be realized on the host platform. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Implementing pop local i (example) Abstraction: Write it in Hack assembly Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Implementing pop local i (example) Abstraction: stack pointer base address of the local segment Implementation: the local segment is stored somewhere in the RAM Write it in Hack assembly Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Implementing pop local i (example) Abstraction: stack pointer Implementation: addr=LCL+2, SP--, *addr=*SP base address of the local segment Implementation: the local segment is stored somewhere in the RAM Notation is slightly confusing because the address is actually RAM[LCL] + 2 or *LCL + 2 Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Implementing pop local i Abstraction: i i stack pointer Implementation: addr=LCL+ i, SP--, *addr=*SP base address of the local segment Hack assembly: Implementation: the local segment is stored somewhere in the RAM You write it! Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken NB: This is considerably more complex than implementing the push instruction. Hint: You will probably need to use a ‘temporary’. Implementing push/pop local i VM code: Assembly pseudo code: pop local i addr = LCL+ i, SP--, *addr = *SP VM Translator push local i addr = LCL+ i, *SP = *addr, SP++ stack pointer base address of the local segment Implementation: the local segment is stored somewhere in the RAM The base address of the local segment will vary throughout the life of a program. It will be different for each function called. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Memory segments memory segments 0 1 2 3 ... Syntax: push/pop segment i local argument this ... ... ... ... ... ... ... ... ... that constant static pointer temp • We know how to implement push/pop local i • We now turn to implementing push/pop operations on the segments argument, this, and that. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Implementing push/pop local/argument/this/that i memory segments 0 1 2 3 ... ... ... ... Syntax: push/pop local/argument/this/that i ... ... ... Why do we need these four segments? ... ... When the compiler translates high-level code into VM code... ... • high-level operations on local variables are translated into VM operations on the entries of the segment local • high-level operations on argument variables are translated into VM operations on the entries of the segment argument • high-level operations on the field variables of the current object are translated into VM operations on the entries of the segment this • high-level operations on array entries are translated into VM operations on the entries of the segment that local argument this that constant static pointer temp We now turn to describe how these four segments can be realized on the host platform. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Implementing push/pop local/argument/this/that i VM code: Assembly pseudo code: push segment i addr = segmentPointer + i, *SP = *addr, SP++ VM translator pop segment i addr = segmentPointer + i, SP--, *addr = *SP segment = {local, argument, this, that} The base addresses of all these segments will vary throughout the life of a program. Host RAM base addresses of the four segments are stored in these pointers • push/pop local i • push/pop argument i • push/pop this i the four segments are stored somewhere in the RAM are implemented precisely the same way • push/pop that i Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Memory segments memory segments 0 1 2 3 ... Syntax: push/pop segment i local argument this ... ... ... ... ... ... ... ... ... that constant static pointer temp Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Implementing push constant i memory segments 0 1 2 3 ... Syntax: push constant i local argument this ... ... ... ... ... ... ... ... ... that constant static pointer temp Why do we need a constant segment? Because we need to represent constants somehow in the VM level. When the compiler translates high-level code into VM code... • high-level operations on the constant i are translated into VM operations on the segment entry constant i • This syntactical convention will make sense when we write the compiler. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Implementing push constant i VM code: push constant i Assembly psuedo code: VM Translator *SP = i, SP++ (no pop constant operation) Implementation: Supplies the specified constant Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Memory segments memory segments 0 1 2 3 ... Syntax: push/pop segment i local argument this ... ... ... ... ... ... ... ... ... that constant static pointer temp Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Implementing push/pop static i memory segments 0 1 2 3 ... Syntax: push/pop static i local argument this ... ... ... ... ... ... ... ... ... that constant static pointer temp Why do we need a static segment? When translating high-level code into VM code: • high-level operations on static variables are translated into VM operations on entries of the segment static • We now turn to discuss how the static segment is realized on the host platform. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Implementing push/pop static i VM code: Generated assembly code: // File Foo.vm ... ... // D = stack.pop (code omitted) pop static 5 @Foo.5 ... VM translator M=D pop static 2 ... ... // D = stack.pop (code omitted) The challenge: static variables should be seen by all the methods in a program @Foo.2 M=D ... Solution: Store them in some “global space”: • Have the VM translator translate each VM reference static i (in file Foo.vm) into an assembly reference Foo.i Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Implementing push/pop static i VM code: Generated assembly code: // File Foo.vm ... ... // D = stack.pop (code omitted) pop static 5 @Foo.5 ... VM translator M=D pop static 2 ... ... // D = stack.pop (code omitted) The challenge: static variables should be seen by all the methods in a program Hack RAM @Foo.2 M=D ... Solution: Store them in some “global space”: • Have the VM translator translate each VM reference static i (in file Foo.vm) into an assembly reference Foo.i • Following assembly, the Hack assembler will map these references onto RAM[16], RAM[17], ..., RAM[255] • Therefore, the entries of the static segment will end up being mapped onto RAM[16], RAM[17], ..., RAM[255], in the order in which they appear in the program. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The static segment’s implementation is different from that of the previous segments. There is no associated ‘pointer’. Memory segments memory segments 0 1 2 3 ... Syntax: push/pop segment i local argument this ... ... ... ... ... ... ... ... ... that constant static temp pointer Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Implementing push/pop temp i memory segments 0 1 2 3 ... Syntax: push/pop temp i local argument this ... ... ... ... ... ... ... ... ... that constant static temp pointer Why do we need the temp segment? • So far, all the variable kinds that we discussed came from the source code. • Sometimes, the compiler needs to use some working variables of its own. (NB: Not to be confused with the implementation’s use of working (temporary) variables.) • Our VM provides 8 such variables, stored in a segment named temp. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Implementing push/pop temp i VM code: push temp i Hack RAM pop temp i Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Implementing push/pop temp i VM code: Assembly psuedo code: push temp i addr = 5 + i, *SP = *addr, SP++ VM Translator Hack RAM pop temp i addr = 5 + i, SP--, *addr = *SP A fixed, 8-place memory segment, stored in RAM locations 5 to 12 NB: There is no RAM location called TEMP that stores the base address. The base address is fixed at 5. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Memory segments memory segments 0 1 2 3 ... Syntax: push/pop segment i local argument this ... ... ... ... ... ... ... ... ... that constant static temp pointer Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Implementing push/pop pointer 0/1 memory segments 0 1 2 3 ... Syntax: push/pop pointer 0/1 local argument this ... ... ... ... ... ... ... ... ... that constant static temp pointer Why do we need the pointer segment? • We use it for storing the base addresses of the segments this and that • The need for this will become clear when we’ll write the compiler. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Implementing push/pop pointer 0/1 VM code: Assembly psuedo code: push pointer 0/1 *SP = THIS/THAT, SP++ VM Translator pop pointer 0/1 SP--, THIS/THAT = *SP A fixed, 2-place segment: • • accessing pointer 0 should result in accessing THIS accessing pointer 1 should result in accessing THAT NB: There is no RAM location called POINTER. References are mapped to THIS and THAT depending on the index used. Implementation: Supplies THIS or THAT // (the base addresses of this and that). Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken VM language Arithmetic / Logical commands add Branching commands label label sub neg goto label eq if-goto label get lt and or not Memory access commands Function commands function functionName nVars call functionName nArgs return pop segment i push segment i Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Review • We have reviewed the operation of the push and pop instructions, which are fundamental to all the low-level operations. • We have introduced the concept of ‘pointer’: a memory location holding the address of another location. • Managing a ‘stack pointer’ (SP) will be crucial to the Hack implementation of the VM. • We have seen how implementation of several of the VM’s segments is supported by dedicated pointers stored in lowaddress RAM locations: LCL, ARG, THIS and THAT. • The constant, pointer, static and temp segments have distinctive implementations in the Hack architecture. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Virtual machine: lecture plan ü The road ahead • The VM emulator ü Program compilation overview • VM implementation on the Hack platform ü VM abstraction: • The VM translator: proposed implementation ü the stack ü memory segments ü VM implementation: • Building the VM translator, Part I ü the stack ü memory segments Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The VM Emulator Typical uses of the VM emulator: • Running (compiled) Jack programs • Experimenting with VM commands • Observing the VM internals (stack, memory segments) • Observing how the VM is realized on the host platform. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The VM Emulator execution controls Multi-purpose pane: • Program output VM code Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The VM Emulator execution controls Multi-purpose pane: • Program output • Test script • Output file • Compare file VM code stack memory segments Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Example BasicTest.vm ... push constant 10 pop local 0 push constant 21 push constant 22 pop argument 2 pop argument 1 push constant 36 pop this 6 ... VM code abstraction Things to watch for: (during the code’s execution) • Stack state • Memory segments states implementation How the stack and memory segments are realized on the host platform Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Test script BasicTest.vm BasicTestVME.tst ... push constant 10 pop local 0 push constant 21 push constant 22 pop argument 2 pop argument 1 push constant 36 pop this 6 ... Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Test script There’s no need to delve into the code of test scripts BasicTestVME.tst BasicTest.vm load BasicTest.vm, output-file BasicTest.out, compare-to BasicTest.cmp, output-list RAM[256]%D1.6.1 RAM[300]%D1.6.1 ... ... push constant 10 pop local 0 push constant 21 push constant 22 pop argument 2 pop argument 1 push constant 36 pop this 6 ... BasicTest.out BasicTest.cmp |RAM[256]|RAM[300]|RAM[401]|RAM[402]|RAM[3006|RAM[3012|RAM[3015|RAM[11] | | 472 | 10 | 21 | 22 | 36 | 42 | 45 | 510 | Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Test script There’s no need to delve into the code of test scripts BasicTestVME.tst BasicTest.vm load BasicTest.vm, output-file BasicTest.out, compare-to BasicTest.cmp, output-list RAM[256]%D1.6.1 RAM[300]%D1.6.1 ... ... push constant 10 pop local 0 push constant 21 push constant 22 pop argument 2 pop argument 1 push constant 36 pop this 6 ... repeat 25 { vmstep; } // BasicTest.vm has 25 instructions // Outputs some values, as specified by the output-list // (stack base + selected values from the tested mem. segments) output; BasicTest.out BasicTest.cmp |RAM[256]|RAM[300]|RAM[401]|RAM[402]|RAM[3006|RAM[3012|RAM[3015|RAM[11] | | 472 | 10 | 21 | 22 | 36 | 42 | 45 | 510 | Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Test script There’s no need to delve into the code of test scripts BasicTestVME.tst BasicTest.vm load BasicTest.vm, output-file BasicTest.out, compare-to BasicTest.cmp, output-list RAM[256]%D1.6.1 RAM[300]%D1.6.1 ... ... push constant 10 pop local 0 push constant 21 push constant 22 pop argument 2 pop argument 1 push constant 36 pop this 6 ... repeat 25 { vmstep; } // BasicTest.vm has 25 instructions // Outputs some values, as specified by the output-list // (stack base + selected values from the tested mem. segments) output; BasicTest.out if (.out == .cmp ) the test is successful else error |RAM[256]|RAM[300]|RAM[401]|RAM[402]|RAM[3006|RAM[3012|RAM[3015|RAM[11] | | 472 | 10 | 21 | 22 | 36 | 42 | 45 | 510 | BasicTest.cmp |RAM[256]|RAM[300]|RAM[401]|RAM[402]|RAM[3006|RAM[3012|RAM[3015|RAM[11] | | 472 | 10 | 21 | 22 | 36 | 42 | 45 | 510 | Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Some missing elements BasicTest.vm ... push constant 10 pop local 0 push constant 21 push constant 22 pop argument 2 pop argument 1 push constant 36 pop this 6 ... BasicTestVME.tst There’s no need to delve into the code of test scripts load BasicTest.vm, output-file BasicTest.out, compare-to BasicTest.cmp, output-list RAM[256]%D1.6.1 RAM[300]%D1.6.1 ... repeat 25 { vmstep; } // BasicTest.vm has 25 instructions // Outputs some values, as specified by the output-list // (stack base + selected values from the tested mem. segments) output; Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Some missing elements BasicTest.vm function Foo.bar ... push constant 10 pop local 0 push constant 21 push constant 22 pop argument 2 pop argument 1 push constant 36 pop this 6 ... return BasicTestVME.tst There’s no need to delve into the code of test scripts load BasicTest.vm, output-file BasicTest.out, compare-to BasicTest.cmp, output-list RAM[256]%D1.6.1 RAM[300]%D1.6.1 ... set sp 256, set local 300, set argument 400, set this 3000, set that 3010, // stack pointer // base address of the local segment // base address of the argument segment // base address of the this segment // base address of the that segment repeat 25 { vmstep; } // BasicTest.vm has 25 instructions // Outputs some values, as specified by the output-list // (stack base + selected values from the tested mem. segments) output; Some missing elements • function / return “envelope” Initialization is handled manually by the supplied test script • Initializing the stack and the memory segments on the host RAM • (both will be added in project 8) Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Recap: the VM Emulator The VM emulator helps us: • Run and test high-level programs • Understand ... o the VM abstraction o the VM implementation Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Virtual machine: lecture plan ü The road ahead ü The VM emulator ü Program compilation overview • VM implementation on the Hack platform ü VM abstraction: • The VM translator: proposed implementation ü the stack ü memory segments ü VM implementation: • Building the VM translator, Part I ü the stack ü memory segments Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken VM translator VM code push constant 2 push local 0 sub push local 1 push constant 5 add sub pop local 2 ... Assembly code VM translator Each VM command is translated into several assembly commands // push constant 2 @2 D=A @SP A=M M=D @SP M=M+1 // push local 0 ... In order to write a VM translator, we must be familiar with: Ø the source language the target language Ø the VM mapping on the target platform. Ø Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Source: VM language Arithmetic / Logical commands add sub neg eq gt lt Branching commands label label goto label if-goto label Function commands and or function functionName nVars not call functionName nArgs return Memory access commands pop segment i push segment i Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Target: symbolic Hack code A instruction: @ value where value is either a non-negative decimal constant or a symbol referring to such a constant sets the A register to value; q makes M the RAM location whose address is value. q (M stands for RAM[A]) Semantics: q C instruction: dest = comp ; jump (dest and jump are optional) where: comp = dest = jump = Semantics: 0, 1, -1, D, A, !D, !A, -D, -A, D+1, A+1, D-1, A-1, D+A, D-A, A-D, D&A, D|A, M, !M, -M, M+1, M-1, D+M, D-M, M-D, D&M, D|M null, M, D, MD, A, AM, AD, AMD q (M stands for RAM[A]) null, JGT, JEQ, JGE, JLT, JNE, JLE, JMP q computes the value of comp and stores the result in dest; q if (comp jump 0) is true, jumps to execute the instruction in ROM[A]. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Standard VM mapping on the Hack platform VM mapping decisions: • How to map the VM’s data structures using the host hardware platform • How to express the VM’s commands using the host machine language Standard mapping: • Specifies how to do the mapping in an agreed-upon way • Benefits: q Compatibility with other software systems q Standard testing. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Standard VM mapping on the Hack platform Hack RAM Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Standard VM mapping on the Hack platform Hack RAM local, argument, this, that: allocated dynamically to the RAM. The base addresses of these allocations are kept in the segment pointers LCL, ARG, THIS, THAT accessing segment i should result in accessing RAM[*segmentPointer + i] constant: accessing constant i should result in supplying the constant i static: accessing static i within file Foo.vm should result in accessing the assembly variable Foo.i temp: fixed segment, mapped on RAM addresses 5-12. accessing temp i should result in accessing RAM[5+i] pointer: fixed segment, mapped on RAM addresses 3-4. accessing pointer 0 should result in accessing THIS accessing pointer 1 should result in accessing THAT Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Standard VM mapping on the Hack platform Hack RAM In order to realize this mapping, the VM translator should use some special variables / symbols: Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Standard VM mapping on the Hack platform Hack RAM In order to realize this mapping, the VM translator should use some special variables / symbols: Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Standard VM mapping on the Hack platform Hack RAM In order to realize this mapping, the VM translator should use some special variables / symbols: Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Standard VM mapping on the Hack platform Hack RAM In order to realize this mapping, the VM translator should use some special variables / symbols: Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Standard VM mapping on the Hack platform Hack RAM In order to realize this mapping, the VM translator should use some special variables / symbols: Implementation note: The standard mapping will be extended in project 8, when we’ll complete the VM translator’s implementation. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Virtual machine: lecture plan ü The road ahead ü The VM emulator ü Program compilation overview ü VM implementation on the Hack platform ü VM abstraction: • The VM translator: proposed implementation ü the stack ü memory segments ü VM implementation: • Building the VM translator, Part I ü the stack ü memory segments Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The VM translator VM code ( fileName.vm) Generated assembly code ( fileName.asm) ... push constant 17 push local 2 add VM translator pop argument 1 ... Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The VM translator VM code ( fileName.vm) Generated assembly code ( fileName.asm) ... ... push constant 17 push local 2 add VM translator // push constant 17 @17 D=A ... additional assembly commands that complete the implementation of push constant 17 pop argument 1 ... Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The VM translator VM code ( fileName.vm) Generated assembly code ( fileName.asm) ... ... push constant 17 push local 2 add VM translator // push constant 17 @17 D=A ... additional assembly commands that complete the implementation of push constant 17 pop argument 1 ... Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The VM translator VM code ( fileName.vm) Generated assembly code ( fileName.asm) ... ... push constant 17 push local 2 add pop argument 1 VM translator // push constant 17 @17 D=A ... additional assembly commands that complete the implementation of push constant 17 // push local 2 ... generated assembly code that implements push local 2 ... Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The VM translator VM code ( fileName.vm) Generated assembly code ( fileName.asm) ... ... push constant 17 push local 2 add pop argument 1 VM translator // push constant 17 @17 D=A ... additional assembly commands that complete the implementation of push constant 17 // push local 2 ... generated assembly code that implements push local 2 ... Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The VM translator VM code ( fileName.vm) Generated assembly code ( fileName.asm) ... ... push constant 17 push local 2 add pop argument 1 ... VM translator // push constant 17 @17 D=A ... additional assembly commands that complete the implementation of push constant 17 // push local 2 ... generated assembly code that implements push local 2 // add ... generated assembly code that implements add Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The VM translator VM code ( fileName.vm) Generated assembly code ( fileName.asm) ... ... push constant 17 push local 2 add pop argument 1 ... VM translator // push constant 17 @17 D=A ... additional assembly commands that complete the implementation of push constant 17 // push local 2 ... generated assembly code that implements push local 2 // add ... generated assembly code that implements add Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The VM translator VM code ( fileName.vm) Generated assembly code ( fileName.asm) ... ... push constant 17 push local 2 add pop argument 1 ... VM translator // push constant 17 @17 D=A ... additional assembly commands that complete the implementation of push constant 17 // push local 2 ... generated assembly code that implements push local 2 // add ... generated assembly code that implements add // pop argument 1 ... generated assembly code that implements push argument 1 ... Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The VM translator: usage % % java VMTranslator myProg.vm % Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Implementation Proposed design: • Parser: parses each VM command into its lexical elements • CodeWriter: writes the assembly code that implements the parsed command • Main: drives the process (VMTranslator) Main (VMTranslator) Input: fileName.vm Output: fileName.asm Main logic: • Constructs a Parser to handle the input file • Constructs a CodeWriter to handle the output file • Marches through the input file, parsing each line and generating code from it Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Parser • Handles the parsing of a single .vm file • Reads a VM command, parses the command into its lexical components, and provides convenient access to these components • Ignores all white space and comments Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Parser • Handles the parsing of a single .vm file • Reads a VM command, parses the command into its lexical components, and provides convenient access to these components • Ignores all white space and comments Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Parser • Handles the parsing of a single .vm file • Reads a VM command, parses the command into its lexical components, and provides convenient access to these components • Ignores all white space and comments Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Parser • Handles the parsing of a single .vm file • Reads a VM command, parses the command into its lexical components, and provides convenient access to these components • Ignores all white space and comments Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken CodeWriter Generates assembly code from the parsed VM command: Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken CodeWriter Generates assembly code from the parsed VM command: Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken CodeWriter Generates assembly code from the parsed VM command: Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken CodeWriter Generates assembly code from the parsed VM command: More routines will be added to this module in Project 8, when we complete the implementation of the VM translator. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The big picture VM language: Arithmetic / Logical commands: add sub neg eq gt lt and or not Branching commands: label label goto label if-goto label Function commands: function functionName nVars call functionName nArgs return Memory access commands: pop segment i push segment i Project 7 Project 8 Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Virtual machine: lecture plan ü The road ahead ü The VM emulator ü Program compilation overview ü VM implementation on the Hack platform ü VM abstraction: ü The VM translator: proposed implementation ü the stack ü memory segments ü VM implementation: • Building the VM translator, Part I ü the stack ü memory segments Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The big picture human thought write a program abstraction p9 high-level language compiler abstraction p10 OS p12 p11 VM translator VM code abstraction p7 p8 machine language Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The big picture human thought write a program abstraction p9 high-level language compiler abstraction p10 OS p12 p11 VM translator VM code abstraction p7 p8 machine language Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken The VM language VM language: Arithmetic / Logical commands: add sub neg eq gt lt and or not Branching commands: label label goto label if-goto label Function commands: function functionName nVars call functionName nArgs return Memory access commands: pop segment i push segment i Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Project 7 Objective: build a basic VM translator that handles a subset of the VM language: stack arithmetic and memory access (push/pop) commands VM language: Arithmetic / Logical commands: add sub neg eq gt lt and or not Branching commands: label label goto label if-goto label Function commands: function functionName nVars call functionName nArgs return Memory access commands: pop segment i push segment i Project 7 Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Project 7 Objective: build a basic VM translator that handles a subset of the VM language: stack arithmetic and memory access (push/pop) commands fileName.vm fileName.asm ... push constant 17 push local 2 add pop argument 1 VM translator ... Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Project 7 Objective: build a basic VM translator that handles a subset of the VM language: stack arithmetic and memory access (push/pop) commands fileName.vm fileName.asm ... ... push constant 17 // push constant 17 @17 D=A ... // push local 2 ... generated assembly code that implements push local 2 push local 2 add pop argument 1 ... VM translator // add ... generated assembly code that implements add // pop argument 1 ... generated assembly code that implements push argument 1 ... To test the translation: Run the generated code on the target platform Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Project 7: testing human thought write a program abstraction p9 high-level language compiler abstraction p10 OS p12 p11 VM translator VM code abstraction p7 p8 machine language p6 Testing option 1: • Translate the generated assembly code into machine language, • Run the binary code of the Hack computer Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Project 7: testing human thought write a program abstraction p9 high-level language compiler abstraction p10 OS p12 p11 VM translator VM code abstraction p7 p8 machine language Testing option 2 (simpler): • Run the generated assembly code on the CPU emulator. CPU or emulat Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Development Plan Objective: build a basic VM translator that handles the VM language stack arithmetic and memory access (push/pop) commands Contract • Write a VM-to-Hack translator, conforming to the Standard VM-onHack Mapping • Use your VM translator to translate and test the supplied .vm programs, yielding corresponding .asm programs Test programs q q SimpleAdd StackTest q BasicTest PointerTest q StaticTest q q q q q BasicTest.vm BasicTest.tst BasicTest.cmp BasicTestVME.tst BasicTest.vm (example) ... push constant 510 pop temp 6 push local 0 BasicTest.asm push that 5 add ... push argument 1// push constant 510 sub @510 ... D=A ... Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Development Plan Objective: build a basic VM translator that handles the VM language stack arithmetic and memory access (push/pop) commands Contract • Write a VM-to-Hack translator, conforming to the Standard VM-onHack Mapping • Use your VM translator to translate and test the supplied .vm programs, yielding corresponding .asm programs • When executed on the supplied CPU emulator, the generated .asm programs should deliver the same results mandated by the supplied test scripts and compare files. Test programs q q SimpleAdd StackTest q BasicTest PointerTest q StaticTest q q q q q BasicTest.vm BasicTest.tst BasicTest.cmp BasicTestVME.tst BasicTest.vm (example) ... push constant 510 pop temp 6 push local 0 BasicTest.asm push that 5 add ... push argument 1// push constant 510 sub @510 ... D=A ... Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Development Plan Objective: build a basic VM translator that handles the VM language stack arithmetic and memory access (push/pop) commands For each test xxx.vm program: 0. (optional) load xxxVME.tst into the VM emulator; run the test script and inspect the program’s operation 1. use your translator to translate xxx.vm; The result will be a file named xxx.asm 2. inspect the generated code; If there’s a problem, fix your translator and go to stage 1 3. Load xxx.tst into the CPU emulator 4. Run the test script, inspect the results 5. If there’s a problem, fix your translator and go to stage 1. Test programs q q SimpleAdd StackTest q BasicTest PointerTest q StaticTest q q q q q BasicTest.vm BasicTest.tst BasicTest.cmp BasicTestVME.tst BasicTest.vm (example) ... push constant 510 pop temp 6 push local 0 BasicTest.asm push that 5 add ... push argument 1// push constant 510 sub @510 ... D=A ... Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Tools and resources Objective: build a basic VM translator that handles the VM language stack arithmetic and memory access (push/pop) commands Tools and resources: • Test programs and compare files: nand2tetris/projects/07 • Experimenting with the test VM programs: the supplied VM emulator • Translating the test VM programs into assembly: your VM translator • Testing the resulting assembly code: the supplied CPU emulator • Programming language for implementing your VM translator: Java, Python, ... • Tutorials: VM emulator, CPU emulator (nand2tetris web site) • Reference: chapter 7 in The Elements of Computing Systems Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Some testing issues Objective: build a basic VM translator that will be extended in project 8 BasicTest.vm ... push constant 510 pop temp 6 push local 0 push that 5 add push argument 1 BasicTest.asm sub ... push this 6 // push constant 510 ... @510 D=A ... Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Some testing issues Objective: build a basic VM translator that will be extended in project 8 BasicTest.tst (for CPU emulator) BasicTest.vm function Foo.bar ... push constant 510 pop temp 6 push local 0 push that 5 add push argument 1 BasicTest.asm sub ... push this 6 // push constant 510 ... return @510 D=A ... Missing elements (in project 7) • function / return “envelope” • Mapping of the stack and the memory segments on the host RAM Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Some testing issues Objective: build a basic VM translator that will be extended in project 8 BasicTest.tst (for CPU emulator) BasicTest.vm load BasicTest.asm, function Foo.bar ... push constant 510 pop temp 6 push local 0 push that 5 There’s no need to delve into the test’s code add push argument 1 BasicTest.asm sub ... push this 6 // push constant 510 ... return @510 D=A ... output-file BasicTest.out, compare-to BasicTest.cmp, output-list RAM[256] RAM[300] ... set RAM[0] 256, // base of stack set RAM[1] 300, set RAM[2] 400, set RAM[3] 3000, set RAM[4] 3010, // base of local // base of argument // base of this // base of that repeat 600 { ticktock; } output; Missing elements (in project 7) • function / return “envelope” • Mapping of the stack and the memory segments on the host RAM The stack and segment base addresses are handled by the supplied test scripts, using fixed addresses (In project 8 the mappings will be handled dynamically, by the VM implementation) Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Recap VM language: Arithmetic / Logical commands: add sub neg eq gt lt and or not Branching commands: label label goto label if-goto label Function commands: function functionName nVars call functionName nArgs return Memory access commands: push segment i pop segment i Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Recap Objective: build a basic VM translator that handles the VM language stack arithmetic and memory access (push/pop) commands VM language: Arithmetic / Logical commands: add sub neg eq gt lt and or not Branching commands: label label goto label if-goto label Function commands: function functionName nVars call functionName nArgs return Memory access commands: push segment i pop segment i Project 7 Project 8 Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken Perspective (A subset of historical notes and additional issues) • History of VMs and two-tier compilation: q p-code q Sun q Cellphones • How close is our VM to Java’s JVM? • Efficiency and optimization • Different VM implementations: q q q Stack machine Register machine Other approaches. Nand to Tetris / www.nand2tetris.org / Chapter 7 / Copyright © Noam Nisan and Shimon Schocken CO557: The Virtual Machine, Part II David Barnes Chapter 8 Design of the VM These slides support chapter 8 of the book The Elements of Computing Systems By Noam Nisan and Shimon Schocken MIT Press Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Virtual machine Overview • Program control Branching • Abstraction • Implementation Functions Implementing function call-and-return: • Implementation overview • Run-time simulation • Detailed implementation VM implementation on the Hack platform: • Standard mapping • Abstraction • VM translator: proposed implementation • Implementation • Project 8 overview Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Program control x = -b + b 2 - 4 × a × c This is what we would like to be able to write. High-level expression: x = −b + sqrt(power(b,2) – 4 * a * c) Or: x = −b + sqrt(disc(a,b,c)) Functions: • sqrt, power, and disc are abstractions • Functions and class definitions allow us to extend the basic language. Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Program control High-level code VM code (pseudo) if !(a==0) x=(−b+sqrt(disc(a,b,c))/(2*a); else x=-c/b; // code continues compiler push a push 0 eq not if-goto A_NEQ_ZERO // We get here if a==0 push c neg push b call div pop x goto CONTINUE label A_NEQ_ZERO // We get here if !(a==0) push b neg push a push b push c call disc call sqrt add push 2 push a call mult call div pop x label CONTINUE // code continues Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken NB: Remember that the VM doesn’t have a != operation, but it’s effect can be realised by combining == with boolean negation. NB: Notice that the order of the code for the true and false destinations has been swapped. Program control High-level code VM code (pseudo) if !(a==0) x=(−b+sqrt(disc(a,b,c))/(2*a); else x=-c/b; // code continues compiler push a push 0 eq not if-goto A_NEQ_ZERO // We get here if a==0 push c neg push b call div pop x goto CONTINUE label A_NEQ_ZERO // We get here if !(a==0) push b neg push a push b push c call disc call sqrt add push 2 push a call mult call div pop x label CONTINUE // code continues Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Program control VM code (pseudo) VM branching commands: • goto label • if-goto label • label label VM function commands: • call function • function function • return Challenges: • Understanding what the commands do (abstraction) • Realizing the commands on the host platform (implementation) push a push 0 eq not if-goto A_NEQ_ZERO // We get here if a==0 push c neg push b call div pop x goto CONTINUE label A_NEQ_ZERO // We get here if !(a==0) push b neg push a push b push c call disc call sqrt add push 2 push a call mult call div pop x label CONTINUE // code continues Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Program control • Why was the order of the code swapped when translating the if statement? if !(a==0) x=(−b+sqrt(disc(a,b,c))/(2*a); • In the more ‘natural’ translation else there will always be a jump. x=-c/b; // code continues • An alternative would be to retain the natural order but ‘invert’ the boolean condition. push a push 0 eq if-goto A_EQ_ZERO // We get here if !(a==0) push b … goto CONTINUE label A_EQ_ZERO // We get here if a==0 … label CONTINUE // code continues Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken push a push 0 eq not if-goto A_NEQ_ZERO goto A_EQ_ZERO label A_NEQ_ZERO // We get here if !(a==0) push b neg push a push b push c call disc call sqrt add push 2 push a call mult call div pop x goto CONTINUE label A_EQ_ZERO // We get here if a==0 push c neg push b call div pop x label CONTINUE // code continues To be covered … Understanding how programs are executed: • Branching • Function call-and-return Related implementation issues: • Stack processing Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Branching command command command label a Branching: command command • Unconditional command if condition goto b • Conditional command command command command command label b command command command command command if condition goto c command command command label c command command command goto a Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Branching High-level program // Returns x * y int mult(int x, int y) { Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Branching High-level program // Returns x * y int mult(int x, int y) { int sum = 0; int n = 1; // sum = sum + x, y times while !(n > y) { sum += x; n++; } return sum; } Notice, again, that the more natural n <= y is being represented as !(n > y) because the VM only has gt, lt and eq operations. Let’s focus on the while logic In practice, we could write the code more naturally at the source level and the compiler would take care of the mapping to accommodate the VM definition. Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Branching High-level program // Returns x * y int mult(int x, int y) { int sum = 0; int n = 1; // sum = sum + x, y times while !(n > y) { sum += x; n++; } return sum; } compiler Pseudo VM code function mult(x,y) push 0 pop sum push 1 pop n label WHILE_LOOP push n push y gt if-goto ENDLOOP push sum push x add pop sum push n push 1 add pop n goto WHILE_LOOP label ENDLOOP push sum return Notice, again, that the more natural n <= y is being represented as !(n > y) because the VM only has gt, lt and eq operations. In practice, we could write the code more naturally at the source level and the compiler would take care of the mapping to accommodate the VM definition. Notice the inversion of the logic, as suggested previously. Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Branching High-level program // Returns x * y int mult(int x, int y) { int sum = 0; int n = 1; // sum = sum + x, y times while !(n > y) { sum += x; n++; } return sum; } compiler Pseudo VM code function mult(x,y) push 0 pop sum push 1 pop n label WHILE_LOOP push n push y gt if-goto ENDLOOP push sum push x add pop sum push n push 1 add pop n goto WHILE_LOOP label ENDLOOP push sum return Unconditional branching: goto label Jumps to execute the command just after label. Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Branching High-level program // Returns x * y int mult(int x, int y) { int sum = 0; int n = 1; // sum = sum + x, y times while !(n > y) { sum += x; n++; } return sum; } compiler Pseudo VM code function mult(x,y) push 0 pop sum push 1 pop n label LOOP push n push y gt if-goto ENDLOOP push sum push x add pop sum push n push 1 add pop n goto WHILE_LOOP label ENDLOOP push sum return Conditional branching: if-goto label Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Branching High-level program // Returns x * y int mult(int x, int y) { int sum = 0; int n = 1; // sum = sum + x, y times while !(n > y) { sum += x; n++; } return sum; } compiler Pseudo VM code function mult(x,y) push 0 pop sum push 1 pop n label LOOP push n push y gt if-goto ENDLOOP push sum push x add pop sum push n push 1 add pop n goto WHILE_LOOP label ENDLOOP push sum return Conditional branching: if-goto label VM logic: 1. cond = pop; 2. if cond jump to execute the command just after label. (The relational operations push their result to the stack.) Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Branching Recap: VM branching commands: • goto label // jump to execute the command just after label • if-goto label // cond = pop; // if cond jump to execute the command just after label • label label // label declaration command Implementation (VM translation): Translate each branching command into assembly instructions that effect the specified operation on the host machine Simple implementation: the assembly language has similar branching commands. Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken VM language Arithmetic / Logical commands Branching commands add label label sub goto label neg eq gt lt if-goto label Function commands and function functionName nVars or call functionName nArgs not return Memory segment commands pop segment i push segment i Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Functions High-level programming languages can be extended using: • Subroutines • Functions • Procedures • Methods ‘functions’ in VM terminology • Etc. (Different names for the same underlying concept.) Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Functions in the VM language High-level program Pseudo VM code ... ... sqrt(x – 17 + x * 5) ... compiler Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Functions in the VM language High-level program ... sqrt(x – 17 + x * 5) ... compiler Pseudo VM code ... push x push 17 sub push x push 5 call Math.mult add No ‘multiply’ operation in the VM. call Math.sqrt ... • The VM language features: q primitive operations (fixed): add, sub, ... q abstract operations (extensible): mult, sqrt, ... Programming style: q Applying a primitive operator or calling a function have the same look-and-feel within the VM code. Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Functions in the VM language: defining High-level program // Returns x * y int mult(int x, int y) { int sum = 0; int n = 1; // sum = sum + x, y times while !(n > y) { sum += x; n++; } return sum; } compiler Pseudo VM code function mult(x,y) push 0 pop sum push 1 pop n label LOOP push n push y gt if-goto END push sum push x add pop sum push n push 1 add pop n goto LOOP label END push sum return Final VM code function mult 2 // 2 local vars. push constant 0 // sum=0 pop local 0 push constant 1 // n=1 pop local 1 label LOOP push local 1 // if !(n>y) push argument 1 // goto END gt if-goto END push local 0 // sum+=x push argument 0 add pop local 0 push local 1 // n++ push constant 1 add pop local 1 goto LOOP label END push local 0 // return sum return Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Constants, locals and arguments mapped to distinct segments. Functions in the VM language: executing (stack view) // Computes 3 +5 * 8 0 function main 0 1 push constant 3 2 push constant 8 3 push constant 5 4 call mult 2 5 add 6 return caller // Computes the product of two given arguments 0 function mult 2 1 push constant 0 2 pop local 0 (same code as previous 3 push constant 1 slide, with line numbers, 4 pop local 1 for easy reference) 5 label LOOP 6 push local 1 7 push argument 1 //... computes the product into local 0 19 label END 20 push local 0 callee 21 return main view: after line 3 is executed: after line 4 is executed: Now from the view of mult. after line 5 is executed: Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Functions in the VM language: executing (stack and segments) // Computes 3 +5 * 8 0 function main 0 1 push constant 3 2 push constant 8 3 push constant 5 4 call mult 2 5 add 6 return caller // Computes the product of two given arguments 0 function mult 2 1 push constant 0 2 pop local 0 3 push constant 1 4 pop local 1 5 label LOOP 6 push local 1 7 push argument 1 //... computes the product into local 0 19 label END 20 push local 0 callee 21 return main view: after line 3 is executed: mult view: after line 0 is executed: after line 4 is executed: Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Conceptually, each function has its own stack and separate argument and local areas. Practically, everything is mapped to a contiguous area of the Hack machine’s RAM. Functions in the VM language: executing // Computes the product of two given arguments 0 function mult 2 1 push constant 0 2 pop local 0 (same code as previous 3 push constant 1 slide, with line numbers, 4 pop local 1 for easy reference) 5 label LOOP 6 push local 1 7 push argument 1 //... computes the product into local 0 19 label END 20 push local 0 callee 21 return // Computes 3 +5 * 8 0 function main 0 1 push constant 3 2 push constant 8 3 push constant 5 4 call mult 2 5 add 6 return caller main view: mult view: after line 0 is executed: after line 3 is executed: after line 4 is executed: re tu rn after line 7 is executed: after line 20 is executed: Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Functions in the VM language: executing // Computes 3 +5 * 8 0 function main 0 1 push constant 3 2 push constant 8 3 push constant 5 4 call mult 2 5 add 6 return caller // Computes the product of two given arguments 0 function mult 2 1 push constant 0 2 pop local 0 3 push constant 1 4 pop local 1 5 label LOOP 6 push local 1 7 push argument 1 //... computes the product into local 0 19 label END 20 push local 0 callee 22 return main view: after line 3 is executed: after line 4 is executed: after line 5 is executed: mult view: after line 0 is executed: after line 7 is executed: after line 20 is executed: Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Functions in the VM language: implementation // Computes 3 +5 * 8 function main 0 push constant 3 push constant 8 push constant 5 call mult 2 add return caller // Computes the product of two given arguments function mult 2 push constant 0 pop local 0 push constant 1 pop local 1 label LOOP push local 1 push argument 1 //... computes the product into local 0 label END push local 0 callee return Implementation How to orchestrate the processes just described? We can write low-level code that manages the parameter passing, the saving and re-instating of function states, etc. This task can be realized by writing code that... • Handles the VM command call • Handles the VM command function • Handles the VM command return. Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Functions in the VM language: implementation // Computes 3 +5 * 8 function main 0 push constant 3 push constant 8 push constant 5 call mult 2 add return caller // Computes the product of two given arguments function mult 2 push constant 0 pop local 0 push constant 1 pop local 1 label LOOP push local 1 push argument 1 //... computes the product into local 0 label END push local 0 callee return Handling call: Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Functions in the VM language: implementation // Computes 3 +5 * 8 function main 0 push constant 3 push constant 8 push constant 5 call mult 2 add return caller // Computes the product of two given arguments function mult 2 push constant 0 pop local 0 push constant 1 pop local 1 label LOOP push local 1 push argument 1 //... computes the product into local 0 label END push local 0 callee return Handling call: • Determine the return address within the caller’s code; • Save the caller’s return address, stack and memory segments; • Pass parameters from the caller to the callee; • Jump to execute the callee. Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Conceptually. Practically, only a few ‘pointers’ need to be saved. Functions in the VM language: implementation // Computes 3 +5 * 8 function main 0 push constant 3 push constant 8 push constant 5 call mult 2 add return caller // Computes the product of two given arguments function mult 2 push constant 0 pop local 0 push constant 1 pop local 1 label LOOP push local 1 push argument 1 //... computes the product into local 0 label END push local 0 callee return Handling function: • Initialize the local variables of the callee; • Handle some other simple initializations (later). Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Functions in the VM language: implementation // Computes 3 +5 * 8 function main 0 push constant 3 push constant 8 push constant 5 call mult 2 add return caller // Computes the product of two given arguments function mult 2 push constant 0 pop local 0 push constant 1 pop local 1 label LOOP push local 1 push argument 1 //... computes the product into local 0 label END push local 0 callee return Handling return: • (a function always ends by pushing a return value on the stack) • Return the return value to the caller; • Recycle the memory resources used by the callee; • Reinstate the caller’s stack and memory segments; • Jump to the return address in the caller’s code. Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Review • We have covered basic program flow control commands: label, goto, if-goto. • We have looked at the way in which translation of boolean conditions often involves manipulations such as code movement or condition inversion, for the sake of efficiency. • We have looked at the mechanisms of function definition, call and return. Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken CO557: The Virtual Machine, Part II David Barnes Chapter 8 Implementation of function call and return These slides support chapter 8 of the book The Elements of Computing Systems By Noam Nisan and Shimon Schocken MIT Press Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function execution • A computer program typically consists of many functions • At any given point of time, only a few functions are executing • Calling chain: foo > bar > sqrt > ... For each function in the calling chain during run-time, we must maintain the function’s state Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The function’s state memory segments 0 1 2 3 ... ... ... ... ... During run-time: • Each function uses a working stack + memory segments Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The function’s state memory segments 0 1 2 3 ... ... ... ... ... During run-time: • Each function uses a working stack + memory segments • The working stack and some of the segments should be: q Created when the function starts running, q Maintained as long as the function is executing, q Recycled when the function returns. Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The function’s state function mult 2 function main 0 push constant 0 pop local 0 ... label LOOP push local 1 push constant 3 push constant 8 push constant 5 call mult 2 add return caller //... computes the product label END push local 0 callee return Challenge: • Maintain the states of all the functions up the calling chain • Can be done by using a single global stack. Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function call and return: abstraction Example: computing mult(17,212) Caller’s stack (before) sp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function call and return: abstraction Example: computing mult(17,212) Caller’s stack (before) 17 212 sp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function call and return: abstraction Example: computing mult(17,212) Caller’s stack (after) Caller’s stack (before) call mult 2 17 212 3604 sp sp Net effect: The function’s arguments were replaced by the function’s value. In effect, the called function ‘consumes’ its arguments and leaves behind the result it has calculated. The arguments and return value are the only way in which caller and callee ‘communicate’. Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function call and return: implementation The function is running, doing something sp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function call and return: implementation The function prepares to call another function: sp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function call and return: implementation The function prepares to call another function: sp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function call and return: implementation The function says: call foo nArgs nArgs sp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function call and return: implementation The function says: call foo nArgs VM implementation (handling call): nArgs sp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function call and return: implementation The function says: call foo nArgs VM implementation (handling call): 1. Saves the caller’s frame sp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken A function’s ‘frame’ is its execution context: local variables, its own arguments, etc. Function call and return: implementation The function says: call foo nArgs VM implementation (handling call): 1. Saves the caller’s frame A function’s ‘frame’ is its execution context: local variables, its own arguments, etc. Note that SP is not saved. We will see why later. sp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function call and return: implementation The function says: call foo nArgs VM implementation (handling call): 1. Saves the caller’s frame 2. Sets ARG sp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function call and return: implementation The function says: call foo nArgs VM implementation (handling call): 1. Saves the caller’s frame 2. Sets ARG 3. Jumps to execute foo sp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function call and return: implementation The called function is entered: function foo nVars VM implementation (handling call): 1. Saves the caller’s frame 2. Sets ARG 3. Jumps to execute foo sp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function call and return: implementation The called function is entered: function foo nVars VM implementation (handling call): 1. Saves the caller’s frame 2. Sets ARG 3. Jumps to execute foo VM implementation (handling function): sp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function call and return: implementation The called function is entered: function foo nVars VM implementation (handling call): 1. Saves the caller’s frame 2. Sets ARG 3. Jumps to execute foo VM implementation (handling function): • Sets up the local segment of the called function sp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function call and return: implementation The called function is entered: function foo nVars VM implementation (handling call): 1. Saves the caller’s frame 2. Sets ARG 3. Jumps to execute foo VM implementation (handling function): • Sets up the local segment of the called function nVars sp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function call and return: implementation The called function is entered: function foo nVars VM implementation (handling call): 1. Saves the caller’s frame 2. Sets ARG 3. Jumps to execute foo VM implementation (handling function): • Sets up the local segment of the called function sp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function call and return: implementation The called function is running, doing something sp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function call and return: implementation The called function is running, doing something sp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function call and return: implementation The called function prepares to return: it pushes a return value sp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function call and return: implementation The called function prepares to return: it pushes a return value sp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function call and return: implementation The called function says: return sp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function call and return: implementation The called function says: return VM implementation (handling call): 1. Saves the caller’s frame 2. Sets ARG 3. Jumps to execute foo VM implementation (handling function): • Sets up the local segment of the called function VM implementation (handling return): sp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function call and return: implementation The called function says: return VM implementation (handling call): 1. Saves the caller’s frame returned value 2. Sets ARG 3. Jumps to execute foo VM implementation (handling function): • Sets up the local segment of the called function VM implementation (handling return): 1. Copies the return value onto argument 0 sp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function call and return: implementation The called function says: return VM implementation (handling call): 1. Saves the caller’s frame returned value 2. Sets ARG 3. Jumps to execute foo VM implementation (handling function): • Sets up the local segment of the called function VM implementation (handling return): 1. Copies the return value onto argument 0 2. Sets SP for the caller sp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken This is why SP was not saved as part of the caller’s frame. Function call and return: implementation The called function says: return VM implementation (handling call): 1. Saves the caller’s frame sp returned value 2. Sets ARG 3. Jumps to execute foo VM implementation (handling function): • Sets up the local segment of the called function VM implementation (handling return): 1. Copies the return value onto argument 0 2. Sets SP for the caller Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken This is why SP was not saved as part of the caller’s frame. Function call and return: implementation The called function says: return VM implementation (handling call): 1. Saves the caller’s frame sp returned value 2. Sets ARG 3. Jumps to execute foo VM implementation (handling function): • Sets up the local segment of the called function VM implementation (handling return): 1. Copies the return value onto argument 0 2. Sets SP for the caller 3. Restores the segment pointers of the caller Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function call and return: implementation The called function says: return VM implementation (handling call): 1. Saves the caller’s frame sp returned value 2. Sets ARG 3. Jumps to execute foo VM implementation (handling function): • Sets up the local segment of the called function VM implementation (handling return): 1. Copies the return value onto argument 0 2. Sets SP for the caller 3. Restores the segment pointers of the caller Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function call and return: implementation The called function says: return VM implementation (handling call): 1. Saves the caller’s frame sp returned value 2. Sets ARG 3. Jumps to execute foo VM implementation (handling function): • Sets up the local segment of the called function VM implementation (handling return): 1. Copies the return value onto argument 0 2. Sets SP for the caller 3. Restores the segment pointers of the caller 4. Jumps to the return address within the caller’s code 5. (note that the stack space between old and new sp is recycled) Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function call and return: implementation The caller resumes its execution VM implementation (handling call): 1. Saves the caller’s frame sp returned value 2. Sets ARG 3. Jumps to execute foo VM implementation (handling function): • Sets up the local segment of the called function VM implementation (handling return): 1. Copies the return value onto argument 0 2. Sets SP for the caller 3. Restores the segment pointers of the caller 4. Jumps to the return address within the caller’s code 5. (note that the stack space between old and new sp is recycled) Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The global stack sp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The global stack global stack states of other functions up the calling chain (possibly many) similar blocks, one for each function up the calling chain “block” sp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Review: function call and return The caller says: call foo nArgs The caller resumes its execution Abstraction: sp return value of foo sp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Review: function call and return The caller says: The caller resumes its execution Implementation: call foo nArgs sp returned value sp return value of foo sp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Virtual machine: lecture plan Overview • Program control Branching • Abstraction • Implementation Functions Implementing function call-and-return: • Implementation overview • Run-time simulation • Detailed implementation VM implementation on the Hack platform: • Standard mapping • Abstraction • VM translator: proposed implementation • Implementation • Project 8 overview Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Example: factorial High-level program // Tests the factorial function int main() { return factorial(3); } // Returns n! int factorial(int n) { if (n==1) return 1; else return n * factorial(n-1); } compiler Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Example: factorial High-level program // Tests the factorial function int main() { return factorial(3); } Pseudo VM code function main push 3 call factorial return // Returns n! int factorial(int n) { if (n==1) return 1; else return n * factorial(n-1); } compiler Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Example: factorial High-level program // Tests the factorial function int main() { return factorial(3); } // Returns n! int factorial(int n) { if (n==1) return 1; else return n * factorial(n-1); } compiler Pseudo VM code function main push 3 call factorial return function factorial(n) push n push 1 eq if-goto BASECASE push n push n push 1 sub call factorial call mult return label BASECASE push 1 return function mult(a,b) // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Example: factorial High-level program // Tests the factorial function int main() { return factorial(3); } // Returns n! int factorial(int n) { if (n==1) return 1; else return n * factorial(n-1); } compiler Pseudo VM code VM program function main push 3 call factorial return function main 0 push constant 3 call factorial 1 return function factorial(n) push n push 1 eq if-goto BASECASE function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push n push n push 1 sub call factorial call mult return push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push 1 return label BASECASE push constant 1 return function mult(a,b) // Code omitted function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example VM program function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return impact on the global stack not shown function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return impact on the global stack not shown function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return impact on the global stack not shown function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return get the return address function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return handle the return value function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return impact on the global stack not shown (except for end result) function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return get return address function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return handle the return value function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return impact on the global stack not shown (except for end result) function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return 6 impact on the global stack not shown (except for end result) function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return 6 get return address function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return 6 6 handle the return value function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return 6 function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Run-time example function main 0 push constant 3 call factorial 1 return 6 function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Recap function main 0 push constant 3 call factorial 1 return function factorial 0 push argument 0 push constant 1 eq if-goto BASECASE push argument 0 push argument 0 push constant 1 sub call factorial 1 call mult 2 return label BASECASE push constant 1 return 6 The caller (main function) wanted to compute 3! q it pushed 3, called factorial, and got 6 q from the caller’s view, nothing exciting happenned... abstraction implementation function mult 2 // Code omitted Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Virtual machine: lecture plan Overview • Program control Branching • Abstraction • Implementation Functions Implementing function call-and-return: • Implementation overview • Run-time simulation • Detailed implementation VM implementation on the Hack platform: • Standard mapping • Abstraction • VM translator: proposed implementation • Implementation • Project 8 overview Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function call and return VM code (arbitrary example) function Foo.main 4 ... // computes –(19 * (local 3)) push constant 19 push local 3 call Bar.mult 2 neg ... caller callee function Bar.mult 2 // Computes the product of the first two // arguments and puts the result in local 1 ... push local 1 // return value return We focus on the VM function commands: • call functionName nArgs • function functionName nVars • return Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Contract: the caller’s view VM code caller function Foo.main 4 ... // computes –(19 * (local 3)) push constant 19 push local 3 call Bar.mult 2 neg ... function Bar.mult 2 // Computes the product of the first two // arguments and puts the result in local 1 ... push local 1 // return value return • Before calling another function, I must push as many arguments as the function expects to get • Next, I invoke the function using call functionName nArgs • After the called function returns, the argument values that I pushed before the call have disappeared from the stack, and a return value (that always exists) appears at the top of the stack; • After the called function returns, all my memory segments are exactly the same as they were before the call • (except that temp is undefined and some values of my static segment may have changed). Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Contract: the caller’s view VM code caller function Foo.main 4 ... // computes –(19 * (local 3)) push constant 19 push local 3 call Bar.mult 2 neg ... function Bar.mult 2 // Computes the product of the first two // arguments and puts the result in local 1 ... push local 1 // return value return • Before calling another function, I must push as many arguments as the function expects to get • Next, I invoke the function using call functionName nArgs • After the called function returns, the argument values that I pushed before the call have disappeared from the stack, and a return value (that always exists) appears at the top of the stack; • After the called function returns, all my memory segments are exactly the same as they were before the call • (except that temp is undefined and some values of my static segment may have changed). blue: must be handled by the VM implementation Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Contract: the callee’s view VM code callee function Foo.main 4 ... // computes –(19 * (local 3)) push constant 19 push local 3 call Bar.mult 2 neg ... • Before I start executing, my argument segment has been initialized with the argument values passed by the caller function Bar.mult 2 // Computes the product of the first two // arguments and puts the result in local 1 ... push local 1 // return value return • (memory segments this, that, pointer, and temp are undefined upon entry) • My local variables segment has been allocated and initialized to zeros • My static segment has been set to the static segment of the VM file to which I belong • My stack is empty • Before returning, I must push a value onto the stack. Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Contract: the callee’s view VM code callee function Foo.main 4 ... // computes –(19 * (local 3)) push constant 19 push local 3 call Bar.mult 2 neg ... • Before I start executing, my argument segment has been initialized with the argument values passed by the caller function Bar.mult 2 // Computes the product of the first two // arguments and puts the result in local 1 ... push local 1 // return value return • (memory segments this, that, pointer, and temp are undefined upon entry) • My local variables segment has been allocated and initialized to zeros • My static segment has been set to the static segment of the VM file to which I belong • My stack is empty • Before returning, I must push a value onto the stack. blue: must be handled by the VM implementation Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The VM implementation view VM code Generated assembly code function Foo.main 4 ... // computes –(19 * (local 3)) push constant 19 push local 3 call Bar.mult 2 neg ... VM translator function Bar.mult 2 // Computes the product of the first two // arguments and puts the result in local 1 ... push local 1 // return value return Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The VM implementation view VM code function Foo.main 4 ... // computes –(19 * (local 3)) push constant 19 push local 3 call Bar.mult 2 neg ... VM translator Generated assembly code (Foo.main) // created and plugged by the translator // assembly code that handles the initialization of the // function’s execution ... function Bar.mult 2 // Computes the product of the first two // arguments and puts the result in local 1 ... push local 1 // return value return Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The VM implementation view VM code function Foo.main 4 ... // computes –(19 * (local 3)) push constant 19 push local 3 call Bar.mult 2 neg ... VM translator Generated assembly code (Foo.main) // created and plugged by the translator // assembly code that handles the initialization of the // function’s execution ... // assembly code that handles push constant 19 // assembly code that handles push local 3 function Bar.mult 2 // Computes the product of the first two // arguments and puts the result in local 1 ... push local 1 // return value return Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The VM implementation view VM code function Foo.main 4 ... // computes –(19 * (local 3)) push constant 19 push local 3 call Bar.mult 2 neg ... VM translator function Bar.mult 2 // Computes the product of the first two // arguments and puts the result in local 1 ... push local 1 // return value return Generated assembly code (Foo.main) // created and plugged by the translator // assembly code that handles the initialization of the // function’s execution ... // assembly code that handles push constant 19 // assembly code that handles push local 3 // assembly code that saves the caller’s state on the stack, // sets up for the function call, and then: goto Bar.mult // (in assembly) (Foo$ret.1) // created and plugged by the translator Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The VM implementation view VM code function Foo.main 4 ... // computes –(19 * (local 3)) push constant 19 push local 3 call Bar.mult 2 neg ... VM translator function Bar.mult 2 // Computes the product of the first two // arguments and puts the result in local 1 ... push local 1 // return value return Generated assembly code (Foo.main) // created and plugged by the translator // assembly code that handles the initialization of the // function’s execution ... // assembly code that handles push constant 19 // assembly code that handles push local 3 // assembly code that saves the caller’s state on the stack, // sets up for the function call, and then: goto Bar.mult // (in assembly) (Foo$ret.1) // created and plugged by the translator // assembly code that handles neg ... Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The VM implementation view VM code function Foo.main 4 ... // computes –(19 * (local 3)) push constant 19 push local 3 call Bar.mult 2 neg ... VM translator function Bar.mult 2 // Computes the product of the first two // arguments and puts the result in local 1 ... push local 1 // return value return Generated assembly code (Foo.main) // created and plugged by the translator // assembly code that handles the initialization of the // function’s execution ... // assembly code that handles push constant 19 // assembly code that handles push local 3 // assembly code that saves the caller’s state on the stack, // sets up for the function call, and then: goto Bar.mult // (in assembly) (Foo$ret.1) // created and plugged by the translator // assembly code that handles neg ... (Bar.mult) // created and plugged by the translator // assembly code that handles the initialization of the // function’s execution ... Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The VM implementation view VM code function Foo.main 4 ... // computes –(19 * (local 3)) push constant 19 push local 3 call Bar.mult 2 neg ... VM translator function Bar.mult 2 // Computes the product of the first two // arguments and puts the result in local 1 ... push local 1 // return value return Generated assembly code (Foo.main) // created and plugged by the translator // assembly code that handles the initialization of the // function’s execution ... // assembly code that handles push constant 19 // assembly code that handles push local 3 // assembly code that saves the caller’s state on the stack, // sets up for the function call, and then: goto Bar.mult // (in assembly) (Foo$ret.1) // created and plugged by the translator // assembly code that handles neg ... (Bar.mult) // created and plugged by the translator // assembly code that handles the initialization of the // function’s execution ... // assembly code that handles push local 1 Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The VM implementation view VM code function Foo.main 4 ... // computes –(19 * (local 3)) push constant 19 push local 3 call Bar.mult 2 neg ... VM translator function Bar.mult 2 // Computes the product of the first two // arguments and puts the result in local 1 ... push local 1 // return value return Generated assembly code (Foo.main) // created and plugged by the translator // assembly code that handles the initialization of the // function’s execution ... // assembly code that handles push constant 19 // assembly code that handles push local 3 // assembly code that saves the caller’s state on the stack, // sets up for the function call, and then: goto Bar.mult // (in assembly) (Foo$ret.1) // created and plugged by the translator // assembly code that handles neg ... (Bar.mult) // created and plugged by the translator // assembly code that handles the initialization of the // function’s execution ... // assembly code that handles push local 1 // Assembly code that gets the return address (which happens // to be Foo$ret.1) off the stack, copies the return value to // the caller, reinstates the caller’s state, and then: goto Foo$ret.1 // (in assembly) Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The VM implementation view VM code function Foo.main 4 ... // computes –(19 * (local 3)) push constant 19 push local 3 call Bar.mult 2 neg ... VM translator function Bar.mult 2 // Computes the product of the first two // arguments and puts the result in local 1 ... push local 1 // return value return We now turn to describe the more detailed handling of the VM commands: • call • function • return Generated assembly code (Foo.main) // created and plugged by the translator // assembly code that handles the initialization of the // function’s execution ... // assembly code that handles push constant 19 // assembly code that handles push local 3 // assembly code that saves the caller’s state on the stack, // sets up for the function call, and then: pseudo code goto Bar.mult // (in assembly) (Foo$ret.1) // created and plugged by the translator // assembly code that handles neg ... (Bar.mult) // created and plugged by the translator // assembly code that handles the initialization of the // function’s execution ... // assembly code that handles push local 1 // Assembly code that gets the return address (which happens // to be Foo$ret.1) off the stack, copies the return value to // the caller, reinstates the caller’s state, and then: goto Foo$ret.1 // (in assembly) Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The VM implementation view VM code function Foo.main 4 ... // computes –(19 * (local 3)) push constant 19 push local 3 call Bar.mult 2 neg ... VM translator function Bar.mult 2 // Computes the product of the first two // arguments and puts the result in local 1 ... push local 1 // return value return Generated assembly code (Foo.main) // created and plugged by the translator // assembly code that handles the initialization of the // function’s execution ... // assembly code that handles push constant 19 // assembly code that handles push local 3 // assembly code that saves the caller’s state on the stack, // sets up for the function call, and then: goto Bar.mult // (in assembly) (Foo$ret.1) // created and plugged by the translator // assembly code that handles neg ... (Bar.mult) // created and plugged by the translator // assembly code that handles the initialization of the // function’s execution ... // assembly code that handles push local 1 // Assembly code that gets the return address (which happens // to be Foo$ret.1) off the stack, copies the return value to // the caller, reinstates the caller’s state, and then: goto Foo$ret.1 // (in assembly) Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling call VM command: call functionName nArgs (calls a function, informing that nArgs arguments have been pushed onto the stack) global stack states of other functions up the calling chain the caller is running, doing some work... Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling call VM command: call functionName nArgs (calls a function, informing that nArgs arguments have been pushed onto the stack) global stack states of other functions up the calling chain nArgs Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling call VM command: call functionName nArgs (calls a function, informing that nArgs arguments have been pushed onto the stack) Assembly code (generated by the translator): global stack states of other functions up the calling chain nArgs Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling call VM command: call functionName nArgs (calls a function, informing that nArgs arguments have been pushed onto the stack) Assembly code (generated by the translator): push retAddrLabel global stack states of other functions up the calling chain nArgs // Using a translator-generated label Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling call VM command: call functionName nArgs (calls a function, informing that nArgs arguments have been pushed onto the stack) Assembly code (generated by the translator): push retAddrLabel global stack states of other functions up the calling chain nArgs // Using a translator-generated label Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling call VM command: call functionName nArgs (calls a function, informing that nArgs arguments have been pushed onto the stack) Assembly code (generated by the translator): push retAddrLabel // Using a translator-generated label push LCL // Saves LCL of the caller global stack states of other functions up the calling chain nArgs Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling call VM command: call functionName nArgs (calls a function, informing that nArgs arguments have been pushed onto the stack) Assembly code (generated by the translator): push retAddrLabel // Using a translator-generated label push LCL // Saves LCL of the caller global stack states of other functions up the calling chain nArgs Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling call VM command: call functionName nArgs (calls a function, informing that nArgs arguments have been pushed onto the stack) Assembly code (generated by the translator): push retAddrLabel // Using a translator-generated label push LCL // Saves LCL of the caller push ARG // Saves ARG of the caller global stack states of other functions up the calling chain nArgs Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling call VM command: call functionName nArgs (calls a function, informing that nArgs arguments have been pushed onto the stack) Assembly code (generated by the translator): push retAddrLabel // Using a translator-generated label push LCL // Saves LCL of the caller push ARG // Saves ARG of the caller global stack states of other functions up the calling chain nArgs Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling call VM command: call functionName nArgs (calls a function, informing that nArgs arguments have been pushed onto the stack) Assembly code (generated by the translator): push retAddrLabel // Using a translator-generated label push LCL // Saves LCL of the caller push ARG // Saves ARG of the caller push THIS // Saves THIS of the caller global stack states of other functions up the calling chain nArgs Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling call VM command: call functionName nArgs (calls a function, informing that nArgs arguments have been pushed onto the stack) Assembly code (generated by the translator): push retAddrLabel // Using a translator-generated label push LCL // Saves LCL of the caller push ARG // Saves ARG of the caller push THIS // Saves THIS of the caller global stack states of other functions up the calling chain nArgs Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling call VM command: call functionName nArgs (calls a function, informing that nArgs arguments have been pushed onto the stack) Assembly code (generated by the translator): push retAddrLabel // Using a translator-generated label push LCL // Saves LCL of the caller push ARG // Saves ARG of the caller push THIS // Saves THIS of the caller push THAT // Saves THAT of the caller global stack states of other functions up the calling chain nArgs Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling call VM command: call functionName nArgs (calls a function, informing that nArgs arguments have been pushed onto the stack) Assembly code (generated by the translator): push retAddrLabel // Using a translator-generated label push LCL // Saves LCL of the caller push ARG // Saves ARG of the caller push THIS // Saves THIS of the caller push THAT // Saves THAT of the caller global stack states of other functions up the calling chain nArgs Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling call VM command: call functionName nArgs (calls a function, informing that nArgs arguments have been pushed onto the stack) Assembly code (generated by the translator): push retAddrLabel // Using a translator-generated label push LCL // Saves LCL of the caller push ARG // Saves ARG of the caller push THIS // Saves THIS of the caller push THAT // Saves THAT of the caller ARG = SP-5-nArgs // Repositions ARG global stack states of other functions up the calling chain nArgs Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling call VM command: call functionName nArgs (calls a function, informing that nArgs arguments have been pushed onto the stack) Assembly code (generated by the translator): push retAddrLabel // Using a translator-generated label push LCL // Saves LCL of the caller push ARG // Saves ARG of the caller push THIS // Saves THIS of the caller push THAT // Saves THAT of the caller ARG = SP-5-nArgs // Repositions ARG global stack states of other functions up the calling chain nArgs Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling call VM command: call functionName nArgs (calls a function, informing that nArgs arguments have been pushed onto the stack) Assembly code (generated by the translator): push retAddrLabel // Using a translator-generated label push LCL // Saves LCL of the caller push ARG // Saves ARG of the caller push THIS // Saves THIS of the caller push THAT // Saves THAT of the caller ARG = SP-5-nArgs // Repositions ARG LCL = SP // Repositions LCL global stack states of other functions up the calling chain nArgs Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling call VM command: call functionName nArgs (calls a function, informing that nArgs arguments have been pushed onto the stack) Assembly code (generated by the translator): push retAddrLabel // Using a translator-generated label push LCL // Saves LCL of the caller push ARG // Saves ARG of the caller push THIS // Saves THIS of the caller push THAT // Saves THAT of the caller ARG = SP-5-nArgs // Repositions ARG LCL = SP // Repositions LCL global stack states of other functions up the calling chain nArgs Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling call VM command: call functionName nArgs (calls a function, informing that nArgs arguments have been pushed onto the stack) Assembly code (generated by the translator): push retAddrLabel // Using a translator-generated label push LCL // Saves LCL of the caller push ARG // Saves ARG of the caller push THIS // Saves THIS of the caller push THAT // Saves THAT of the caller ARG = SP-5-nArgs // Repositions ARG LCL = SP // Repositions LCL goto functionName // Transfers control to the called function global stack states of other functions up the calling chain nArgs Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling call VM command: call functionName nArgs (calls a function, informing that nArgs arguments have been pushed onto the stack) Assembly code (generated by the translator): push retAddrLabel // Using a translator-generated label push LCL // Saves LCL of the caller push ARG // Saves ARG of the caller push THIS // Saves THIS of the caller push THAT // Saves THAT of the caller ARG = SP-5-nArgs // Repositions ARG LCL = SP // Repositions LCL goto functionName // Transfers control to the called function (retAddrLabel) global stack states of other functions up the calling chain nArgs // the same translator-generated label Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling call VM code function Foo.main 4 ... // computes –(19 * (local 3)) push constant 19 push local 3 call Bar.mult 2 neg ... VM translator function Bar.mult 2 // Computes the product of the first two // arguments and puts the result in local 1 ... push local 1 // return value return Generated assembly code (Foo.main) // created and plugged by the translator // assembly code that handles the initialization of the // function’s execution ... // assembly code that handles push constant 19 // assembly code that handles push local 3 // assembly code that saves the caller’s state on the stack, // sets up for the function call, and then: goto Bar.mult // (in assembly) (Foo$ret.1) // created and plugged by the translator // assembly code that handles neg ... (Bar.mult) // created and plugged by the translator // assembly code that handles the initialization of the // function’s execution ... // assembly code that handles push local 1 // Assembly code that gets the return address (which happens // to be Foo$ret.1) off the stack, copies the return value to // the caller, reinstates the caller’s state, and then: goto Foo$ret.1 // (in assembly) Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling function VM code function Foo.main 4 ... // computes –(19 * (local 3)) push constant 19 push local 3 call Bar.mult 2 neg ... VM translator function Bar.mult 2 // Computes the product of the first two // arguments and puts the result in local 1 ... push local 1 // return value return Generated assembly code (Foo.main) // created and plugged by the translator // assembly code that handles the initialization of the // function’s execution ... // assembly code that handles push constant 19 // assembly code that handles push local 3 // assembly code that saves the caller’s state on the stack, // sets up for the function call, and then: goto Bar.mult // (in assembly) (Foo$ret.1) // created and plugged by the translator // assembly code that handles neg ... (Bar.mult) // created and plugged by the translator // assembly code that handles the initialization of the // function’s execution ... // assembly code that handles push local 1 // Assembly code that gets the return address (which happens // to be Foo$ret.1) off the stack, copies the return value to // the caller, reinstates the caller’s state, and then: goto Foo$ret.1 // (in assembly) Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling function VM command: function functionName nVars (here starts a function that has nVars local variables) global stack states of other functions up the calling chain Assembly code (generated by the translator): Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling function VM command: function functionName nVars (here starts a function that has nVars local variables) global stack states of other functions up the calling chain Assembly code (generated by the translator): (functionName) // using a translator-generated label Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling function VM command: function functionName nVars (here starts a function that has nVars local variables) global stack states of other functions up the calling chain Assembly code (generated by the translator): (functionName) // using a translator-generated label repeat nVars times: // nVars = number of local variables push 0 // initializes the local variables to 0 Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling function VM command: function functionName nVars (here starts a function that has nVars local variables) global stack states of other functions up the calling chain Assembly code (generated by the translator): (functionName) // using a translator-generated label repeat nVars times: // nVars = number of local variables push 0 // initializes the local variables to 0 nVars Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling function VM command: function functionName nVars (here starts a function that has nVars local variables) global stack states of other functions up the calling chain Assembly code (generated by the translator): (functionName) // using a translator-generated label repeat nVars times: // nVars = number of local variables push 0 // initializes the local variables to 0 Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling function VM code function Foo.main 4 ... // computes –(19 * (local 3)) push constant 19 push local 3 call Bar.mult 2 neg ... VM translator function Bar.mult 2 // Computes the product of the first two // arguments and puts the result in local 1 ... push local 1 // return value return Generated assembly code (Foo.main) // created and plugged by the translator // assembly code that handles the initialization of the // function’s execution ... // assembly code that handles push constant 19 // assembly code that handles push local 3 // assembly code that saves the caller’s state on the stack, // sets up for the function call, and then: goto Bar.mult // (in assembly) (Foo$ret.1) // created and plugged by the translator // assembly code that handles neg ... (Bar.mult) // created and plugged by the translator // assembly code that handles the initialization of the // function’s execution ... // assembly code that handles push local 1 // Assembly code that gets the return address (which happens // to be Foo$ret.1) off the stack, copies the return value to // the caller, reinstates the caller’s state, and then: goto Foo$ret.1 // (in assembly) Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling function VM code function Foo.main 4 ... // computes –(19 * (local 3)) push constant 19 push local 3 call Bar.mult 2 neg ... VM translator function Bar.mult 2 // Computes the product of the first two // arguments and puts the result in local 1 ... push local 1 // return value return Generated assembly code (Foo.main) // created and plugged by the translator // assembly code that handles the initialization of the // function’s execution ... // assembly code that handles push constant 19 // assembly code that handles push local 3 // assembly code that saves the caller’s state on the stack, // sets up for the function call, and then: goto Bar.mult // (in assembly) (Foo$ret.1) // created and plugged by the translator // assembly code that handles neg ... (Bar.mult) // created and plugged by the translator // assembly code that handles the initialization of the // function’s execution ... // assembly code that handles push local 1 // Assembly code that gets the return address (which happens // to be Foo$ret.1) off the stack, copies the return value to // the caller, reinstates the caller’s state, and then: goto Foo$ret.1 // (in assembly) Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling return global stack states of other functions up the calling chain the callee is running, doing some work... Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling return global stack VM command: return states of other functions up the calling chain the callee is running, doing some work... Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling return global stack VM command: return states of other functions up the calling chain return value Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling return global stack VM command: return states of other functions up the calling chain Assembly code (generated by the translator): Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling return global stack VM command: return states of other functions up the calling chain Assembly code (generated by the translator): endFrame = LCL // endframe is a temporary variable retAddr = *(endFrame – 5) // gets the return address Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling return global stack VM command: return states of other functions up the calling chain Assembly code (generated by the translator): endFrame = LCL // endframe is a temporary variable retAddr = *(endFrame – 5) // gets the return address *ARG = pop() // repositions the return value for the caller Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling return global stack VM command: return states of other functions up the calling chain Assembly code (generated by the translator): return value endFrame = LCL // endframe is a temporary variable retAddr = *(endFrame – 5) // gets the return address *ARG = pop() // repositions the return value for the caller Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling return global stack VM command: return states of other functions up the calling chain Assembly code (generated by the translator): return value endFrame = LCL // endframe is a temporary variable retAddr = *(endFrame – 5) // gets the return address *ARG = pop() // repositions the return value for the caller SP = ARG + 1 // repositions SP of the caller Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling return global stack VM command: return states of other functions up the calling chain Assembly code (generated by the translator): return value endFrame = LCL // endframe is a temporary variable retAddr = *(endFrame – 5) // gets the return address *ARG = pop() // repositions the return value for the caller SP = ARG + 1 // repositions SP of the caller Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling return global stack VM command: return states of other functions up the calling chain Assembly code (generated by the translator): return value endFrame = LCL // endframe is a temporary variable retAddr = *(endFrame – 5) // gets the return address *ARG = pop() // repositions the return value for the caller SP = ARG + 1 // repositions SP of the caller recycled Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling return global stack VM command: return states of other functions up the calling chain Assembly code (generated by the translator): return value endFrame = LCL // endframe is a temporary variable retAddr = *(endFrame – 5) // gets the return address *ARG = pop() // repositions the return value for the caller SP = ARG + 1 // repositions SP of the caller THAT = *(endFrame – 1) // restores THAT of the caller THIS = *(endFrame – 2) // restores THIS of the caller ARG = *(endFrame – 3) // restores ARG of the caller LCL = *(endFrame – 4) // restores LCL of the caller goto retAddr // goes to the caller’s return address recycled Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Handling return global stack VM command: return states of other functions up the calling chain Assembly code (generated by the translator): return value endFrame = LCL // endframe is a temporary variable retAddr = *(endFrame – 5) // gets the return address *ARG = pop() // repositions the return value for the caller SP = ARG + 1 // repositions SP of the caller THAT = *(endFrame – 1) // restores THAT of the caller THIS = *(endFrame – 2) // restores THIS of the caller ARG = *(endFrame – 3) // restores ARG of the caller LCL = *(endFrame – 4) // restores LCL of the caller goto retAddr // goes to the caller’s return address Net impact: the caller is back in business, with the return value at the top of the stack Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Function call and return VM code function Foo.main 4 ... // computes –(19 * (local 3)) push constant 19 push local 3 call Bar.mult 2 neg ... VM translator function Bar.mult 2 // Computes the product of the first two // arguments and puts the result in local 1 ... push local 1 // return value return Generated assembly code (Foo.main) // assembly code that handles the setting up of // a function’s execution ... // assembly code that handles push constant 19 // assembly code that handles push local 3 // assembly code that saves the caller’s state, // handles some pointers, and then: goto Bar.mult // (in assembly) (Foo$ret.1) // assembly code that handles neg ... (Bar.mult) // assembly code that handles the setting up of // a function’s execution ... // assembly code that handles push local 1 // Assembly code that moves the return value to the // caller, reinstates the caller’s state, and then: goto Foo$ret.1 // (in assembly) Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Recap • We showed how to generate the assembly code that, when executed, will end up building and maintaining the global stack during run-time global stack states of other functions up the calling chain return value • This code will implement the function call-and-return commands and behavior • The code is language- and platform-independent • It can be implemented in any machine language. Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken VM language Arithmetic / Logical commands add Branching commands label label sub neg goto label eq if-goto label gt lt and or not Memory access commands Function commands function functionName nVars call functionName nArgs return pop segment i push segment i Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Virtual machine: lecture plan Overview • Program control Branching • Abstraction • Implementation Functions Implementing function call-and-return: • Implementation overview • Run-time simulation • Detailed implementation VM implementation on the Hack platform: • Standard mapping • Abstraction • VM translator: proposed implementation • Implementation • Project 8 overview Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The big picture: program compilation and translation myProg directory myProg directory Foo.jack myProg.asm Foo.vm class Foo function Foo.main function main {. . . } method bla {. . . } ... function Foo.bla ... } Bar.jack compiler class Bar constructor new {. . . } method bla {. . . } } myProg directory (Foo.main) ... (Foo.bla) VM translator Bar.vm ... (Bar.new) function Bar.new ... ... function Bar.bla ... • Compiling a program directory: > JackCompiler directoryName • Translating a program directory: > VMTranslator directoryName (Bar.bla) ... (later in the course) The VM translator developed in projects 7-8 Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Booting VM program convention • one file in any VM program is expected to be named Main.vm; • one VM function in this file is expected to be named main VM implementation conventions • the stack starts in address 256 in the host RAM • when the VM implementation starts running, or is reset, it starts executing an argument-less OS function named Sys.init • Sys.init is designed to call Main.main, and then enter an infinite loop These conventions are realized by the following code: // Bootstrap code (should be written in assembly) SP = 256 call Sys.init In the Hack platform, this code should be put in the ROM, starting at address 0 Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Standard mapping of the VM on the Hack platform Hack RAM Hack RAM VM implementation 24576 24577 Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Special symbols in translated VM programs Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Special symbols in translated VM programs Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Virtual machine: lecture plan Overview • Program control Branching • Abstraction • Implementation Functions Implementing function call-and-return: • Implementation overview • Run-time simulation • Detailed implementation VM implementation on the Hack platform: • Standard mapping • Abstraction • VM translator: proposed implementation • Implementation • Project 8 overview Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The VM translator VM code (example) Generated assembly code ... push constant 17 goto LOOP ... call Foo.bar 3 ... VM translator function Foo.bar 2 ... push local 4 return ... Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The VM translator VM code (example) Generated assembly code ... push constant 17 goto LOOP ... call Foo.bar 3 ... VM translator function Foo.bar 2 ... push local 4 return ... Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The VM translator VM code (example) Generated assembly code ... push constant 17 goto LOOP ... call Foo.bar 3 ... VM translator ... // push constant 17 @17 D=A ... // additional assembly commands that complete the // implementation of push constant 17 function Foo.bar 2 ... push local 4 return ... Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The VM translator VM code Generated assembly code ... push constant 17 goto LOOP ... call Foo.bar 3 ... VM translator ... // push constant 17 @17 D=A ... // additional assembly commands that complete the // implementation of push constant 17 function Foo.bar 2 ... push local 4 return ... Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The VM translator VM code Generated assembly code ... push constant 17 goto LOOP ... call Foo.bar 3 ... function Foo.bar 2 ... VM translator ... // push constant 17 @17 D=A ... // additional assembly commands that complete the // implementation of push constant 17 // goto LOOP ... // generated assembly code that implements goto LOOP push local 4 return ... Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The VM translator VM code Generated assembly code ... push constant 17 goto LOOP ... call Foo.bar 3 ... function Foo.bar 2 ... VM translator ... // push constant 17 @17 D=A ... // additional assembly commands that complete the // implementation of push constant 17 // goto LOOP ... // generated assembly code that implements goto LOOP push local 4 return ... Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The VM translator VM code Generated assembly code ... push constant 17 goto LOOP ... call Foo.bar 3 ... function Foo.bar 2 ... push local 4 return VM translator ... // push constant 17 @17 D=A ... // additional assembly commands that complete the // implementation of push constant 17 // goto LOOP ... // generated assembly code that implements goto LOOP // call Foo.bar 3 ... // generated ... code that implements call Foo.bar 3 ... Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The VM translator VM code Generated assembly code ... push constant 17 goto LOOP ... call Foo.bar 3 ... function Foo.bar 2 ... push local 4 return VM translator ... // push constant 17 @17 D=A ... // additional assembly commands that complete the // implementation of push constant 17 // goto LOOP ... // generated assembly code that implements goto LOOP // call Foo.bar 3 ... // generated ... code that implements call Foo.bar 3 ... Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The VM translator VM code Generated assembly code ... push constant 17 goto LOOP ... call Foo.bar 3 ... function Foo.bar 2 ... push local 4 return VM translator ... // push constant 17 @17 D=A ... // additional assembly commands that complete the // implementation of push constant 17 // goto LOOP ... // generated assembly code that implements goto LOOP // call Foo.bar 3 ... // generated ... code that implements call Foo.bar 3 ... // function Foo.bar 2 ... // generated ... that implements function Foo.bar 2 Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The VM translator VM code Generated assembly code ... push constant 17 goto LOOP ... call Foo.bar 3 ... function Foo.bar 2 ... push local 4 return VM translator ... // push constant 17 @17 D=A ... // additional assembly commands that complete the // implementation of push constant 17 // goto LOOP ... // generated assembly code that implements goto LOOP // call Foo.bar 3 ... // generated ... code that implements call Foo.bar 3 ... // function Foo.bar 2 ... // generated ... that implements function Foo.bar 2 Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The VM translator VM code Generated assembly code ... push constant 17 goto LOOP ... call Foo.bar 3 ... function Foo.bar 2 ... push local 4 return VM translator ... // push constant 17 @17 D=A ... // additional assembly commands that complete the // implementation of push constant 17 // goto LOOP ... // generated assembly code that implements goto LOOP // call Foo.bar 3 ... // generated ... code that implements call Foo.bar 3 ... // function Foo.bar 2 ... // generated ... that implements function Foo.bar 2 // push local 4 ... // generated ... that implements push local 4 Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The VM translator VM code Generated assembly code ... push constant 17 goto LOOP ... call Foo.bar 3 ... function Foo.bar 2 ... push local 4 return VM translator ... // push constant 17 @17 D=A ... // additional assembly commands that complete the // implementation of push constant 17 // goto LOOP ... // generated assembly code that implements goto LOOP // call Foo.bar 3 ... // generated ... code that implements call Foo.bar 3 ... // function Foo.bar 2 ... // generated ... that implements function Foo.bar 2 // push local 4 ... // generated ... that implements push local 4 Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The VM translator VM code Generated assembly code ... push constant 17 goto LOOP ... call Foo.bar 3 ... function Foo.bar 2 ... push local 4 return VM translator ... // push constant 17 @17 D=A ... // additional assembly commands that complete the // implementation of push constant 17 // goto LOOP ... // generated assembly code that implements goto LOOP // call Foo.bar 3 ... // generated ... code that implements call Foo.bar 3 ... // function Foo.bar 2 ... // generated ... that implements function Foo.bar 2 // push local 4 ... // generated ... that implements push local 4 // return ... // generated assembly code that implements return Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The VM translator VM code (example) Generated assembly code ... push constant 17 goto LOOP ... call Foo.bar 3 ... VM translator function Foo.bar 2 ... push local 4 return ... // push constant 17 @17 D=A ... // additional assembly commands that complete the // implementation of push constant 17 // goto LOOP ... // generated assembly code that implements goto LOOP // call Foo.bar 3 ... // generated ... code that implements call Foo.bar 3 ... // function Foo.bar 2 ... // generated ... that implements function Foo.bar 2 The VM translator: • An extension of the basic VM translator written in project 7 • Adds the implementation of the branching and function commands // push local 4 ... // generated ... that implements push local 4 // return ... // generated assembly code that implements return ... Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The VM translator Source language: Target language: compiler Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The VM translator myProg directory myProg directory Foo.vm myProg.asm function Foo.main ... function Foo.bla ... (Foo.main) ... VM translator Bar.vm function Bar.new ... function Bar.bla ... (Foo.bla) ... (Bar.new) ... (Bar.bla) ... Proposed design: • Parser: parses each VM command into its lexical elements • CodeWriter: writes the assembly code that implements the parsed command • Main: drives the process (VMTranslator) same design as the basic VM translator built in project 7 Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Main Input: q fileName.vm : the name of a single source file, or q directoryName: the name of a directory containing one or more .vm source files Output: q fileName.asm file, or q directoryName.asm file Process: • Constructs a CodeWriter • If the input is a .vm file: q Constructs a Parser to handle the input file q Marches through the input file, parsing each line and generating code from it • If the input is a directory: q Handles every .vm file in the directory in the manner described above. Implementation note: An extension of the Main program written in project 7. Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Parser • Handles the parsing of a single .vm file • Reads a VM command, parses the command into its lexical components, and provides convenient access to these components • Removes all white space and comments. Implementation notes • Same Parser that was implemented in project 7 • If the Parser that you’ve developed in project 7 does not handle the parsing of the VM commands goto, if-goto, label, call, function, and return, add this parsing functionality now. Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken CodeWriter The API of the basic CodeWriter (developed in project 7): Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken CodeWriter Additional functionality: Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken CodeWriter Additional functionality: Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken CodeWriter Additional functionality: Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken CodeWriter Additional functionality: The generated assembly code must follow the guidelines and symbols described in the “standard mapping of the VM on the Hack platform” contract. Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Virtual machine: lecture plan Overview • Program control Branching • Abstraction • Implementation Functions Implementing function call-and-return: • Implementation overview • Run-time simulation • Detailed implementation VM implementation on the Hack platform: • Standard mapping • Abstraction • VM translator: proposed implementation • Implementation • Project 8 overview Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The big picture Human Thought write a program abstraction high-level language OS compiler abstraction VM Code VM translator abstraction machine language Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The big picture Human Thought write a program abstraction p9 high-level language OS p12 compiler abstraction p10 p11 VM translator VM Code abstraction p7 p8 machine language Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The big picture Human Thought write a program abstraction p9 high-level language OS p12 compiler abstraction p10 p11 VM translator VM Code abstraction p7 p8 machine language Objective: build a VM translator that translates programs written in the VM language into programs written in the Hack assembly language To test the translator: Run the generated nachine-level code on the target platform: Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken The big picture Human Thought write a program abstraction p9 high-level language OS p12 compiler abstraction p10 p11 VM translator VM Code abstraction p7 p8 machine language Objective: build a VM translator that translates programs written in the VM language into programs written in the Hack assembly language To test the translator: Run the generated nachine-level code on the target platform: CPU or emulat Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs ProgramFlow: q BasicLoop q FibonacciSeries FunctionCalls: q SimpleFunction q NestedCall q FibonacciElement q StaticsTest Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: BasicLoop ProgramFlow: u BasicLoop BasicLoop.vm BasicLoopVME.tst BasicLoop.tst Testing routine • Load and run XxxVME.tst on the VM emulator; • This script loads Xxx.vm into the VM emulator, allowing you to experiment with its code BasicLoop.cmp q FibonacciSeries FunctionCalls: q SimpleFunction NestedCall q FibonacciElement q q StaticsTest Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: BasicLoop ProgramFlow: u BasicLoop BasicLoop.vm BasicLoopVME.tst BasicLoop.tst BasicLoop.cmp q FibonacciSeries Testing routine • Load and run XxxVME.tst on the VM emulator; • This script loads Xxx.vm into the VM emulator, allowing you to experiment with its code • Use your VM translator to translate Xxx.vm; • The result will be a file named Xxx.asm FunctionCalls: q SimpleFunction NestedCall q FibonacciElement q q StaticsTest Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: BasicLoop ProgramFlow: u BasicLoop BasicLoop.vm BasicLoopVME.tst BasicLoop.tst BasicLoop.cmp q FibonacciSeries FunctionCalls: q SimpleFunction NestedCall q FibonacciElement q q Testing routine • Load and run XxxVME.tst on the VM emulator; • This script loads Xxx.vm into the VM emulator, allowing you to experiment with its code • Use your VM translator to translate Xxx.vm; • The result will be a file named Xxx.asm • Load and run Xxx.tst on the CPU emulator; • This script is designed to load Xxx.asm, execute it, and compares its output to Xxx.cmp StaticsTest Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: BasicLoop BasicLoop.vm ProgramFlow: u BasicLoop BasicLoop.vm BasicLoopVME.tst BasicLoop.tst BasicLoop.cmp q FibonacciSeries FunctionCalls: q SimpleFunction NestedCall q FibonacciElement q q StaticsTest Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: BasicLoop BasicLoop.vm ProgramFlow: u BasicLoop // Computes the sum 1 + 2 + ... + argument[0], // and pushes the result onto the stack. BasicLoop.vm BasicLoopVME.tst BasicLoop.tst BasicLoop.cmp q FibonacciSeries FunctionCalls: q SimpleFunction NestedCall q FibonacciElement q q StaticsTest Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: BasicLoop BasicLoop.vm ProgramFlow: u BasicLoop BasicLoop.vm BasicLoopVME.tst // Computes the sum 1 + 2 + ... + argument[0], // and pushes the result onto the stack. // The translated version, BasicLoop.asm (not shown here), can be tested on // the CPU emulator. BasicLoop.tst BasicLoop.cmp q FibonacciSeries FunctionCalls: q SimpleFunction NestedCall q FibonacciElement q q StaticsTest Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: BasicLoop BasicLoop.vm ProgramFlow: u BasicLoop BasicLoop.vm BasicLoopVME.tst BasicLoop.tst BasicLoop.cmp q FibonacciSeries FunctionCalls: q SimpleFunction NestedCall q FibonacciElement q q StaticsTest Typical loop logic: while (counter > 0) { sum += counter counter-- } // Computes the sum 1 + 2 + ... + argument[0], // and pushes the result onto the stack. // The translated version, BasicLoop.asm (not shown here), can be tested on // the CPU emulator. // This can be done using BasicLoop.tst. This script initializes the VM // memory segments as well as argument[0], and then loads and executes // BasicLoop.asm. push constant 0 pop local 0 // initialize sum = 0 label LOOP_START push argument 0 push local 0 add pop local 0 // sum = sum + counter push argument 0 push constant 1 sub pop argument 0 // counter-push argument 0 if-goto LOOP_START // if counter > 0, goto LOOP_START push local 0 Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: BasicLoop BasicLoop.vm ProgramFlow: u BasicLoop BasicLoop.vm BasicLoopVME.tst BasicLoop.tst BasicLoop.cmp q FibonacciSeries FunctionCalls: q SimpleFunction NestedCall q FibonacciElement q q StaticsTest Typical loop logic: while (counter > 0) { sum += counter counter-- } Designed to test the handling of the VM commands: // Computes the sum 1 + 2 + ... + argument[0], // and pushes the result onto the stack. // The translated version, BasicLoop.asm (not shown here), can be tested on // the CPU emulator. // This can be done using BasicLoop.tst. This script initializes the VM // memory segments as well as argument[0], and then loads and executes // BasicLoop.asm. push constant 0 pop local 0 // initialize sum = 0 label LOOP_START push argument 0 push local 0 add pop local 0 // sum = sum + counter push argument 0 push constant 1 sub pop argument 0 // counter-push argument 0 if-goto LOOP_START // if counter > 0, goto LOOP_START push local 0 • label • if-goto Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs ProgramFlow: q BasicLoop q FibonacciSeries FunctionCalls: q SimpleFunction q NestedCall q FibonacciElement q StaticsTest Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: FibonacciSeries FibSeries.vm ProgramFlow: q BasicLoop u FibonacciSeries FibSeries.vm FibSeriesVME.tst FibSeries.tst FibSeries.cmp FunctionCalls: q SimpleFunction NestedCall q FibonacciElement q q StaticsTest Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: FibonacciSeries FibSeries.vm ProgramFlow: q BasicLoop u FibonacciSeries // Computes the first argument[0] elements of the Fibonacci series. // Puts the elements in the RAM, starting at the address given in argument[1]. FibSeries.vm FibSeriesVME.tst FibSeries.tst FibSeries.cmp FunctionCalls: q SimpleFunction NestedCall q FibonacciElement q q StaticsTest Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: FibonacciSeries FibSeries.vm ProgramFlow: q BasicLoop u FibonacciSeries FibSeries.vm FibSeriesVME.tst // Computes the first argument[0] elements of the Fibonacci series. // Puts the elements in the RAM, starting at the address given in argument[1]. // FibSeries.tst initializes the VM memory segments as well as // argument[0] and argument[1], and then executes the translated // machine code, stored in FibSeries.asm, on the CPU emulator. FibSeries.tst FibSeries.cmp FunctionCalls: q SimpleFunction NestedCall q FibonacciElement q q StaticsTest Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: FibonacciSeries FibSeries.vm ProgramFlow: q BasicLoop u FibonacciSeries FibSeries.vm FibSeriesVME.tst FibSeries.tst FibSeries.cmp FunctionCalls: q SimpleFunction NestedCall q FibonacciElement q q StaticsTest typical array processing logic: arr[i] = arr[i-1] + arr[i-2] // Computes the first argument[0] elements of the Fibonacci series. // Puts the elements in the RAM, starting at the address given in argument[1]. // FibSeries.tst initializes the VM memory segments as well as // argument[0] and argument[1], and then executes the translated // machine code, stored in FibSeries.asm, on the CPU emulator. push argument 1 pop pointer 1 // that = argument[1] push constant 0 pop that 0 // first series element = 0 push constant 1 pop that 1 // second series element = 1 ... label MAIN_LOOP_START push argument 0 if-goto COMPUTE_ELEMENT // if ... goto COMPUTE_ELEMENT goto END_PROGRAM // otherwise, goto END_PROGRAM label COMPUTE_ELEMENT push that 0 push that 1 add ... goto MAIN_LOOP_START label END_PROGRAM Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: FibonacciSeries FibSeries.vm ProgramFlow: q BasicLoop u FibonacciSeries FibSeries.vm FibSeriesVME.tst FibSeries.tst FibSeries.cmp FunctionCalls: q SimpleFunction NestedCall q FibonacciElement q q StaticsTest typical array processing logic: arr[i] = arr[i-1] + arr[i-2] Designed to perform a more elaborate test of handling the VM commands: • label • goto • if-goto // Computes the first argument[0] elements of the Fibonacci series. // Puts the elements in the RAM, starting at the address given in argument[1]. // FibSeries.tst initializes the VM memory segments as well as // argument[0] and argument[1], and then executes the translated // machine code, stored in FibSeries.asm, on the CPU emulator. push argument 1 pop pointer 1 // that = argument[1] push constant 0 pop that 0 // first series element = 0 push constant 1 pop that 1 // second series element = 1 ... label MAIN_LOOP_START push argument 0 if-goto COMPUTE_ELEMENT // if ... goto COMPUTE_ELEMENT goto END_PROGRAM // otherwise, goto END_PROGRAM label COMPUTE_ELEMENT push that 0 push that 1 add ... goto MAIN_LOOP_START label END_PROGRAM Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs ProgramFlow: q BasicLoop q FibonacciSeries FunctionCalls: q SimpleFunction q NestedCall q FibonacciElement q StaticsTest Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: SimpleFunction ProgramFlow: q BasicLoop q FibonacciSeries FunctionCalls: u SimpleFunction SimpleFunction.vm SimpleFunctionVME.tst SimpleFunction.tst SimpleFunction.cmp NestedCall q FibonacciElement q q StaticsTest Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: SimpleFunction SimpleFunction.vm ProgramFlow: q BasicLoop q FibonacciSeries FunctionCalls: u SimpleFunction SimpleFunction.vm SimpleFunctionVME.tst SimpleFunction.tst SimpleFunction.cmp NestedCall q FibonacciElement q q StaticsTest Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: SimpleFunction SimpleFunction.vm ProgramFlow: q BasicLoop q FibonacciSeries // Performs a simple (and meaningless) calculation involving local // and argument values, and returns the result. FunctionCalls: u SimpleFunction SimpleFunction.vm SimpleFunctionVME.tst SimpleFunction.tst SimpleFunction.cmp NestedCall q FibonacciElement q q StaticsTest Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: SimpleFunction SimpleFunction.vm ProgramFlow: q BasicLoop q FibonacciSeries FunctionCalls: u SimpleFunction SimpleFunction.vm SimpleFunctionVME.tst SimpleFunction.tst SimpleFunction.cmp NestedCall q FibonacciElement q q StaticsTest // Performs a simple (and meaningless) calculation involving local // and argument values, and returns the result. // SimpleFunction.tst initializes the VM memory segments as well // as some argument values, and then executes the translated // machine code, stored in SimpleFunction.asm, in the CPU emulator. function SimpleFunction.test 2 push local 0 push local 1 add not push argument 0 add push argument 1 sub return Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: SimpleFunction SimpleFunction.vm ProgramFlow: q BasicLoop q FibonacciSeries FunctionCalls: u SimpleFunction SimpleFunction.vm SimpleFunctionVME.tst SimpleFunction.tst SimpleFunction.cmp NestedCall q FibonacciElement q q StaticsTest // Performs a simple (and meaningless) calculation involving local // and argument values, and returns the result. // SimpleFunction.tst initializes the VM memory segments as well // as some argument values, and then executes the translated // machine code, stored in SimpleFunction.asm, in the CPU emulator. function SimpleFunction.test 2 push local 0 push local 1 add not push argument 0 add push argument 1 sub return Tests the handling of the VM commands: • function • return Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: SimpleFunction SimpleFunction.vm ProgramFlow: q BasicLoop q FibonacciSeries FunctionCalls: u SimpleFunction SimpleFunction.vm SimpleFunctionVME.tst SimpleFunction.tst SimpleFunction.cmp NestedCall q FibonacciElement q q StaticsTest // Performs a simple (and meaningless) calculation involving local // and argument values, and returns the result. // SimpleFunction.tst initializes the VM memory segments as well // as some argument values, and then executes the translated // machine code, stored in SimpleFunction.asm, in the CPU emulator. function SimpleFunction.test 2 push local 0 push local 1 add not push argument 0 add push argument 1 sub return Tests the handling of the VM commands: • function • return Simple test, since it involves no caller Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs ProgramFlow: q BasicLoop q FibonacciSeries FunctionCalls: q SimpleFunction q NestedCall q FibonacciElement q StaticsTest Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: FibonacciElement ProgramFlow: q BasicLoop q FibonacciSeries FunctionCalls: q SimpleFunction q NestedCall u FibonacciElement Main.vm > VMTranslator FibonacciElement Sys.vm FibElementVME.tst FibElement.tst FibElement.cmp q Should yield a single output file: FibonacciElement.asm StaticsTest Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: FibonacciElement Main.vm ProgramFlow: q BasicLoop q FibonacciSeries FunctionCalls: q SimpleFunction q NestedCall u FibonacciElement // Main.fibonacci: computes the n'th element of the Fibonacci series, // recursively. The n value is supplied by the caller, and stored in // argument 0. function Main.fibonacci 0 Main.vm Sys.vm FibElementVME.tst FibElement.tst FibElement.cmp q StaticsTest Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: FibonacciElement Main.vm ProgramFlow: q BasicLoop q FibonacciSeries FunctionCalls: q SimpleFunction q NestedCall u FibonacciElement Main.vm Sys.vm FibElementVME.tst FibElement.tst FibElement.cmp q StaticsTest typical recursive logic: function fib(n): if n<2 return n else return fib(n-1)+fib(n-2) // Main.fibonacci: computes the n'th element of the Fibonacci series, // recursively. The n value is supplied by the caller, and stored in // argument 0. function Main.fibonacci 0 push argument 0 push constant 2 lt // checks if n<2 if-goto IF_TRUE goto IF_FALSE label IF_TRUE // if n<2 returns n push argument 0 return label IF_FALSE // if n>=2 returns fib(n-2)+fib(n-1) push argument 0 push constant 2 sub call Main.fibonacci 1 // computes fib(n-2) push argument 0 push constant 1 sub call Main.fibonacci 1 // computes fib(n-1) add // returns fib(n-1) + fib(n-2) return Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: FibonacciElement Main.vm (abbreviated) ProgramFlow: q BasicLoop q FibonacciSeries FunctionCalls: q SimpleFunction q NestedCall u FibonacciElement Main.vm Sys.vm FibElementVME.tst FibElement.tst // Main.fibonacci: computes the n'th element of the Fibonacci series, // recursively. The n value is supplied by the caller, and stored in // argument 0. function Main.fibonacci 0 ... call Main.fibonacci 1 // computes fib(n-2) push argument 0 push constant 1 sub call Main.fibonacci 1 // computes fib(n-1) add // returns fib(n-1) + fib(n-2) return FibElement.cmp q StaticsTest Sys.vm // Normally, Sys.init: pushes n should onto thecall stack, calls Main.main. Main.fibonacii Sys.init the and function // to compute the n’th Fibonacci element. 8, we function use it to call various test functions. // In TheProject Sys.init should be called by the bootstrap code. function Sys.init 0 Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: FibonacciElement Main.vm (abbreviated) ProgramFlow: q BasicLoop q FibonacciSeries FunctionCalls: q SimpleFunction q NestedCall u FibonacciElement Main.vm Sys.vm FibElementVME.tst FibElement.tst // Main.fibonacci: computes the n'th element of the Fibonacci series, // recursively. The n value is supplied by the caller, and stored in // argument 0. function Main.fibonacci 0 ... call Main.fibonacci 1 // computes fib(n-2) push argument 0 push constant 1 sub call Main.fibonacci 1 // computes fib(n-1) add // returns fib(n-1) + fib(n-2) return FibElement.cmp q StaticsTest Sys.vm // Normally, Sys.init: pushes n should onto thecall stack, calls Main.main. Main.fibonacii Sys.init the and function // to compute the n’th Fibonacci element. 8, we function use it to call various test functions. // In TheProject Sys.init should be called by the bootstrap code. function Sys.init 0 push constant 4 call Main.fibonacci 1 // test: computes the 4'th Fib. element label WHILE goto WHILE // loops forever Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: FibonacciElement Main.vm (abbreviated) ProgramFlow: q BasicLoop q FibonacciSeries FunctionCalls: q SimpleFunction q NestedCall u FibonacciElement Main.vm Sys.vm FibElementVME.tst FibElement.tst // Main.fibonacci: computes the n'th element of the Fibonacci series, // recursively. The n value is supplied by the caller, and stored in // argument 0. function Main.fibonacci 0 ... call Main.fibonacci 1 // computes fib(n-2) push argument 0 push constant 1 sub call Main.fibonacci 1 // computes fib(n-1) add // returns fib(n-1) + fib(n-2) return FibElement.cmp q StaticsTest • Tests the handling of function, return, and call (and many other VM commands) Sys.vm // Normally, Sys.init: pushes n should onto thecall stack, calls Main.main. Main.fibonacii Sys.init the and function // to compute the n’th Fibonacci element. 8, we function use it to call various test functions. // In TheProject Sys.init should be called by the bootstrap code. function Sys.init 0 push constant 4 call Main.fibonacci 1 // test: computes the 4'th Fib. element label WHILE goto WHILE // loops forever Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: FibonacciElement Main.vm (abbreviated) ProgramFlow: q BasicLoop q FibonacciSeries FunctionCalls: q SimpleFunction q NestedCall u FibonacciElement Main.vm Sys.vm FibElementVME.tst FibElement.tst // Main.fibonacci: computes the n'th element of the Fibonacci series, // recursively. The n value is supplied by the caller, and stored in // argument 0. function Main.fibonacci 0 ... call Main.fibonacci 1 // computes fib(n-2) push argument 0 push constant 1 sub call Main.fibonacci 1 // computes fib(n-1) add // returns fib(n-1) + fib(n-2) return FibElement.cmp q StaticsTest • Tests the handling of function, return, and call (and many other VM commands) • Tests that the VM implementation (your translator) initializes the memory segments Sys.vm // Normally, Sys.init: pushes n should onto thecall stack, calls Main.main. Main.fibonacii Sys.init the and function // to compute the n’th Fibonacci element. 8, we function use it to call various test functions. // In TheProject Sys.init should be called by the bootstrap code. function Sys.init 0 push constant 4 call Main.fibonacci 1 // test: computes the 4'th Fib. element label WHILE goto WHILE // loops forever • Tests that the the bootsrap code of the VM implementation initializes the stack and calls Sys.init Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs ProgramFlow: q BasicLoop q FibonacciSeries FunctionCalls: q SimpleFunction q NestedCall q FibonacciElement q StaticsTest Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: NestedCall ProgramFlow: q BasicLoop q FibonacciSeries FunctionCalls: q SimpleFunction u NestedCall Sys.vm NestedCallVME.tst NestedCall.tst NestedCall.cmp NestedCall.html NestedCallStack.html q FibonacciElement q StaticsTest • Closes testing gaps between SimpleFunction and FibonacciElement • Recommended when SimpleFunction tests successfully and FibonacciElement fails or crashes • Self-documented Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs ProgramFlow: q BasicLoop q FibonacciSeries FunctionCalls: q SimpleFunction q NestedCall q FibonacciElement q StaticsTest Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: StaticsTest ProgramFlow: q BasicLoop q FibonacciSeries FunctionCalls: q SimpleFunction q NestedCall q FibonacciElement u StaticsTest Class1.vm Class2.vm Sys.vm > VMTranslator StaticsTest StaticsTestVME.tst Should yield a single output file: StaticsTest.tst StaticsTest.asm StaticsTest.cmp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: StaticsTest class1.vm ProgramFlow: q BasicLoop q FibonacciSeries // Stores two supplied arguments in static 0 and static 1 function Class1.set 0 FunctionCalls: q SimpleFunction q NestedCall q FibonacciElement u StaticsTest Class1.vm Class2.vm Sys.vm StaticsTestVME.tst StaticsTest.tst StaticsTest.cmp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: StaticsTest class1.vm ProgramFlow: q BasicLoop q FibonacciSeries FunctionCalls: q SimpleFunction q NestedCall q FibonacciElement u StaticsTest Class1.vm Class2.vm Sys.vm StaticsTestVME.tst StaticsTest.tst StaticsTest.cmp // Stores two supplied arguments in static 0 and static 1 function Class1.set 0 push argument 0 pop static 0 push argument 1 pop static 1 push constant 0 return // Returns (static 0) – (static 1) function Class1.get 0 push static 0 push static 1 sub return Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: StaticsTest class1.vm ProgramFlow: q BasicLoop q FibonacciSeries FunctionCalls: q SimpleFunction q NestedCall q FibonacciElement u StaticsTest Class1.vm Class2.vm Sys.vm StaticsTestVME.tst // Stores two supplied arguments in static 0 and static 1 function Class1.set 0 push argument 0 pop static 0 class2.vm push argument 1 // Stores two supplied arguments in static 0 and static 1 pop static 1 function push constant 0 Class2.set 0 push argument 0 return pop static 0 argument // Returns (static push 0) – (static 1) 1 pop static 1 function Class1.get 0 constant 0 push static push 0 push static return 1 StaticsTest.tst StaticsTest.cmp sub return • The two class files have the same logic // Returns (static 0) – (static 1) function Class2.get 0 push static 0 push static 1 sub return • But, different .vm files should have different static segments Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: StaticsTest class1.vm (abbreviated) ProgramFlow: q BasicLoop q FibonacciSeries FunctionCalls: q SimpleFunction q NestedCall q FibonacciElement u StaticsTest Class1.vm Class2.vm Sys.vm // Stores two supplied arguments in static 0 and static 1 function Class1.set 0 ... // Returns (static 0) – (static 1) function Class1.get 0 class2.vm ... // Stores two supplied arguments in static 0 and static 1 function Class1.set 0 Sys.vm ... function Sys.init 0 // Returns (static 0) – (static 1) function Class1.get 0 ... StaticsTestVME.tst StaticsTest.tst StaticsTest.cmp Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Test programs: StaticsTest class1.vm (abbreviated) ProgramFlow: q BasicLoop q FibonacciSeries FunctionCalls: q SimpleFunction q NestedCall q FibonacciElement u StaticsTest Class1.vm Class2.vm Sys.vm StaticsTestVME.tst StaticsTest.tst StaticsTest.cmp Tests that the static segments of different files are handled correctly. // Stores two supplied arguments in static 0 and static 1 function Class1.set 0 ... // Returns (static 0) – (static 1) function Class1.get 0 class2.vm ... // Stores two supplied arguments in static 0 and static 1 function Class1.set 0 Sys.vm ... function Sys.init 0 // Returns (static 0) – (static 1) // Calls Class1.set with 6 and 8 function Class1.get 0 push constant 6 ... push constant 8 call Class1.set 2 pop temp 0 // dumps the return value // Calls Class2.set with 23 and 15 push constant 23 push constant 15 call Class2.set 2 pop temp 0 // dumps the return value // Checks the two resulting static segments call Class1.get 0 call Class2.get 0 label WHILE // loops forever goto WHILE Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken Tools and resources • Test programs and compare files: nand2tetris/projects/08 • Reference: chapter 8 in The Elements of Computing Systems Same as in project 7: • Experimenting with the test VM programs: the supplied VM emulator • Translating the test VM programs into assembly: your VM translator • Testing the resulting assembly code: the supplied CPU emulator • Programming language for implementing your VM translator: Java, Python, ... • Tutorials: VM emulator, CPU emulator (nand2tetris web site). Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken • Chapter 8 • Virtual Machine, Part II These slides support chapter 8 of the book The Elements of Computing Systems By Noam Nisan and Shimon Schocken MIT Press Nand to Tetris / www.nand2tetris.org / Chapter 8 / Copyright © Noam Nisan and Shimon Schocken CO557: The Jack Language David Barnes Chapter 9 Features of the Language These slides support chapter 9 of the book The Elements of Computing Systems By Noam Nisan and Shimon Schocken MIT Press Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Overview • An introduction to the features of the Jack language. • A comparison with other languages, such as Java. • A critique of some of its features. Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Jack in a nutshell /** Demo: working with Point objects. */ class Main { function void main() { var Point p1, p2, p3; let p1 = Point.new(1,2); let p2 = Point.new(3,4); let p3 = p1.plus(p2); do p3.print(); do Output.println(); do Output.printInt(p1.distance(p3)); return; } } /** Represents a Point object. */ class Point { field int x, y; static int pointCount; /** Constructs a new point */ constructor Point new(int ax, int ay) { let x = ax; let y = ay; let pointCount = pointCount + 1; return this; } // More Point methods... } • A simple, Java-like language. • Object-based, no inheritance. • Multi-purpose. • Lends itself to interactive apps. • Can be learned in about an hour. • The syntax is regular for the sake of the parser. Lack of strong typing makes the language closer to C than Java in some ways. Lack of automated garbage collection. • • Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Take home lessons An inside view of how high-level OO languages ... • are designed • handle primitive types and class types • create, represent, and dispose objects • deal with strings, arrays, and lists • interact with the host OS • ... and many more issues Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Hello world /** Hello World program. */ class Main { function void main() { /* Prints some text using the standard library. */ How many numbers? 3 Hello world! 12 Enter a number: EnterFraction a number: 8 API Enter a number: 5 The average is 8 do Output.printString(”Hello world!”); do Output.println(); // New line return; } } Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Language constructs • Comments: /** Hello World program. */ class Main { function void main() { /* Prints some text using the standard library. */ do Output.printString(”Hello world!”); do Output.println(); return; // New line How many numbers? 3 EnterAPI a number: q /** block12comment */ Enter a number: 8 q /* block comment */ Enter a number: 5 The average is 8 q // in-line comment • White space acts as a separator. } } Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Language constructs Jack code // 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; } } • A Jack program is a collection of one or more Jack classes, one of which must be named Main • The Main class must have at least one function, named main • Program’s entry point: Main.main Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken How many numbers? 3 Fraction API Enter a number: 12 Enter a number: 8 Enter a number: 5 The average is 8 Language constructs Jack code // 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; } } Jack data types: • Primitive: • int • char • boolean • Class types: • OS: Array, String, ... • Additional ADT’s can be defined and used, as needed Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken How many numbers? 3 Fraction API Enter a number: 12 Enter a number: 8 Enter a number: 5 The average is 8 Language constructs Jack code // 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; } } How many numbers? 3 Fraction API Enter a number: 12 Enter a number: 8 Enter a number: 5 The average is 8 Flow of control: • if / if...else • while • do Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Language constructs Jack code // 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; } } Arrays: • Array is implemented as part of the standard class library • Jack arrays are not typed Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken How many numbers? 3 Fraction API Enter a number: 12 Enter a number: 8 Enter a number: 5 The average is 8 Language constructs Jack code // 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; } } OS services: • Keyboard.readInt • Output.printString • Output.printInt • More... Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken How many numbers? 3 Fraction API Enter a number: 12 Enter a number: 8 Enter a number: 5 The average is 8 OO programming: building a class Fraction class /** Represents the Fraction type and related operations. */ class Fraction { Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken OO programming: fields and accessors Fraction class /** Represents the Fraction type and related operations. */ class Fraction { field, aka property, aka member variable field int numerator, denominator; /** Accessors. */ method int getNumerator() { return numerator; } the only way to access field values from outside the class is through accessors method int getDenominator() { return denominator; } // More Fraction methods follow. } // Fraction class Some Jack class class Foo { ... var Fraction x; let x = Fraction.new(5,17); Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken OO programming: fields and accessors Fraction class /** Represents the Fraction type and related operations. */ class Fraction { field, aka property, aka member variable field int numerator, denominator; /** Accessors. */ method int getNumerator() { return numerator; } the only way to access field values from outside the class is through accessors method int getDenominator() { return denominator; } // More Fraction methods follow. } // Fraction class Some Jack class class Foo { ... var Fraction x; let x = Fraction.new(5,17); do Output.printInt(x.numerator); // not allowed do Output.printInt(x.getNumerator()); // ok ... Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken OO programming: subroutines – constructor, method, function Fraction class /** Represents the Fraction type and related operations. */ class Fraction { field int numerator, denominator; /** Constructs a (reduced) fraction from the given numerator and denominator. */ constructor Fraction new(int x, int y) { let numerator = x; let denominator = y; do reduce(); // reduces the fraction return this; // returns the base address of the new object } • this: a reference to the current object Jack subroutines: • methods • constructors • functions (base address) // Reduces this fraction. • a constructor must return the (base method void reduce() { address of) the newly created object var int g; let g = Fraction.gcd(numerator, denominator); if (g > 1) {let numerator = numerator / g; let denominator = denominator / g;} return; a subroutine must terminate with a return command } } // Computes the greatest common divisor of the given integers. function int gcd(int a, int b) { var int r; while (~(b = 0)) { // applies Euclid’s algorithm. let r = a – (b * (a / b)); // r = remainder of the integer division a/b let a = b; let b = r; } return a; } // More Fraction code in next slide Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken OO programming: memory management Fraction class /** Represents the Fraction type and related operations. */ class Fraction { field int numerator, denominator; /** Disposes this fraction. */ method void dispose() { do Memory.deAlloc(this); return; } // uses an OS routine to recycle the object’s memory. } // Fraction class Garbage collection • Jack has no garbage collection • Objects must be disposed explicitly • Best practice: every class that has a constructor should also feature a dispose method. Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken NB: There are no safeguards to prevent access to deallocated memory. OO programming: object representation Fraction class RAM ... /** Represents the Fraction type and related operations. */ class Fraction { 256 ... field int numerator, denominator; /** Constructs a (reduced) fraction from the given numerator and denominator */ constructor Fraction new(int x, int y) { let numerator = x; let denominator = y; do reduce(); The compiled constructor’s VM code return this; includes OS calls that allocate and manage } RAM space for representing the new object // More Fraction methods ... var Fraction a, b, c; ... let a = Fraction.new(2,3); let b = Fraction.new(1,5); ... a 4112 b 2047 2048 ... Issues: • allocating memory • de-allocating memory (handled by the compiler and the OS) The client’s view 4112 1 4113 ... 5 15087 2 15088 ... 3 heap 16383 ... 2 3 1 stack ... } Client code 15087 5 Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken NB: Effect of deallocation is undefined. OO programming: object representation RAM ... 256 ... 15087 a 4112 b stack ... 2047 2048 Implementation ... Abstraction 4112 1 4113 ... 5 15087 2 15088 ... 3 heap 16383 ... 2 3 1 5 Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Syntax /** Procedural processing example */ class Main { /* Inputs some numbers and computes their average */ 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; Syntax elements: • White space / comments • keywords • Symbols • Constants • Identifiers } ... } Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Syntax: white space / comments /** Procedural processing example */ class Main { /* Inputs some numbers and computes their average */ 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; Syntax elements: • White space / comments • keywords • Symbols • Constants • Identifiers } ... } Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Syntax: white space / comments /** Procedural processing example */ class Main { /* Inputs some numbers and computes their average */ 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; Syntax elements: • White space / comments • keywords • Symbols • Constants • Identifiers } ... } Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Syntax: keywords /** Procedural processing example */ class Main { /* Inputs some numbers and computes their average */ 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; Syntax elements: • White space / comments • keywords • Symbols • Constants • Identifiers } ... } Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Syntax: keywords /** Procedural processing example */ class Main { /* Inputs some numbers and computes their average */ 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; Syntax elements: • White space / comments • keywords • Symbols • Constants • Identifiers } ... } Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Syntax: symbols /** Procedural processing example */ class Main { /* Inputs some numbers and computes their average */ 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; Syntax elements: • White space / comments • keywords • Symbols • Constants • Identifiers } ... } Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Syntax: symbols /** Procedural processing example */ class Main { /* Inputs some numbers and computes their average */ 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; Syntax elements: • White space / comments • keywords • Symbols • Constants • Identifiers } ... } Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Syntax: constants /** Procedural processing example */ class Main { /* Inputs some numbers and computes their average */ 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; Syntax elements: • White space / comments • keywords • Symbols • Constants • Identifiers } ... } Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Syntax: constants /** Procedural processing example */ class Main { /* Inputs some numbers and computes their average */ 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; Syntax elements: • White space / comments • keywords • Symbols • Constants • Identifiers } ... } NB: No character literals: ‘a’ Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Syntax: identifiers /** Procedural processing example */ class Main { /* Inputs some numbers and computes their average */ 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; Syntax elements: • White space / comments • keywords • Symbols • Constants • Identifiers } ... } Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Syntax: identifiers /** Procedural processing example */ class Main { /* Inputs some numbers and computes their average */ 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; Syntax elements: • White space / comments • keywords • Symbols • Constants • Identifiers } ... } Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Recap /** Procedural processing example */ class Main { /* Inputs some numbers and computes their average */ 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; Syntax elements: • White space / comments • keywords • Symbols • Constants • Identifiers } ... } Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Data types /** Procedural processing example */ class Main { /* Inputs some numbers and computes their average */ 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; Primitive types q int: Non-negative 2’s-complement 16-bit integer, i.e. an integer in the range 0,..., 32767 q boolean: true or false q char: Integer values representing characters } ... } Class types • OS types: String, Array • User-defined types: Fraction, List, ... Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Type conversions Characters and integers can be converted into each other, as needed: var char c; var String s; Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Type conversions Characters and integers can be converted into each other, as needed: var char c; var String s; let c = 65; // 'A' let c = 'A'; // Not supported by the Jack language let s = "A"; let c = s.charAt(0); // 'A', ok An integer can be assigned to a reference variables, in which case it is treated as a memory address: var Array arr; // creates a pointer variable • Lack of strict typing is a significant feature. • Simplifies the ‘front end’ dramatically. Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Type conversions Characters and integers can be converted into each other, as needed: var char c; var String s; let c = 65; // 'A' let c = 'A'; // Not supported by the Jack language let s = "A"; let c = s.charAt(0); // 'A', ok An integer can be assigned to a reference variables, in which case it is treated as a memory address: var Array arr; // creates a pointer variable let arr = 5000; // ok... let arr[100] = 17; // sets memory address 5100 to 17 • Lack of strict typing is a significant feature. • Simplifies the ‘front end’ dramatically. An object can be converted into an Array, and vice versa: var Array arr; let arr = Array.new(2); let arr[0] = 2; let arr[1] = 5; Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Type conversions Characters and integers can be converted into each other, as needed: var char c; var String s; let c = 65; // 'A' let c = 'A'; // Not supported by the Jack language let s = "A"; let c = s.charAt(0); // 'A', ok An integer can be assigned to a reference variables, in which case it is treated as a memory address: var Array arr; // creates a pointer variable let arr = 5000; // ok... let arr[100] = 17; // sets memory address 5100 to 17 • Lack of strict typing is a significant feature. • Simplifies the ‘front end’ dramatically. An object can be converted into an Array, and vice versa: var Array arr; let arr = Array.new(2); let arr[0] = 2; let arr[1] = 5; var Fraction x; // a Fraction object has two int fields: numerator and denominator. let x = arr; // sets x to the base address of the memory block representing the array [2,5] do x.print() // prints 2/5 (using the print method of the Fraction class) Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Review • We have looked at the basic language features of Jack. • It supports object-based programming. • Instance variables and static variables are supported. • Instance methods and static methods are supported. • Its syntactic structure will make the task of parsing relatively easy. • Its ‘wordy’ and prescriptive syntactic structure is painful for a programmer. • Its lack of proper typing makes it closer to C than Java in some respects. • Its approach to heap management is risky. Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken CO557: The Jack Language David Barnes Chapter 9 Syntax and the API/OS These slides support chapter 9 of the book The Elements of Computing Systems By Noam Nisan and Shimon Schocken MIT Press Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Jack application • A Jack program, or application, is a collection of one or more Jack classes, one of which must be named Main • The Main class must have at least one function, named main • Program’s entry point: Main.main Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Classes • Class = basic compilation unit • Each class Foo is stored in a separate Foo.jack file • The class name’s first character must be an uppercase letter. Foo.jack file class Foo { field variable declarations static variable declarations must precede the subroutine declarations subroutine declarations } constructors, methods, functions Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Classes that represent entities (objects) • Examples: Fraction, List, String, ... • A class that contains at least one method • Used to represent an object type and operations on this object • Typically contains fields and methods • Can also contain functions, recommended for “helper” purpose only Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Utility classes • A class that contains only functions (“static methods”) can be called a “utility class” • (no fields, constructors, or methods) • Offers a “library of services” Math class API (example) Provides various mathematical operations. • function int abs(int x): returns the absolute value of x. • function int multiply(int x, int y): returns the product of x and y. • function int divide(int x, int y): returns the integer part of x/y. • function int min(int x, int y): returns the minimum of x and y. • function int max(int x, int y): returns the maximum of x and y. • function int sqrt(int x): returns the integer part of the square root of x. Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Jack’s standard class library / OS Jack code // 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; } } Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Jack’s standard class library / OS Jack code // 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; } } OS purpose: How many numbers? 3 • Closes gaps 12 between Enter a number: Enter a number: 8 high-level programs and Enter a number: 5 the host hardware The average is 8 • Provides efficient implementations of commonly-used functions • Provides efficient implementations of commonly-used ADTs OS implementation: • A collection of classes • Similar to Java’s standard class library Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Jack’s standard class library / OS Complete OS API: Nand2Tetris book / website Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Classes: syntax class Foo { field variable declarations static variable declarations subroutine declarations } Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Subroutines Subroutine declaration constructor | method | function type subroutineName (parameter-list) { local variable declarations statements } Jack subroutines • Constructors: create new objects • Methods: operate on the current object • Functions: static methods Subroutine types and return values • Method and function type can be either void, a primitive data type, or a class name • Each subroutine must end with return value or return. Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Constructors Constructor declaration constructor ClassName constructorName (parameter-list) { local variable declarations statements } Constructors • 0, 1, or more in a class • Common name: new • The constructor’s type must be the name of the constructor’s class • The constructor must return a reference to an object of the class type. class Point { field int x; field int y; ... /* Creates a Point. */ constructor Point new(int ax, int ay) { let x = ax; let y = ay; return this; } ... } Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Variables Variable kinds: q q q q field variables: object properties, can be manipulated by the class constructors and methods static variables: class-level variables, can be manipulated by the class subroutines local variables: used by subroutines, for local computations parameter variables: used to pass values to subroutines, behave like local variables /** Represents a Point object. */ class Point { field int x, y; static int pointCount; ... method int bla(int z) { int foo; let foo = z * (x + y); return foo; } ... } Variables must be ... • Declared before they are used • Typed. Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Variables Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Statements: syntax return Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Expressions Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Expressions Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Expressions NB: expression is defined recursively (in terms of itself). Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Expressions Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Expressions NB: No defined order of evaluation! Leads to inconsistent implementations. Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Subroutine calls Examples: class Foo { ... method void f() { var Bar b; // declares a local variable of class type Bar var int i; ... // declares a local variable of primitive type int Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Subroutine calls Examples: class Foo { ... method void f() { var Bar b; // declares a local variable of class type Bar var int i; ... // declares a local variable of primitive type int do g(); // calls method g of the current class on this object do Foo.p(3); // calls function p of the current class do Bar.h(); // calls function h of class Bar let b = Bar.r(); // calls function or constructor r of class Bar do b.q(); // calls method q of class Bar on the b object let i = w(b.s(), Foo.t()); // calls method w on this object. The arguments are // the results of calling method s on object b, // and function or constructor t of class Foo ... } } Subroutine call syntax: subroutineName(argument-list) • The number and type of arguments must agree with those of the subroutine’s parameters. • Each argument can be an expression of unlimited complexity. Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken NB: requirement to check match between formal and actual parameters. Strings Examples: ... var String s; // Creates an object variable (pointer), initialized to null var char c; // Creates a primitive variable, initialized to zero Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Strings Examples: ... var String s; // Creates an object variable (pointer), initialized to null var char c; // Creates a primitive variable, initialized to zero ... // Suppose we want s to refer to the string “Hello World!”: let s = String.new(12); // Followed by a loop that uses String’s appendChar method to set s to “Hello World!” // (loop code not shown) NB: assumption that Strings can grow in length. Difficult to implement in practice in view of the memory management. // Alternatively, the Jack compiler allows using: let s = ”Hello World”; // “syntactic sugar” // Accessing some character within a string: let c = s.charAt(6); // Sets c to the numeric value representing ‘W’. For more String and character operations, see the String class API Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken capacity of this String? Arrays: untyped Examples: ... var Array arr; var String helloWorld; let helloWorld = “Hello World!” ... Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Arrays: untyped Examples: ... var Array arr; var String helloWorld; let helloWorld = “Hello World!” ... let arr = Array.new(4); let arr[0] = 12; let arr[1] = false; let arr[2] = Fraction.new(314/100); let arr[3] = helloWorld; ... • Jack arrays are ... q q q instances (objects) of the OS class Array not typed uni-dimensional • Multi-dimensional arrays can be obtained by using an arrays of arrays. Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken End note: peculiar features of the Jack language • The keyword let: must be used in assignments: let x = 0; • The keyword do: must be used for calling a method or a function outside an expression: do reduce(); • The body of a statement must be within curly brackets, even if it contains a single statement: if (a > 0) {return a;} else {return –a;} • All subroutine must end with a return • No operator priority: q The following value is unpredictable: 2 + 3 * 4 q To enforce priority of operations, use parentheses: 2 + (3 * 4) • The language is weakly typed. These concessions make the life of the compiler writer much easier. Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Developing a Jack application Put all the app files in one directory, whose name is the app name Write / edit your Jack class files using a standard text editor Compile your Jack files / directory using the supplied JackCompiler (available in nand2tetris/tools) Execute your app by loading the app directory (which now contains the compiled .vm files) into the supplied VM emulator, and running the code Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Running a Jack application • Compile to VM code. • Run via the VM emulator. Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Handling output: text Textual apps: • Screen: 23 rows of 64 characters, b&w • Font: featured by the Jack OS • Output: Jack OS Output class class Output { function void moveCursor(int i, int j) function void printChar(char c) function void printString(String s) function void printInt(int i) function void println() OS class, for handling textual output function void backSpace() } Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Handling output: graphics Graphical apps: • Screen: 256 rows of 512 pixels, b&w • Output: Jack OS Screen class (or do your own) Class Screen { function void clearScreen() function void setColor(boolean b) function void drawPixel(int x, int y) function void drawLine(int x1, int y1, int x2, int y2) function void drawRectangle(int x1, int y1, int x2, int y2) function void drawCircle(int x, int y, int r) } OS class, for handling graphical output Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Handling inputs Input device: • Standard keyboard • Input programming: • use the OS Keyboard class Class Keyboard { function char keyPressed() function char readChar() function String readLine(String message) function int readInt(String message) } OS class, for handling input from the keyboard Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken The Jack character set key code key code key code key code key code (space) 32 0 48 A 65 a 97 newline 128 ! 33 1 49 B 66 b 98 backspace 129 “ 34 … … C … c 99 left arrow 130 # 35 9 57 … … … … up arrow 131 $ 36 90 z 122 right arrow 132 37 58 Z % : [ 91 { 123 133 38 59 down arrow & ; / 92 | 124 134 39 60 home ‘ < ] 93 } 125 135 40 61 end ( = ^ 94 ~ 126 136 41 62 Page up ) > _ 95 137 42 63 Page down * ? ` 96 138 43 64 insert + @ delete 139 , 44 esc 140 - 45 f1 141 . 46 … … / 47 f12 152 Keyboard.keypress() returns the code of the currently pressed key, or 0 when no key is pressed Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken The Jack OS: Math class Math { function void init() function int abs(int x) function int multiply(int x, int y) function int divide(int x, int y) function int min(int x, int y) function int max(int x, int y) function int sqrt(int x) } Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken The Jack OS: String Class String { constructor String new(int maxLength) method void dispose() method int length() method char charAt(int j) method void setCharAt(int j, char c) 0 termination (C style) or length and capacity? method String appendChar(char c) method void eraseLastChar() method int intValue() method void setInt(int j) function char backSpace() function char doubleQuote() function char newLine() } Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken The Jack OS: Array Class Array { function Array new(int size) method void dispose() } Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken The Jack OS: Memory class Memory { function int peek(int address) function void poke(int address, int value) function Array alloc(int size) function void deAlloc(Array o) } Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Allows examination (and modification) of arbitrary RAM locations, in effect. Consider the effect of poke(0, …). The Jack OS: Sys Class Sys { function void halt(): function void error(int errorCode) function void wait(int duration) } Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Sample Jack programs q Square: a simple, interactive, multi-class OO application q Pong: a complete, interactive, multi-class OO application q Average: illustrates simple array processing q ComplexArrays: illustrates various array manipulations, including two-dimensional arrays q ConvertToBin: illustrates algebraic operations, and working with peek and poke Code: nand2tetris/projects/11 Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken Review • We have started to consider the syntactic structure of the Jack language: q The sequence of symbols in classes and subroutines. • Some ‘semantic’ checks of validity will be required: Check that a called method exists within the associated class. q Check that the number (and types?) of parameters in caller and callee match. q • OS (API) classes provide: q Utility functionality; e.g., Math. q Efficient access to OS features; e.g., Screen, Keyboard. • Some significant issues: Order of evaluation of expressions is undefined. q No array-bound checking. q String capacity is unclear. q Nand to Tetris / www.nand2tetris.org / Chapter 9 / Copyright © Noam Nisan and Shimon Schocken CO557: Parsing I David Barnes Chapter 10 Compiling I These slides support chapter 10 of the book The Elements of Computing Systems By Noam Nisan and Shimon Schocken MIT Press Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken The big picture: compilation high-level program class Main { function void main() { var Point p1, p2, p3; let p1 = Point.new(1,2); let p2 = Point.new(3,4); let p3 = p1.plus(p2); do p3.print(); Compiler // should print (4,6) do Output.println(); do Output.printInt(p1.distance(p3)); // should print 5 return; } } /** Represents a Point. */ class Point { field int x, y; static int pointCount; /** Constructs a new point */ constructor Point new(int ax, int ay) { let x = ax; let y = ay; let pointCount = pointCount + 1; return this; } // ... more Point methods machine code 0000000000010000 1110111111001000 0000000000010001 1110101010001000 0000000000010000 1111110000010000 0000000000000000 1111010011010000 execute 0000000000010010 1110001100000001 0000000000010000 1111110000010000 0000000000010001 0000000000010000 1110111111001000 0000000000010001 1110101010001000 0000000000010000 1111110000010000 0000000000000000 1111010011010000 0000000000010010 1110001100000001 0000000000010000 1111110000010000 0000000000010001 ... (4,6) 5 Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Two-tier compilation high-level program class Main { function void main() { var Point p1, p2, p3; let p1 = Point.new(1,2); let p2 = Point.new(3,4); let p3 = p1.plus(p2); do p3.print(); Compiler // should print (4,6) do Output.println(); do Output.printInt(p1.distance(p3)); // should print 5 return; } } /** Represents a Point. */ class Point { field int x, y; static int pointCount; /** Constructs a new point */ constructor Point new(int ax, int ay) { let x = ax; let y = ay; let pointCount = pointCount + 1; return this; } // ... more Point methods VM code push local 0 push constant 0 eq not push argument 1 neg push local VM1translator call div pop argument 3 push local 1 neg push local 0 push local 1 push local 2 add push constant 2 push local 0 pop argument 1 push local 0 push constant 0 not push local 1 push local 0 push local 1 add ... machine code 0000000000010000 1110111111001000 0000000000010001 1110101010001000 0000000000010000 1111110000010000 0000000000000000 1111010011010000 0000000000010010 1110001100000001 0000000000010000 1111110000010000 0000000000010001 0000000000010000 1110111111001000 0000000000010001 1110101010001000 0000000000010000 1111110000010000 0000000000000000 1111010011010000 0000000000010010 1110001100000001 0000000000010000 1111110000010000 0000000000010001 ... Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Compiler development roadmap Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Compiler development roadmap Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Compiler development roadmap We will skip XML generation. this chapter Syntax analyzer implementation: • Tokenizer • Parser / compilation engine Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Tokenizing (first approximation) tokenized input Prog.jack (input) ... if (x < 0) { // prints the sign let sign = "negative"; } ... stream of characters tokenizing ... if ( x < 0 { let sign = "negative" ; } ... compiler stream of tokens Tokenizing = grouping characters into tokens A token is a string of characters that has a meaning A programming language specification must document (among other things) its allowable tokens. Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Jack tokens Prog.jack (input) ... if (x < 0) { // prints the sign let sign = "negative"; } ... • keywords • symbols • integers • strings • identifiers Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Jack tokens Prog.jack (input) ... if (x < 0) { // prints the sign let sign = "negative"; } ... keyword: 'class' | 'constructor' | 'function' | 'method' | 'field' | 'static' | 'var' | 'int' | 'char' | 'boolean' | 'void' | 'true' | 'false' | 'null' | 'this' | 'let' | 'do' | 'if' | 'else' | 'while' | 'return’ symbol: '{' | '}' | '(' | ')' | '[' | ']' | '. ' | ', ' | '; ' | '+' | '-' | '*' | '/' | '&' | '|' | '<' | '>' | '=' | '~' integerConstant: a decimal number in the range 0 ... 32767 StringConstant: '"' a sequence of Unicode characters, not including double quote or newline '"' identifier: a sequence of letters, digits, and underscore ( '_' ) not starting with a digit. Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Jack tokenizer output Prog.jack ... ... if (x < 0) { // prints the sign let sign = "negative"; } ... Tokenizer keyword: 'class' | 'constructor' | 'function' | 'method' | 'field' | 'static' | 'var' | 'int' | 'char' | 'boolean' | 'void' | 'true' | 'false' | 'null' | 'this' | 'let' | 'do' | 'if' | 'else' | 'while' | 'return’ symbol: '{' | '}' | '(' | ')' | '[' | ']' | '. ' | ', ' | '; ' | '+' | '-' | '*' | '/' | '&' | '|' | '<' | '>' | '=' | '~' integerConstant: a decimal number in the range 0 ... 32767 StringConstant: '"' a sequence of Unicode characters, not including double quote or newline '"' identifier: a sequence of letters, digits, and underscore ( '_' ) not starting with a digit. Tokenizer: • Handles the compiler’s input • Allows advancing the input • Supplies the current token’s value and type • (complete API, later) Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Jack tokenizer output Prog.jack ... if (x < 0) { // prints the sign let sign = "negative"; } ... Tokenizer keyword: 'class' | 'constructor' | 'function' | 'method' | 'field' | 'static' | 'var' | 'int' | 'char' | 'boolean' | 'void' | 'true' | 'false' | 'null' | 'this' | 'let' | 'do' | 'if' | 'else' | 'while' | 'return’ symbol: '{' | '}' | '(' | ')' | '[' | ']' | '. ' | ', ' | '; ' | '+' | '-' | '*' | '/' | '&' | '|' | '<' | '>' | '=' | '~' integerConstant: a decimal number in the range 0 ... 32767 StringConstant: '"' a sequence of Unicode characters, not including double quote or newline '"' identifier: a sequence of letters, digits, and underscore ( '_' ) not starting with a digit. ... <keyword> if </keyword> <symbol> ( </symbol> <identifier> x </identifier> <symbol> < </symbol> <intConst> 0 </intCons> <symbol> ) </symbol> <symbol> { </symbol> <keyword> let </keyword> <identifier> sign </identifier> <symbol> = </symbol> <stringConst> negative </stringConst> <symbol> ; </symbol> <symbol> } </symbol> ... Tokenizer: • Handles the compiler’s input • Allows advancing the input • Supplies the current token’s value and type • (complete API, later) Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Basic lexical process for Jack char c = skipBlanksAndComments(); if(Character.isAlphabetic(c) || c == ‘_’) { gather consecutive alphabetic, digits and underscores into a token String; if(token matches one of the keywords) { classify as KEYWORD; } else { classify as IDENTIFIER; } } else if(Character.isDigit(c)) { gather consecutive digits into a token String; classify as INTEGER; } else if(c == ‘”’) {classify as STRING; } else if(…) { … } else { deal with a single character symbol; } Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Compiler development roadmap Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Compiler development roadmap Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Grammar A grammar is a set of rules, describing how tokens can be combined to create valid language constructs sentence: nounPhrase verbPhrase Alternative notation: BNF, Backus-Naur Form sentence ::= nounPhrase verbPhrase ; I tend to use something close to BNF in assessments and exam questions. Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Grammar A grammar is a set of rules, describing how tokens can be combined to create valid language constructs sentence: Each rule has a Alternative left side and a notation: right side nounPhrase verbPhrase nounPhrase: determiner? noun verbPhrase: verb nounPhrase nounPhrase ::= [ determiner ] noun ; noun: 'dog' | ’school' | 'dina' | ’he' | ’she' | 'homework’ | ... verb: 'went' | 'ate' | ’said' | ... determiner: 'the' | 'to' | 'my’ | ... ... Items between quote marks are ‘terminal symbols’. Dina went to school She said The dog ate my homework Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken The set of rules can be used in two distinct ways: • As a generator. • As a checker. Grammar Jack grammar (subset) Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Grammar Jack grammar (subset) statement: ifStatement | whileStatement | letStatement Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Grammar Jack grammar (subset) Input examples statement: ifStatement | whileStatement | letStatement statements: statement* Alternative notation: ifStatement: 'if' '(' expression ')’ '{' statements '}’ statements ::= { statement } ; whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beginning with a digit constant: a decimal number Expressions 17 x x + 17 x - y op: '+' | '-' | '=' | '>' | '<' Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Grammar Jack grammar (subset) statement: ifStatement | whileStatement | letStatement Input examples let x = 100; statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beginning with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Grammar Jack grammar (subset) statement: ifStatement | whileStatement | letStatement Input examples let x = 100; statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ let x = x + 1; whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beginning with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Grammar Jack grammar (subset) statement: ifStatement | whileStatement | letStatement Input examples let x = 100; statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' let x = x + 1; while (n < lim) let n = n + 1; } expression: term (op term)? term: varName | constant varName: a string not beginning with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Grammar Jack grammar (subset) statement: ifStatement | whileStatement | letStatement Input examples let x = 100; statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' let x = x + 1; while (n < lim) let n = n + 1; } expression: term (op term)? term: varName | constant varName: a string not beginning with a digit constant: a decimal number if (x = 1) { let x = 100; let x = x + 1; } op: '+' | '-' | '=' | '>' | '<' Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Grammar Jack grammar (subset) statement: ifStatement | whileStatement | letStatement statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term) * term: varName | constant varName: a string not beginning with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' Input examples while (lim < 100) { if (x = 1) { let z = 100; while (z > 0) { let z = z – 1; } } let lim = lim + 10; } Parsing: Determining if a given input conforms to a grammar In the process, uncovering the grammatical structure of the given input. Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken NB: Evidence of recursion in the definition: a whileStatement can contain a whileStatement … Parse tree sentence: nounPhrase verbPhrase nounPhrase: determiner ? noun verbPhrase: verb nounPhrase noun: 'dog' | ’school' | 'dina' | ’he' | ’she' | 'homework’ | ... verb: 'went' | 'ate' | ’said' | ... determiner: 'the' | 'to' | 'my’ | ... ... Parsing • Determine if the given input conforms to the grammar • In the process, construct the grammatical structure of the input input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parse tree sentence: nounPhrase verbPhrase NB: The parse tree can either be built ‘bottom up’ or ‘top down’. nounPhrase: determiner ? noun verbPhrase: verb nounPhrase noun: 'dog' | ’school' | 'dina' | ’he' | ’she' | 'homework’ | ... verb: 'went' | 'ate' | ’said' | ... determiner: 'the' | 'to' | 'my’ | ... ... Parsing • Determine if the given input conforms to the grammar • In the process, construct the grammatical structure of the input input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parse tree statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parse tree statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ If the parse tree shows valid input, the code generator ‘walks’ the tree to generate equivalent VM code. whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Because the grammar is a recursive definition (cf statement), both the parser and code generator will involve recursive routines (methods). Review • We have looked at the basic structure of a compiler: q q Lexical analysis: the identification of tokens. Syntax analysis (parsing): the identification of a program’s structure. q The creation of a ‘parse tree’. q Generation of code from the tree. • The parsing process is driven by the grammar of the language. • Correctness checking normally also involves some semantic checking. q Checking that variables are declared. q Checking type compatibility in assignments. q These are largely ignored in the Jack compiler. Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken CO557: Parsing II David Barnes Chapter 10 Compiling I These slides support chapter 10 of the book The Elements of Computing Systems By Noam Nisan and Shimon Schocken MIT Press Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parser design (sneak preview) statement: ifStatement | whileStatement | letStatement grammar statements: statement* Parser class CompilationEngine { compileStatements() { // code for compiling statements } ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ compileIfStatement() { // code for compiling an if statement } letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit compileWhileStatement() { // code for compiling an while statement } constant: a decimal number op: '+' | '-' | '=' | '>' | '<' ... The parser consists of a set of compilexxx methods; compileTerm() { // code for compiling a term } } each compilexxx method implements the right hand side of the grammar rule describing xxx Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Actually, better to keep the parsing concept separate from the code generation, for the sake of generality. So, I prefer, e.g., parseWhileStatement in the Parser. Parser design (sneak preview) statement: ifStatement | whileStatement | letStatement grammar statements: statement* Parser class CompilationEngine { compileStatements() { // code for compiling statements } ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ compileIfStatement() { // code for compiling an if statement } letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit compileWhileStatement() { // code for compiling an while statement } constant: a decimal number op: '+' | '-' | '=' | '>' | '<' ... The parser consists of a set of compilexxx methods; compileTerm() { // code for compiling a term } } each compilexxx method implements the right hand side of the grammar rule describing xxx Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Actually, better to keep the parsing concept separate from the code generation, for the sake of generality. So, I prefer, e.g., parseWhileStatement in the Parser. Parsing process statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant Parsing process • Follow the right-hand side of the rule, and parse the input accordingly • If the right-hand side specifies a non-terminal rule xxx, call compilexxx • Do this recursively. varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant Parsing process • Follow the right-hand side of the rule, and parse the input accordingly • If the right-hand side specifies a non-terminal rule xxx, call compilexxx • Do this recursively. varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' Example: input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant Parsing process • Follow the right-hand side of the rule, and parse the input accordingly • If the right-hand side specifies a non-terminal rule xxx, call compilexxx • Do this recursively. varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' Example: Let us assume that we read while, so we know that we have to call the method compileWhileStatement input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar parser output statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar <whileStatement> parser output statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar <whileStatement> <keyword> while </keyword> parser output statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar <whileStatement> <keyword> while </keyword> parser output statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar <whileStatement> <keyword> while </keyword> <symbol> ( </symbol> parser output statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar <whileStatement> <keyword> while </keyword> <symbol> ( </symbol> parser output statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* <whileStatement> <keyword> while </keyword> <symbol> ( </symbol> <expression> parser output compileExpression ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ <whileStatement> <keyword> while </keyword> <symbol> ( </symbol> <expression> <term> parser output compileExpression compileTerm whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> <intConstant> 100 </intConstant> expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> <intConstant> 100 </intConstant> expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> <intConstant> 100 </intConstant> </term> term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> <intConstant> 100 </intConstant> </term> term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> <intConstant> 100 </intConstant> </term> </expression> varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> <intConstant> 100 </intConstant> </term> </expression> varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> <intConstant> 100 </intConstant> </term> </expression> <symbol> ) </symbol> constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> <intConstant> 100 </intConstant> </term> </expression> <symbol> ) </symbol> constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> <intConstant> 100 </intConstant> </term> </expression> <symbol> ) </symbol> <symbol> { </symbol> op: '+' | '-' | '=' | '>' | '<' input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> <intConstant> 100 </intConstant> </term> </expression> <symbol> ) </symbol> <symbol> { </symbol> op: '+' | '-' | '=' | '>' | '<' input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> <intConstant> 100 </intConstant> </term> </expression> <symbol> ) </symbol> <symbol> { </symbol> compileStatements <statements> op: '+' | '-' | '=' | '>' | '<' input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> <intConstant> 100 </intConstant> </term> </expression> <symbol> ) </symbol> <symbol> { </symbol> compileStatements <statements> compileLetStatement <letStatement> input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> <intConstant> 100 </intConstant> </term> </expression> <symbol> ) </symbol> <symbol> { </symbol> compileStatements <statements> compileLetStatement <letStatement> <keyword> let </keyword> input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> <intConstant> 100 </intConstant> </term> </expression> <symbol> ) </symbol> <symbol> { </symbol> compileStatements <statements> compileLetStatement <letStatement> <keyword> let </keyword> input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> <intConstant> 100 </intConstant> </term> </expression> <symbol> ) </symbol> <symbol> { </symbol> compileStatements <statements> compileLetStatement <letStatement> <keyword> let </keyword> <identifier> count </identifier> input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> <intConstant> 100 </intConstant> </term> </expression> <symbol> ) </symbol> <symbol> { </symbol> compileStatements <statements> compileLetStatement <letStatement> <keyword> let </keyword> <identifier> count </identifier> input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> <intConstant> 100 </intConstant> </term> </expression> <symbol> ) </symbol> <symbol> { </symbol> compileStatements <statements> compileLetStatement <letStatement> <keyword> let </keyword> <identifier> count </identifier> <symbol> = </symbol> input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> <intConstant> 100 </intConstant> </term> </expression> <symbol> ) </symbol> <symbol> { </symbol> compileStatements <statements> compileLetStatement <letStatement> <keyword> let </keyword> <identifier> count </identifier> <symbol> = </symbol> input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> <intConstant> 100 </intConstant> </term> </expression> <symbol> ) </symbol> <symbol> { </symbol> compileStatements <statements> compileLetStatement <letStatement> <keyword> let </keyword> <identifier> count </identifier> compileExpression <symbol> = </symbol> input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> <intConstant> 100 </intConstant> </term> </expression> <symbol> ) </symbol> <symbol> { </symbol> compileStatements <statements> compileLetStatement <letStatement> <keyword> let </keyword> <identifier> count </identifier> compileExpression <symbol> = </symbol> <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> + </symbol> compileTerm <term> <intConstant> 1 </intConstant> </term> </expression> input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> <intConstant> 100 </intConstant> </term> </expression> <symbol> ) </symbol> <symbol> { </symbol> compileStatements <statements> compileLetStatement <letStatement> <keyword> let </keyword> <identifier> count </identifier> compileExpression <symbol> = </symbol> <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> + </symbol> compileTerm <term> <intConstant> 1 </intConstant> </term> </expression> input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> <intConstant> 100 </intConstant> </term> </expression> <symbol> ) </symbol> <symbol> { </symbol> compileStatements <statements> compileLetStatement <letStatement> <keyword> let </keyword> <identifier> count </identifier> compileExpression <symbol> = </symbol> <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> + </symbol> compileTerm <term> <intConstant> 1 </intConstant> </term> </expression> <symbol> ; </symbol> input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> <intConstant> 100 </intConstant> </term> </expression> <symbol> ) </symbol> <symbol> { </symbol> compileStatements <statements> compileLetStatement <letStatement> <keyword> let </keyword> <identifier> count </identifier> compileExpression <symbol> = </symbol> <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> + </symbol> compileTerm <term> <intConstant> 1 </intConstant> </term> </expression> <symbol> ; </symbol> input Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> <intConstant> 100 </intConstant> </term> </expression> <symbol> ) </symbol> <symbol> { </symbol> compileStatements <statements> compileLetStatement <letStatement> <keyword> let </keyword> <identifier> count </identifier> compileExpression <symbol> = </symbol> <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> + </symbol> compileTerm <term> <intConstant> 1 </intConstant> </term> </expression> <symbol> ; </symbol> </letStatement> Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> <intConstant> 100 </intConstant> </term> </expression> <symbol> ) </symbol> <symbol> { </symbol> compileStatements <statements> compileLetStatement <letStatement> <keyword> let </keyword> <identifier> count </identifier> compileExpression <symbol> = </symbol> <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> + </symbol> compileTerm <term> <intConstant> 1 </intConstant> </term> </expression> <symbol> ; </symbol> </letStatement> Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> <intConstant> 100 </intConstant> </term> </expression> <symbol> ) </symbol> <symbol> { </symbol> compileStatements <statements> compileLetStatement <letStatement> <keyword> let </keyword> <identifier> count </identifier> compileExpression <symbol> = </symbol> <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> + </symbol> compileTerm <term> <intConstant> 1 </intConstant> </term> </expression> <symbol> ; </symbol> </letStatement> </statements> Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> <intConstant> 100 </intConstant> </term> </expression> <symbol> ) </symbol> <symbol> { </symbol> compileStatements <statements> compileLetStatement <letStatement> <keyword> let </keyword> <identifier> count </identifier> compileExpression <symbol> = </symbol> <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> + </symbol> compileTerm <term> <intConstant> 1 </intConstant> </term> </expression> <symbol> ; </symbol> </letStatement> </statements> Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> <intConstant> 100 </intConstant> </term> </expression> <symbol> ) </symbol> <symbol> { </symbol> compileStatements <statements> compileLetStatement <letStatement> <keyword> let </keyword> <identifier> count </identifier> compileExpression <symbol> = </symbol> <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> + </symbol> compileTerm <term> <intConstant> 1 </intConstant> </term> </expression> <symbol> ; </symbol> </letStatement> </statements> <symbol> } </symbol> Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process compileWhileStatement statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input <whileStatement> parser output <keyword> while </keyword> <symbol> ( </symbol> compileExpression <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> < </symbol> compileTerm <term> <intConstant> 100 </intConstant> </term> </expression> <symbol> ) </symbol> <symbol> { </symbol> compileStatements <statements> compileLetStatement <letStatement> <keyword> let </keyword> <identifier> count </identifier> compileExpression <symbol> = </symbol> <expression> compileTerm <term> <identifier> count </identifier> </term> <symbol> + </symbol> compileTerm <term> <intConstant> 1 </intConstant> </term> </expression> <symbol> ; </symbol> </letStatement> </statements> <symbol> } </symbol> </whileStatement> Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parsing process statement: ifStatement | whileStatement | letStatement grammar statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' input <whileStatement> <keyword> while </keyword> <symbol> ( </symbol> <expression> <term> <identifier> count </identifier> </term> <symbol> < </symbol> <term> <intConstant> 100 </intConstant> </term> </expression> <symbol> ) </symbol> <symbol> { </symbol> <statements> <letStatement> <keyword> let </keyword> <identifier> count </identifier> <symbol> = </symbol> parser output <expression> <term> <identifier> count </identifier> </term> <symbol> + </symbol> <term> <intConstant> 1 </intConstant> </term> </expression> <symbol> ; </symbol> </letStatement> </statements> <symbol> } </symbol> </whileStatement> Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parser design Grammar Parser statement: ifStatement | whileStatement | letStatement class CompilationEngine { compileStatements() { // code for compiling statements } statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ compileIfStatement() { // code for compiling an if statement } whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? varName: a string not beg. with a digit compileWhileStatement() { // code for compiling an while statement } constant: a decimal number ... term: varName | constant op: '+' | '-' | '=' | '>' | '<' Parser’s design: compileTerm() { // code for compiling a term } } • A set of compilexxx methods; • each compilexxx method implements the right hand side of the grammar rule describing xxx Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Parser design Grammar Parsing process statement: ifStatement | whileStatement | letStatement statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant class CompilationEngine { ... compileWhileStatement() { eat('while’); code to handle 'while' ; eat('('); code to handle '(' ; compileExpression(); eat(')'); code to handle ')'; ... varName: a string not beg. with a digit constant: a decimal number eat(string) { op: '+' | '-' | '=' | '>' | '<' if (currentToken <> string) error... else advance... } • The code of each compilexxx method follows the right-hand side of the rule xxx • Each compilexxx method is responsible for advancing and handling its own part of the input. Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken LL grammar Grammar statement: ifStatement | whileStatement | letStatement statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' • LL grammar: can be parsed by a recursive descent parser without backtracking • LL(k) parser: a parser that needs to look ahead at most k tokens in order to determine which rule is applicable • The grammar that we saw so far is LL(1). Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Essentially, no left-recursive rules, such as: expr ::= expr op term ; Grammar notation statement: ifStatement | whileStatement | letStatement statements: statement* ifStatement: 'if' '(' expression ')’ '{' statements '}’ whileStatement: 'while' '(' expression ')’ '{' statements '}’ letStatement: 'let' varName '=' expression ';' expression: term (op term)? term: varName | constant varName: a string not beg. with a digit constant: a decimal number op: '+' | '-' | '=' | '>' | '<' Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken I sometimes use { } for 0-or-more grouping of multiple T/NT symbols. Writing parseX/compileX routines: Assessement hints! • Driven by the nature of the rhs of a grammar rule. X: terminal NB: Failing to match does not mean there is an error. There might be an alternative to consider at a higher-level non terminal. boolean parseX() { if(currentToken matches terminal) { get next token; return true; } else { return false; } } Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Writing parseX/compileX routines • Driven by the nature of the rhs of a grammar rule. X: terminal1 | terminal2 boolean parseX() { if(currentToken matches terminal1) { get next token; return true; } else if(currentToken matches terminal2) { get next token; return true; } else { return false; } } Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Writing parseX/compileX routines • Driven by the nature of the rhs of a grammar rule. X: nt1 | nt2 boolean parseX() { if(parseNT1()) { return true; } else if(parseNT2()) { return true; } else { return false; } } Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Writing parseX/compileX routines • Driven by the nature of the rhs of a grammar rule. X: nt1 ( terminal nt2 )? boolean parseX() { if(parseNT1()) { if(currentToken matches terminal) { get next token; if(!parseNT2()) { error – missing nt; } } return true; } else { return false; } } Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Writing parseX/compileX routines • Driven by the nature of the rhs of a grammar rule. X: nt1 ( terminal nt2 )* boolean parseX() { if(parseNT1()) { while(currentToken matches terminal) { get next token; if(!parseNT2()) { error – missing nt; } } return true; } else { return false; } } Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Jack grammar Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Jack grammar: program structure A Jack program is a collection of classes, each appearing in a separate file, and each compiled separately. Each class is structured as follows: Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Jack grammar: program structure A Jack program is a collection of classes, each appearing in a separate file, and each compiled separately. Each class is structured as follows: Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Jack grammar: program structure A Jack program is a collection of classes, each appearing in a separate file, and each compiled separately. Each class is structured as follows: Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Jack grammar: program structure A Jack program is a collection of classes, each appearing in a separate file, and each compiled separately. Each class is structured as follows: Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Jack grammar: program structure A Jack program is a collection of classes, each appearing in a separate file, and each compiled separately. Each class is structured as follows: Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Jack grammar: statements A Jack program includes statements, as follows: Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Jack grammar: statements A Jack program includes statements, as follows: Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Jack grammar: expressions A Jack program includes expressions, as follows: Alternative: expression: term (op expression)? NB: the grammar does not capture normally expected operator precedences. Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Jack grammar: expressions A Jack program includes expressions, as follows: Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken End note: parsing Parser’s design • A set of parsexxx or compilexxx methods, structured according to the grammar rules defining xxx • Each method outputs some of the parse tree (XML), and advances the input • The parsing logic of each method follows the right-hand side of the rule that it implements. Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken End note: parsing expressions Parser’s design • A set of compilexxx methods, structured according to the grammar rules defining xxx • Each method outputs some of the parse tree (XML), and advances the input • The parsing logic of each method follows the right-hand side of the rule that it implements. Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken End note: parsing expressions When the current token is a varName (some identifier), it can be the first token in any one of these possibilities: To resolve which possibility we are in, the parser should “look ahead”: q save the current token, and q advance to get the next one. foo foo[expression] foo.bar(expressionList) Foo.bar(expressionList) This is the only case in the Jack grammar in which the language becomes LL(2) rather than LL(1). bar(expressionList) Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken Review • We have looked at some of the practicalities of the parsing process. q A parsing routing for each non-terminal symbol. q Use of ‘lookahead’ to determine the next applicable rule. • We have looked at the notation used to define grammars. • We have looked at how to use the notation within a rule to structure the code to parse it. Nand to Tetris / www.nand2tetris.org / Chapter 10 / Copyright © Noam Nisan and Shimon Schocken CO557: Code generation I David Barnes Chapter 11 Compiling II These slides support chapter 11 of the book The Elements of Computing Systems By Noam Nisan and Shimon Schocken MIT Press Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Compiler development roadmap Objective: developing a full-scale compiler Methodology: • Adding code generation capabilities. Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Program compilation class Point { field int x, y; static int pointCount; class declaration constructor Point new(int ax, int ay) {} method int getx() {} method int gety() {} function int getPointCount() {} subroutines: method Point plus(Point other) {} q method int distance(Point other) { var int dx, dy; let dx = x - other.getx(); let dy = y - other.gety(); return Math.sqrt((dx*dx)+ (dy*dy)); q q constructors methods functions } method void print() {} } Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Program compilation class Point { field int x, y; static int pointCount; constructor Point new(int ax, int ay) {} method int getx() {} method int gety() {} function int getPointCount() {} Compilation • class-level code • subroutine-level code q constructors q methods q functions method Point plus(Point other) {} method int distance(Point other) { var int dx, dy; let dx = x - other.getx(); let dy = y - other.gety(); return Math.sqrt((dx*dx)+ (dy*dy)); } method void print() {} } Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Compilation challenges • Handling variables • Handling expressions • Handling flow of control • Handling objects • Handling arrays The challenge: expressing the above semantics in the VM language. Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Variables High-level (Jack) code class Foo { VM code (pseudo) ... field int a, b, c; static int x, y; ... ... push a2 method int bar(int a1; int a2) { // let c = a2 + (x – v3) compiler var int v1, v2, v3; ... let c = a2 + (x – v3); ... } ... push x push v3 sub VM code add ... pop c ... push argument 1 push static 0 push local 2 } sub In order to generate VM code, the compiler must know: • Whether each variable is a field, static, local, or argument add pop this 2 ... • Whether each variable is the first, second, third... variable of its kind Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Variables High-level (Jack) code class Point { field int x, y; static int pointCount; Variable properties: q name (identifier) q type (int, char, boolean, class name) q kind (field, static, local, argument) q index (0, 1, 2, ...) q scope (class level, subroutine level) ... method int distance(Point other) { var int dx, dy; let dx = x - other.getx(); let dy = y - other.gety(); return Math.sqrt((dx*dx)+ (dy*dy)); } ... } Variable properties: • Needed for code generation • Can be recorded and managed using a symbol table Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Jack does not need scope to be represented separately. Symbol tables: construction High-level (Jack) code class-level symbol table class Point { field int x, y; static int pointCount; (field, static) ... method int distance(Point other) { var int dx, dy; let dx = x - other.getx(); let dy = y - other.gety(); return Math.sqrt((dx*dx)+ (dy*dy)); } ... } (4,6) 5 Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Symbol tables: construction High-level (Jack) code class-level symbol table class Point { field int x, y; static int pointCount; (field, static) ... method int distance(Point other) { var int dx, dy; let dx = x - other.getx(); let dy = y - other.gety(); return Math.sqrt((dx*dx)+ (dy*dy)); subroutine-level symbol table (argument, local) } ... } In methods only (not in constructors and functions): (4,6) • in addition to the explicit arguments, there is always an 5 implicit argument: • argument 0 is always named this, and its type is always set to the class name Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Symbol tables: construction High-level (Jack) code class Point { field int x, y; static int pointCount; ... method int distance(Point other) { var int dx, dy; let dx = x - other.getx(); let dy = y - other.gety(); return Math.sqrt((dx*dx)+ (dy*dy)); } ... } Handling variable declarations: • (4,6) 5 , static, argument, local), Each time the compiler detects a variable declaration (field it adds an entry to the symbol table • The entry records the variable’s properties. Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Symbol tables: usage High-level (Jack) code class Point { field int x, y; static int pointCount; ... method int distance(Point other) { var int dx, dy; let dx = x - other.getx(); let dy = y - other.gety(); return Math.sqrt((dx*dx)+ (dy*dy)); } ... } (4,6) Handling variables that appear in statements and expressions: 5 • Each time the compiler detects a variable in some statement or expression, it first looks up the variable in the subroutine-level symbol table • If not found there, it looks it up in the class-level symbol table. Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Symbol tables: usage High-level (Jack) code class Point { field int x, y; static int pointCount; ... method int distance(Point other) { var int dx, dy; let dx = x - other.getx(); let dy = y - other.gety(); return Math.sqrt((dx*dx)+ (dy*dy)); } ... look-up } VM code source code example: ... let y = y + dy; ... compiler push this 1 // y push local 1 // dy add pop this 1 // y Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken NB: The right-hand side is translated first, then the result stored into the variable on the left-hand side. Handling variables’ life cycles Static variables: Seen by all the class subroutines; must exist throughout the program’s execution High-level (Jack) code class Point { field int x, y; static int pointCount; Field variables: Each instance will have its own set. ... method int distance(Point other) { var int dx, dy; let dx = x - other.getx(); let dy = y - other.gety(); return Math.sqrt((dx*dx)+ (dy*dy)); Local variables: During run-time, each time a subroutine is invoked, it must get a fresh set of local variables; each time a subroutine returns, its local variables must be recycled } ... } Argument variables: Same as local variables Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken End note: handling nested scoping class foo { // class level variable declarations method bar () { // method level variable declarations ... { // scope 1 level variable declarations ... { // scope 2 level variable declarations ... } • Some high-level languages (not Jack) feature unlimited nested variable scoping } } } Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken End note: handling nested scoping class foo { // class level variable declarations method bar () { // method level variable declarations • Some high-level languages (not Jack) feature unlimited nested variable scoping ... { // scope 1 level variable declarations ... { // scope 2 level variable declarations ... } • Can be handled using a linked list of symbol tables } } } symbol tables ... scope 2 level scope 1 level method level class level symbol table symbol table symbol table symbol table Variable lookup: start in the first table in the list: if not found, look up the next table, and so on. Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Compilation challenges • Handling variables • Handling expressions • Handling flow of control • Handling objects • Handling arrays Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Parse tree prefix infix postfix * a + b c a * (b + c) a b c + * functional human oriented stack oriented *(a,+(b,c)) Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Generating code for expressions: a two-stage approach stack-machine code source code x + g(2,y,-z) - 5 parse tree code generation push x push 2 push y push z (infix) call g + push 5 - (postfix) When executed, the generated code ends up leaving the value of the expression at the top of the stack. Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Walk the tree from root to leaves, generating code from the leaves to the root. Generating code for expressions: a one-stage approach codeWrite(exp): source code x + g(2,y,-z) * 5 Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Generating code for expressions: a one-pass approach codeWrite(exp): source code x + g(2,y,-z) * 5 NB: Typo * instead of - stack-machine code if exp is a number n: output “push n” if exp is a variable var: output “push var” resulting code push x push 2 push y if exp is “exp1 op exp2”: codeWrite(exp1), remember op, codeWrite(exp2), output “op” push z if exp is “op exp”: remember op, codeWrite(exp), output “op” push 5 if exp is “f (exp1, exp2, ...)”: remember f, codeWrite(exp1), codeWrite(exp2), ..., output “call f ” call g + * When executed, the generated code ends up leaving the value of the expression at the top of the stack. Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Generating code for expressions: a two-pass approach source code x + g(2,y,-z) - 5 parse tree Walk the tree from root to leaves, generating code from the leaves to the root. (infix) Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Generating code for expressions: walking a parse tree stack-machine code walk(node): source code x + g(2,y,-z) * 5 NB: Typo * instead of - if node is leaf num: output “push num” parse tree if node is leaf var: output “push var” if node is “lhs op rhs”: walk(lhs), walk(rhs), output “op” if node is “op operand”: walk(operand), output “op” if node is “f (n1, n2, ...)”: walk(n1), walk(n2), ..., output “call f ” Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken resulting code push x push 2 push y push z call g + push 5 * End note: operator priority/precedence • The Jack language definition specifies no operator priority; • To simplify the compiler writing, we assume left-to-right priority: push a let x = a + b * c; compiler push b + push c * pop x The Jack language definition specifies that expressions in parentheses are evaluated first: push a let x = a + (b * c); compiler push b push c * + pop x This is a really bad idea! General comment: The Jack language designers decided to leave the question of how to handle operator order priority up to the compiler’s implementation. Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Compilation challenges • Handling variables • Handling expressions • Handling flow of control • Handling objects • Handling arrays Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken The challenge high-level code let low = 0; let high = x; while ((high – low) > epsilon) { let mid = (high + low) / 2; if ((mid * mid) > x) { high = mid; } else { let low = mid; } } return low; VM code, using: translate to: • goto • if-goto • label Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Compiling if statements VM code source code compiled (expression) if (expression) statements1 else statements2 ... not compiler if-goto L1 compiled (statements1) goto L2 label L1 compiled (statements2) label L2 ... the labels are generated by the compiler Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken NB: In the translation, the condition is inverted to avoid jumping over a jump if the condition is true. Compiling while statements VM code source code while (expression) statements ... compiler label L1 compiled (expression) not if-goto L2 compiled (statements) goto L1 label L2 ... Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Review high-level code let low = 0; let high = x; while ((high – low) > epsilon) { let mid = (high + low) / 2; if ((mid * mid) > x) { high = mid; } else { let low = mid; } } return low; Our compiler (front-end) knows how to handle • Variables • Expressions • Flow of control Our compiler (back-end) knows how to handle • Functions • Function call-and-return • Memory allocation Conclusion: We can write a compiler for a simple procedural language! Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Objects and arrays remain to be dealt with. CO557: Code generation II David Barnes Chapter 11 Compiling II These slides support chapter 11 of the book The Elements of Computing Systems By Noam Nisan and Shimon Schocken MIT Press Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Compilation challenges • Handling variables • Handling expressions • Handling flow of control • Handling objects • Handling arrays Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Handling variables: the big picture /** Represents a Point. */ class Point { field int x, y; static int pointCount; /** Constructs a new point */ constructor Point new(int ax, int ay) { let x = ax; let y = ay; let pointCount = pointCount + 1; return this; } // ... more Point methods high-level view VM translator compiler low-level view intermediate-level view • High-level OO programs operate on high-level, symbolic variables • Mid-level VM programs operate on virtual memory segments • Low-level machine programs operate directly on the RAM High-level The compilation challenge: bridging the gaps. view Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Handling local and argument variables (review) Compilation challenge: • How to represent local and argument variables using the host RAM • How to initialize and recycle local and argument variables when methods start / return Solution • The compiler maps the high-level local and argument variables on local 0, 1, ... and on argument 0, 1, ... local and argument segments • The compiler translates high-level operations on local and argument variables into VM segment-based operations on local 0,1,... and on argument 0,1,... • During run-time, the VM implementation initializes and recycles the local and argument segments, as needed, using the global stack. Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Handling field variables (object data) class Point { field int x, y; static int pointCount; ... method int distance(Point other) { var int dx, dy; let dx = x - other.getx(); let dy = y - other.gety(); return Math.sqrt((dx*dx)+ (dy*dy)); } ... local and argument variables } • There may be many objects (class instances) of type Point • Each storing by its own set of x,y values (fields). • As long as the program is running, all these objects must be managed. Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Handling field variables (object data) Abstraction: • Each object is represented by a bundle of field variable values (each object has a private copy of these values) • When I call a method, say bar.foo(), I want foo to operate on a specific object, in this case bar local and argument variables Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Handling field variables (object data) Abstraction: • Each object is represented by a bundle of field variable values (each object has a private copy of these values) • When I call a method, say bar.foo(), I want foo to operate on a specific object, in this case bar Implementation • Each object is managed as a separate memory block, stored in a RAM area named heap local and argument variables • The current object is represented by the segment this • Basic compilation strategy for accessing object data: q q when we want to operate on a particular object, we set THIS to its base address The memory blocks that represent objects are managed in the heap High-level code that uses field i of the current object can be translated into VM code that operates on this i. Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Accessing the RAM using this Suppose we wish to access RAM words 8000, 8001, 8002... 8000 Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Accessing the RAM using this Suppose we wish to access RAM words 8000, 8001, 8002... VM code (commands) Resulting effect push 8000 pop pointer 0 sets THIS to 8000 8000 Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Accessing the RAM using this Suppose we wish to access RAM words 8000, 8001, 8002... VM code (commands) Resulting effect 8000 push 8000 pop pointer 0 sets THIS to 8000 push/pop this 0 accesses RAM[8000] push/pop this 1 accesses RAM[8001] ... ... push/pop this i accesses RAM[8000+i] 8000 Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Accessing the RAM using this Suppose we wish to access RAM words 8000, 8001, 8002... VM code (commands) Resulting effect 8000 push 8000 pop pointer 0 sets THIS to 8000 push/pop this 0 accesses RAM[8000] push/pop this 1 accesses RAM[8001] ... ... push/pop this i accesses RAM[8000+i] example: // Sets the second element // of the memory block // beginning at 8000 to 17: 8000 Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Accessing the RAM using this Suppose we wish to access RAM words 8000, 8001, 8002... VM code (commands) Resulting effect 8000 push 8000 pop pointer 0 sets THIS to 8000 push/pop this 0 accesses RAM[8000] push/pop this 1 accesses RAM[8001] ... ... push/pop this i accesses RAM[8000+i] example: // Sets the second element // of the memory block // beginning at 8000 to 17: 8000 push 8000 pop pointer 0 Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Accessing the RAM using this Suppose we wish to access RAM words 8000, 8001, 8002... VM code (commands) Resulting effect 8000 push 8000 pop pointer 0 sets THIS to 8000 push/pop this 0 accesses RAM[8000] push/pop this 1 accesses RAM[8001] ... ... push/pop this i accesses RAM[8000+i] Example: basic technique for accessing object data // Sets the second element // of the memory block // beginning at 8000 to 17: 8000 17 17 push 8000 pop pointer 0 push 17 pop this 1 Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Compilation challenges • Handling variables • Handling expressions • Handling flow of control • Handling objects q Construction • Compiling “new” • Compiling constructors q Manipulation • Handling arrays Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Object construction: the big picture some class ... var Point p1; ... callee let p1 = Point.new(2,3); Point class ... class Point { caller ... constructor Point new(...) ... } Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Object construction: the caller’s side source code ... var Point p1, p2; var int d; 0 p1 0 p2 0 d Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Object construction: the caller’s side source code ... var Point p1, p2; var int d; ... let p1 = Point.new(2,3); ... 0 p1 0 p2 0 d Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Object construction: the caller’s side source code ... var Point p1, p2; var int d; ... let p1 = Point.new(2,3); ... p1 0 p2 0 d Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Object construction: the caller’s side source code compiled VM (pseudo) code ... var Point p1, p2; var int d; ... let p1 = Point.new(2,3); let p2 = Point.new(5,7); ... // var Point p1, p2 // var int d; name type kind # p1 Point local 0 p2 Point local 1 d int local 2 // The compiler updates the subroutine’s symbol table; // No code is generated. Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Object construction: the caller’s side source code compiled VM (pseudo) code ... var Point p1, p2; var int d; ... let p1 = Point.new(2,3); let p2 = Point.new(5,7); ... // var Point p1, p2 // var int d; // The compiler updates the subroutine’s symbol table. // No code is generated. ... // let p1 = Point.new(2,3) // Subroutine call: name type kind # push 2 push 3 call Point.new p1 Point local 0 pop p1 p2 Point local 1 d int local 2 Contract: the caller assumes that the constructor’s code (i) arranges a memory block to store the new object, and (ii) returns its base address to the caller. // p1 = base address of the new object Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Object construction: the caller’s side source code compiled VM (pseudo) code ... var Point p1, p2; var int d; ... let p1 = Point.new(2,3); let p2 = Point.new(5,7); ... // var Point p1, p2 // var int d; // The compiler updates the subroutine’s symbol table. // No code is generated. ... // let p1 = Point.new(2,3) // Subroutine call: name type kind # push 2 push 3 call Point.new p1 Point local 0 pop p1 p2 Point local 1 d int local 2 Contract: the caller assumes that the constructor’s code (i) arranges a memory block to store the new object, and (ii) returns its base address to the caller. // p1 = base address of the new object // let p2 = Point.new(5,7) // Similar, code omitted. ... Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Resulting impact source code ... var Point p1, p2; var int d; ... let p1 = Point.new(2,3); let p2 = Point.new(5,7); ... • During compile-time, the compiler maps p1 on local 0, p2 on local 1, and d on local 2. • During run-time, the execution of the constructor’s code effects the creation of the objects themselves, on the heap. Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Object construction: the big picture some class var Point p1; ... let p1 = Point.new(2,3); callee Point class caller class Point { ... constructor Point new(...) ... } Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Object construction: the big picture Requirements: • The constructor must create a new object • Just like any method, the constructor must be able to manipulate the fields of the current object • In the case of constructors, the current object is the newly constructed object Implementation: callee The compiled constructor’s code ... • starts by creating a memory block for representing the new object (details later) class Point { • Next, it sets THIS to the base address of this block (using pointer) • From now on, the constructor’s code can access the object’s fields using the this segment. ... constructor Point new(...) ... } Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken NB: The constructor starts off acting like a static subroutine but then behaves like an instance method. Compiling constructors caller’s code Caller’s code: compiled separately, shown for context var Point p1; ... let p1 = Point.new(2,3); ... /** Represents a Point. */ class Point { field int x, y; static int pointCount; ... /** Constructs a new point */ constructor Point new(int ax, int ay) { let x = ax; let y = ay; let pointCount = pointCount + 1; return this; } ... Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Compiling constructors caller’s code compiled constructor's code var Point p1; ... let p1 = Point.new(2,3); ... ... // constructor Point new(int ax, int ay) // The compiler creates the subroutine’s symbol table. /** Represents a Point. */ class Point { field int x, y; static int pointCount; ... /** Constructs a new point */ constructor Point new(int ax, int ay) { let x = ax; let y = ay; let pointCount = pointCount + 1; return this; } ... classlevel constructorlevel / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Nand to Tetris / www.nand2tetris.org Compiling constructors caller’s code compiled constructor's code var Point p1; ... let p1 = Point.new(2,3); ... ... // constructor Point new(int ax, int ay) // The compiler creates the subroutine’s symbol table. /** Represents a Point. */ class Point { field int x, y; static int pointCount; ... /** Constructs a new point */ constructor Point new(int ax, int ay) { let x = ax; let y = ay; let pointCount = pointCount + 1; return this; } ... // The compiler figures out the size of an object of this // class (n), and writes code that calls Memory.alloc(n). // This OS method finds a memory block of the required // size, and returns its base address. push 2 // two 16-bit words are required (x and y) call Memory.alloc 1 // one argument pop pointer 0 // anchors this at the base address classlevel constructorlevel / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Nand to Tetris / www.nand2tetris.org Compiling constructors caller’s code compiled constructor's code var Point p1; ... let p1 = Point.new(2,3); ... ... // constructor Point new(int ax, int ay) // The compiler creates the subroutine’s symbol table. /** Represents a Point. */ class Point { field int x, y; static int pointCount; ... /** Constructs a new point */ constructor Point new(int ax, int ay) { let x = ax; let y = ay; let pointCount = pointCount + 1; return this; } ... // The compiler figures out the size of an object of this // class (n), and writes code that calls Memory.alloc(n). // This OS method finds a memory block of the required // size, and returns its base address. push 2 // two 16-bit words are required (x and y) call Memory.alloc 1 // one argument pop pointer 0 // anchors this at the base address // let x = ax; let y = ay; push argument 0 pop this 0 push argument 1 pop this 1 classlevel constructorlevel / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Nand to Tetris / www.nand2tetris.org Compiling constructors caller’s code compiled constructor's code var Point p1; ... let p1 = Point.new(2,3); ... ... // constructor Point new(int ax, int ay) // The compiler creates the subroutine’s symbol table. /** Represents a Point. */ class Point { field int x, y; static int pointCount; ... /** Constructs a new point */ constructor Point new(int ax, int ay) { let x = ax; let y = ay; let pointCount = pointCount + 1; return this; } ... classlevel // The compiler figures out the size of an object of this // class (n), and writes code that calls Memory.alloc(n). // This OS method finds a memory block of the required // size, and returns its base address. push 2 // two 16-bit words are required (x and y) call Memory.alloc 1 // one argument pop pointer 0 // anchors this at the base address // let x = ax; let y = ay; push argument 0 pop this 0 push argument 1 pop this 1 // let pointCount = pointCount + 1; push static 0 push constant 1 add pop static 0 // return this push pointer 0 return // returns the base address of the new object constructorlevel / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Nand to Tetris / www.nand2tetris.org Compiling constructors caller’s code var Point p1; ... let p1 = Point.new(2,3); ... compiled constructor's code ... // constructor Point new(int ax, int ay) // The compiler creates the subroutine’s symbol table. // The compiler figures out the size of an object of this // class (n), and writes code that calls Memory.alloc(n). // This OS method finds a memory block of the required // size, and returns its base address. push 2 // two 16-bit words are required (x and y) call Memory.alloc 1 // one argument pop pointer 0 // anchors this at the base address // let x = ax; let y = ay; push argument 0 pop this 0 push argument 1 pop this 1 // let pointCount = pointCount + 1; push static 0 push constant 1 add pop static 0 // return this push pointer 0 return // returns the base address of the new object Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Compiling constructors caller’s code compiled constructor's code var Point p1; ... let p1 = Point.new(2,3); ... compiled caller’s code // let p1 = Point.new(2,3) push constant 2 push constant 3 call Point.new pop local 0 ... // constructor Point new(int ax, int ay) // The compiler creates the subroutine’s symbol table. // The compiler figures out the size of an object of this // class (n), and writes code that calls Memory.alloc(n). // This OS method finds a memory block of the required // size, and returns its base address. push 2 // two 16-bit words are required (x and y) call Memory.alloc 1 // one argument pop pointer 0 // anchors this at the base address // let x = ax; let y = ay; push argument 0 pop this 0 push argument 1 pop this 1 // let pointCount = pointCount + 1; push static 0 push constant 1 add pop static 0 // return this push pointer 0 return // returns the base address of the new object Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Object construction: the big picture var Point p1; ... let p1 = Point.new(2,3); callee caller class Point { ... constructor Point new(...) ... } Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Compilation challenges • Handling variables • Handling expressions • Handling flow of control • Handling objects q Construction q Manipulation • Handling arrays Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Compilation challenges • Handling variables • Handling expressions • Handling flow of control • Handling objects q Construction q Manipulation • Compiling method calls (caller side) • Compiling methods (callee side) • Handling arrays Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Object manipulation: high-level Point class some class class Point { ... var Point p1, p2, p3; var int x, d; ... let p1 = Point.new(2,3); let p2 = Point.new(5,7); ... let x = p1.getx(); let p3 = p1.plus(p2); let d = p1.distance(p2); ... field int x, y; static int pointCount; constructor Point new(int ax, int ay) {} method int getx() {} method int gety() {} method int getPointCount() {} method Point plus(Point other) {} method int distance(Point other) { var int dx, dy; let dx = x - other.getx(); let dy = y - other.gety(); return Math.sqrt((dx*dx)+ (dy*dy)); caller callee } method void print() {} } Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Compiling method calls Source code (OO) Target code (procedural) ... p1.distance(p2) ... ... distance(p1,p2) ... ... p3.getx() ... ... getx(p3) ... ... obj.foo(x1,x2,...) ... ... foo(obj,x1,x2,...) ... • The target language is procedural • Therefore, the compiler must generate procedural code • Solution: when calling a method, the object on which the method is called to operate is always passed as a first, implicit argument. Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Compiling method calls: the general technique generated VM (pseudo) code source code obj.foo(x1,x2,...) compiler // obj.foo(x1,x2,...) // Pushes the object on which the method // is called to operate (implicit argument), // then pushes the method arguments, // then calls the method for its effect. push obj push x1 push x2 push ... call foo generated VM (pseudo) code example: ... ... let d = p1.distance(p2); ... compiler push p1 push p2 call distance pop d ... Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Object manipulation: the big picture Point class some class class Point { ... var Point p1, p2, p3; var int x, d; ... let p1 = Point.new(2,3); let p2 = Point.new(5,7); ... let x = p1.getx(); let p3 = p1.plus(p2); let d = p1.distance(p2); ... field int x, y; static int pointCount; constructor Point new(int ax, int ay) {} method int getx() {} method int gety() {} method int getPointCount() {} method Point plus(Point other) {} method int distance(Point other) { var int dx, dy; let dx = x - other.getx(); let dy = y - other.gety(); return Math.sqrt((dx*dx) + (dy*dy)); caller callee } method void print() {} } Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Compiling methods Methods are designed to operate on the current object (this): Point class class Point { Therefore, each method’s code needs access to the object’s fields field int x, y; static int pointCount; How to access the object’s fields: method int getx() {} constructor Point new(int ax, int ay) {} method int gety() {} • The method’s code can access the object’s i-th field by accessing this i method int getPointCount() {} method Point plus(Point other) {} method int distance(Point other) { var int dx, dy; let dx = x - other.getx(); let dy = y - other.gety(); return Math.sqrt((dx*dx) + (dy*dy)); • On entry, the method’s code must anchor the this segment on the object’s data, using pointer } method void print() {} } Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Compiling methods /** Represents a Point. */ class Point { field int x, y; static int pointCount; ... /** Distance to the other point */ method int distance(Point other) { var int dx, dy let dx = x – other.getx(); let dy = y – other.gety(); return Math.sqrt((dx*dx) + (dy*dy)); } ... } classlevel methodlevel compiled VM code ... // method int distance(Point other) // var int dx,dy // The compiler constructs the method’s // symbol table. No code is generated. // Next, it generates code that associates the // this memory segment with the object on // which the method was called to operate. push argument 0 pop pointer 0 // THIS = argument 0 // let dx = x – other.getx() push this 0 push argument 1 call Point.getx 1 sub pop local 0 // let dy = y – other.gety() // Similar, code omitted. // return Math.sqrt((dx*dx)+(dy*dy)) push local 0 push local 0 call Math.multiply 2 push local 1 push local 1 call Math.multiply 2 add call Math.sqrt 1 return Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Compiling methods ... let d = p1.distance(p2); ... Caller’s code: compiled separately, shown for context compiled VM code ... // method int distance(Point other) // var int dx,dy // The compiler constructs the method’s // symbol table. No code is generated. // Next, it generates code that associates the // this memory segment with the object on // which the method was called to operate. push argument 0 pop pointer 0 // THIS = argument 0 // let dx = x – other.getx() push this 0 push argument 1 call Point.getx 1 sub pop local 0 // let dy = y – other.gety() // Similar, code omitted. // return Math.sqrt((dx*dx)+(dy*dy)) push local 0 push local 0 call Math.multiply 2 push local 1 push local 1 call Math.multiply 2 add call Math.sqrt 1 return Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Compiling methods ... let d = p1.distance(p2); ... Caller’s code: compiled separately, shown for context compiled caller (pseudo) code ... push p1 push p2 call Point.distance pop d ... compiled VM code ... // method int distance(Point other) // var int dx,dy // The compiler constructs the method’s // symbol table. No code is generated. // Next, it generates code that associates the // this memory segment with the object on // which the method was called to operate. push argument 0 pop pointer 0 // THIS = argument 0 // let dx = x – other.getx() push this 0 push argument 1 call Point.getx 1 sub pop local 0 // let dy = y – other.gety() // Similar, code omitted. // return Math.sqrt((dx*dx)+(dy*dy)) push local 0 push local 0 call Math.multiply 2 push local 1 push local 1 call Math.multiply 2 add call Math.sqrt 1 return Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Compiling void methods ... do p1.print(); ... Caller’s code: compiled separately, shown for context /** Represents a Point. */ class Point { field int x, y; static int pointCount; ... /** Prints the point as (x,y) */ method void print() { ... } ... } compiled VM code ... // method void print() // The compiler constructs the method’s // symbol table. No code is generated. // Next, it generates code that associates the // this memory segment with the object on // which the method is called to operate. push argument 0 pop pointer 0 // THIS = argument 0 ... // Returns a value (all methods must return a value) push constant 0 return classlevel methodlevel Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Compiling void methods ... do p1.print(); ... Caller’s code: compiled separately, shown for context compiled VM code ... // method void print() // The compiler constructs the method’s // symbol table. No code is generated. // Next, it generates code that associates the // this memory segment with the object on // which the method is called to operate. push argument 0 pop pointer 0 // THIS = argument 0 ... // Methods must return a value. push constant 0 return Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Compiling void methods ... do p1.print(); ... Caller’s code: compiled separately, shown for context compiled caller (pseudo) code ... push p1 call Point.print compiled VM code ... // method void print() // The compiler constructs the method’s // symbol table. No code is generated. // Next, it generates code that associates the // this memory segment with the object on // which the method is called to operate. push argument 0 pop pointer 0 // THIS = argument 0 ... // Methods must return a value. push constant 0 return Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Compiling void methods ... do p1.print(); ... Caller’s code: compiled separately, shown for context compiled caller (pseudo) code ... push p1 call Point.print // the caller of a void method // must dump the returned value compiled VM code ... // method void print() // The compiler constructs the method’s // symbol table. No code is generated. // Next, it generates code that associates the // this memory segment with the object on // which the method is called to operate. push argument 0 pop pointer 0 // THIS = argument 0 ... // Methods must return a value. push constant 0 return Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Compiling void methods ... do p1.print(); ... Caller’s code: compiled separately, shown for context compiled caller (pseudo) code ... push p1 call Point.print // the caller of a void method // must dump the returned value pop temp 0 compiled VM code ... // method void print() // The compiler constructs the method’s // symbol table. No code is generated. // Next, it generates code that associates the // this memory segment with the object on // which the method is called to operate. push argument 0 pop pointer 0 // THIS = argument 0 ... // Methods must return a value. push constant 0 return ... Compiler writers, heads up: Callee’s contract (compiled code): before terminating, the callee must return a value (by convention, void methods return 0) Caller’s contract (compiled code): after calling a void method, the caller must dump the topmost stack value Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Object manipulation: the big picture Point class some class class Point { ... var Point p1, p2, p3; var int x, d; ... let p1 = Point.new(2,3); let p2 = Point.new(5,7); ... let x = p1.getx(); let p3 = p1.plus(p2); let d = p1.distance(p2); ... field int x, y; static int pointCount; constructor Point new(int ax, int ay) {} method int getx() {} method int gety() {} method int getPointCount() {} method Point plus(Point other) {} method int distance(Point other) { var int dx, dy; let dx = x - other.getx(); let dy = y - other.gety(); return Math.sqrt((dx*dx)+ (dy*dy)); caller callee } method void print() {} } Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Compilation challenges • Handling variables • Handling expressions • Handling flow of control • Handling objects • Handling arrays Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Compilation challenges • Handling variables • Handling expressions • Handling flow of control • Handling objects • Handling arrays q Array construction q Array manipulation Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Array construction var Array arr; ... let arr = Array.new(5); ... 0 Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Array construction var Array arr; ... let arr = Array.new(5); ... Code generation • var Array arr: • generates no code; only affects the symbol table • let arr = Array.new(n): • from the caller’s perspective, handled exactly like object construction: pop result into variable’s location. Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Compilation challenges • Handling variables • Handling expressions • Handling flow of control • Handling objects • Handling arrays q Array construction q Array manipulation Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken this and that (reminder) Two virtual memory segments that can be aligned to different RAM addresses VM use: this that used to represent the values of the current object used to represent the values of the current array Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken this and that (reminder) Two virtual memory segments that can be aligned to different RAM addresses this that VM use: used to represent the values of the current object used to represent the values of the current array pointer (base address) THIS THAT how to set: pop pointer 0 (sets THIS) pop pointer 1 (sets THAT) Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken NB: Why do we have to set THIS and THAT indirectly via pointer? Example: RAM access using that // RAM[8056] = 17 Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Example: RAM access using that // RAM[8056] = 17 push 8056 pop pointer 1 Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Example: RAM access using that // RAM[8056] = 17 push 8056 pop pointer 1 push 17 pop that 0 Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Example: RAM access using that // RAM[8056] = 17 push constant 8056 pop pointer 1 push constant 17 pop that 0 17 Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Example: RAM access using that // RAM[8056] = 17 push constant 8056 pop pointer 1 push constant 17 pop that 0 However, to access arr[expr] we cannot generate: push base address of arr pop pointer 1 push/pop that value-of-expr push base address of arr evaluate expr add // address arr+expr now on ToS pop pointer 1 push/pop that 0 17 Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Compilation challenges • Handling variables • Handling expressions • Handling flow of control • Handling objects • Handling arrays Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Review • We have looked at the generation of code to handle objects. • Objects occupy space in the heap: Memory.alloc. • The fields of an object persist throughout its lifetime. • Multiple instances of a class mean that multiple copies of its fields will exist simultaneously. • The this segment is used to provide access to the fields of the ‘current’ object: the one on which the current active method has been invoked. • When a method is invoked, the caller must push the callee’s object reference as the first ‘argument’. • The callee copies argument 0 to pointer 0. • A constructor call returns the newly-created object reference as its result. Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken Review • Arrays are stored in the heap. • An array is accessed via the that segment. • The base address of the that segment is set via pointer 1. Nand to Tetris / www.nand2tetris.org / Chapter 11 / Copyright © Noam Nisan and Shimon Schocken