├── 10 ├── CompilationEngine.py ├── JackAnalyzer.py └── JackTokenizer.py ├── 11 ├── CompilationEngine.py ├── JackCompiler.py ├── JackTokenizer.py ├── SymbolTable.py └── VMWriter.py ├── 12 ├── Array.jack ├── Keyboard.jack ├── Math.jack ├── Memory.jack ├── Output.jack ├── Screen.jack ├── String.jack └── Sys.jack ├── .gitattributes ├── .gitignore ├── 05 ├── CPU.hdl ├── Computer.hdl └── Memory.hdl ├── 06 ├── nosymbol │ ├── Code.py │ ├── Parser.py │ ├── assembler.py │ └── prog.hack └── symbol │ ├── Code.py │ ├── Parser.py │ ├── SymbolTable.py │ ├── assembler.py │ └── prog.hack ├── 07 ├── CodeWriter.py ├── Parser.py └── Vmtranslator.py └── 08 ├── CodeWriter.py ├── Parser.py └── Vmtranslator.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # ========================= 18 | # Operating System Files 19 | # ========================= 20 | 21 | # OSX 22 | # ========================= 23 | 24 | .DS_Store 25 | .AppleDouble 26 | .LSOverride 27 | 28 | # Icon must ends with two \r. 29 | Icon 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | -------------------------------------------------------------------------------- /05/CPU.hdl: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | // File name: projects/05/CPU.hdl 5 | 6 | /** 7 | * The Central Processing unit (CPU). 8 | * Consists of an ALU and a set of registers, designed to fetch and 9 | * execute instructions written in the Hack machine language. 10 | * In particular, functions as follows: 11 | * Executes the inputted instruction according to the Hack machine 12 | * language specification. The D and A in the language specification 13 | * refer to CPU-resident registers, while M refers to the external 14 | * memory location addressed by A, i.e. to Memory[A]. The inM input 15 | * holds the value of this location. If the current instruction needs 16 | * to write a value to M, the value is placed in outM, the address 17 | * of the target location is placed in the addressM output, and the 18 | * writeM control bit is asserted. (When writeM=0, any value may 19 | * appear in outM). The outM and writeM outputs are combinational: 20 | * they are affected instantaneously by the execution of the current 21 | * instruction. The addressM and pc outputs are clocked: although they 22 | * are affected by the execution of the current instruction, they commit 23 | * to their new values only in the next time unit. If reset=1 then the 24 | * CPU jumps to address 0 (i.e. sets pc=0 in next time unit) rather 25 | * than to the address resulting from executing the current instruction. 26 | */ 27 | 28 | CHIP CPU { 29 | 30 | IN inM[16], // M value input (M = contents of RAM[A]) 31 | instruction[16], // Instruction for execution 32 | reset; // Signals whether to re-start the current 33 | // program (reset=1) or continue executing 34 | // the current program (reset=0). 35 | 36 | OUT outM[16], // M value output 37 | writeM, // Write into M? 38 | addressM[15], // Address in data memory (of M) 39 | pc[15]; // address of next instruction 40 | 41 | PARTS: 42 | // Put your code here: 43 | Mux16(a=instruction,b=outALU,sel=instruction[15],out=outMux1); 44 | 45 | //Register A 46 | Not(in=instruction[15],out=notAnd); 47 | Or(a=notAnd,b=instruction[5],out=outOr); 48 | ARegister(in=outMux1,load=outOr,out=outA,out[0..14]=addressM); 49 | 50 | //D 51 | And(a=instruction[15],b=instruction[4],out=loadD); 52 | DRegister(in=outALU,load=loadD,out=outD); 53 | 54 | //Mux A&M 55 | Mux16(a=outA,b=inM,sel=instruction[12],out=outAM); 56 | 57 | //ALU 58 | ALU(x=outD,y=outAM,zx=instruction[11],nx=instruction[10],zy=instruction[9], 59 | ny=instruction[8], f=instruction[7], no=instruction[6], 60 | out=outALU,out=outM,zr=zr,ng=ng); 61 | 62 | //Mux writeM 63 | And(a=instruction[3],b=instruction[15],out=writeM); 64 | 65 | //PC 66 | Not(in=zr,out=notzr); 67 | Not(in=ng,out=notng); 68 | And(a=notzr,b=notng,out=ps); 69 | And(a=ng,b=instruction[2],out=and1); 70 | And(a=zr,b=instruction[1],out=and2); 71 | And(a=ps,b=instruction[0],out=and3); 72 | Or(a=and1,b=and2,out=or1); 73 | Or(a=or1,b=and3,out=or2); 74 | 75 | //禁止A指令时PC采取load行为 76 | And(a=or2,b=instruction[15],out=outAnd3); 77 | PC(in=outAM,load=outAnd3,reset=reset,inc=true,out[0..14]=pc); 78 | 79 | } -------------------------------------------------------------------------------- /05/Computer.hdl: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | // File name: projects/05/Computer.hdl 5 | 6 | /** 7 | * The HACK computer, including CPU, ROM and RAM. 8 | * When reset is 0, the program stored in the computer's ROM executes. 9 | * When reset is 1, the execution of the program restarts. 10 | * Thus, to start a program's execution, reset must be pushed "up" (1) 11 | * and "down" (0). From this point onward the user is at the mercy of 12 | * the software. In particular, depending on the program's code, the 13 | * screen may show some output and the user may be able to interact 14 | * with the computer via the keyboard. 15 | */ 16 | 17 | CHIP Computer { 18 | 19 | IN reset; 20 | 21 | PARTS: 22 | // Put your code here: 23 | CPU(inM=outM0,instruction=outins,reset=reset,writeM=writeM,outM=outM,addressM=addressM,pc=pc); 24 | Memory(in=outM,load=writeM,address=addressM,out=outM0); 25 | ROM32K(address=pc,out=outins); 26 | } 27 | -------------------------------------------------------------------------------- /05/Memory.hdl: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | // File name: projects/05/Memory.hdl 5 | 6 | /** 7 | * The complete address space of the computer's memory, 8 | * including RAM and memory mapped I/O. 9 | * The chip facilitates read and write operations, as follows: 10 | * Read: out(t) = Memory[address(t)](t) 11 | * Write: If load(t-1) then Memory[address(t-1)](t) = in(t-1) 12 | * In words: the chip always outputs the value stored at the memory 13 | * location specified by address. If load=1, the in value is loaded 14 | * into the memory location specified by address. This value becomes 15 | * available through the out output in the next time step. 16 | * Address space rules: 17 | * Only the upper 16K+8K+1 words of the Memory chip are used. 18 | * Access to address>0x6000 is invalid. Access to any address in 19 | * the range 0x4000-0x5FFF results in accessing the screen memory 20 | * map. Access to address 0x6000 results in accessing the keyboard 21 | * memory map. The behavior in these addresses is described in the 22 | * Screen and Keyboard chip specifications given in the book. 23 | */ 24 | 25 | CHIP Memory { 26 | IN in[16], load, address[15]; 27 | OUT out[16]; 28 | 29 | PARTS: 30 | // Put your code here: 31 | Mux(a=load, b=false, sel=address[14], out=rload); //address[14]=0时,RAM的load有效 32 | Mux(a=false, b=load, sel=address[14], out=sload); //address[14]=0时,Screen的load无效 33 | 34 | RAM16K(in=in, load=rload, address=address[0..13], out=rout); 35 | Screen(in=in, load=sload, address=address[0..12], out=sout); 36 | Keyboard(out=kout); 37 | 38 | Mux16(a=sout, b=kout, sel=address[13], out=hout); 39 | Mux16(a=rout, b=hout, sel=address[14], out=out); 40 | 41 | } -------------------------------------------------------------------------------- /06/nosymbol/Code.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import Parser 3 | 4 | def dest(line): 5 | destdict={'null':'000','M':'001','D':'010','MD':'011','A':'100','AM':'101','AD':'110','AMD':'111'} 6 | destcode=destdict[Parser.dest(line)] 7 | return destcode 8 | 9 | def comp(line): 10 | compdict={'0':'0101010','1':'0111111','-1':'0111010','D':'0001100','A':'0110000',\ 11 | '!D':'0001101','!A':'0110001','-D':'0001111','-A':'0110011','D+1':'0011111',\ 12 | 'A+1':'0110111','D-1':'0001110','A-1':'0110010','D+A':'0000010','D-A':'0010011',\ 13 | 'A-D':'0000111','D&A':'0000000','D|A':'0010101','M':'1110000','!M':'1110001',\ 14 | '-M':'1110011','M+1':'1110111','M-1':'1110010','D+M':'1000010','D-M':'1010011',\ 15 | 'M-D':'1000111','D&M':'1000000','D|M':'1010101'} 16 | compcode=compdict[Parser.comp(line)] 17 | return compcode 18 | 19 | def jump(line): 20 | jumpdict={'null':'000','JGT':'001','JEQ':'010','JGE':'011','JLT':'100','JNE':'101',\ 21 | 'JLE':'110','JMP':'111'} 22 | jumpcode=jumpdict[Parser.jump(line)] 23 | return jumpcode -------------------------------------------------------------------------------- /06/nosymbol/Parser.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | def hasMoreCommands(line): 3 | if not line: 4 | return 0 5 | else: 6 | return 1 7 | 8 | def advance(rfile,line): 9 | line=rfile.readline() 10 | return line 11 | 12 | def commandType(line): 13 | if line.find('@')>=0: 14 | return 'A_COMMAND' 15 | elif line.find('=')>=0 or line.find(';')>=0: 16 | return 'C_COMMAND' 17 | elif line.find('(')>=0: 18 | return 'L_COMMAND' 19 | 20 | def symbol(line): 21 | symbolflag=line.strip(' @()\n') 22 | #be careful about striping needless letters 23 | return symbolflag 24 | 25 | def dest(line): 26 | if line.find('=')>=0: 27 | destlist=line.split('=') 28 | return destlist[0].strip(' ') 29 | elif line.find(';')>=0: 30 | return 'null' 31 | 32 | def comp(line): 33 | if line.find('=')>=0: 34 | complist1=line.split('=') 35 | return complist1[1].strip('\n') 36 | elif line.find(';')>=0: 37 | complist2=line.split(';') 38 | return complist2[0].strip(' ') 39 | 40 | def jump(line): 41 | if line.find('=')>=0: 42 | return 'null' 43 | elif line.find(';')>=0: 44 | jumplist=line.split(';') 45 | return jumplist[1].strip(' \n') -------------------------------------------------------------------------------- /06/nosymbol/assembler.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import sys 3 | import Parser 4 | import Code 5 | 6 | filename=sys.argv[1] 7 | rfile = open(filename,'r') 8 | wfile = open('prog.hack','w') 9 | 10 | #main loop 11 | line=rfile.readline() 12 | flag=Parser.hasMoreCommands(line) 13 | while flag: 14 | #clean the line which starts with // or blank lines 15 | while line == '\n' or line.startswith('//'): 16 | line=rfile.readline() 17 | 18 | ctype=Parser.commandType(line) 19 | #compare command type 20 | if ctype is 'A_COMMAND': 21 | AS=Parser.symbol(line) 22 | AS1=bin(int(AS))[2:] 23 | AString=AS1.zfill(15) 24 | wfile.write('0'+AString+'\n') 25 | 26 | elif ctype is 'L_COMMAND': 27 | LString=Parser.symbol(line) 28 | wfile.write('0'+LString+'\n') 29 | #L_COMMAND has no meaning in this part 30 | 31 | if ctype is 'C_COMMAND': 32 | DestString=Code.dest(line) 33 | CompString=Code.comp(line) 34 | JumpString=Code.jump(line) 35 | wfile.write('111'+CompString+DestString+JumpString+'\n') 36 | 37 | line=Parser.advance(rfile,line) 38 | flag=Parser.hasMoreCommands(line) 39 | 40 | rfile.close() 41 | wfile.close() -------------------------------------------------------------------------------- /06/nosymbol/prog.hack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThomasCJY/The_Elements_of_Computing_Systems/27bc467f50e5bdb4b956804d526e59af9745c0f5/06/nosymbol/prog.hack -------------------------------------------------------------------------------- /06/symbol/Code.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import Parser 3 | 4 | def dest(line): 5 | destdict={'null':'000','M':'001','D':'010','MD':'011','A':'100','AM':'101','AD':'110','AMD':'111'} 6 | destcode=destdict[Parser.dest(line)] 7 | return destcode 8 | 9 | def comp(line): 10 | compdict={'0':'0101010','1':'0111111','-1':'0111010','D':'0001100','A':'0110000',\ 11 | '!D':'0001101','!A':'0110001','-D':'0001111','-A':'0110011','D+1':'0011111',\ 12 | 'A+1':'0110111','D-1':'0001110','A-1':'0110010','D+A':'0000010','D-A':'0010011',\ 13 | 'A-D':'0000111','D&A':'0000000','D|A':'0010101','M':'1110000','!M':'1110001',\ 14 | '-M':'1110011','M+1':'1110111','M-1':'1110010','D+M':'1000010','D-M':'1010011',\ 15 | 'M-D':'1000111','D&M':'1000000','D|M':'1010101'} 16 | compcode=compdict[Parser.comp(line)] 17 | return compcode 18 | 19 | def jump(line): 20 | jumpdict={'null':'000','JGT':'001','JEQ':'010','JGE':'011','JLT':'100','JNE':'101',\ 21 | 'JLE':'110','JMP':'111'} 22 | jumpcode=jumpdict[Parser.jump(line)] 23 | return jumpcode -------------------------------------------------------------------------------- /06/symbol/Parser.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | def hasMoreCommands(line): 3 | if not line: 4 | return 0 5 | else: 6 | return 1 7 | 8 | def advance(rfile,line): 9 | line=rfile.readline() 10 | return line 11 | 12 | def commandType(line): 13 | if line.find('@')>=0: 14 | return 'A_COMMAND' 15 | elif line.find('=')>=0 or line.find(';')>=0: 16 | return 'C_COMMAND' 17 | elif line.find('(')>=0: 18 | return 'L_COMMAND' 19 | 20 | def symbol(line): 21 | symbolflag=line.strip(' @()\n') 22 | return symbolflag 23 | 24 | def dest(line): 25 | if line.find('=')>=0: 26 | destlist=line.split('=') 27 | return destlist[0].strip(' ') 28 | elif line.find(';')>=0: 29 | return 'null' 30 | 31 | def comp(line): 32 | if line.find('=')>=0: 33 | complist1=line.split('=') 34 | return complist1[1].strip('\n') 35 | elif line.find(';')>=0: 36 | complist2=line.split(';') 37 | return complist2[0].strip(' ') 38 | 39 | def jump(line): 40 | if line.find('=')>=0: 41 | return 'null' 42 | elif line.find(';')>=0: 43 | jumplist=line.split(';') 44 | return jumplist[1].strip(' \n') -------------------------------------------------------------------------------- /06/symbol/SymbolTable.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | def Constructor(): 3 | symboldict={'SP' : 0,'LCL' : 1,'ARG' : 2,'THIS' : 3,'THAT' : 4,\ 4 | 'R0' : 0,'R1' : 1,'R2' : 2,'R3' : 3,'R4' : 4,'R5' : 5,'R6' : 6,'R7' : 7,\ 5 | 'R8' : 8,'R9' : 9,'R10' : 10,'R11' : 11,'R12' : 12,'R13' : 13,'R14' : 14,\ 6 | 'R15' : 15,'SCREEN' : 16384,'KBD' : 24576} 7 | return symboldict 8 | 9 | def addEntry(symbol,address,symboldict): 10 | symboldict[symbol]=address 11 | return symboldict 12 | 13 | def contains(symbol,symboldict): 14 | return symboldict.has_key(symbol) 15 | 16 | def GetAddress(symbol,symboldict): 17 | return symboldict[symbol] -------------------------------------------------------------------------------- /06/symbol/assembler.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import sys 3 | import Parser 4 | import Code 5 | import SymbolTable 6 | 7 | filename=sys.argv[1] 8 | #The first Loop, aiming to decide the lables' addresses 9 | symboldict=SymbolTable.Constructor() 10 | rfile = open(filename,'r') 11 | i=0 #i is the sum of the construction numbers above lables 12 | linepre=rfile.readline() 13 | flag=Parser.hasMoreCommands(linepre) 14 | while flag: 15 | #clean the line which starts with // or blank lines 16 | while linepre == '\n' or linepre.startswith('//'): 17 | linepre=rfile.readline() 18 | 19 | if linepre.find('(')>=0: 20 | symbol=linepre.strip('()\n') 21 | if not SymbolTable.contains(symbol,symboldict): 22 | symboldict=SymbolTable.addEntry(symbol,i,symboldict) 23 | else: 24 | i+=1 25 | 26 | linepre=Parser.advance(rfile,linepre) 27 | flag=Parser.hasMoreCommands(linepre) 28 | 29 | rfile.close() 30 | 31 | #The second Loop 32 | j=0 #j records the total number of previous variables 33 | rfile = open(filename,'r') 34 | wfile = open('prog.hack','w') 35 | #main loop 36 | line=rfile.readline() 37 | flag=Parser.hasMoreCommands(line) 38 | while flag: 39 | while line == '\n' or line.startswith('//'): 40 | line=rfile.readline() 41 | 42 | ctype=Parser.commandType(line) 43 | #compare command type 44 | if ctype is 'A_COMMAND': 45 | AS=Parser.symbol(line) 46 | if not AS.isdigit(): 47 | if not SymbolTable.contains(AS,symboldict): 48 | symboldict=SymbolTable.addEntry(AS,j+16,symboldict) 49 | j+=1 50 | binAS=bin(SymbolTable.GetAddress(AS,symboldict))[2:] 51 | else: 52 | binAS=bin(int(AS))[2:] 53 | AString=binAS.zfill(15) 54 | wfile.write('0'+AString+'\n') 55 | 56 | #L_COMMAND should be deleted 57 | 58 | elif ctype is 'C_COMMAND': 59 | DestString=Code.dest(line) 60 | CompString=Code.comp(line) 61 | JumpString=Code.jump(line) 62 | wfile.write('111'+CompString+DestString+JumpString+'\n') 63 | 64 | line=Parser.advance(rfile,line) 65 | flag=Parser.hasMoreCommands(line) 66 | 67 | rfile.close() 68 | wfile.close() -------------------------------------------------------------------------------- /06/symbol/prog.hack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThomasCJY/The_Elements_of_Computing_Systems/27bc467f50e5bdb4b956804d526e59af9745c0f5/06/symbol/prog.hack -------------------------------------------------------------------------------- /07/CodeWriter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import sys,os 3 | import Parser 4 | CODEFLAG1=0 5 | CODEFLAG2=0 6 | 7 | def setFileName(filename): 8 | filetuple=os.path.splitext(filename) 9 | wfile = open(filetuple[0]+'.asm','w') 10 | return wfile 11 | 12 | def writeArithmatic(wfile,command): 13 | global CODEFLAG1,CODEFLAG2 14 | if command == 'add': 15 | wfile.write('@SP\nM=M-1\nA=M\nD=M\n@SP\nM=M-1\nA=M\nM=D+M\n@SP\nM=M+1\n') 16 | elif command == 'sub': 17 | wfile.write('@SP\nM=M-1\nA=M\nD=M\n@SP\nM=M-1\nA=M\nM=M-D\n@SP\nM=M+1\n') 18 | elif command == 'neg': 19 | wfile.write('@SP\nM=M-1\nA=M\nM=-M\n@SP\nM=M+1\n') 20 | elif command == 'and': 21 | wfile.write('@SP\nM=M-1\nA=M\nD=M\n@SP\nM=M-1\nA=M\nM=D&M\n@SP\nM=M+1\n') 22 | elif command == 'or': 23 | wfile.write('@SP\nM=M-1\nA=M\nD=M\n@SP\nM=M-1\nA=M\nM=D|M\n@SP\nM=M+1\n') 24 | elif command == 'not': 25 | wfile.write('@SP\nM=M-1\nA=M\nM=!M\n@SP\nM=M+1\n') 26 | elif command == 'eq': 27 | wfile.write('@SP\nM=M-1\nA=M\nD=M\n@SP\nM=M-1\nA=M\nD=D-M\n@RET_TRUE'+str(CODEFLAG1)+'\ 28 | \nD;JEQ\nD=0\n@CONTINUE'+str(CODEFLAG2)+'\n0;JMP\n(RET_TRUE'+str(CODEFLAG1)+')\nD=-1\ 29 | \n(CONTINUE'+str(CODEFLAG2)+')\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') 30 | CODEFLAG1+=1 31 | CODEFLAG2+=1 32 | elif command == 'gt': 33 | wfile.write('@SP\nM=M-1\nA=M\nD=M\n@SP\nM=M-1\nA=M\nD=M-D\n@RET_TRUE'+str(CODEFLAG1)+'\ 34 | \nD;JGT\nD=0\n@CONTINUE'+str(CODEFLAG2)+'\n0;JMP\n(RET_TRUE'+str(CODEFLAG1)+')\nD=-1\ 35 | \n(CONTINUE'+str(CODEFLAG2)+')\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') 36 | CODEFLAG1+=1 37 | CODEFLAG2+=1 38 | elif command == 'lt': 39 | wfile.write('@SP\nM=M-1\nA=M\nD=M\n@SP\nM=M-1\nA=M\nD=M-D\n@RET_TRUE'+str(CODEFLAG1)+'\ 40 | \nD;JLT\nD=0\n@CONTINUE'+str(CODEFLAG2)+'\n0;JMP\n(RET_TRUE'+str(CODEFLAG1)+')\nD=-1\ 41 | \n(CONTINUE'+str(CODEFLAG2)+')\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') 42 | CODEFLAG1+=1 43 | CODEFLAG2+=1 44 | 45 | 46 | def writePushPop(wfile,command,segment,index): 47 | if command == 'C_PUSH': 48 | if segment == 'constant': 49 | wfile.write('@'+index+'\nD=A\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') 50 | elif segment == 'local': 51 | wfile.write('@LCL\nD=M\n@'+index+'\nA=A+D\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') 52 | elif segment == 'argument': 53 | wfile.write('@ARG\nD=M\n@'+index+'\nA=A+D\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') 54 | elif segment == 'this': 55 | wfile.write('@THIS\nD=M\n@'+index+'\nA=A+D\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') 56 | elif segment == 'that': 57 | wfile.write('@THAT\nD=M\n@'+index+'\nA=A+D\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') 58 | elif segment == 'pointer': 59 | if index == '0': 60 | wfile.write('@3\n') 61 | elif index == '1': 62 | wfile.write('@4\n') 63 | wfile.write('D=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') 64 | elif segment == 'static': 65 | wfile.write('@'+index+'\nD=A\n@16\nD=A+D\nA=D\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') 66 | elif command =='C_POP': 67 | if segment == 'local': 68 | wfile.write('@SP\nM=M-1\nA=M\nD=M\n@LCL\nA=M\n') 69 | for i in range (0,int(index)): 70 | wfile.write('A=A+1\n') 71 | wfile.write('M=D\n') 72 | if segment =='argument': 73 | wfile.write('@SP\nM=M-1\nA=M\nD=M\n@ARG\nA=M\n') 74 | for i in range (0,int(index)): 75 | wfile.write('A=A+1\n') 76 | wfile.write('M=D\n') 77 | if segment == 'this': 78 | wfile.write('@SP\nM=M-1\nA=M\nD=M\n@THIS\nA=M\n') 79 | for i in range (0,int(index)): 80 | wfile.write('A=A+1\n') 81 | wfile.write('M=D\n') 82 | if segment == 'that': 83 | wfile.write('@SP\nM=M-1\nA=M\nD=M\n@THAT\nA=M\n') 84 | for i in range (0,int(index)): 85 | wfile.write('A=A+1\n') 86 | wfile.write('M=D\n') 87 | if segment == 'pointer': 88 | wfile.write('@SP\nM=M-1\nA=M\nD=M\n') 89 | if index == '0': 90 | wfile.write('@3\n') 91 | else: 92 | wfile.write('@4\n') 93 | wfile.write('M=D\n') 94 | if segment == 'static': 95 | wfile.write('@SP\nM=M-1\nA=M\nD=M\n@16\n') 96 | for i in range (0,int(index)): 97 | wfile.write('A=A+1\n') 98 | wfile.write('M=D\n') 99 | 100 | def Close(wfile): 101 | wfile.close() 102 | -------------------------------------------------------------------------------- /07/Parser.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | Arith=('add','sub','neg','eq','gt','lt','and','or','not') 3 | 4 | def hasMoreCommands(line): 5 | if not line: 6 | return 0 7 | else: 8 | return 1 9 | 10 | def advance(rfile): 11 | line=rfile.readline() 12 | return line 13 | 14 | def commandType(line): 15 | if line.find('push')>=0: 16 | return 'C_PUSH' 17 | elif line.find('pop')>=0: 18 | return 'C_POP' 19 | elif line.strip() in Arith: 20 | return 'C_ARITHMATIC' 21 | 22 | def arg1(line): 23 | if commandType(line) is 'C_ARITHMATIC': 24 | return line.strip() 25 | else: 26 | spline=line.split(' ') 27 | return spline[1] 28 | 29 | def arg2(line): 30 | if commandType(line) in ('C_POP','C_PUSH','C_FUNCTION','C_CALL'): 31 | spline=line.split(' ') 32 | return spline[2] 33 | 34 | -------------------------------------------------------------------------------- /07/Vmtranslator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import sys,os 3 | import Parser 4 | import CodeWriter 5 | 6 | filename=sys.argv[1] 7 | rfile = open(filename,'r') 8 | wfile = CodeWriter.setFileName(filename) 9 | wfile.write('@256\nD=A\n@SP\nM=D\n') 10 | line=Parser.advance(rfile) 11 | flag=Parser.hasMoreCommands(line) 12 | while flag: 13 | while line == '\n' or line.startswith('//'): 14 | line=rfile.readline() 15 | ctype=Parser.commandType(line) 16 | if ctype == 'C_ARITHMATIC': 17 | attribute1=Parser.arg1(line).strip() 18 | CodeWriter.writeArithmatic(wfile,attribute1) 19 | elif ctype in ('C_PUSH','C_POP'): 20 | attribute1=Parser.arg1(line).strip() 21 | attribute2=Parser.arg2(line).strip() 22 | CodeWriter.writePushPop(wfile,ctype,attribute1,attribute2) 23 | line=Parser.advance(rfile) 24 | flag=Parser.hasMoreCommands(line) 25 | 26 | rfile.close() 27 | CodeWriter.Close(wfile) -------------------------------------------------------------------------------- /08/CodeWriter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import sys,os 3 | import Parser 4 | CODEFLAG1=0 5 | CODEFLAG2=0 6 | RETURNFLAG=1 7 | 8 | def setFileName(filename): 9 | filetuple=os.path.splitext(filename) 10 | wfile = open(filetuple[0]+'.asm','w') 11 | return wfile 12 | 13 | def writeArithmatic(wfile,command): 14 | global CODEFLAG1,CODEFLAG2 15 | if command == 'add': 16 | wfile.write('@SP\nM=M-1\nA=M\nD=M\n@SP\nM=M-1\nA=M\nM=D+M\n@SP\nM=M+1\n') 17 | elif command == 'sub': 18 | wfile.write('@SP\nM=M-1\nA=M\nD=M\n@SP\nM=M-1\nA=M\nM=M-D\n@SP\nM=M+1\n') 19 | elif command == 'neg': 20 | wfile.write('@SP\nM=M-1\nA=M\nM=-M\n@SP\nM=M+1\n') 21 | elif command == 'and': 22 | wfile.write('@SP\nM=M-1\nA=M\nD=M\n@SP\nM=M-1\nA=M\nM=D&M\n@SP\nM=M+1\n') 23 | elif command == 'or': 24 | wfile.write('@SP\nM=M-1\nA=M\nD=M\n@SP\nM=M-1\nA=M\nM=D|M\n@SP\nM=M+1\n') 25 | elif command == 'not': 26 | wfile.write('@SP\nM=M-1\nA=M\nM=!M\n@SP\nM=M+1\n') 27 | elif command == 'eq': 28 | wfile.write('@SP\nM=M-1\nA=M\nD=M\n@SP\nM=M-1\nA=M\nD=D-M\n@RET_TRUE'+str(CODEFLAG1)+'\ 29 | \nD;JEQ\nD=0\n@CONTINUE'+str(CODEFLAG2)+'\n0;JMP\n(RET_TRUE'+str(CODEFLAG1)+')\nD=-1\ 30 | \n(CONTINUE'+str(CODEFLAG2)+')\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') 31 | CODEFLAG1+=1 32 | CODEFLAG2+=1 33 | elif command == 'gt': 34 | wfile.write('@SP\nM=M-1\nA=M\nD=M\n@SP\nM=M-1\nA=M\nD=M-D\n@RET_TRUE'+str(CODEFLAG1)+'\ 35 | \nD;JGT\nD=0\n@CONTINUE'+str(CODEFLAG2)+'\n0;JMP\n(RET_TRUE'+str(CODEFLAG1)+')\nD=-1\ 36 | \n(CONTINUE'+str(CODEFLAG2)+')\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') 37 | CODEFLAG1+=1 38 | CODEFLAG2+=1 39 | elif command == 'lt': 40 | wfile.write('@SP\nM=M-1\nA=M\nD=M\n@SP\nM=M-1\nA=M\nD=M-D\n@RET_TRUE'+str(CODEFLAG1)+'\ 41 | \nD;JLT\nD=0\n@CONTINUE'+str(CODEFLAG2)+'\n0;JMP\n(RET_TRUE'+str(CODEFLAG1)+')\nD=-1\ 42 | \n(CONTINUE'+str(CODEFLAG2)+')\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') 43 | CODEFLAG1+=1 44 | CODEFLAG2+=1 45 | 46 | 47 | def writePushPop(wfile,command,segment,index,filename): 48 | if command == 'C_PUSH': 49 | if segment == 'constant': 50 | wfile.write('@'+index+'\nD=A\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') 51 | elif segment == 'local': 52 | wfile.write('@LCL\nD=M\n@'+index+'\nA=A+D\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') 53 | elif segment == 'argument': 54 | wfile.write('@ARG\nD=M\n@'+index+'\nA=A+D\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') 55 | elif segment == 'this': 56 | wfile.write('@THIS\nD=M\n@'+index+'\nA=A+D\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') 57 | elif segment == 'that': 58 | wfile.write('@THAT\nD=M\n@'+index+'\nA=A+D\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') 59 | elif segment == 'pointer': 60 | if index == '0': 61 | wfile.write('@3\n') 62 | elif index == '1': 63 | wfile.write('@4\n') 64 | wfile.write('D=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') 65 | elif segment == 'static': 66 | staticname=filename.strip('.vm')+'.'+index 67 | wfile.write('@'+staticname+'\nD=A\nA=D\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n') 68 | elif command =='C_POP': 69 | if segment == 'local': 70 | wfile.write('@SP\nM=M-1\nA=M\nD=M\n@LCL\nA=M\n') 71 | for i in range (0,int(index)): 72 | wfile.write('A=A+1\n') 73 | wfile.write('M=D\n') 74 | if segment =='argument': 75 | wfile.write('@SP\nM=M-1\nA=M\nD=M\n@ARG\nA=M\n') 76 | for i in range (0,int(index)): 77 | wfile.write('A=A+1\n') 78 | wfile.write('M=D\n') 79 | if segment == 'this': 80 | wfile.write('@SP\nM=M-1\nA=M\nD=M\n@THIS\nA=M\n') 81 | for i in range (0,int(index)): 82 | wfile.write('A=A+1\n') 83 | wfile.write('M=D\n') 84 | if segment == 'that': 85 | wfile.write('@SP\nM=M-1\nA=M\nD=M\n@THAT\nA=M\n') 86 | for i in range (0,int(index)): 87 | wfile.write('A=A+1\n') 88 | wfile.write('M=D\n') 89 | if segment == 'pointer': 90 | wfile.write('@SP\nM=M-1\nA=M\nD=M\n') 91 | if index == '0': 92 | wfile.write('@3\n') 93 | else: 94 | wfile.write('@4\n') 95 | wfile.write('M=D\n') 96 | if segment == 'static': 97 | staticname=filename.strip('.vm')+'.'+index 98 | wfile.write('@SP\nM=M-1\nA=M\nD=M\n@'+staticname+'\nM=D\n') 99 | if segment == 'temp': 100 | wfile.write('@SP\nM=M-1\nA=M\nD=M\n@R5\n') 101 | for i in range (0,int(index)): 102 | wfile.write('A=A+1\n') 103 | wfile.write('M=D\n') 104 | 105 | def writeLabel(wfile,labelstring): 106 | wfile.write('('+labelstring+')\n') 107 | 108 | def writeGoto(wfile,labelstring): 109 | wfile.write('@'+labelstring+'\n0;JMP\n') 110 | 111 | def writeIf(wfile,labelstring): 112 | wfile.write('@SP\nM=M-1\nA=M\nD=M\n@'+labelstring+'\nD;JNE\n') 113 | 114 | def writeFunction(wfile,functionName,numlocals): 115 | wfile.write('('+functionName+')\n@LCL\nD=M\n@SP\nM=D\n') 116 | for i in range(0,int(numlocals)): 117 | wfile.write('@SP\nA=M\nM=0\nD=A+1\n@SP\nM=D\n') 118 | 119 | def writeCall(wfile,functionName,numArgs): 120 | global RETURNFLAG 121 | wfile.write('@return_address'+str(RETURNFLAG)+'\nD=A\n@SP\nA=M\nM=D\n@SP\nM=M+1\ 122 | \n@LCL\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n@ARG\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\ 123 | \n@THIS\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n@THAT\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\ 124 | \n@'+numArgs+'\nD=A\n@5\nD=D+A\n@SP\nD=M-D\n@ARG\nM=D\n@SP\nD=M\n@LCL\nM=D\ 125 | \n@'+functionName+'\n0;JMP\n(return_address'+str(RETURNFLAG)+')\n') 126 | RETURNFLAG+=1 127 | 128 | def writeReturn(wfile): 129 | wfile.write('@LCL\nD=M\n@R13\nM=D\n@5\nD=D-A\nA=D\nD=M\ 130 | \n@R14\nM=D\n@SP\nM=M-1\nA=M\nD=M\n@ARG\nA=M\ 131 | \nM=D\n@ARG\nD=M+1\n@SP\nM=D\n@R13\nD=M\nD=D-1\ 132 | \nA=D\nD=M\n@THAT\nM=D\n@R13\nD=M\nD=D-1\nD=D-1\ 133 | \nA=D\nD=M\n@THIS\nM=D\n@R13\nD=M\nD=D-1\nD=D-1\ 134 | \nD=D-1\nA=D\nD=M\n@ARG\nM=D\n@R13\nD=M\nD=D-1\ 135 | \nD=D-1\nD=D-1\nD=D-1\nA=D\nD=M\n@LCL\nM=D\n@R14\nA=M\n0;JMP\n') 136 | 137 | 138 | def Close(wfile): 139 | wfile.close() 140 | -------------------------------------------------------------------------------- /08/Parser.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | Arith=('add','sub','neg','eq','gt','lt','and','or','not') 3 | 4 | def hasMoreCommands(line): 5 | if not line: 6 | return 0 7 | else: 8 | return 1 9 | 10 | def advance(rfile): 11 | line=rfile.readline() 12 | return line 13 | 14 | def commandType(line): 15 | if line.find('push')>=0: 16 | return 'C_PUSH' 17 | elif line.find('pop')>=0: 18 | return 'C_POP' 19 | elif line.startswith('label'): 20 | return 'C_LABEL' 21 | elif line.startswith('goto'): 22 | return 'C_GOTO' 23 | elif line.startswith('if-goto'): 24 | return 'C_IF' 25 | elif line.strip() in Arith: 26 | return 'C_ARITHMATIC' 27 | elif line.startswith('function'): 28 | return 'C_FUNCTION' 29 | elif line.startswith('return'): 30 | return 'C_RETURN' 31 | elif line.startswith('call'): 32 | return 'C_CALL' 33 | 34 | def arg1(line): 35 | if commandType(line) is 'C_ARITHMATIC': 36 | return line.strip() 37 | else: 38 | spline=line.split(' ') 39 | return spline[1] 40 | 41 | def arg2(line): 42 | if commandType(line) in ('C_POP','C_PUSH','C_FUNCTION','C_CALL'): 43 | spline=line.split(' ') 44 | return spline[2] 45 | 46 | -------------------------------------------------------------------------------- /08/Vmtranslator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import sys,os 3 | import Parser 4 | import CodeWriter 5 | DELETEFLAG=0 6 | 7 | def Main(rfile,wfile,filename): 8 | line=Parser.advance(rfile) 9 | flag=Parser.hasMoreCommands(line) 10 | while flag: 11 | while line == '\n' or line.startswith('//'): 12 | line=rfile.readline() 13 | if '//' in line: 14 | line=line[:line.find('//')] 15 | ctype=Parser.commandType(line) 16 | if ctype == 'C_ARITHMATIC': 17 | attribute1=Parser.arg1(line).strip() 18 | CodeWriter.writeArithmatic(wfile,attribute1) 19 | elif ctype in ('C_PUSH','C_POP'): 20 | attribute1=Parser.arg1(line).strip() 21 | attribute2=Parser.arg2(line).strip() 22 | CodeWriter.writePushPop(wfile,ctype,attribute1,attribute2,filename) 23 | elif ctype =='C_LABEL': 24 | attribute1=Parser.arg1(line).strip() 25 | CodeWriter.writeLabel(wfile,attribute1) 26 | elif ctype =='C_GOTO': 27 | attribute1=Parser.arg1(line).strip() 28 | CodeWriter.writeGoto(wfile,attribute1) 29 | elif ctype =='C_IF': 30 | attribute1=Parser.arg1(line).strip() 31 | CodeWriter.writeIf(wfile,attribute1) 32 | elif ctype =='C_FUNCTION': 33 | attribute1=Parser.arg1(line).strip() 34 | attribute2=Parser.arg2(line).strip() 35 | CodeWriter.writeFunction(wfile,attribute1,attribute2) 36 | elif ctype =='C_RETURN': 37 | CodeWriter.writeReturn(wfile) 38 | elif ctype =='C_CALL': 39 | attribute1=Parser.arg1(line).strip() 40 | attribute2=Parser.arg2(line).strip() 41 | CodeWriter.writeCall(wfile,attribute1,attribute2) 42 | line=Parser.advance(rfile) 43 | flag=Parser.hasMoreCommands(line) 44 | 45 | 46 | 47 | 48 | 49 | filename=sys.argv[1] 50 | #if filename exists in the dir, open the file directly 51 | if os.path.isfile(filename): 52 | rfile = open(filename,'r') 53 | wfile = CodeWriter.setFileName(filename) 54 | wfile.write('@256\nD=A\n@SP\nM=D\n') 55 | Main(rfile,wfile,filename) 56 | #if filename doesn't exist, find all the .vm files 57 | elif os.path.isfile('Sys.vm'): 58 | wfile = CodeWriter.setFileName(filename) 59 | wfile.write('@256\nD=A\n@SP\nM=D\n') 60 | wfile.write('@return_address0\nD=A\n@SP\nA=M\nM=D\n@SP\nM=M+1\ 61 | \n@LCL\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n@ARG\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\ 62 | \n@THIS\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n@THAT\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\ 63 | \n@0\nD=A\n@5\nD=D+A\n@SP\nD=M-D\n@ARG\nM=D\n@SP\nD=M\n@LCL\nM=D\ 64 | \n@Sys.init\n0;JMP\n(return_address0)\n') 65 | #check all the files in the dir 66 | for i in os.walk(os.getcwd()): 67 | filelist=i[2] 68 | for j in range(0,len(filelist)): 69 | if filelist[j].endswith('.vm'): 70 | #readfile, copy to the end 71 | filename=filelist[j] 72 | rfile = open(filename,'r') 73 | Main(rfile,wfile,filename) 74 | DELETEFLAG=1 75 | else: 76 | print 'Wrong Instruction!' 77 | exit() 78 | 79 | rfile.close() 80 | CodeWriter.Close(wfile) 81 | 82 | if DELETEFLAG == 1: 83 | os.remove(filename) 84 | 85 | 86 | -------------------------------------------------------------------------------- /10/CompilationEngine.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import JackTokenizer 3 | 4 | class Compile(): 5 | def __init__(self,rfile,wfile): 6 | self.rfile=rfile 7 | self.wfile=wfile 8 | self.tokenizer=JackTokenizer.Tokenizer(self.rfile) 9 | 10 | def writeXmlTag(self,token): 11 | self.wfile.write(token) 12 | 13 | def writeXml(self,tType,token): 14 | if tType == 'symbol': 15 | if self.tokenizer.token=='>': 16 | self.writeXmlTag('<'+tType+'> '+'>'+' \n') 17 | elif self.tokenizer.token=='<': 18 | self.writeXmlTag('<'+tType+'> '+'<'+' \n') 19 | elif self.tokenizer.token=='&': 20 | self.writeXmlTag('<'+tType+'> '+'&'+' \n') 21 | else: 22 | self.writeXmlTag('<'+tType+'> '+token+' \n') 23 | else: 24 | self.writeXmlTag('<'+tType+'> '+token+' \n') 25 | 26 | def NextToken(self): 27 | if self.tokenizer.hasMoreTokens(): 28 | self.tokenizer.advance() 29 | else: 30 | pass 31 | 32 | def moveBack(self): 33 | lennum=-len(self.tokenizer.token) 34 | self.rfile.seek(lennum,1) 35 | 36 | def compileType(self): 37 | tType=self.tokenizer.tokenType() 38 | if tType == 'KEYWORD': 39 | self.writeXml('keyword',self.tokenizer.token) 40 | elif tType == 'SYMBOL': 41 | if self.tokenizer.token=='>': 42 | self.writeXml('symbol','>') 43 | elif self.tokenizer.token=='<': 44 | self.writeXml('symbol','<') 45 | elif self.tokenizer.token=='&': 46 | self.writeXml('symbol','&') 47 | else: 48 | self.writeXml('symbol',self.tokenizer.token) 49 | elif tType == 'IDENTIFIER': 50 | self.writeXml('identifier',self.tokenizer.token) 51 | elif tType == 'INT_CONSTANT': 52 | self.writeXml('integerConstant',self.tokenizer.token) 53 | elif tType == 'STRING_CONSTANT': 54 | self.writeXml('stringConstant',self.tokenizer.token.strip('"')) 55 | 56 | def compileVarDec(self): 57 | ''' 58 | var type varName(,'varName')*; 59 | ''' 60 | self.writeXmlTag('\n') 61 | self.writeXml('keyword','var') 62 | #type 63 | self.NextToken() 64 | self.compileType() 65 | #varName 66 | self.NextToken() 67 | self.writeXml('identifier',self.tokenizer.token) 68 | #(,varName)* 69 | self.NextToken() 70 | while self.tokenizer.token != ';': 71 | self.writeXml('symbol',self.tokenizer.token) 72 | self.NextToken() 73 | self.writeXml('identifier',self.tokenizer.token) 74 | self.NextToken() 75 | self.writeXml('symbol',self.tokenizer.token) 76 | self.writeXmlTag('\n') 77 | 78 | def compileParameterList(self): 79 | ''' 80 | ((type varName)(, type varName)*)? 81 | ''' 82 | self.writeXmlTag('\n') 83 | self.NextToken() 84 | while self.tokenizer.token != ')': 85 | if self.tokenizer.token != ',': 86 | self.compileType() 87 | self.NextToken() 88 | self.writeXml('identifier',self.tokenizer.token) 89 | self.NextToken() 90 | else: 91 | self.writeXml('symbol',self.tokenizer.token) 92 | self.NextToken() 93 | self.compileType() 94 | self.NextToken() 95 | self.writeXml('identifier',self.tokenizer.token) 96 | self.NextToken() 97 | self.writeXmlTag('/\n') 98 | 99 | def compileClassVarDec(self): 100 | ''' 101 | ('static'|'field') type varName(, varName)*; 102 | ''' 103 | self.writeXmlTag('\n') 104 | self.writeXml('keyword',self.tokenizer.token) 105 | self.NextToken() 106 | self.compileType() 107 | #varName 108 | self.NextToken() 109 | self.writeXml('identifier',self.tokenizer.token) 110 | #(,varName)* 111 | self.NextToken() 112 | while self.tokenizer.token != ';': 113 | self.writeXml('symbol',self.tokenizer.token) 114 | self.NextToken() 115 | self.writeXml('identifier',self.tokenizer.token) 116 | self.NextToken() 117 | self.writeXml('symbol',self.tokenizer.token) 118 | self.writeXmlTag('\n') 119 | 120 | def compileTerm(self): 121 | self.writeXmlTag('\n') 122 | self.NextToken() 123 | tType=self.tokenizer.tokenType() 124 | if tType == 'IDENTIFIER': 125 | temp=self.rfile.read(1) 126 | if temp=='.': 127 | lennum=-len(self.tokenizer.token)-1 128 | self.rfile.seek(lennum,1) 129 | self.subroutinCall() 130 | elif temp=='[': 131 | self.writeXml('identifier',self.tokenizer.token) 132 | self.writeXml('symbol','[') 133 | self.compileExpression() 134 | self.writeXml('symbol',']') 135 | else: 136 | self.rfile.seek(-1,1) 137 | self.writeXml('identifier',self.tokenizer.token) 138 | elif self.tokenizer.token in ('-','~'): 139 | self.writeXml('symbol',self.tokenizer.token) 140 | self.compileTerm() 141 | elif self.tokenizer.token == '(': 142 | self.writeXml('symbol',self.tokenizer.token) 143 | self.compileExpression() 144 | self.writeXml('symbol',')') 145 | else: 146 | self.compileType() 147 | self.writeXmlTag('\n') 148 | 149 | def compileExpression(self): 150 | ''' 151 | term (op term)* 152 | ''' 153 | self.writeXmlTag('\n') 154 | self.compileTerm() 155 | self.NextToken() 156 | while (self.tokenizer.tokenType() == 'SYMBOL' and \ 157 | self.tokenizer.Symbol() in '+-*/&|<>='): 158 | 159 | self.writeXml('symbol', self.tokenizer.token) 160 | self.compileTerm() 161 | self.NextToken() 162 | 163 | self.writeXmlTag('\n') 164 | 165 | def compileExpressionList(self): 166 | self.writeXmlTag('\n') 167 | self.NextToken() 168 | while self.tokenizer.token != ')': 169 | if self.tokenizer.token != ',': 170 | self.moveBack() 171 | self.compileExpression() 172 | else: 173 | self.writeXml('symbol',self.tokenizer.token) 174 | self.compileExpression() 175 | self.writeXmlTag('\n') 176 | 177 | def subroutinCall(self): 178 | self.NextToken() 179 | self.writeXml('identifier',self.tokenizer.token) 180 | self.NextToken() 181 | if self.tokenizer.token=='.': 182 | self.writeXml('symbol',self.tokenizer.token) 183 | self.NextToken() 184 | self.writeXml('identifier',self.tokenizer.token) 185 | self.rfile.read(1) 186 | self.writeXml('symbol','(') 187 | self.compileExpressionList() 188 | self.writeXml('symbol',')') 189 | elif self.tokenizer.token=='(': 190 | self.writeXml('symbol','(') 191 | self.compileExpressionList() 192 | self.writeXml('symbol',')') 193 | 194 | def compileDo(self): 195 | self.writeXmlTag('\n') 196 | self.writeXml('keyword',self.tokenizer.token) 197 | self.subroutinCall() 198 | self.NextToken() 199 | self.writeXml('symbol',self.tokenizer.token) 200 | self.writeXmlTag('\n') 201 | 202 | def compileLet(self): 203 | self.writeXmlTag('\n') 204 | self.writeXml('keyword',self.tokenizer.token) 205 | self.NextToken() 206 | self.writeXml('identifier',self.tokenizer.token) 207 | self.NextToken() 208 | temp=self.tokenizer.token 209 | if temp=='[': 210 | self.writeXml('symbol',self.tokenizer.token) 211 | self.compileExpression() 212 | self.writeXml('symbol',']') 213 | self.NextToken() 214 | self.writeXml('symbol',self.tokenizer.token) 215 | elif temp == '=': 216 | self.writeXml('symbol',self.tokenizer.token) 217 | self.compileExpression() 218 | self.writeXml('symbol',';') 219 | self.writeXmlTag('\n') 220 | 221 | def compileWhile(self): 222 | self.writeXmlTag('\n') 223 | self.writeXml('keyword',self.tokenizer.token) 224 | #(expression) 225 | self.NextToken() 226 | self.writeXml('symbol',self.tokenizer.token) 227 | self.compileExpression() 228 | self.writeXml('symbol',')') 229 | #{statements} 230 | self.NextToken() 231 | self.writeXml('symbol',self.tokenizer.token) 232 | self.compileStatements() 233 | self.writeXml('symbol',self.tokenizer.token) 234 | self.writeXmlTag('\n') 235 | 236 | def compileReturn(self): 237 | self.writeXmlTag('\n') 238 | self.writeXml('keyword',self.tokenizer.token) 239 | #expression? 240 | self.NextToken() 241 | if self.tokenizer.token == ';': 242 | self.writeXml('symbol',self.tokenizer.token) 243 | else: 244 | self.moveBack() 245 | self.compileExpression() 246 | self.writeXml('symbol',';') 247 | self.writeXmlTag('\n') 248 | 249 | def compileStatements(self): 250 | self.writeXmlTag('\n') 251 | self.NextToken() 252 | while self.tokenizer.token != '}': 253 | if self.tokenizer.token =='let': 254 | self.compileLet() 255 | elif self.tokenizer.token == 'if': 256 | self.compileIf() 257 | elif self.tokenizer.token == 'while': 258 | self.compileWhile() 259 | elif self.tokenizer.token == 'do': 260 | self.compileDo() 261 | elif self.tokenizer.token == 'return': 262 | self.compileReturn() 263 | else: 264 | print 'Error!'+token 265 | exit() 266 | self.NextToken() 267 | self.writeXmlTag('\n') 268 | 269 | def compileIf(self): 270 | self.writeXmlTag('\n') 271 | self.writeXml('keyword',self.tokenizer.token) 272 | #(expression) 273 | self.NextToken() 274 | self.writeXml('symbol',self.tokenizer.token) 275 | self.compileExpression() 276 | self.writeXml('symbol',')') 277 | #{statements} 278 | self.NextToken() 279 | self.writeXml('symbol',self.tokenizer.token) 280 | self.compileStatements() 281 | self.writeXml('symbol',self.tokenizer.token) 282 | #(else {statements})? 283 | self.NextToken() 284 | if self.tokenizer.token=='else': 285 | self.writeXml('keyword',self.tokenizer.token) 286 | self.NextToken() 287 | self.writeXml('symbol',self.tokenizer.token) 288 | self.compileStatements() 289 | self.writeXml('symbol',self.tokenizer.token) 290 | else: 291 | self.moveBack() 292 | self.writeXmlTag('\n') 293 | 294 | def compileClass(self): 295 | self.writeXmlTag('\n') 296 | self.NextToken() 297 | self.writeXml('keyword',self.tokenizer.token) 298 | self.NextToken() 299 | self.writeXml('identifier',self.tokenizer.token) 300 | self.NextToken() 301 | self.writeXml('keyword',self.tokenizer.token) 302 | #classVarDec* 303 | self.NextToken() 304 | while self.tokenizer.token in ('static','field'): 305 | self.compileClassVarDec() 306 | self.NextToken() 307 | #subroutineDec* 308 | while self.tokenizer.token in ('constructor','function','method'): 309 | self.compileSubroutine() 310 | self.NextToken() 311 | self.writeXml('symbol',self.tokenizer.token) 312 | self.writeXmlTag('\n') 313 | 314 | def compileSubroutine(self): 315 | self.writeXmlTag('\n') 316 | self.writeXml('keyword',self.tokenizer.token) 317 | #(void|type) subroutineName (parameterList) 318 | self.NextToken() 319 | self.compileType() 320 | self.NextToken() 321 | self.writeXml('identifier',self.tokenizer.token) 322 | self.NextToken() 323 | self.writeXml('symbol',self.tokenizer.token) 324 | self.compileParameterList() 325 | self.writeXml('symbol',self.tokenizer.token) 326 | #subroutinBody 327 | self.compileSubroutineBody() 328 | self.writeXmlTag('\n') 329 | 330 | def compileSubroutineBody(self): 331 | self.writeXmlTag('\n') 332 | #{varDec* statements} 333 | self.NextToken() 334 | self.writeXml('symbol',self.tokenizer.token) 335 | self.NextToken() 336 | while self.tokenizer.token == 'var': 337 | self.compileVarDec() 338 | self.NextToken() 339 | self.moveBack() 340 | self.compileStatements() 341 | self.writeXml('symbol',self.tokenizer.token) 342 | self.writeXmlTag('\n') -------------------------------------------------------------------------------- /10/JackAnalyzer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import JackTokenizer 3 | import CompilationEngine 4 | import sys,os 5 | 6 | filename=sys.argv[1] 7 | readfile = open(filename,'r') 8 | 9 | #clear all the // /* ... notes, create a new file to save the result 10 | copyfile = open('copyfile','w') 11 | line=readfile.readline() 12 | while line: 13 | while line == '\n' or line.startswith('//'): 14 | line=readfile.readline() 15 | if '//' in line: 16 | line=line[:line.find('//')] 17 | if '/*' in line: 18 | aline=line[:line.find('/*')] 19 | while line.find('*/')<0: 20 | line=readfile.readline() 21 | bline=line[line.find('*/')+2:] 22 | line=aline+bline 23 | copyfile.write(line) 24 | line=readfile.readline() 25 | copyfile.close() 26 | readfile.close() 27 | 28 | rfile=open('copyfile','r') 29 | wfile=open(filename.strip('.jack')+'.xml','w') 30 | 31 | outputCompile=CompilationEngine.Compile(rfile,wfile) 32 | outputCompile.compileClass() 33 | 34 | rfile.close() 35 | wfile.close() 36 | os.remove('copyfile') -------------------------------------------------------------------------------- /10/JackTokenizer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | STable=('{','}','(',')','[',']','.',',',';','+','-','*','/','&','|','<','>','=','~') 3 | KWtable=('class','constructor','function','method','field','static','var','int','char','boolean',\ 4 | 'void','true','false','null','this','let','do','if','else','while','return') 5 | 6 | class Tokenizer(): 7 | def __init__(self,rfile): 8 | self.rfile=rfile 9 | self.token='' 10 | 11 | def hasMoreTokens(self): 12 | temp=self.rfile.read(1) 13 | while temp in ' \n\t' and temp != '': 14 | temp=self.rfile.read(1) 15 | if not temp: 16 | return 0 17 | else: 18 | self.rfile.seek(-1,1) 19 | return 1 20 | 21 | def advance(self): 22 | self.token='' 23 | temp=self.rfile.read(1) 24 | 25 | if temp.isalpha() or temp.isdigit() or temp == '_': 26 | while temp.isalpha() or temp.isdigit() or temp == '_': 27 | self.token+=temp 28 | temp=self.rfile.read(1) 29 | if temp in STable or temp =='"': 30 | self.rfile.seek(-1,1) 31 | elif temp == ' ' or temp == '\n': 32 | self.rfile.seek(-1,1) 33 | elif temp in STable: 34 | self.token=temp 35 | elif temp =='"': 36 | self.token += '"' 37 | temp=self.rfile.read(1) 38 | while temp != '"': 39 | self.token+=temp 40 | temp=self.rfile.read(1) 41 | self.token+='"' 42 | 43 | def tokenType(self): 44 | if self.token in KWtable: 45 | return 'KEYWORD' 46 | elif self.token in STable: 47 | return 'SYMBOL' 48 | elif self.token.isdigit(): 49 | return 'INT_CONSTANT' 50 | elif self.token.startswith('"'): 51 | return 'STRING_CONSTANT' 52 | else: 53 | return 'IDENTIFIER' 54 | 55 | def Keyword(self): 56 | return self.token 57 | 58 | def Symbol(self): 59 | return self.token 60 | 61 | def Identifier(self): 62 | return self.token 63 | 64 | def intVal(self): 65 | return int(self.token) 66 | 67 | def stringVal(self): 68 | return self.token -------------------------------------------------------------------------------- /11/CompilationEngine.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import JackTokenizer 3 | import SymbolTable 4 | import VMWriter 5 | 6 | class Compile(): 7 | def __init__(self,rfile,wfile,wVmFile): 8 | self.rfile=rfile 9 | self.wfile=wfile #Write XML file 10 | self.vmWriter=VMWriter.VMwriter(wVmFile) #Write VM file 11 | self.tokenizer=JackTokenizer.Tokenizer(self.rfile) 12 | self.class_symbol=SymbolTable.SymbolTable() 13 | self.sub_symbol=SymbolTable.SymbolTable() 14 | self.Stype='' #Stype records the type of the identifier. 15 | self.Skind='' 16 | #ClassName records the name of the class, used to make the sub_functionName 17 | self.ClassName='' 18 | self.expressionListNum=0 #Record the number of expression in ExpressionList. 19 | self.WHILEFLAG=0 #the index of while_loop in case of tautonomy 20 | self.IFFLAG=0 21 | 22 | 23 | def writeXmlTag(self,token): 24 | self.wfile.write(token) 25 | 26 | def writeXml(self,tType,token): 27 | if tType == 'symbol': 28 | if self.tokenizer.token=='>': 29 | self.writeXmlTag('<'+tType+'> '+'>'+' \n') 30 | elif self.tokenizer.token=='<': 31 | self.writeXmlTag('<'+tType+'> '+'<'+' \n') 32 | elif self.tokenizer.token=='&': 33 | self.writeXmlTag('<'+tType+'> '+'&'+' \n') 34 | else: 35 | self.writeXmlTag('<'+tType+'> '+token+' \n') 36 | else: 37 | self.writeXmlTag('<'+tType+'> '+token+' \n') 38 | 39 | def NextToken(self): 40 | if self.tokenizer.hasMoreTokens(): 41 | self.tokenizer.advance() 42 | 43 | def moveBack(self): 44 | #Move back to the last token. 45 | lennum=-len(self.tokenizer.token) 46 | self.rfile.seek(lennum,1) 47 | 48 | def writeArrayPush(self,symbolName): 49 | #This function is used in 'Push' Array Terms. 50 | SubTag=self.sub_symbol.FoundName(symbolName) 51 | if SubTag==-1: 52 | ClassTag=self.class_symbol.FoundName(symbolName) 53 | if ClassTag==-1: 54 | print 'Error Term!' 55 | exit() 56 | else: 57 | self.vmWriter.writePush('this',self.class_symbol.Scope[ClassTag][3]) 58 | else: 59 | KINDFLAG=self.sub_symbol.Scope[SubTag][2] 60 | self.vmWriter.writePush(KINDFLAG,self.sub_symbol.Scope[SubTag][3]) 61 | 62 | def defineSymbol(self,symbolName,_symbol): 63 | #This function adds symbolName into SymbolTable. 64 | _symbol.Define(symbolName,self.Stype,self.Skind) 65 | 66 | def checkSymbol(self,symbolName): 67 | #Check the index of the Identifier 68 | SubTag=self.sub_symbol.FoundName(symbolName) 69 | if SubTag==-1: 70 | ClassTag=self.class_symbol.FoundName(symbolName) 71 | if ClassTag==-1: 72 | return -1 73 | else: 74 | return self.class_symbol.Scope[ClassTag] 75 | else: 76 | return self.sub_symbol.Scope[SubTag] 77 | 78 | def compileType(self): 79 | tType=self.tokenizer.tokenType() 80 | if tType == 'KEYWORD': 81 | self.Stype=self.tokenizer.token 82 | self.writeXml('keyword',self.tokenizer.token) 83 | elif tType == 'IDENTIFIER': 84 | self.Stype=self.tokenizer.token 85 | self.writeXml('identifier',self.tokenizer.token) 86 | 87 | def compileTermType(self): 88 | tType=self.tokenizer.tokenType() 89 | if tType == 'KEYWORD': 90 | kWord=self.tokenizer.token 91 | if kWord=='true': 92 | self.vmWriter.writePush('constant',1) 93 | self.vmWriter.writeArithmetic('neg') 94 | elif kWord=='false' or kWord=='null': 95 | self.vmWriter.writePush('constant',0) 96 | elif kWord=='this': 97 | self.vmWriter.writePush('pointer',0) 98 | self.writeXml('keyword',self.tokenizer.token) 99 | elif tType == 'INT_CONSTANT': 100 | self.writeXml('integerConstant',self.tokenizer.token) 101 | self.vmWriter.writePush('constant',int(self.tokenizer.token)) 102 | elif tType == 'STRING_CONSTANT': 103 | string_copy=self.tokenizer.token.strip('"') 104 | self.writeXml('stringConstant',string_copy) 105 | string_length=len(string_copy) 106 | self.vmWriter.writePush('constant',string_length) 107 | self.vmWriter.writeCall('String.new',1) 108 | for i in range(0,string_length): 109 | self.vmWriter.writePush('constant',ord(string_copy[i])) 110 | self.vmWriter.writeCall('String.appendChar',2) 111 | 112 | def compileVarDec(self): 113 | ''' 114 | var type varName(,'varName')*; 115 | ''' 116 | self.writeXmlTag('\n') 117 | self.writeXml('keyword','var') 118 | self.Skind='var' 119 | #type 120 | self.NextToken() 121 | self.compileType() 122 | #varName 123 | self.NextToken() 124 | self.writeXml('identifier',self.tokenizer.token) 125 | self.defineSymbol(self.tokenizer.token,self.sub_symbol) 126 | #(,varName)* 127 | self.NextToken() 128 | while self.tokenizer.token != ';': 129 | self.writeXml('symbol',self.tokenizer.token) 130 | self.NextToken() 131 | self.writeXml('identifier',self.tokenizer.token) 132 | self.defineSymbol(self.tokenizer.token,self.sub_symbol) 133 | self.NextToken() 134 | self.writeXml('symbol',self.tokenizer.token) 135 | self.writeXmlTag('\n') 136 | 137 | def compileParameterList(self): 138 | ''' 139 | ((type varName)(, type varName)*)? 140 | ''' 141 | self.writeXmlTag('\n') 142 | self.NextToken() 143 | while self.tokenizer.token != ')': 144 | self.Skind='argument' 145 | if self.tokenizer.token != ',': 146 | self.compileType() 147 | self.NextToken() 148 | self.writeXml('identifier',self.tokenizer.token) 149 | self.defineSymbol(self.tokenizer.token,self.sub_symbol) 150 | self.NextToken() 151 | else: 152 | self.writeXml('symbol',self.tokenizer.token) 153 | self.NextToken() 154 | self.compileType() 155 | self.NextToken() 156 | self.writeXml('identifier',self.tokenizer.token) 157 | self.defineSymbol(self.tokenizer.token,self.sub_symbol) 158 | self.NextToken() 159 | self.writeXmlTag('\n') 160 | 161 | def compileClassVarDec(self): 162 | ''' 163 | ('static'|'field') type varName(, varName)*; 164 | ''' 165 | self.writeXmlTag('\n') 166 | self.writeXml('keyword',self.tokenizer.token) 167 | self.Skind=self.tokenizer.token 168 | 169 | self.NextToken() 170 | self.compileType() 171 | #varName 172 | self.NextToken() 173 | self.writeXml('identifier',self.tokenizer.token) 174 | self.defineSymbol(self.tokenizer.token,self.class_symbol) 175 | #(,varName)* 176 | self.NextToken() 177 | while self.tokenizer.token != ';': 178 | self.writeXml('symbol',self.tokenizer.token) 179 | self.NextToken() 180 | self.writeXml('identifier',self.tokenizer.token) 181 | self.defineSymbol(self.tokenizer.token,self.class_symbol) 182 | self.NextToken() 183 | self.writeXml('symbol',self.tokenizer.token) 184 | self.writeXmlTag('\n') 185 | 186 | def compileTerm(self): 187 | self.writeXmlTag('\n') 188 | self.NextToken() 189 | tType=self.tokenizer.tokenType() 190 | if tType == 'IDENTIFIER': 191 | temp=self.rfile.read(1) 192 | if temp=='.': 193 | lennum=-len(self.tokenizer.token)-1 194 | self.rfile.seek(lennum,1) 195 | self.subroutineCall() 196 | elif temp=='[': 197 | self.writeXml('identifier',self.tokenizer.token) 198 | self.writeArrayPush(self.tokenizer.token) 199 | self.writeXml('symbol','[') 200 | self.compileExpression() 201 | self.vmWriter.writeArithmetic('add') 202 | self.vmWriter.writePop('pointer',1) 203 | self.vmWriter.writePush('that',0) 204 | self.writeXml('symbol',']') 205 | else: 206 | self.rfile.seek(-1,1) 207 | self.writeXml('identifier',self.tokenizer.token) 208 | ListSeg=self.checkSymbol(self.tokenizer.token) 209 | self.vmWriter.writePush(ListSeg[2],ListSeg[3]) 210 | elif self.tokenizer.token in ('-','~'): 211 | UnaryOp=self.tokenizer.token 212 | self.writeXml('symbol',self.tokenizer.token) 213 | self.compileTerm() 214 | if UnaryOp == '-': 215 | self.vmWriter.writeArithmetic('neg') 216 | else: 217 | self.vmWriter.writeArithmetic('not') 218 | elif self.tokenizer.token == '(': 219 | self.writeXml('symbol',self.tokenizer.token) 220 | self.compileExpression() 221 | self.writeXml('symbol',')') 222 | else: 223 | self.compileTermType() 224 | self.writeXmlTag('\n') 225 | 226 | def compileExpression(self): 227 | ''' 228 | term (op term)* 229 | ''' 230 | self.writeXmlTag('\n') 231 | self.compileTerm() 232 | self.NextToken() 233 | while (self.tokenizer.tokenType() == 'SYMBOL' and \ 234 | self.tokenizer.Symbol() in '+-*/&|<>='): 235 | operator = self.tokenizer.Symbol() 236 | self.writeXml('symbol', self.tokenizer.token) 237 | self.compileTerm() 238 | if operator == '+': 239 | self.vmWriter.writeArithmetic('add') 240 | elif operator == '-': 241 | self.vmWriter.writeArithmetic('sub') 242 | elif operator == '*': 243 | self.vmWriter.writeCall('Math.multiply', 2) 244 | elif operator == '/': 245 | self.vmWriter.writeCall('Math.divide', 2) 246 | elif operator == '&': 247 | self.vmWriter.writeArithmetic('and') 248 | elif operator == '|': 249 | self.vmWriter.writeArithmetic('or') 250 | elif operator == '<': 251 | self.vmWriter.writeArithmetic('lt') 252 | elif operator == '>': 253 | self.vmWriter.writeArithmetic('gt') 254 | elif operator == '=': 255 | self.vmWriter.writeArithmetic('eq') 256 | self.NextToken() 257 | 258 | self.writeXmlTag('\n') 259 | 260 | def compileExpressionList(self): 261 | self.writeXmlTag('\n') 262 | self.expressionListNum=0 263 | self.NextToken() 264 | while self.tokenizer.token != ')': 265 | if self.tokenizer.token != ',': 266 | self.moveBack() 267 | self.compileExpression() 268 | self.expressionListNum+=1 269 | else: 270 | self.writeXml('symbol',self.tokenizer.token) 271 | self.compileExpression() 272 | self.expressionListNum+=1 273 | self.writeXmlTag('\n') 274 | 275 | def subroutineCall(self): 276 | sub_MethodFlag=False 277 | self.NextToken() 278 | self.writeXml('identifier',self.tokenizer.token) 279 | sub_className=self.tokenizer.token 280 | self.NextToken() 281 | if self.tokenizer.token=='.': 282 | self.writeXml('symbol',self.tokenizer.token) 283 | self.NextToken() 284 | self.writeXml('identifier',self.tokenizer.token) 285 | sub_funcName=self.tokenizer.token 286 | #To check if sub_className is a ClassName or an instance 287 | SubCallTag=self.sub_symbol.FoundName(sub_className) 288 | if SubCallTag==-1: 289 | ClassCallTag=self.class_symbol.FoundName(sub_className) 290 | if ClassCallTag==-1: 291 | sub_Name=sub_className+'.'+sub_funcName 292 | else: 293 | sub_MethodFlag=True 294 | sub_className=self.class_symbol.Scope[ClassCallTag][1] 295 | sub_index=self.class_symbol.Scope[ClassCallTag][3] 296 | self.vmWriter.writePush('this',sub_index) 297 | sub_Name=sub_className+'.'+sub_funcName 298 | else: 299 | sub_MethodFlag=True 300 | sub_className=self.sub_symbol.Scope[SubCallTag][1] 301 | sub_index=self.sub_symbol.Scope[SubCallTag][3] 302 | self.vmWriter.writePush('local',sub_index) 303 | sub_Name=sub_className+'.'+sub_funcName 304 | self.rfile.read(1) 305 | self.writeXml('symbol','(') 306 | self.compileExpressionList() 307 | self.writeXml('symbol',')') 308 | if sub_MethodFlag: 309 | self.vmWriter.writeCall(sub_Name,self.expressionListNum+1) 310 | else: 311 | self.vmWriter.writeCall(sub_Name,self.expressionListNum) 312 | elif self.tokenizer.token=='(': 313 | sub_Name=self.ClassName+'.'+sub_className 314 | self.writeXml('symbol','(') 315 | self.vmWriter.writePush('pointer',0) 316 | self.compileExpressionList() 317 | self.vmWriter.writeCall(sub_Name,self.expressionListNum+1) 318 | self.writeXml('symbol',')') 319 | 320 | def compileDo(self): 321 | self.writeXmlTag('\n') 322 | self.writeXml('keyword',self.tokenizer.token) 323 | self.subroutineCall() 324 | self.vmWriter.writePop('temp',0) 325 | self.NextToken() 326 | self.writeXml('symbol',self.tokenizer.token) 327 | self.writeXmlTag('\n') 328 | 329 | def compileLet(self): 330 | ''' 331 | If the term on the left of '=' is Array, the order of the VM code is 332 | totally different from other conditions. 333 | ''' 334 | self.writeXmlTag('\n') 335 | self.writeXml('keyword',self.tokenizer.token) 336 | self.NextToken() 337 | self.writeXml('identifier',self.tokenizer.token) 338 | LetVarName=self.tokenizer.token 339 | ListSeg=self.checkSymbol(LetVarName) 340 | self.NextToken() 341 | temp=self.tokenizer.token 342 | if temp=='[': 343 | self.writeArrayPush(LetVarName) 344 | self.writeXml('symbol',self.tokenizer.token) 345 | self.compileExpression() 346 | self.writeXml('symbol',']') 347 | self.vmWriter.writeArithmetic('add') 348 | self.NextToken() 349 | self.writeXml('symbol',self.tokenizer.token) 350 | self.compileExpression() 351 | self.vmWriter.writePop('temp',0) 352 | self.vmWriter.writePop('pointer',1) 353 | self.vmWriter.writePush('temp',0) 354 | self.vmWriter.writePop('that',0) 355 | self.writeXml('symbol',';') 356 | self.writeXmlTag('\n') 357 | elif temp == '=': 358 | self.writeXml('symbol',self.tokenizer.token) 359 | self.compileExpression() 360 | self.vmWriter.writePop(ListSeg[2],ListSeg[3]) 361 | self.writeXml('symbol',';') 362 | self.writeXmlTag('\n') 363 | 364 | def compileWhile(self): 365 | self.writeXmlTag('\n') 366 | self.writeXml('keyword',self.tokenizer.token) 367 | sub_WHILEFLAG=self.WHILEFLAG 368 | self.WHILEFLAG+=1 369 | self.vmWriter.writeLabel('WHILE_START'+str(sub_WHILEFLAG)) 370 | #(expression) 371 | self.NextToken() 372 | self.writeXml('symbol',self.tokenizer.token) 373 | self.compileExpression() 374 | self.writeXml('symbol',')') 375 | self.vmWriter.writeArithmetic('not') 376 | self.vmWriter.writeIf('WHILE_OVER'+str(sub_WHILEFLAG)) 377 | #{statements} 378 | self.NextToken() 379 | self.writeXml('symbol',self.tokenizer.token) 380 | self.compileStatements() 381 | self.vmWriter.writeGoto('WHILE_START'+str(sub_WHILEFLAG)) 382 | self.vmWriter.writeLabel('WHILE_OVER'+str(sub_WHILEFLAG)) 383 | self.writeXml('symbol',self.tokenizer.token) 384 | self.writeXmlTag('\n') 385 | 386 | def compileReturn(self): 387 | self.writeXmlTag('\n') 388 | self.writeXml('keyword',self.tokenizer.token) 389 | #expression? 390 | self.NextToken() 391 | if self.tokenizer.token == ';': 392 | self.writeXml('symbol',self.tokenizer.token) 393 | self.vmWriter.writePush('constant',0) 394 | self.vmWriter.writeReturn() 395 | else: 396 | self.moveBack() 397 | self.compileExpression() 398 | self.vmWriter.writeReturn() 399 | self.writeXml('symbol',';') 400 | self.writeXmlTag('\n') 401 | 402 | def compileStatements(self): 403 | self.writeXmlTag('\n') 404 | self.NextToken() 405 | while self.tokenizer.token != '}': 406 | if self.tokenizer.token =='let': 407 | self.compileLet() 408 | elif self.tokenizer.token == 'if': 409 | self.compileIf() 410 | elif self.tokenizer.token == 'while': 411 | self.compileWhile() 412 | elif self.tokenizer.token == 'do': 413 | self.compileDo() 414 | elif self.tokenizer.token == 'return': 415 | self.compileReturn() 416 | else: 417 | print 'Error!'+self.tokenizer.token 418 | exit() 419 | self.NextToken() 420 | self.writeXmlTag('\n') 421 | 422 | def compileIf(self): 423 | self.writeXmlTag('\n') 424 | sub_IFFLAG=self.IFFLAG 425 | self.IFFLAG+=1 426 | self.writeXml('keyword',self.tokenizer.token) 427 | #(expression) 428 | self.NextToken() 429 | self.writeXml('symbol',self.tokenizer.token) 430 | self.compileExpression() 431 | self.writeXml('symbol',')') 432 | self.vmWriter.writeArithmetic('not') 433 | self.vmWriter.writeIf('IF_RIGHT'+str(sub_IFFLAG)) 434 | #{statements} 435 | self.NextToken() 436 | self.writeXml('symbol',self.tokenizer.token) 437 | self.compileStatements() 438 | self.writeXml('symbol',self.tokenizer.token) 439 | #(else {statements})? 440 | self.NextToken() 441 | if self.tokenizer.token=='else': 442 | self.vmWriter.writeGoto('IF_WRONG'+str(sub_IFFLAG)) 443 | self.vmWriter.writeLabel('IF_RIGHT'+str(sub_IFFLAG)) 444 | self.writeXml('keyword',self.tokenizer.token) 445 | self.NextToken() 446 | self.writeXml('symbol',self.tokenizer.token) 447 | self.compileStatements() 448 | self.vmWriter.writeLabel('IF_WRONG'+str(sub_IFFLAG)) 449 | self.writeXml('symbol',self.tokenizer.token) 450 | else: 451 | self.vmWriter.writeLabel('IF_RIGHT'+str(sub_IFFLAG)) 452 | self.moveBack() 453 | self.writeXmlTag('\n') 454 | 455 | def compileClass(self): 456 | self.writeXmlTag('\n') 457 | self.NextToken() 458 | self.writeXml('keyword',self.tokenizer.token) 459 | self.NextToken() 460 | self.writeXml('identifier',self.tokenizer.token) 461 | self.ClassName=self.tokenizer.token 462 | self.NextToken() 463 | self.writeXml('keyword',self.tokenizer.token) 464 | #classVarDec* 465 | self.NextToken() 466 | while self.tokenizer.token in ('static','field'): 467 | self.compileClassVarDec() 468 | self.NextToken() 469 | #subroutineDec* 470 | while self.tokenizer.token in ('constructor','function','method'): 471 | self.compileSubroutine() 472 | self.NextToken() 473 | self.writeXml('symbol',self.tokenizer.token) 474 | self.writeXmlTag('\n') 475 | 476 | def compileSubroutine(self): 477 | Subroutine_Flag='' 478 | self.WHILEFLAG=0 479 | self.IFFLAG=0 480 | self.writeXmlTag('\n') 481 | self.writeXml('keyword',self.tokenizer.token) 482 | self.sub_symbol.startSubroutine() 483 | if self.tokenizer.token =='method': 484 | self.sub_symbol.Define('this',self.ClassName,'argument') 485 | Subroutine_Flag='METHOD' 486 | elif self.tokenizer.token == 'constructor': 487 | Subroutine_Flag='CONSTRUCTOR' 488 | else: 489 | Subroutine_Flag='FUNCTION' 490 | #(void|type) subroutineName (parameterList) 491 | self.NextToken() 492 | self.compileType() 493 | self.NextToken() 494 | self.writeXml('identifier',self.tokenizer.token) 495 | #special, to be xxx.yyy 496 | FunctionName=self.ClassName+'.'+self.tokenizer.token 497 | self.NextToken() 498 | self.writeXml('symbol',self.tokenizer.token) 499 | self.compileParameterList() 500 | self.writeXml('symbol',self.tokenizer.token) 501 | #subroutinBody 502 | self.writeXmlTag('\n') 503 | #{varDec* statements} 504 | self.NextToken() 505 | self.writeXml('symbol',self.tokenizer.token) 506 | self.NextToken() 507 | while self.tokenizer.token == 'var': 508 | self.compileVarDec() 509 | self.NextToken() 510 | self.moveBack() 511 | LclNum=self.sub_symbol.VarCount('var') 512 | self.vmWriter.writeFunction(FunctionName,LclNum) 513 | if Subroutine_Flag == 'METHOD': 514 | self.vmWriter.writePush('argument',0) 515 | self.vmWriter.writePop('pointer',0) 516 | elif Subroutine_Flag=='CONSTRUCTOR': 517 | FieldNum=self.class_symbol.VarCount('field') 518 | self.vmWriter.writePush('constant',FieldNum) 519 | self.vmWriter.writeCall('Memory.alloc',1) 520 | self.vmWriter.writePop('pointer',0) 521 | self.compileStatements() 522 | self.writeXml('symbol',self.tokenizer.token) 523 | self.writeXmlTag('\n') 524 | self.writeXmlTag('\n') 525 | -------------------------------------------------------------------------------- /11/JackCompiler.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import CompilationEngine 3 | import SymbolTable 4 | import sys,os 5 | 6 | ''' 7 | The command line of this module is : JackCompiler.py (-x) sourcename 8 | The first option is -x, which decides whether to run xmlWriter() and to output the constructive xml file\ 9 | putting forward by CompilationEngine. 10 | ''' 11 | 12 | option=sys.argv[1] 13 | if option == '-x': 14 | filename=sys.argv[2] 15 | else: 16 | filename=sys.argv[1] 17 | 18 | #clear all the // /* ... notes, create a new file to save the result 19 | readfile = open(filename,'r') 20 | copyfile = open('copyfile','w') 21 | line=readfile.readline() 22 | while line: 23 | while line == '\n' or line.startswith('//'): 24 | line=readfile.readline() 25 | if '//' in line: 26 | line=line[:line.find('//')] 27 | if '/*' in line: 28 | aline=line[:line.find('/*')] 29 | while line.find('*/')<0: 30 | line=readfile.readline() 31 | bline=line[line.find('*/')+2:] 32 | line=aline+bline 33 | copyfile.write(line) 34 | line=readfile.readline() 35 | copyfile.close() 36 | readfile.close() 37 | 38 | #Main Function 39 | readCopyFile=open('copyfile','r') 40 | writeXmlFile=open(filename.strip('.jack')+'.xml','w') 41 | writeVmFile=open(filename.strip('.jack')+'.vm','w') 42 | 43 | outputCompile=CompilationEngine.Compile(readCopyFile,writeXmlFile,writeVmFile) 44 | outputCompile.compileClass() 45 | 46 | readCopyFile.close() 47 | writeXmlFile.close() 48 | writeVmFile.close() 49 | os.remove('copyfile') 50 | 51 | if option != '-x': 52 | os.remove(filename.strip('.jack')+'.xml') 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /11/JackTokenizer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | STable=('{','}','(',')','[',']','.',',',';','+','-','*','/','&','|','<','>','=','~') 3 | KWtable=('class','constructor','function','method','field','static','var','int','char','boolean',\ 4 | 'void','true','false','null','this','let','do','if','else','while','return') 5 | 6 | class Tokenizer(): 7 | def __init__(self,rfile): 8 | self.rfile=rfile 9 | self.token='' 10 | 11 | def hasMoreTokens(self): 12 | temp=self.rfile.read(1) 13 | while temp in ' \n\t' and temp != '': 14 | temp=self.rfile.read(1) 15 | if not temp: 16 | return 0 17 | else: 18 | self.rfile.seek(-1,1) 19 | return 1 20 | 21 | def advance(self): 22 | self.token='' 23 | temp=self.rfile.read(1) 24 | 25 | if temp.isalpha() or temp.isdigit() or temp == '_': 26 | while temp.isalpha() or temp.isdigit() or temp == '_': 27 | self.token+=temp 28 | temp=self.rfile.read(1) 29 | if temp in STable or temp =='"': 30 | self.rfile.seek(-1,1) 31 | elif temp == ' ' or temp == '\n': 32 | self.rfile.seek(-1,1) 33 | elif temp in STable: 34 | self.token=temp 35 | elif temp =='"': 36 | self.token += '"' 37 | temp=self.rfile.read(1) 38 | while temp != '"': 39 | self.token+=temp 40 | temp=self.rfile.read(1) 41 | self.token+='"' 42 | 43 | def tokenType(self): 44 | if self.token in KWtable: 45 | return 'KEYWORD' 46 | elif self.token in STable: 47 | return 'SYMBOL' 48 | elif self.token.isdigit(): 49 | return 'INT_CONSTANT' 50 | elif self.token.startswith('"'): 51 | return 'STRING_CONSTANT' 52 | else: 53 | return 'IDENTIFIER' 54 | 55 | def Keyword(self): 56 | return self.token 57 | 58 | def Symbol(self): 59 | return self.token 60 | 61 | def Identifier(self): 62 | return self.token 63 | 64 | def intVal(self): 65 | return int(self.token) 66 | 67 | def stringVal(self): 68 | return self.token -------------------------------------------------------------------------------- /11/SymbolTable.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | class SymbolTable: 3 | ''' 4 | SymbolTable is a two-dimensional list. 5 | The first list contains all the names of the symbols. And Each name 6 | is also a single list, containing the [name,type,kind,index] of the 7 | symbol. 8 | ''' 9 | def __init__(self): 10 | self.Scope=[] 11 | 12 | def Constructor(self): 13 | self.Scope=[] 14 | 15 | def startSubroutine(self): 16 | self.Scope=[] 17 | 18 | def FoundName(self,name): 19 | #Search the funcName in SymbolTable 20 | for i in range(0,len(self.Scope)): 21 | if name == self.Scope[i][0]: 22 | return i 23 | return -1 24 | 25 | def Define(self,name,segType,kind): 26 | #Add new elements into the List. 27 | index=self.VarCount(kind) 28 | if kind == 'field': 29 | kind='this' 30 | elif kind == 'var': 31 | kind='local' 32 | name=[name,segType,kind,index] 33 | self.Scope.append(name) 34 | 35 | def VarCount(self,kind): 36 | #count the number of existed elements with 'kind'. 37 | #It is used to count the index of the elements. 38 | if kind == 'field': 39 | kind='this' 40 | elif kind == 'var': 41 | kind='local' 42 | lengthKind=0 43 | for i in range(0,len(self.Scope)): 44 | if self.Scope[i][2]==kind: 45 | lengthKind+=1 46 | return lengthKind 47 | 48 | def KindOf(self,name): 49 | for i in range(0,len(self.Scope)): 50 | if name == self.Scope[i][0]: 51 | return self.Scope[i][2] 52 | return 'NONE' 53 | 54 | def TypeOf(self,name): 55 | for i in range(0,len(self.Scope)): 56 | if name == self.Scope[i][0]: 57 | return self.Scope[i][1] 58 | return 'NONE' 59 | 60 | def IndexOf(self,name): 61 | for i in range(0,len(self.Scope)): 62 | if name == self.Scope[i][0]: 63 | return self.Scope[i][3] 64 | return 'NONE' 65 | 66 | 67 | -------------------------------------------------------------------------------- /11/VMWriter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | class VMwriter: 4 | def __init__(self,wfile): 5 | self.wfile=wfile 6 | 7 | def writePush(self,segment,index): 8 | self.wfile.write('push '+segment+' '+str(index)+'\n') 9 | 10 | def writePop(self,segment,index): 11 | self.wfile.write('pop '+segment+' '+str(index)+'\n') 12 | 13 | def writeArithmetic(self,command): 14 | self.wfile.write(command+'\n') 15 | 16 | def writeFunction(self,functionName,LclNum): 17 | self.wfile.write('function '+functionName+' '+str(LclNum)+'\n') 18 | 19 | def writeReturn(self): 20 | self.wfile.write('return\n') 21 | 22 | def writeCall(self,functionName,ELNum): 23 | self.wfile.write('call '+functionName+' '+str(ELNum)+'\n') 24 | 25 | def writeLabel(self,label): 26 | self.wfile.write('label '+label+'\n') 27 | 28 | def writeGoto(self,label): 29 | self.wfile.write('goto '+label+'\n') 30 | 31 | def writeIf(self,label): 32 | self.wfile.write('if-goto '+label+'\n') 33 | 34 | -------------------------------------------------------------------------------- /12/Array.jack: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | // File name: projects/12/Array.jack 5 | 6 | /** 7 | * Represents an array. Can be used to hold any type of object. 8 | */ 9 | class Array { 10 | 11 | /** Constructs a new Array of the given size. */ 12 | function Array new(int size) { 13 | var Array a; 14 | let a=Memory.alloc(size); 15 | return a; 16 | } 17 | 18 | /** De-allocates the array and frees its space. */ 19 | method void dispose() { 20 | do Memory.deAlloc(this); 21 | return; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /12/Keyboard.jack: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | // File name: projects/12/Keyboard.jack 5 | 6 | /** 7 | * A library for handling user input from the keyboard. 8 | */ 9 | class Keyboard { 10 | 11 | /** Initializes the keyboard. */ 12 | function void init() { 13 | return; 14 | } 15 | 16 | /** 17 | * Returns the ASCII code (as char) of the currently pressed key, 18 | * or 0 if no key is currently pressed. 19 | * Recognizes all ASCII characters, as well as the following extension 20 | * of action keys: 21 | * New line = 128 = String.newline() 22 | * Backspace = 129 = String.backspace() 23 | * Left Arrow = 130 24 | * Up Arrow = 131 25 | * Right Arrow = 132 26 | * Down Arrow = 133 27 | * Home = 134 28 | * End = 135 29 | * Page Up = 136 30 | * Page Down = 137 31 | * Insert = 138 32 | * Delete = 139 33 | * ESC = 140 34 | * F1 - F12 = 141 - 152 35 | */ 36 | function char keyPressed() { 37 | return Memory.peek(24576); 38 | } 39 | 40 | /** 41 | * Reads the next character from the keyboard. 42 | * waits until a key is pressed and then released, then echoes 43 | * the key to the screen, and returns the value of the pressed key. 44 | */ 45 | function char readChar() { 46 | var char c; 47 | while(~(Keyboard.keyPressed())){} 48 | let c=Keyboard.keyPressed(); 49 | while(c=Keyboard.keyPressed()){} 50 | do Output.printChar(c); 51 | return c; 52 | } 53 | 54 | /** 55 | * Prints the message on the screen, reads the next line 56 | * (until a newline character) from the keyboard, and returns its value. 57 | */ 58 | function String readLine(String message) { 59 | var String s; 60 | var char c; 61 | do Output.printString(message); 62 | let s=String.new(100); 63 | while(true){ 64 | let c=Keyboard.readChar(); 65 | if (c=128){ 66 | do Output.printChar(128); 67 | return s; 68 | } 69 | if (c=129){ 70 | do s.eraseLastChar(); 71 | do Output.backSpace(); 72 | } 73 | else{ 74 | let s=s.appendChar(c); 75 | } 76 | } 77 | return s; 78 | } 79 | 80 | /** 81 | * Prints the message on the screen, reads the next line 82 | * (until a newline character) from the keyboard, and returns its 83 | * integer value (until the first non numeric character). 84 | */ 85 | function int readInt(String message) { 86 | var String s; 87 | let s=Keyboard.readLine(message); 88 | return s.intValue(); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /12/Math.jack: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | // File name: projects/12/Math.jack 5 | 6 | /** 7 | * A basic math library. 8 | */ 9 | class Math { 10 | 11 | /** Initializes the library. */ 12 | function void init() { 13 | return; 14 | } 15 | 16 | /** Returns the absolute value of x. */ 17 | function int abs(int x) { 18 | var int absNum; 19 | if (x < 0){ 20 | let absNum = -x; 21 | } 22 | else{ 23 | let absNum = x; 24 | } 25 | return absNum; 26 | } 27 | 28 | /** Returns the product of x and y. */ 29 | function int multiply(int x, int y) { 30 | var int sum; 31 | var int shiftedX,functionY; 32 | var int flag,j; 33 | var boolean WhetherNeg; 34 | let sum = 0; 35 | let shiftedX = Math.abs(x); 36 | let functionY= Math.abs(y); 37 | let flag=1; 38 | let j=0; 39 | if ((x=0)|(y=0)){ 40 | return 0; 41 | } 42 | let WhetherNeg = ((x<0)=(y<0)); 43 | while(j<16){ 44 | if(functionY&flag=flag){ 45 | let sum = sum + shiftedX; 46 | } 47 | let shiftedX=shiftedX+shiftedX; 48 | let flag=flag+flag; 49 | let j=j+1; 50 | } 51 | if (~WhetherNeg){ 52 | let sum=-sum; 53 | } 54 | return sum; 55 | } 56 | 57 | /** Returns the integer part of x/y (x>0,y>0). */ 58 | function int div(int x, int y) { 59 | var int q,qy; 60 | if((y<0)|(y>x)){ 61 | return 0; 62 | } 63 | let q = Math.div(x,y+y); 64 | let qy = Math.multiply(q,y); 65 | if (x-qy-qy16384)&((x<32767)|(x=32767))){ 95 | return 15; 96 | } 97 | let powerTwo = 1; 98 | let flag = 0; 99 | while (powerTwo0 ){ 116 | let result = Math.multiply(result,x); 117 | let flag=flag-1; 118 | } 119 | return result; 120 | } 121 | 122 | /** Returns the integer part of the square root of x. */ 123 | function int sqrt(int x) { 124 | var int y,j,flag,powerJ; 125 | var int n,halfN; 126 | let y=0; 127 | let n = Math.logTwo(x); 128 | let halfN = Math.divide(n,2); 129 | let j=halfN; 130 | if (x<0){ 131 | return Sys.error(3); 132 | } 133 | while (j>-1){ 134 | let powerJ = Math.power(2,j); 135 | let flag = y+powerJ; 136 | let flag = Math.multiply(flag,flag); 137 | if (((flag < x) | (flag = x)) & (flag > 0)){ 138 | let y = y + powerJ; 139 | } 140 | let j=j-1; 141 | } 142 | return y; 143 | } 144 | 145 | /** Returns the greater number. */ 146 | function int max(int a, int b) { 147 | if (a>b){ 148 | return a; 149 | } 150 | else{ 151 | return b; 152 | } 153 | } 154 | 155 | /** Returns the smaller number. */ 156 | function int min(int a, int b) { 157 | if (alistRoom){ 42 | let listTag=listTag+1; 43 | let listTag=Memory.peek(listTag); 44 | let listRoom=Memory.peek(listTag); 45 | if(listTag=0) { 46 | do Sys.error(7); 47 | } 48 | } 49 | let returnVal=listTag+2; 50 | do Memory.poke(listTag,0); 51 | let listTag=listTag+1; 52 | let tempAdd=Memory.peek(listTag)+size; 53 | do Memory.poke(listTag,tempAdd); 54 | do Memory.poke(tempAdd,listRoom-size-2); 55 | let listTag=tempAdd+1; 56 | do Memory.poke(listTag,listTag+1); 57 | return returnVal; 58 | } 59 | 60 | /** De-allocates the given object and frees its space. */ 61 | function void deAlloc(int object) { 62 | var int length; 63 | let length = Memory.peek(object+1)-object-2; 64 | do Memory.poke(object,length); 65 | return; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /12/Output.jack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThomasCJY/The_Elements_of_Computing_Systems/27bc467f50e5bdb4b956804d526e59af9745c0f5/12/Output.jack -------------------------------------------------------------------------------- /12/Screen.jack: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | // File name: projects/12/Screen.jack 5 | 6 | /** 7 | * Graphic screen library. 8 | */ 9 | class Screen { 10 | static boolean color; 11 | 12 | /** Initializes the Screen. */ 13 | function void init() { 14 | let color = true; 15 | return; 16 | } 17 | 18 | /** Erases the whole screen. */ 19 | function void clearScreen() { 20 | var int address; 21 | let address=16384; 22 | while(address<24576){ 23 | do Memory.poke(address,0); 24 | let address=address+1; 25 | } 26 | return; 27 | } 28 | 29 | /** Sets the color to be used in further draw commands 30 | * where white = false, black = true. */ 31 | function void setColor(boolean b) { 32 | let color=b; 33 | return; 34 | } 35 | 36 | /** Draws the (x, y) pixel. */ 37 | function void drawPixel(int x, int y) { 38 | var int i,divNum,address,remain,temp; 39 | if((x>511)|(y>255)){ 40 | do Sys.error(11); 41 | } 42 | let i=1; 43 | let divNum=Math.divide(x,16); 44 | let address=16384+Math.multiply(y,32)+divNum; 45 | let remain=x-Math.multiply(divNum,16); 46 | let temp=Memory.peek(address); 47 | while(remain>0){ 48 | let i=i+i; 49 | let remain=remain-1; 50 | } 51 | //if color = false, negate the i to draw white pixel 52 | if(color){ 53 | let temp=(temp|i); 54 | } 55 | else{ 56 | let i = ~i; 57 | let temp = (temp&i); 58 | } 59 | do Memory.poke(address,temp); 60 | return; 61 | } 62 | 63 | /** Draws a line from (x1, y1) to (x2, y2). */ 64 | function void drawLine(int x1, int y1, int x2, int y2) { 65 | var int a,b,dx,dy,compDx,compDy,adyMinusbdx; 66 | let dx=x2-x1; 67 | let dy=y2-y1; 68 | let compDx=Math.abs(dx)+1; 69 | let compDy=Math.abs(dy)+1; 70 | let a=0; 71 | let b=0; 72 | if (dy=0){ 73 | if(dx>0){ 74 | while(a0){ 90 | while(a0)&(dy>0)){ 106 | let adyMinusbdx=0; 107 | while((a0)&(dy<1)){ 138 | let adyMinusbdx=0; 139 | while((a0)&(dx<1)){ 154 | let adyMinusbdx=0; 155 | while((a511)|(cy>255)|(r>181)){ 188 | do Sys.error(12); 189 | } 190 | let dy=-r; 191 | let rPower=Math.multiply(r,r); 192 | while(dy47)&(a[i]<58)){ 88 | let temp = a[i]-48; 89 | let result = Math.multiply(result,10) + temp; 90 | let i=i+1; 91 | } 92 | else{ 93 | if (flag){ 94 | let result = -result; 95 | } 96 | return result; 97 | } 98 | } 99 | if (flag){ 100 | let result = -result; 101 | } 102 | return result; 103 | } 104 | 105 | /** Sets this String to hold a representation of the given number. */ 106 | method void setInt(int number) { 107 | var int lastDigit; 108 | var int divNumber,tenNumber; 109 | var int c; 110 | let stringLength = 0; 111 | if (number < 0){ 112 | let negFlag = true; 113 | let number = Math.abs(number); 114 | } 115 | let divNumber = Math.divide(number,10); 116 | let tenNumber = Math.multiply(divNumber,10); 117 | let lastDigit = number - tenNumber; 118 | let c = lastDigit+48; 119 | if (number<10){ 120 | if (negFlag){ 121 | do appendChar(45); 122 | let negFlag = false; 123 | } 124 | do appendChar(c); 125 | } 126 | else{ 127 | do setInt(divNumber); 128 | do appendChar(c); 129 | } 130 | return; 131 | } 132 | 133 | /** Returns the new line character. */ 134 | function char newLine() { 135 | return 128; 136 | } 137 | 138 | /** Returns the backspace character. */ 139 | function char backSpace() { 140 | return 129; 141 | } 142 | 143 | /** Returns the double quote (") character. */ 144 | function char doubleQuote() { 145 | return 34; 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /12/Sys.jack: -------------------------------------------------------------------------------- 1 | // This file is part of www.nand2tetris.org 2 | // and the book "The Elements of Computing Systems" 3 | // by Nisan and Schocken, MIT Press. 4 | // File name: projects/12/Sys.jack 5 | 6 | /** 7 | * A library of basic system services. 8 | */ 9 | class Sys { 10 | 11 | /** Performs all the initializations required by the OS. */ 12 | function void init() { 13 | do Memory.init(); 14 | do Math.init(); 15 | do Screen.init(); 16 | do Output.init(); 17 | do Keyboard.init(); 18 | do Main.main(); 19 | do Sys.halt(); 20 | return; 21 | } 22 | 23 | /** Halts execution. */ 24 | function void halt() { 25 | while(true){} 26 | return; 27 | } 28 | 29 | /** Waits approximately duration milliseconds and then returns. */ 30 | function void wait(int duration) { 31 | var int temp; 32 | if(duration<0){ 33 | do Sys.error(1); 34 | } 35 | while(duration>0){ 36 | let temp=50; 37 | while(temp>0){ 38 | let temp=temp-1; 39 | } 40 | let duration=duration-1; 41 | } 42 | return; 43 | } 44 | 45 | /** Prints the given error code in the form "ERR", and halts. */ 46 | function void error(int errorCode) { 47 | var String s; 48 | let s=String.new(3); 49 | let s="ERR"; 50 | do Output.printString(s); 51 | do Output.printInt(errorCode); 52 | do Sys.halt(); 53 | return; 54 | } 55 | } 56 | --------------------------------------------------------------------------------