[08] Finishes call/init implementation

Found 2 bugs:

0. ic+=10 is incorrect jump for the boolean compare methods
1. Another bug was in the write() method, which was increasing the instruction
counter even for label commands, which aren't supposed to do that.

Another minor issue in my interpretation of the "call" to `Sys.init`
which I was so far just doing via a jump. Changed that to a proper call
This commit is contained in:
Nemo 2020-06-04 15:43:38 +05:30
parent 4fdc98bb72
commit 286df5b147
3 changed files with 553 additions and 509 deletions

View File

@ -1,370 +1,417 @@
@256 // init starts @256 // init starts // (L0:0)
D=A D=A // (L0:1)
@SP @SP // (L0:2)
M=D // initialized SP to 256 M=D // initialized SP to 256 // (L0:3)
@300 @3000 // (L0:4)
D=A D=A // (L0:5)
@LCL @LCL // (L0:6)
M=D // initialized @LCL to 300 M=D // initialized @LCL to 3000 // (L0:7)
@400 @4000 // (L0:8)
D=A D=A // (L0:9)
@ARG @ARG // (L0:10)
M=D // initialized @ARG to 400, init ends M=D // initialized @ARG to 4000, init ends // (L0:11)
@Sys.init @18d95170022c2d762027b64da6c88d0a // call Sys.init 0 start // (L0:12)
0;JMP D=A // (L0:13)
(Main.fibonacci) // function Main.fibonacci 0 @SP // (L0:14)
@ARG A=M // (L0:15)
A=M M=D // (L0:16)
D=M @SP // (L0:17)
@SP M=M+1 // (L0:18)
A=M @LCL // Read @LCL to A // (L0:19)
M=D D=M // Put @LCL to D // (L0:20)
@SP @SP // (L0:21)
M=M+1 // end push argument 0 (L1) A=M // (L0:22)
@2 // push constant 2 M=D // Save @LCL to SP // (L0:23)
D=A @SP // (L0:24)
@SP M=M+1 // end @LCL pushed to SP // (L0:25)
A=M @ARG // Read @ARG to A // (L0:26)
M=D D=M // Put @ARG to D // (L0:27)
@SP @SP // (L0:28)
M=M+1 // end push constant 2 (L2) A=M // (L0:29)
@SP // ==== lt ==== M=D // Save @ARG to SP // (L0:30)
A=M-1 @SP // (L0:31)
D=M M=M+1 // end @ARG pushed to SP // (L0:32)
A=A-1 @THIS // Read @THIS to A // (L0:33)
D=M-D D=M // Put @THIS to D // (L0:34)
M=0 @SP // (L0:35)
M=M-1 A=M // (L0:36)
@43 M=D // Save @THIS to SP // (L0:37)
D;JLT @SP // (L0:38)
@SP M=M+1 // end @THIS pushed to SP // (L0:39)
A=M-1 @THAT // Read @THAT to A // (L0:40)
A=A-1 D=M // Put @THAT to D // (L0:41)
M=0 @SP // (L0:42)
@SP A=M // (L0:43)
M=M-1 // end lt (L3) M=D // Save @THAT to SP // (L0:44)
@SP @SP // (L0:45)
AM=M-1 M=M+1 // end @THAT pushed to SP // (L0:46)
D=M @SP // (L0:47)
@Main.fibonacciIF_TRUE D=M // (L0:48)
D;JNE // end if-goto IF_TRUE (L4) @LCL // (L0:49)
@Main.fibonacciIF_FALSE M=D // Update LCL=SP // (L0:50)
0;JMP // end goto IF_FALSE (L5) D=D-1 // should repeat 5 times // (L0:51)
(Main.fibonacciIF_TRUE) // end label IF_TRUE (L6) D=D-1 // should repeat 5 times // (L0:52)
@ARG D=D-1 // should repeat 5 times // (L0:53)
A=M D=D-1 // should repeat 5 times // (L0:54)
D=M D=D-1 // should repeat 5 times // (L0:55)
@SP @ARG // write D to ARG // (L0:56)
A=M M=D // (L0:57)
M=D @Sys.init // Jump to Sys.init // (L0:58)
@SP 0;JMP // (L0:59)
M=M+1 // end push argument 0 (L7) (18d95170022c2d762027b64da6c88d0a) // return back from function here (CALL ENDS) // (L0:60)
@SP (Main.fibonacci) // function Main.fibonacci 0 // (L0:60)
A=M-1 @ARG // (L1:60)
D=M A=M // (L1:61)
@ARG D=M // (L1:62)
A=M @SP // (L1:63)
M=D A=M // (L1:64)
@ARG M=D // (L1:65)
D=M+1 @SP // (L1:66)
@SP M=M+1 // end push argument 0 // (L1:67)
M=D // @SP = ARG+1 @2 // push constant 2 // (L2:68)
@LCL D=A // (L2:69)
D=M @SP // (L2:70)
@R13 A=M // (L2:71)
M=D // Save LCL to R13 M=D // (L2:72)
A=D-1 // A=*LCL-1 @SP // (L2:73)
D=M // D=*(*LCL-1) M=M+1 // end push constant 2 // (L2:74)
@THAT // A=THAT @SP // ==== lt ==== // (L3:75)
M=D // *that = *(*lcl-1) A=M-1 // (L3:76)
@R13 D=M // (L3:77)
A=M-1 A=A-1 // (L3:78)
A=A-1 // A=*LCL-2 D=M-D // (L3:79)
D=M // D=*(*LCL-2) M=0 // (L3:80)
@THIS // A=THIS M=M-1 // (L3:81)
M=D // *THIS = *(*lcl-2) @89 // (L3:82)
@R13 D;JLT // (L3:83)
A=M-1 @SP // (L3:84)
A=A-1 A=M-1 // (L3:85)
A=A-1 // A=*LCL-3 A=A-1 // (L3:86)
D=M // D=*(*LCL-3) M=0 // (L3:87)
@ARG // A=ARG @SP // (L3:88)
M=D // *ARG = *(*lcl-3) M=M-1 // end lt // (L3:89)
@R13 @SP // (L4:90)
A=M-1 AM=M-1 // (L4:91)
A=A-1 D=M // (L4:92)
A=A-1 @Main.fibonacciIF_TRUE // (L4:93)
A=A-1 // A=*LCL-4 D;JNE // end if-goto IF_TRUE // (L4:94)
D=M // D=*(*LCL-4) @Main.fibonacciIF_FALSE // (L5:95)
@LCL // A=LCL 0;JMP // end goto IF_FALSE // (L5:96)
M=D // *LCL = *(*lcl-4) (Main.fibonacciIF_TRUE) // end label IF_TRUE // (L6:97)
@R13 @ARG // (L7:97)
A=M-1 A=M // (L7:98)
A=A-1 D=M // (L7:99)
A=A-1 @SP // (L7:100)
A=A-1 A=M // (L7:101)
A=A-1 // A=*LCL-5 M=D // (L7:102)
A=M // A=*(*LCL-5) @SP // (L7:103)
0;JMP // Jump to *(LCL-5) M=M+1 // end push argument 0 // (L7:104)
(Main.fibonacciIF_FALSE) // end label IF_FALSE (L9) @SP // (L8:105)
@ARG A=M-1 // (L8:106)
A=M D=M // (L8:107)
D=M @ARG // (L8:108)
@SP A=M // (L8:109)
A=M M=D // (L8:110)
M=D @ARG // (L8:111)
@SP D=M+1 // (L8:112)
M=M+1 // end push argument 0 (L10) @SP // (L8:113)
@2 // push constant 2 M=D // @SP = ARG+1 // (L8:114)
D=A @LCL // (L8:115)
@SP D=M // (L8:116)
A=M @R13 // (L8:117)
M=D M=D // Save LCL to R13 // (L8:118)
@SP A=D-1 // A=*LCL-1 // (L8:119)
M=M+1 // end push constant 2 (L11) D=M // D=*(*LCL-1) // (L8:120)
@SP // ==== sub ==== @THAT // A=THAT // (L8:121)
A=M-1 M=D // *that = *(*lcl-1) // (L8:122)
D=M @R13 // (L8:123)
A=A-1 A=M-1 // (L8:124)
M=M-D A=A-1 // A=*LCL-2 // (L8:125)
@SP D=M // D=*(*LCL-2) // (L8:126)
M=M-1 // end sub (L12) @THIS // A=THIS // (L8:127)
@5fd25fdab54b4bfd5a91536ecfd6806e M=D // *THIS = *(*lcl-2) // (L8:128)
D=A @R13 // (L8:129)
@SP A=M-1 // (L8:130)
A=M A=A-1 // (L8:131)
M=D A=A-1 // A=*LCL-3 // (L8:132)
@SP D=M // D=*(*LCL-3) // (L8:133)
M=M+1 @ARG // A=ARG // (L8:134)
@LCL // Read @LCL to A M=D // *ARG = *(*lcl-3) // (L8:135)
D=M // Put @LCL to D @R13 // (L8:136)
@SP A=M-1 // (L8:137)
A=M A=A-1 // (L8:138)
M=D // Save @LCL to SP A=A-1 // (L8:139)
@SP A=A-1 // A=*LCL-4 // (L8:140)
M=M+1 D=M // D=*(*LCL-4) // (L8:141)
@ARG // Read @ARG to A @LCL // A=LCL // (L8:142)
D=M // Put @ARG to D M=D // *LCL = *(*lcl-4) // (L8:143)
@SP @R13 // (L8:144)
A=M A=M-1 // (L8:145)
M=D // Save @ARG to SP A=A-1 // (L8:146)
@SP A=A-1 // (L8:147)
M=M+1 A=A-1 // (L8:148)
@THIS // Read @THIS to A A=A-1 // A=*LCL-5 // (L8:149)
D=M // Put @THIS to D A=M // A=*(*LCL-5) // (L8:150)
@SP 0;JMP // Jump to *(LCL-5) // (L8:151)
A=M (Main.fibonacciIF_FALSE) // end label IF_FALSE // (L9:152)
M=D // Save @THIS to SP @ARG // (L10:152)
@SP A=M // (L10:153)
M=M+1 D=M // (L10:154)
@THAT // Read @THAT to A @SP // (L10:155)
D=M // Put @THAT to D A=M // (L10:156)
@SP M=D // (L10:157)
A=M @SP // (L10:158)
M=D // Save @THAT to SP M=M+1 // end push argument 0 // (L10:159)
@SP @2 // push constant 2 // (L11:160)
M=M+1 D=A // (L11:161)
@SP @SP // (L11:162)
D=M A=M // (L11:163)
@LCL M=D // (L11:164)
M=D @SP // (L11:165)
D=D-1 M=M+1 // end push constant 2 // (L11:166)
D=D-1 @SP // ==== sub ==== // (L12:167)
D=D-1 A=M-1 // (L12:168)
D=D-1 D=M // (L12:169)
D=D-1 A=A-1 // (L12:170)
D=D-1 M=M-D // (L12:171)
@ARG @SP // (L12:172)
M=D M=M-1 // end sub // (L12:173)
@Main.fibonacci // Jump to Main.fibonacci @a3b7fa05917ee725f45e2c66ce232f37 // call Main.fibonacci 1 start // (L13:174)
0;JMP D=A // (L13:175)
(5fd25fdab54b4bfd5a91536ecfd6806e) // return back from function here @SP // (L13:176)
@ARG A=M // (L13:177)
A=M M=D // (L13:178)
D=M @SP // (L13:179)
@SP M=M+1 // (L13:180)
A=M @LCL // Read @LCL to A // (L13:181)
M=D D=M // Put @LCL to D // (L13:182)
@SP @SP // (L13:183)
M=M+1 // end push argument 0 (L14) A=M // (L13:184)
@1 // push constant 1 M=D // Save @LCL to SP // (L13:185)
D=A @SP // (L13:186)
@SP M=M+1 // end @LCL pushed to SP // (L13:187)
A=M @ARG // Read @ARG to A // (L13:188)
M=D D=M // Put @ARG to D // (L13:189)
@SP @SP // (L13:190)
M=M+1 // end push constant 1 (L15) A=M // (L13:191)
@SP // ==== sub ==== M=D // Save @ARG to SP // (L13:192)
A=M-1 @SP // (L13:193)
D=M M=M+1 // end @ARG pushed to SP // (L13:194)
A=A-1 @THIS // Read @THIS to A // (L13:195)
M=M-D D=M // Put @THIS to D // (L13:196)
@SP @SP // (L13:197)
M=M-1 // end sub (L16) A=M // (L13:198)
@a954c9cff71cdccc09f4338e60df6394 M=D // Save @THIS to SP // (L13:199)
D=A @SP // (L13:200)
@SP M=M+1 // end @THIS pushed to SP // (L13:201)
A=M @THAT // Read @THAT to A // (L13:202)
M=D D=M // Put @THAT to D // (L13:203)
@SP @SP // (L13:204)
M=M+1 A=M // (L13:205)
@LCL // Read @LCL to A M=D // Save @THAT to SP // (L13:206)
D=M // Put @LCL to D @SP // (L13:207)
@SP M=M+1 // end @THAT pushed to SP // (L13:208)
A=M @SP // (L13:209)
M=D // Save @LCL to SP D=M // (L13:210)
@SP @LCL // (L13:211)
M=M+1 M=D // Update LCL=SP // (L13:212)
@ARG // Read @ARG to A D=D-1 // should repeat 6 times // (L13:213)
D=M // Put @ARG to D D=D-1 // should repeat 6 times // (L13:214)
@SP D=D-1 // should repeat 6 times // (L13:215)
A=M D=D-1 // should repeat 6 times // (L13:216)
M=D // Save @ARG to SP D=D-1 // should repeat 6 times // (L13:217)
@SP D=D-1 // should repeat 6 times // (L13:218)
M=M+1 @ARG // write D to ARG // (L13:219)
@THIS // Read @THIS to A M=D // (L13:220)
D=M // Put @THIS to D @Main.fibonacci // Jump to Main.fibonacci // (L13:221)
@SP 0;JMP // (L13:222)
A=M (a3b7fa05917ee725f45e2c66ce232f37) // return back from function here (CALL ENDS) // (L13:223)
M=D // Save @THIS to SP @ARG // (L14:223)
@SP A=M // (L14:224)
M=M+1 D=M // (L14:225)
@THAT // Read @THAT to A @SP // (L14:226)
D=M // Put @THAT to D A=M // (L14:227)
@SP M=D // (L14:228)
A=M @SP // (L14:229)
M=D // Save @THAT to SP M=M+1 // end push argument 0 // (L14:230)
@SP @1 // push constant 1 // (L15:231)
M=M+1 D=A // (L15:232)
@SP @SP // (L15:233)
D=M A=M // (L15:234)
@LCL M=D // (L15:235)
M=D @SP // (L15:236)
D=D-1 M=M+1 // end push constant 1 // (L15:237)
D=D-1 @SP // ==== sub ==== // (L16:238)
D=D-1 A=M-1 // (L16:239)
D=D-1 D=M // (L16:240)
D=D-1 A=A-1 // (L16:241)
D=D-1 M=M-D // (L16:242)
@ARG @SP // (L16:243)
M=D M=M-1 // end sub // (L16:244)
@Main.fibonacci // Jump to Main.fibonacci @59c3e1ed914ff5e6e713615a6bb2a5e2 // call Main.fibonacci 1 start // (L17:245)
0;JMP D=A // (L17:246)
(a954c9cff71cdccc09f4338e60df6394) // return back from function here @SP // (L17:247)
@SP // ==== add ==== A=M // (L17:248)
A=M-1 M=D // (L17:249)
D=M @SP // (L17:250)
A=A-1 M=M+1 // (L17:251)
M=D+M @LCL // Read @LCL to A // (L17:252)
@SP D=M // Put @LCL to D // (L17:253)
M=M-1 // end add (L18) @SP // (L17:254)
@SP A=M // (L17:255)
A=M-1 M=D // Save @LCL to SP // (L17:256)
D=M @SP // (L17:257)
@ARG M=M+1 // end @LCL pushed to SP // (L17:258)
A=M @ARG // Read @ARG to A // (L17:259)
M=D D=M // Put @ARG to D // (L17:260)
@ARG @SP // (L17:261)
D=M+1 A=M // (L17:262)
@SP M=D // Save @ARG to SP // (L17:263)
M=D // @SP = ARG+1 @SP // (L17:264)
@LCL M=M+1 // end @ARG pushed to SP // (L17:265)
D=M @THIS // Read @THIS to A // (L17:266)
@R13 D=M // Put @THIS to D // (L17:267)
M=D // Save LCL to R13 @SP // (L17:268)
A=D-1 // A=*LCL-1 A=M // (L17:269)
D=M // D=*(*LCL-1) M=D // Save @THIS to SP // (L17:270)
@THAT // A=THAT @SP // (L17:271)
M=D // *that = *(*lcl-1) M=M+1 // end @THIS pushed to SP // (L17:272)
@R13 @THAT // Read @THAT to A // (L17:273)
A=M-1 D=M // Put @THAT to D // (L17:274)
A=A-1 // A=*LCL-2 @SP // (L17:275)
D=M // D=*(*LCL-2) A=M // (L17:276)
@THIS // A=THIS M=D // Save @THAT to SP // (L17:277)
M=D // *THIS = *(*lcl-2) @SP // (L17:278)
@R13 M=M+1 // end @THAT pushed to SP // (L17:279)
A=M-1 @SP // (L17:280)
A=A-1 D=M // (L17:281)
A=A-1 // A=*LCL-3 @LCL // (L17:282)
D=M // D=*(*LCL-3) M=D // Update LCL=SP // (L17:283)
@ARG // A=ARG D=D-1 // should repeat 6 times // (L17:284)
M=D // *ARG = *(*lcl-3) D=D-1 // should repeat 6 times // (L17:285)
@R13 D=D-1 // should repeat 6 times // (L17:286)
A=M-1 D=D-1 // should repeat 6 times // (L17:287)
A=A-1 D=D-1 // should repeat 6 times // (L17:288)
A=A-1 D=D-1 // should repeat 6 times // (L17:289)
A=A-1 // A=*LCL-4 @ARG // write D to ARG // (L17:290)
D=M // D=*(*LCL-4) M=D // (L17:291)
@LCL // A=LCL @Main.fibonacci // Jump to Main.fibonacci // (L17:292)
M=D // *LCL = *(*lcl-4) 0;JMP // (L17:293)
@R13 (59c3e1ed914ff5e6e713615a6bb2a5e2) // return back from function here (CALL ENDS) // (L17:294)
A=M-1 @SP // ==== add ==== // (L18:294)
A=A-1 A=M-1 // (L18:295)
A=A-1 D=M // (L18:296)
A=A-1 A=A-1 // (L18:297)
A=A-1 // A=*LCL-5 M=D+M // (L18:298)
A=M // A=*(*LCL-5) @SP // (L18:299)
0;JMP // Jump to *(LCL-5) M=M-1 // end add // (L18:300)
(Sys.init) // function Sys.init 0 @SP // (L19:301)
@4 // push constant 4 A=M-1 // (L19:302)
D=A D=M // (L19:303)
@SP @ARG // (L19:304)
A=M A=M // (L19:305)
M=D M=D // (L19:306)
@SP @ARG // (L19:307)
M=M+1 // end push constant 4 (L21) D=M+1 // (L19:308)
@dd19df789547baebfea110998cdf5713 @SP // (L19:309)
D=A M=D // @SP = ARG+1 // (L19:310)
@SP @LCL // (L19:311)
A=M D=M // (L19:312)
M=D @R13 // (L19:313)
@SP M=D // Save LCL to R13 // (L19:314)
M=M+1 A=D-1 // A=*LCL-1 // (L19:315)
@LCL // Read @LCL to A D=M // D=*(*LCL-1) // (L19:316)
D=M // Put @LCL to D @THAT // A=THAT // (L19:317)
@SP M=D // *that = *(*lcl-1) // (L19:318)
A=M @R13 // (L19:319)
M=D // Save @LCL to SP A=M-1 // (L19:320)
@SP A=A-1 // A=*LCL-2 // (L19:321)
M=M+1 D=M // D=*(*LCL-2) // (L19:322)
@ARG // Read @ARG to A @THIS // A=THIS // (L19:323)
D=M // Put @ARG to D M=D // *THIS = *(*lcl-2) // (L19:324)
@SP @R13 // (L19:325)
A=M A=M-1 // (L19:326)
M=D // Save @ARG to SP A=A-1 // (L19:327)
@SP A=A-1 // A=*LCL-3 // (L19:328)
M=M+1 D=M // D=*(*LCL-3) // (L19:329)
@THIS // Read @THIS to A @ARG // A=ARG // (L19:330)
D=M // Put @THIS to D M=D // *ARG = *(*lcl-3) // (L19:331)
@SP @R13 // (L19:332)
A=M A=M-1 // (L19:333)
M=D // Save @THIS to SP A=A-1 // (L19:334)
@SP A=A-1 // (L19:335)
M=M+1 A=A-1 // A=*LCL-4 // (L19:336)
@THAT // Read @THAT to A D=M // D=*(*LCL-4) // (L19:337)
D=M // Put @THAT to D @LCL // A=LCL // (L19:338)
@SP M=D // *LCL = *(*lcl-4) // (L19:339)
A=M @R13 // (L19:340)
M=D // Save @THAT to SP A=M-1 // (L19:341)
@SP A=A-1 // (L19:342)
M=M+1 A=A-1 // (L19:343)
@SP A=A-1 // (L19:344)
D=M A=A-1 // A=*LCL-5 // (L19:345)
@LCL A=M // A=*(*LCL-5) // (L19:346)
M=D 0;JMP // Jump to *(LCL-5) // (L19:347)
D=D-1 (Sys.init) // function Sys.init 0 // (L20:348)
D=D-1 @4 // push constant 4 // (L21:348)
D=D-1 D=A // (L21:349)
D=D-1 @SP // (L21:350)
D=D-1 A=M // (L21:351)
D=D-1 M=D // (L21:352)
@ARG @SP // (L21:353)
M=D M=M+1 // end push constant 4 // (L21:354)
@Main.fibonacci // Jump to Main.fibonacci @c28123f096da12e9e9a4357d4823b8d2 // call Main.fibonacci 1 start // (L22:355)
0;JMP D=A // (L22:356)
(dd19df789547baebfea110998cdf5713) // return back from function here @SP // (L22:357)
(Sys.initWHILE) // end label WHILE (L23) A=M // (L22:358)
@Sys.initWHILE M=D // (L22:359)
0;JMP // end goto WHILE (L24) @SP // (L22:360)
@369 M=M+1 // (L22:361)
0;JMP @LCL // Read @LCL to A // (L22:362)
D=M // Put @LCL to D // (L22:363)
@SP // (L22:364)
A=M // (L22:365)
M=D // Save @LCL to SP // (L22:366)
@SP // (L22:367)
M=M+1 // end @LCL pushed to SP // (L22:368)
@ARG // Read @ARG to A // (L22:369)
D=M // Put @ARG to D // (L22:370)
@SP // (L22:371)
A=M // (L22:372)
M=D // Save @ARG to SP // (L22:373)
@SP // (L22:374)
M=M+1 // end @ARG pushed to SP // (L22:375)
@THIS // Read @THIS to A // (L22:376)
D=M // Put @THIS to D // (L22:377)
@SP // (L22:378)
A=M // (L22:379)
M=D // Save @THIS to SP // (L22:380)
@SP // (L22:381)
M=M+1 // end @THIS pushed to SP // (L22:382)
@THAT // Read @THAT to A // (L22:383)
D=M // Put @THAT to D // (L22:384)
@SP // (L22:385)
A=M // (L22:386)
M=D // Save @THAT to SP // (L22:387)
@SP // (L22:388)
M=M+1 // end @THAT pushed to SP // (L22:389)
@SP // (L22:390)
D=M // (L22:391)
@LCL // (L22:392)
M=D // Update LCL=SP // (L22:393)
D=D-1 // should repeat 6 times // (L22:394)
D=D-1 // should repeat 6 times // (L22:395)
D=D-1 // should repeat 6 times // (L22:396)
D=D-1 // should repeat 6 times // (L22:397)
D=D-1 // should repeat 6 times // (L22:398)
D=D-1 // should repeat 6 times // (L22:399)
@ARG // write D to ARG // (L22:400)
M=D // (L22:401)
@Main.fibonacci // Jump to Main.fibonacci // (L22:402)
0;JMP // (L22:403)
(c28123f096da12e9e9a4357d4823b8d2) // return back from function here (CALL ENDS) // (L22:404)
(Sys.initWHILE) // end label WHILE // (L23:404)
@Sys.initWHILE // (L24:404)
0;JMP // end goto WHILE // (L24:405)
@407 // (L25:406)
0;JMP // (L25:407)

