├── 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+'> '+'>'+' '+tType+'>\n')
17 | elif self.tokenizer.token=='<':
18 | self.writeXmlTag('<'+tType+'> '+'<'+' '+tType+'>\n')
19 | elif self.tokenizer.token=='&':
20 | self.writeXmlTag('<'+tType+'> '+'&'+' '+tType+'>\n')
21 | else:
22 | self.writeXmlTag('<'+tType+'> '+token+' '+tType+'>\n')
23 | else:
24 | self.writeXmlTag('<'+tType+'> '+token+' '+tType+'>\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+'> '+'>'+' '+tType+'>\n')
30 | elif self.tokenizer.token=='<':
31 | self.writeXmlTag('<'+tType+'> '+'<'+' '+tType+'>\n')
32 | elif self.tokenizer.token=='&':
33 | self.writeXmlTag('<'+tType+'> '+'&'+' '+tType+'>\n')
34 | else:
35 | self.writeXmlTag('<'+tType+'> '+token+' '+tType+'>\n')
36 | else:
37 | self.writeXmlTag('<'+tType+'> '+token+' '+tType+'>\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 |
--------------------------------------------------------------------------------