View File

@ -1,2 +1,2 @@
| RAM[0] |RAM[261]| | RAM[0] |RAM[261]|
| 257 | 0 | | 262 | 3 |

View File

@ -17,65 +17,65 @@ class CodeWriter {
public function writeReturn() { public function writeReturn() {
$this->write([ $this->write([
"@SP", '@SP',
"A=M-1", 'A=M-1',
"D=M",// Popped value to D 'D=M',// Popped value to D
// And then write it to *ARG = pop() // And then write it to *ARG = pop()
"@ARG", '@ARG',
"A=M", 'A=M',
"M=D", 'M=D',
// SP=ARG+1 // SP=ARG+1
"@ARG", '@ARG',
"D=M+1", 'D=M+1',
"@SP", '@SP',
"M=D // @SP = ARG+1", 'M=D // @SP = ARG+1',
"@LCL", '@LCL',
"D=M", 'D=M',
"@R13", '@R13',
"M=D // Save LCL to R13", 'M=D // Save LCL to R13',
// now we go restoring THAT, THIS, ARG, LCL // now we go restoring THAT, THIS, ARG, LCL
"A=D-1 // A=*LCL-1", 'A=D-1 // A=*LCL-1',
"D=M // D=*(*LCL-1)", 'D=M // D=*(*LCL-1)',
"@THAT // A=THAT", '@THAT // A=THAT',
"M=D // *that = *(*lcl-1)", 'M=D // *that = *(*lcl-1)',
// now we restore THIS // now we restore THIS
"@R13", '@R13',
"A=M-1", 'A=M-1',
"A=A-1 // A=*LCL-2", 'A=A-1 // A=*LCL-2',
"D=M // D=*(*LCL-2)", 'D=M // D=*(*LCL-2)',
"@THIS // A=THIS", '@THIS // A=THIS',
"M=D // *THIS = *(*lcl-2)", 'M=D // *THIS = *(*lcl-2)',
// now we restore ARG // now we restore ARG
"@R13", '@R13',
"A=M-1", 'A=M-1',
"A=A-1", 'A=A-1',
"A=A-1 // A=*LCL-3", 'A=A-1 // A=*LCL-3',
"D=M // D=*(*LCL-3)", 'D=M // D=*(*LCL-3)',
"@ARG // A=ARG", '@ARG // A=ARG',
"M=D // *ARG = *(*lcl-3)", 'M=D // *ARG = *(*lcl-3)',
// now we restore LCL // now we restore LCL
"@R13", '@R13',
"A=M-1", 'A=M-1',
"A=A-1", 'A=A-1',
"A=A-1", 'A=A-1',
"A=A-1 // A=*LCL-4", 'A=A-1 // A=*LCL-4',
"D=M // D=*(*LCL-4)", 'D=M // D=*(*LCL-4)',
"@LCL // A=LCL", '@LCL // A=LCL',
"M=D // *LCL = *(*lcl-4)", 'M=D // *LCL = *(*lcl-4)',
// Now we hyperjump // Now we hyperjump
"@R13", '@R13',
"A=M-1", 'A=M-1',
"A=A-1", 'A=A-1',
"A=A-1", 'A=A-1',
"A=A-1", 'A=A-1',
"A=A-1 // A=*LCL-5", 'A=A-1 // A=*LCL-5',
"A=M // A=*(*LCL-5)", 'A=M // A=*(*LCL-5)',
"0;JMP // Jump to *(LCL-5)", '0;JMP // Jump to *(LCL-5)',
]); ]);
} }
@ -97,7 +97,8 @@ class CodeWriter {
if ($numArgs > 0) { if ($numArgs > 0) {
$this->write([ $this->write([
// This is only required for the first argument // This is only required for the first argument
"@SP", "A=M" '@SP',
'A=M',
]); ]);
} }
@ -105,9 +106,9 @@ class CodeWriter {
// push a zero to the stack // push a zero to the stack
for($i=0;$i<$numArgs;$i++) { for($i=0;$i<$numArgs;$i++) {
$this->write([ $this->write([
"M=0", 'M=0',
"@SP", '@SP',
"AM=M+1", 'AM=M+1',
]); ]);
} }
} }
@ -121,20 +122,20 @@ class CodeWriter {
// push the label to top of the stack // push the label to top of the stack
$this->write([ $this->write([
"@$label", "@$label // call $functionName $numArgs start",
"D=A", 'D=A',
"@SP", '@SP',
"A=M", 'A=M',
"M=D", 'M=D',
"@SP", '@SP',
"M=M+1" 'M=M+1',
]); ]);
$pushes = [ $pushes = [
"@LCL", '@LCL',
"@ARG", '@ARG',
"@THIS", '@THIS',
"@THAT", '@THAT',
]; ];
// TODO: optimize this by saving LCL, ARG // TODO: optimize this by saving LCL, ARG
@ -144,42 +145,39 @@ class CodeWriter {
$this->write([ $this->write([
"$lookupRegister // Read $lookupRegister to A", "$lookupRegister // Read $lookupRegister to A",
"D=M // Put $lookupRegister to D", "D=M // Put $lookupRegister to D",
"@SP", '@SP',
"A=M", 'A=M',
"M=D // Save $lookupRegister to SP", "M=D // Save $lookupRegister to SP",
"@SP", '@SP',
"M=M+1", "M=M+1 // end $lookupRegister pushed to SP",
]); ]);
} }
// Load current stackpointer to D // Load current stackpointer to D
// and write it to LCL
$this->write([ $this->write([
"@SP", '@SP',
"D=M", 'D=M',
]); '@LCL',
'M=D // Update LCL=SP',
// Write current stackpointer to LCL
$this->write([
"@LCL",
"M=D",
]); ]);
// Reduce D height times = numArgs+5 // Reduce D height times = numArgs+5
$height = $numArgs + 5; $height = $numArgs + 5;
for ($i=0; $i < $height; $i++) { for ($i=0; $i < $height; $i++) {
$this->write([ $this->write([
"D=D-1", "D=D-1 // should repeat $height times",
]); ]);
} }
// now D = SP-n-5 // now D = SP-n-5
// now we need to write D to ARG // now we need to write D to ARG
$this->write([ $this->write([
"@ARG", '@ARG // write D to ARG',
"M=D", 'M=D',
"@$functionName // Jump to $functionName", "@$functionName // Jump to $functionName",
"0;JMP", '0;JMP',
"($label) // return back from function here", "($label) // return back from function here (CALL ENDS)",
]); ]);
} }
@ -188,22 +186,21 @@ class CodeWriter {
*/ */
private function writeInit() { private function writeInit() {
$this->write([ $this->write([
"@256 // init starts", '@256 // init starts',
"D=A", 'D=A',
"@SP", '@SP',
"M=D // initialized SP to 256", 'M=D // initialized SP to 256',
"@300", '@3000',
"D=A", 'D=A',
"@LCL", '@LCL',
"M=D // initialized @LCL to 300", 'M=D // initialized @LCL to 3000',
"@400", '@4000',
"D=A", 'D=A',
"@ARG", '@ARG',
"M=D // initialized @ARG to 400, init ends", 'M=D // initialized @ARG to 4000, init ends',
// We jump to Sys.init
"@Sys.init",
"0;JMP"
]); ]);
$this->writeCall('Sys.init', 0);
} }
function setInputFileName($inputFileName) { function setInputFileName($inputFileName) {
@ -226,7 +223,7 @@ class CodeWriter {
$endJump = $this->ic+1; $endJump = $this->ic+1;
$this->write([ $this->write([
"@$endJump", "@$endJump",
"0;JMP" '0;JMP',
]); ]);
} }
@ -236,7 +233,7 @@ class CodeWriter {
function writeLabel(String $label) { function writeLabel(String $label) {
$globalLabel = $this->resolveLabel($label); $globalLabel = $this->resolveLabel($label);
$this->write([ $this->write([
"($globalLabel) // end label $label (L{$this->sourceLine})", "($globalLabel) // end label $label",
]); ]);
} }
@ -257,7 +254,7 @@ class CodeWriter {
$globalLabel = $this->resolveLabel($label); $globalLabel = $this->resolveLabel($label);
$this->write([ $this->write([
"@$globalLabel", "@$globalLabel",
"0;JMP // end goto $label (L{$this->sourceLine})", "0;JMP // end goto $label",
]); ]);
} }
@ -274,7 +271,7 @@ class CodeWriter {
'AM=M-1', 'AM=M-1',
'D=M', 'D=M',
"@$globalLabel", "@$globalLabel",
"D;JNE // end if-goto $label (L{$this->sourceLine})", "D;JNE // end if-goto $label",
]); ]);
} }
@ -283,8 +280,8 @@ class CodeWriter {
// Read top of stack to D // Read top of stack to D
$this->write([ $this->write([
"@SP // ==== $command ====", "@SP // ==== $command ====",
"A=M-1", 'A=M-1',
"D=M" 'D=M'
]); ]);
switch ($command) { switch ($command) {
@ -293,7 +290,7 @@ class CodeWriter {
case 'sub': case 'sub':
$this->write([ $this->write([
'A=A-1', 'A=A-1',
"M=M-D", 'M=M-D',
]); ]);
break; break;
@ -307,7 +304,7 @@ class CodeWriter {
case 'neg': case 'neg':
$this->write([ $this->write([
"M=-M // end $command (L{$this->sourceLine})", "M=-M // end $command",
]); ]);
$stackDecrease = false; $stackDecrease = false;
break; break;
@ -315,7 +312,7 @@ class CodeWriter {
case 'not': case 'not':
$this->write([ $this->write([
"M=!M // end $command (L{$this->sourceLine})", "M=!M // end $command",
]); ]);
$stackDecrease = false; $stackDecrease = false;
break; break;
@ -336,23 +333,23 @@ class CodeWriter {
// TODO: Combine all the boolean commands // TODO: Combine all the boolean commands
case 'lt': case 'lt':
$jumpPointer = $this->ic+10; $jumpPointer = $this->ic+11;
$this->write([ $this->write([
'A=A-1', 'A=A-1',
'D=M-D', 'D=M-D',
'M=0', 'M=0',
'M=M-1', 'M=M-1',
"@$jumpPointer", "@$jumpPointer",
"D;JLT", 'D;JLT',
"@SP", '@SP',
"A=M-1", 'A=M-1',
"A=A-1", 'A=A-1',
"M=0", 'M=0',
]); ]);
break; break;
case 'gt': case 'gt':
$jumpPointer = $this->ic+10; $jumpPointer = $this->ic+11;
$this->write([ $this->write([
'A=A-1', 'A=A-1',
'D=M-D', 'D=M-D',
@ -360,15 +357,15 @@ class CodeWriter {
'M=M-1', 'M=M-1',
"@$jumpPointer", "@$jumpPointer",
"D;JGT", "D;JGT",
"@SP", '@SP',
"A=M-1", 'A=M-1',
"A=A-1", 'A=A-1',
"M=0", 'M=0',
]); ]);
break; break;
case 'eq': case 'eq':
$jumpPointer = $this->ic+10; $jumpPointer = $this->ic+11;
$this->write([ $this->write([
'A=A-1', 'A=A-1',
'D=M-D', 'D=M-D',
@ -376,10 +373,10 @@ class CodeWriter {
'M=M-1', 'M=M-1',
"@{$jumpPointer}", "@{$jumpPointer}",
'D;JEQ', 'D;JEQ',
"@SP", '@SP',
"A=M-1", 'A=M-1',
"A=A-1", 'A=A-1',
"M=0", 'M=0',
]); ]);
break; break;
@ -391,17 +388,17 @@ class CodeWriter {
if ($stackDecrease) { if ($stackDecrease) {
$this->write([ $this->write([
'@SP', '@SP',
"M=M-1 // end $command (L{$this->sourceLine})" "M=M-1 // end $command"
]); ]);
} }
} }
private function write(Array $lines) { private function write(Array $lines) {
foreach ($lines as $line) { foreach ($lines as $line) {
if (substr($line, 0, 2) !== "//") { fwrite($this->file, "$line // (L{$this->sourceLine}:{$this->ic})\n");
if (substr($line, 0, 2) !== "//" and substr($line, 0, 1) !== "(") {
$this->ic += 1; $this->ic += 1;
} }
fwrite($this->file, "$line\n");
} }
} }
@ -419,7 +416,7 @@ class CodeWriter {
// Take the constant // Take the constant
"@$index // push $segment $index", "@$index // push $segment $index",
// Write it to D // Write it to D
"D=A", 'D=A',
]); ]);
break; break;
case 'argument': case 'argument':
@ -433,8 +430,8 @@ class CodeWriter {
} }
$this->write([ $this->write([
$register, $register,
"A=M", 'A=M',
"D=M", 'D=M',
]); ]);
break; break;
@ -442,7 +439,7 @@ class CodeWriter {
$symbol = $this->resolveStatic($index); $symbol = $this->resolveStatic($index);
$this->write([ $this->write([
$symbol, $symbol,
"D=M" 'D=M'
]); ]);
break; break;
@ -450,7 +447,7 @@ class CodeWriter {
$register = $this->resolvePointer($index); $register = $this->resolvePointer($index);
$this->write([ $this->write([
"$register // pointer $index", "$register // pointer $index",
"D=M" 'D=M'
]); ]);
break; break;
@ -458,7 +455,7 @@ class CodeWriter {
$register = $this->resolveTemp($index); $register = $this->resolveTemp($index);
$this->write([ $this->write([
"$register // temp $index", "$register // temp $index",
"D=M" 'D=M'
]); ]);
break; break;
@ -475,7 +472,7 @@ class CodeWriter {
"M=D", "M=D",
// Bump Stack Pointer // Bump Stack Pointer
"@SP", "@SP",
"M=M+1 // end push $segment $index (L{$this->sourceLine})", "M=M+1 // end push $segment $index",
]); ]);
} }
@ -500,7 +497,7 @@ class CodeWriter {
$register = $this->resolveSegmentToRegister($segment); $register = $this->resolveSegmentToRegister($segment);
$this->write([ $this->write([
"$register // $segment $index" , "$register // $segment $index" ,
"D=M", 'D=M',
"@$index // write $index to A", "@$index // write $index to A",
"D=D+A // D = segment+index", "D=D+A // D = segment+index",
"@R13 // save it to R13", "@R13 // save it to R13",
@ -533,10 +530,10 @@ class CodeWriter {
$this->write([ $this->write([
"@SP // pop", "@SP // pop",
"AM=M-1", "AM=M-1",
"D=M", 'D=M',
$lookupRegister, $lookupRegister,
"A=M // Read $lookupRegister to A (for $segment $index)", "A=M // Read $lookupRegister to A (for $segment $index)",
"M=D // end pop $segment $index (L{$this->sourceLine})", "M=D // end pop $segment $index",
]); ]);
break; break;
@ -545,9 +542,9 @@ class CodeWriter {
$this->write([ $this->write([
"@SP //pop $segment $index", "@SP //pop $segment $index",
"AM=M-1", "AM=M-1",
"D=M", 'D=M',
$symbol, $symbol,
"M=D // end pop $segment $index (L{$this->sourceLine})" "M=D // end pop $segment $index"
]); ]);
break; break;
@ -557,9 +554,9 @@ class CodeWriter {
$this->write([ $this->write([
"@SP // pop", "@SP // pop",
"AM=M-1", "AM=M-1",
"D=M", 'D=M',
$register, $register,
"M=D // (L{$this->sourceLine})" "M=D //"
]); ]);
break; break;
@ -568,9 +565,9 @@ class CodeWriter {
$this->write([ $this->write([
"@SP", "@SP",
"AM=M-1", "AM=M-1",
"D=M", 'D=M',
"$tempRegister", "$tempRegister",
"M=D // end pop temp $index (L{$this->sourceLine})" "M=D // end pop temp $index"
]); ]);
break; break;