This commit is contained in:
QkoSad
2025-07-16 13:00:37 +03:00
commit 7894b48931
806 changed files with 162532 additions and 0 deletions
+35
View File
@@ -0,0 +1,35 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/01/And16.hdl
/**
* 16-bit bitwise And:
* for i = 0..15: out[i] = (a[i] and b[i])
*/
CHIP And16 {
IN a[16], b[16];
OUT out[16];
PARTS:
And(a=a[0],b=b[0],out=out[0]);
And(a=a[1],b=b[1],out=out[1]);
And(a=a[2],b=b[2],out=out[2]);
And(a=a[3],b=b[3],out=out[3]);
And(a=a[4],b=b[4],out=out[4]);
And(a=a[5],b=b[5],out=out[5]);
And(a=a[6],b=b[6],out=out[6]);
And(a=a[7],b=b[7],out=out[7]);
And(a=a[8],b=b[8],out=out[8]);
And(a=a[9],b=b[9],out=out[9]);
And(a=a[10],b=b[10],out=out[10]);
And(a=a[11],b=b[11],out=out[11]);
And(a=a[12],b=b[12],out=out[12]);
And(a=a[13],b=b[13],out=out[13]);
And(a=a[14],b=b[14],out=out[14]);
And(a=a[15],b=b[15],out=out[15]);
}
+21
View File
@@ -0,0 +1,21 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/01/DMux.hdl
/**
* Demultiplexor:
* {a, b} = {in, 0} if sel == 0
* {0, in} if sel == 1
*/
CHIP DMux {
IN in, sel;
OUT a, b;
PARTS:
Not(in=sel,out=notsel);
And(a=in,b=notsel,out=a);
And(a=in,b=sel,out=b);
}
+32
View File
@@ -0,0 +1,32 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/01/DMux4Way.hdl
/**
* 4-way demultiplexor:
* {a, b, c, d} = {in, 0, 0, 0} if sel == 00
* {0, in, 0, 0} if sel == 01
* {0, 0, in, 0} if sel == 10
* {0, 0, 0, in} if sel == 11
*/
CHIP DMux4Way {
IN in, sel[2];
OUT a, b, c, d;
PARTS:
Not(in=sel[1],out=notsel1);
Not(in=sel[0],out=notsel0);
And(a=notsel1,b=notsel0,out=out1);
And(a=notsel1,b=sel[0],out=out2);
And(a=sel[1],b=notsel0,out=out3);
And(a=sel[1],b=sel[0],out=out4);
And(a=in,b=out1,out=a);
And(a=in,b=out2,out=b);
And(a=in,b=out3,out=c);
And(a=in,b=out4,out=d);
}
+47
View File
@@ -0,0 +1,47 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/01/DMux8Way.hdl
/**
* 8-way demultiplexor:
* {a, b, c, d, e, f, g, h} = {in, 0, 0, 0, 0, 0, 0, 0} if sel == 000
* {0, in, 0, 0, 0, 0, 0, 0} if sel == 001
* etc.
* {0, 0, 0, 0, 0, 0, 0, in} if sel == 111
*/
CHIP DMux8Way {
IN in, sel[3];
OUT a, b, c, d, e, f, g, h;
PARTS:
Not(in=sel[0],out=notsel0);
Not(in=sel[1],out=notsel1);
Not(in=sel[2],out=notsel2);
And(a=notsel2,b=notsel1,out=out1);
And(a=out1,b=notsel0,out=outA);
And(a=out1,b=sel[0],out=outB);
And(a=notsel2,b=sel[1],out=out2);
And(a=out2,b=notsel0,out=outC);
And(a=out2,b=sel[0],out=outD);
And(a=sel[2],b=notsel1,out=out3);
And(a=out3,b=notsel0,out=outE);
And(a=out3,b=sel[0],out=outF);
And(a=sel[2],b=sel[1],out=out4);
And(a=out4,b=notsel0,out=outG);
And(a=out4,b=sel[0],out=outH);
And(a=in,b=outA,out=a);
And(a=in,b=outB,out=b);
And(a=in,b=outC,out=c);
And(a=in,b=outD,out=d);
And(a=in,b=outE,out=e);
And(a=in,b=outF,out=f);
And(a=in,b=outG,out=g);
And(a=in,b=outH,out=h);
}
+17
View File
@@ -0,0 +1,17 @@
/**
* Multiplexor:
* out = a if sel == 0
* b otherwise
*/
CHIP Mux {
IN a, b, sel;
OUT out;
PARTS:
Not(in=sel,out=notsel);
And(a=a,b=notsel,out=out1);
And(a=b,b=sel,out=out2);
Or(a=out1,b=out2,out=out);
}
+34
View File
@@ -0,0 +1,34 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/11/Mux16.hdl
/**
* 16-bit multiplexor:
* for i = 1..15 out[i] = a[i] if sel == 1
* b[i] if sel == 1
*/
CHIP Mux16 {
IN a[16], b[16], sel;
OUT out[16];
PARTS:
Mux(a=a[0],b=b[0],sel=sel,out=out[0]);
Mux(a=a[1],b=b[1],sel=sel,out=out[1]);
Mux(a=a[2],b=b[2],sel=sel,out=out[2]);
Mux(a=a[3],b=b[3],sel=sel,out=out[3]);
Mux(a=a[4],b=b[4],sel=sel,out=out[4]);
Mux(a=a[5],b=b[5],sel=sel,out=out[5]);
Mux(a=a[6],b=b[6],sel=sel,out=out[6]);
Mux(a=a[7],b=b[7],sel=sel,out=out[7]);
Mux(a=a[8],b=b[8],sel=sel,out=out[8]);
Mux(a=a[9],b=b[9],sel=sel,out=out[9]);
Mux(a=a[10],b=b[10],sel=sel,out=out[10]);
Mux(a=a[11],b=b[11],sel=sel,out=out[11]);
Mux(a=a[12],b=b[12],sel=sel,out=out[12]);
Mux(a=a[13],b=b[13],sel=sel,out=out[13]);
Mux(a=a[14],b=b[14],sel=sel,out=out[14]);
Mux(a=a[15],b=b[15],sel=sel,out=out[15]);
}
+21
View File
@@ -0,0 +1,21 @@
CHIP Mux4Way {
IN a, b, c, d, sel0, sel1;
OUT out;
PARTS:
Not(in=sel0,out=notsel0);
Not(in=sel1,out=notsel1);
And(a=notsel0,b=notsel1,out=outA);
And(a=sel0,b=notsel1,out=outB);
And(a=notsel0,b=sel1,out=outC);
And(a=sel0,b=sel1,out=outD);
And(a=outA,b=a,out=outA1);
And(a=outB,b=b,out=outB1);
And(a=outC,b=c,out=outC1);
And(a=outD,b=d,out=outD1);
Or(a=outA1,b=outB1,out=out1);
Or(a=outC1,b=outD1,out=out2);
Or(a=out1,b=out2,out=out);
}
+38
View File
@@ -0,0 +1,38 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/01/Mux4Way16.hdl
/**
* 4-way 16-bit multiplexor:
* out = a if sel == 00
* b if sel == 01
* c if sel == 10
* d if sel == 11
*/
CHIP Mux4Way16 {
IN a[16], b[16], c[16], d[16], sel[2];
OUT out[16];
PARTS:
Mux4Way(a=a[0],b=b[0],c=c[0],d=d[0],sel0=sel[0],sel1=sel[1],out=out[0]);
Mux4Way(a=a[1],b=b[1],c=c[1],d=d[1],sel0=sel[0],sel1=sel[1],out=out[1]);
Mux4Way(a=a[2],b=b[2],c=c[2],d=d[2],sel0=sel[0],sel1=sel[1],out=out[2]);
Mux4Way(a=a[3],b=b[3],c=c[3],d=d[3],sel0=sel[0],sel1=sel[1],out=out[3]);
Mux4Way(a=a[4],b=b[4],c=c[4],d=d[4],sel0=sel[0],sel1=sel[1],out=out[4]);
Mux4Way(a=a[5],b=b[5],c=c[5],d=d[5],sel0=sel[0],sel1=sel[1],out=out[5]);
Mux4Way(a=a[6],b=b[6],c=c[6],d=d[6],sel0=sel[0],sel1=sel[1],out=out[6]);
Mux4Way(a=a[7],b=b[7],c=c[7],d=d[7],sel0=sel[0],sel1=sel[1],out=out[7]);
Mux4Way(a=a[8],b=b[8],c=c[8],d=d[8],sel0=sel[0],sel1=sel[1],out=out[8]);
Mux4Way(a=a[9],b=b[9],c=c[9],d=d[9],sel0=sel[0],sel1=sel[1],out=out[9]);
Mux4Way(a=a[10],b=b[10],c=c[10],d=d[10],sel0=sel[0],sel1=sel[1],out=out[10]);
Mux4Way(a=a[11],b=b[11],c=c[11],d=d[11],sel0=sel[0],sel1=sel[1],out=out[11]);
Mux4Way(a=a[12],b=b[12],c=c[12],d=d[12],sel0=sel[0],sel1=sel[1],out=out[12]);
Mux4Way(a=a[13],b=b[13],c=c[13],d=d[13],sel0=sel[0],sel1=sel[1],out=out[13]);
Mux4Way(a=a[14],b=b[14],c=c[14],d=d[14],sel0=sel[0],sel1=sel[1],out=out[14]);
Mux4Way(a=a[15],b=b[15],c=c[15],d=d[15],sel0=sel[0],sel1=sel[1],out=out[15]);
}
+41
View File
@@ -0,0 +1,41 @@
CHIP Mux8Way {
IN a, b, c, d, e, f, g, h, sel0, sel1, sel2;
OUT out;
PARTS:
Not(in=sel0,out=notsel0);
Not(in=sel1,out=notsel1);
Not(in=sel2,out=notsel2);
And(a=notsel0,b=notsel1,out=outA);
And(a=notsel0,b=sel2,out=outC);
And(a=sel0,b=notsel1,out=outE);
And(a=sel0,b=sel1,out=outG);
And(a=outA,b=notsel2,out=outA1);
And(a=outC,b=notsel2,out=outC1);
And(a=outE,b=notsel2,out=outE1);
And(a=outG,b=notsel2,out=outG1);
And(a=outA,b=sel2,out=outB1);
And(a=outG,b=sel2,out=outH1);
And(a=outC,b=sel2,out=outD1);
And(a=outE,b=sel2,out=outF1);
And(a=outA1,b=a,out=outA2);
And(a=outB1,b=b,out=outB2);
And(a=outC1,b=c,out=outC2);
And(a=outD1,b=d,out=outD2);
And(a=outE1,b=e,out=outE2);
And(a=outF1,b=f,out=outF2);
And(a=outG1,b=g,out=outG2);
And(a=outH1,b=h,out=outH2);
Or(a=outA2,b=outB2,out=out1);
Or(a=outC2,b=outD2,out=out2);
Or(a=outE2,b=outF2,out=out4);
Or(a=outG2,b=outH2,out=out5);
Or(a=out4,b=out5,out=out6);
Or(a=out1,b=out2,out=out3);
Or(a=out3,b=out6,out=out);
}
+38
View File
@@ -0,0 +1,38 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/01/Mux8Way16.hdl
/**
* 8-way 16-bit multiplexor:
* out = a if sel == 000
* b if sel == 001
* etc.
* h if sel == 111
*/
CHIP Mux8Way16 {
IN a[16], b[16], c[16], d[16],
e[16], f[16], g[16], h[16],
sel[3];
OUT out[16];
PARTS:
Mux8Way(a=a[0],b=b[0],c=c[0],d=d[0],e=e[0],f=f[0],g=g[0],h=h[0],sel0=sel[0],sel1=sel[1],sel2=sel[2],out=out[0]);
Mux8Way(a=a[1],b=b[1],c=c[1],d=d[1],e=e[1],f=f[1],g=g[1],h=h[1],sel0=sel[0],sel1=sel[1],sel2=sel[2],out=out[1]);
Mux8Way(a=a[2],b=b[2],c=c[2],d=d[2],e=e[2],f=f[2],g=g[2],h=h[2],sel0=sel[0],sel1=sel[1],sel2=sel[2],out=out[2]);
Mux8Way(a=a[3],b=b[3],c=c[3],d=d[3],e=e[3],f=f[3],g=g[3],h=h[3],sel0=sel[0],sel1=sel[1],sel2=sel[2],out=out[3]);
Mux8Way(a=a[4],b=b[4],c=c[4],d=d[4],e=e[4],f=f[4],g=g[4],h=h[4],sel0=sel[0],sel1=sel[1],sel2=sel[2],out=out[4]);
Mux8Way(a=a[5],b=b[5],c=c[5],d=d[5],e=e[5],f=f[5],g=g[5],h=h[5],sel0=sel[0],sel1=sel[1],sel2=sel[2],out=out[5]);
Mux8Way(a=a[6],b=b[6],c=c[6],d=d[6],e=e[6],f=f[6],g=g[6],h=h[6],sel0=sel[0],sel1=sel[1],sel2=sel[2],out=out[6]);
Mux8Way(a=a[7],b=b[7],c=c[7],d=d[7],e=e[7],f=f[7],g=g[7],h=h[7],sel0=sel[0],sel1=sel[1],sel2=sel[2],out=out[7]);
Mux8Way(a=a[8],b=b[8],c=c[8],d=d[8],e=e[8],f=f[8],g=g[8],h=h[8],sel0=sel[0],sel1=sel[1],sel2=sel[2],out=out[8]);
Mux8Way(a=a[9],b=b[9],c=c[9],d=d[9],e=e[9],f=f[9],g=g[9],h=h[9],sel0=sel[0],sel1=sel[1],sel2=sel[2],out=out[9]);
Mux8Way(a=a[11],b=b[11],c=c[11],d=d[11],e=e[11],f=f[11],g=g[11],h=h[11],sel0=sel[0],sel1=sel[1],sel2=sel[2],out=out[11]);
Mux8Way(a=a[12],b=b[12],c=c[12],d=d[12],e=e[12],f=f[12],g=g[12],h=h[12],sel0=sel[0],sel1=sel[1],sel2=sel[2],out=out[12]);
Mux8Way(a=a[14],b=b[14],c=c[14],d=d[14],e=e[14],f=f[14],g=g[14],h=h[14],sel0=sel[0],sel1=sel[1],sel2=sel[2],out=out[14]);
Mux8Way(a=a[13],b=b[13],c=c[13],d=d[13],e=e[13],f=f[13],g=g[13],h=h[13],sel0=sel[0],sel1=sel[1],sel2=sel[2],out=out[13]);
Mux8Way(a=a[15],b=b[15],c=c[15],d=d[15],e=e[15],f=f[15],g=g[15],h=h[15],sel0=sel[0],sel1=sel[1],sel2=sel[2],out=out[15]);
Mux8Way(a=a[10],b=b[10],c=c[10],d=d[10],e=e[10],f=f[10],g=g[10],h=h[10],sel0=sel[0],sel1=sel[1],sel2=sel[2],out=out[10]);
}
+17
View File
@@ -0,0 +1,17 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/01/Not.hdl
/**
* Not gate:
* out = not in
*/
CHIP Not {
IN in;
OUT out;
PARTS:
Nand(a=in,b=in,out=out);
}
+33
View File
@@ -0,0 +1,33 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/01/Not16.hdl
/**
* 16-bit Not:
* for i=0..15: out[i] = not in[i]
*/
CHIP Not16 {
IN in[16];
OUT out[16];
PARTS:
Not(in=in[0],out=out[0]);
Not(in=in[1],out=out[1]);
Not(in=in[2],out=out[2]);
Not(in=in[3],out=out[3]);
Not(in=in[4],out=out[4]);
Not(in=in[5],out=out[5]);
Not(in=in[6],out=out[6]);
Not(in=in[7],out=out[7]);
Not(in=in[8],out=out[8]);
Not(in=in[9],out=out[9]);
Not(in=in[10],out=out[10]);
Not(in=in[11],out=out[11]);
Not(in=in[12],out=out[12]);
Not(in=in[13],out=out[13]);
Not(in=in[14],out=out[14]);
Not(in=in[15],out=out[15]);
}
+9
View File
@@ -0,0 +1,9 @@
CHIP Or {
IN a, b;
OUT out;
PARTS:
Not(in=a,out=nota);
Not(in=b,out=notb);
Nand(a=nota,b=notb,out=out);
}
+33
View File
@@ -0,0 +1,33 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/11/Or16.hdl
/**
* 16-bit bitwise Or:
* for i = 1..15 out[i] = (a[i] or b[i])
*/
CHIP Or16 {
IN a[16], b[16];
OUT out[16];
PARTS:
Or(a=a[0],b=b[0],out=out[0]);
Or(a=a[1],b=b[1],out=out[1]);
Or(a=a[2],b=b[2],out=out[2]);
Or(a=a[3],b=b[3],out=out[3]);
Or(a=a[4],b=b[4],out=out[4]);
Or(a=a[5],b=b[5],out=out[5]);
Or(a=a[6],b=b[6],out=out[6]);
Or(a=a[7],b=b[7],out=out[7]);
Or(a=a[8],b=b[8],out=out[8]);
Or(a=a[9],b=b[9],out=out[9]);
Or(a=a[10],b=b[10],out=out[10]);
Or(a=a[11],b=b[11],out=out[11]);
Or(a=a[12],b=b[12],out=out[12]);
Or(a=a[13],b=b[13],out=out[13]);
Or(a=a[14],b=b[14],out=out[14]);
Or(a=a[15],b=b[15],out=out[15]);
}
+25
View File
@@ -0,0 +1,25 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/01/Or8Way.hdl
/**
* 8-way Or:
* out = (in[0] or in[1] or ... or in[7])
*/
CHIP Or8Way {
IN in[8];
OUT out;
PARTS:
Or(a=in[0],b=in[1],out=out1);
Or(a=out1,b=in[2],out=out2);
Or(a=out2,b=in[3],out=out3);
Or(a=out3,b=in[4],out=out4);
Or(a=out4,b=in[5],out=out5);
Or(a=out5,b=in[6],out=out6);
Or(a=out6,b=in[7],out=out);
}
+66
View File
@@ -0,0 +1,66 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/02/ALU.hdl
/**
* The ALU (Arithmetic Logic Unit).
* Computes one of the following functions:
* x+y, x-y, y-x, 0, 1, -1, x, y, -x, -y, !x, !y,
* x+1, y+1, x-1, y-1, x&y, x|y on two 16-bit inputs,
* according to 6 input bits denoted zx,nx,zy,ny,f,no.
* In addition, the ALU computes two 1-bit outputs:
* if the ALU output == 0, zr is set to 1; otherwise zr is set to 0;
* if the ALU output < 0, ng is set to 1; otherwise ng is set to 0.
*/
// Implementation: the ALU logic manipulates the x and y inputs
// and operates on the resulting values, as follows:
// if (zx == 1) set x = 0 // 16-bit constant
// if (nx == 1) set x = !x // bitwise not
// if (zy == 1) set y = 0 // 16-bit constant
// if (ny == 1) set y = !y // bitwise not
// if (f == 1) set out = x + y // integer 2's complement addition
// if (f == 0) set out = x & y // bitwise and
// if (no == 1) set out = !out // bitwise not
// if (out == 0) set zr = 1
// if (out < 0) set ng = 1
CHIP ALU {
IN
x[16], y[16], // 16-bit inputs
zx, // zero the x input?
nx, // negate the x input?
zy, // zero the y input?
ny, // negate the y input?
f, // compute out = x + y (if 1) or x & y (if 0)
no; // negate the out output?
OUT
out[16], // 16-bit output
zr, // 1 if (out == 0), 0 otherwise
ng; // 1 if (out < 0), 0 otherwise
PARTS:
Mux16(a=x,b[0..15]=false,sel=zx,out=outZx);//zx +
Mux16(a=y,b[0..15]=false,sel=zy,out=outZy);//zy +
Not16(in=outZx,out=outNx1);//nx1
Not16(in=outZy,out=outNy1);//ny1
Mux16(a=outZx,b=outNx1,sel=nx,out=outNx);//nx +
Mux16(a=outZy,b=outNy1,sel=ny,out=outNy);//ny +
Add16(a=outNx,b=outNy,out=outF1);//f1 +
And16(a=outNy,b=outNx,out=outF0);//f0 +
Mux16(a=outF0,b=outF1,sel=f,out=outF);//f
Not16(in=outF,out=outNo1);//no +
Mux16(a=outF, b=outNo1, sel=no, out=out, out[15]=ng, out[0..7]=zr1, out[8..15]=zr2); +
Or8Way(in=zr1,out=out2);
Or8Way(in=zr2,out=out3);
Not(in=out2,out=out4);
Not(in=out3,out=out5);
And(a=out4,b=out5,out=zr);
}
+35
View File
@@ -0,0 +1,35 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/02/Adder16.hdl
/**
* Adds two 16-bit values.
* The most significant carry bit is ignored.
*/
CHIP Add16 {
IN a[16], b[16];
OUT out[16];
PARTS:
HalfAdder(a=a[0], b=b[0], sum=out[0], carry=carry1);
FullAdder(a=a[1], b=b[1], c=carry1, sum=out[1], carry=carry2);
FullAdder(a=a[2], b=b[2], c=carry2, sum=out[2], carry=carry3);
FullAdder(a=a[3], b=b[3], c=carry3, sum=out[3], carry=carry4);
FullAdder(a=a[4], b=b[4], c=carry4, sum=out[4], carry=carry5);
FullAdder(a=a[5], b=b[5], c=carry5, sum=out[5], carry=carry6);
FullAdder(a=a[6], b=b[6], c=carry6, sum=out[6], carry=carry7);
FullAdder(a=a[7], b=b[7], c=carry7, sum=out[7], carry=carry8);
FullAdder(a=a[8], b=b[8], c=carry8, sum=out[8], carry=carry9);
FullAdder(a=a[9], b=b[9], c=carry9, sum=out[9], carry=carry10);
FullAdder(a=a[10],b=b[10],c=carry10,sum=out[10],carry=carry11);
FullAdder(a=a[11],b=b[11],c=carry11,sum=out[11],carry=carry12);
FullAdder(a=a[12],b=b[12],c=carry12,sum=out[12],carry=carry13);
FullAdder(a=a[13],b=b[13],c=carry13,sum=out[13],carry=carry14);
FullAdder(a=a[14],b=b[14],c=carry14,sum=out[14],carry=carry15);
FullAdder(a=a[15],b=b[15],c=carry15,sum=out[15],carry=carry16);
}
+20
View File
@@ -0,0 +1,20 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/02/FullAdder.hdl
/**
* Computes the sum of three bits.
*/
CHIP FullAdder {
IN a, b, c; // 1-bit inputs
OUT sum, // Right bit of a + b + c
carry; // Left bit of a + b + c
PARTS:
HalfAdder(a=b,b=c,sum=sum1,carry=carry1);
HalfAdder(a=a,b=sum1,sum=sum,carry=carry2);
Or(a=carry1,b=carry2,out=carry);
}
+18
View File
@@ -0,0 +1,18 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/02/HalfAdder.hdl
/**
* Computes the sum of two bits.
*/
CHIP HalfAdder {
IN a, b; // 1-bit inputs
OUT sum, // Right bit of a + b
carry; // Left bit of a + b
PARTS:
Xor(a=a,b=b,out=sum);
And(a=a,b=b,out=carry);
}
+18
View File
@@ -0,0 +1,18 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/02/Inc16.hdl
/**
* 16-bit incrementer:
* out = in + 1 (arithmetic addition)
*/
CHIP Inc16 {
IN in[16];
OUT out[16];
PARTS:
Add16(a=in, b[1..15]=false, b[0]=true , out=out);
}
+19
View File
@@ -0,0 +1,19 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/03/a/Bit.hdl
/**
* 1-bit register:
* If load[t] == 1 then out[t+1] = in[t]
* else out does not change (out[t+1] = out[t])
*/
CHIP Bit {
IN in, load;
OUT out;
PARTS:
Mux(a=out2,b=in,sel=load,out=out1);
DFF(in=out1,out=out2,out=out);
}
+22
View File
@@ -0,0 +1,22 @@
CHIP DMux8Way16 {
IN in[16], sel[3];
OUT a[16], b[16], c[16], d[16], e[16], f[16], g[16], h[16];
PARTS:
DMux8Way(a=a[0],b=b[0],c=c[0],d=d[0],e=e[0],f=f[0],g=g[0],h=h[0],sel=sel,in=in[0]);
DMux8Way(a=a[1],b=b[1],c=c[1],d=d[1],e=e[1],f=f[1],g=g[1],h=h[1],sel=sel,in=in[1]);
DMux8Way(a=a[2],b=b[2],c=c[2],d=d[2],e=e[2],f=f[2],g=g[2],h=h[2],sel=sel,in=in[2]);
DMux8Way(a=a[3],b=b[3],c=c[3],d=d[3],e=e[3],f=f[3],g=g[3],h=h[3],sel=sel,in=in[3]);
DMux8Way(a=a[4],b=b[4],c=c[4],d=d[4],e=e[4],f=f[4],g=g[4],h=h[4],sel=sel,in=in[4]);
DMux8Way(a=a[5],b=b[5],c=c[5],d=d[5],e=e[5],f=f[5],g=g[5],h=h[5],sel=sel,in=in[5]);
DMux8Way(a=a[6],b=b[6],c=c[6],d=d[6],e=e[6],f=f[6],g=g[6],h=h[6],sel=sel,in=in[6]);
DMux8Way(a=a[7],b=b[7],c=c[7],d=d[7],e=e[7],f=f[7],g=g[7],h=h[7],sel=sel,in=in[7]);
DMux8Way(a=a[8],b=b[8],c=c[8],d=d[8],e=e[8],f=f[8],g=g[8],h=h[8],sel=sel,in=in[8]);
DMux8Way(a=a[9],b=b[9],c=c[9],d=d[9],e=e[9],f=f[9],g=g[9],h=h[9],sel=sel,in=in[9]);
DMux8Way(a=a[10],b=b[10],c=c[10],d=d[10],e=e[10],f=f[10],g=g[10],h=h[10],sel=sel,in=in[10]);
DMux8Way(a=a[11],b=b[11],c=c[11],d=d[11],e=e[11],f=f[11],g=g[11],h=h[11],sel=sel,in=in[11]);
DMux8Way(a=a[12],b=b[12],c=c[12],d=d[12],e=e[12],f=f[12],g=g[12],h=h[12],sel=sel,in=in[12]);
DMux8Way(a=a[13],b=b[13],c=c[13],d=d[13],e=e[13],f=f[13],g=g[13],h=h[13],sel=sel,in=in[13]);
DMux8Way(a=a[14],b=b[14],c=c[14],d=d[14],e=e[14],f=f[14],g=g[14],h=h[14],sel=sel,in=in[14]);
DMux8Way(a=a[15],b=b[15],c=c[15],d=d[15],e=e[15],f=f[15],g=g[15],h=h[15],sel=sel,in=in[15]);
}
+44
View File
@@ -0,0 +1,44 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/03/a/PC.hdl
/**
* A 16-bit counter with load and reset control bits.
* if (reset[t] == 1) out[t+1] = 0
* else if (load[t] == 1) out[t+1] = in[t]
* else if (inc[t] == 1) out[t+1] = out[t] + 1 (integer addition)
* else out[t+1] = out[t]
*/
CHIP PC {
IN in[16],load,inc,reset;
OUT out[16];
PARTS:
DMux8Way(in=true,sel[0]=reset,sel[1]=load,sel[2]=inc,a=a,b=b,c=c,d=d,e=e,f=f,g=g,h=h);
DFF(in=inc,out=inct);
And(a=inc,b=inct,out=out1);
Mux16(a=in,b=out4,sel=out1,out=out2);
Inc16(in=out2,out=out3);
Register(in=out3,load=load,out=out4,out=out);
Not(in=a,out=notа);
Register(in=in,load=notа,out=outA);
And16(a[0..15]=false,b[0..15]=false,out=outB);
Register(in=in,load=c,out=outC);
And16(a[0..15]=false,b[0..15]=false,out=outD);
And16(a[0..15]=false,b[0..15]=false,out=outF);
Register(in=in,load=g,out=outG);
And16(a[0..15]=false,b[0..15]=false,out=outH);
And16(a[0..15]=false,b[0..15]=false,out=outE);
Mux8Way16(a=outA,b=outB,c=outC,d=outD,e=outE,f=outF,g=outG,h=outH,sel[0]=reset,sel[1]=load,sel[2]=inc,out=out67);
}
+24
View File
@@ -0,0 +1,24 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/03/b/RAM16K.hdl
/**
* Memory of 16K registers, each 16 bit-wide. Out holds the value
* stored at the memory location specified by address. If load==1, then
* the in value is loaded into the memory location specified by address
* (the loaded value will be emitted to out from the next time step onward).
*/
CHIP RAM16K {
IN in[16], load, address[14];
OUT out[16];
PARTS:
DMux4Way(in=load,sel=address[0..1],a=a,b=b,c=c,d=d);
RAM4K(in=in,load=a,address=address[2..13],out=outa);
RAM4K(in=in,load=b,address=address[2..13],out=outb);
RAM4K(in=in,load=c,address=address[2..13],out=outc);
RAM4K(in=in,load=d,address=address[2..13],out=outd);
Mux4Way16(a=outa,b=outb,c=outc,d=outd,sel=address[0..1],out=out);
}
+28
View File
@@ -0,0 +1,28 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/03/b/RAM4K.hdl
/**
* Memory of 4K registers, each 16 bit-wide. Out holds the value
* stored at the memory location specified by address. If load==1, then
* the in value is loaded into the memory location specified by address
* (the loaded value will be emitted to out from the next time step onward).
*/
CHIP RAM4K {
IN in[16], load, address[12];
OUT out[16];
PARTS:
DMux8Way(in=load,sel=address[0..2],a=a,b=b,c=c,d=d,e=e,f=f,g=g,h=h);
RAM512(in=in,load=a,address=address[3..11],out=outa);
RAM512(in=in,load=b,address=address[3..11],out=outb);
RAM512(in=in,load=c,address=address[3..11],out=outc);
RAM512(in=in,load=d,address=address[3..11],out=outd);
RAM512(in=in,load=e,address=address[3..11],out=oute);
RAM512(in=in,load=f,address=address[3..11],out=outf);
RAM512(in=in,load=g,address=address[3..11],out=outg);
RAM512(in=in,load=h,address=address[3..11],out=outh);
Mux8Way16(a=outa,b=outb,c=outc,d=outd,e=oute,f=outf,g=outg,h=outh,sel=address[0..2],out=out);
}
+28
View File
@@ -0,0 +1,28 @@
// This file is part of the materials accompanying the book
// "The Elements of Computing Systems" by Nisan and Schocken,
// MIT Press. Book site: www.idc.ac.il/tecs
// File name: projects/03/b/RAM512.hdl
/**
* Memory of 512 registers, each 16 bit-wide. Out holds the value
* stored at the memory location specified by address. If load==1, then
* the in value is loaded into the memory location specified by address
* (the loaded value will be emitted to out from the next time step onward).
*/
CHIP RAM512 {
IN in[16], load, address[9];
OUT out[16];
PARTS:
DMux8Way(in=load,sel=address[0..2],a=a,b=b,c=c,d=d,e=e,f=f,g=g,h=h);
RAM64(in=in,load=a,address=address[3..8],out=outa);
RAM64(in=in,load=b,address=address[3..8],out=outb);
RAM64(in=in,load=c,address=address[3..8],out=outc);
RAM64(in=in,load=d,address=address[3..8],out=outd);
RAM64(in=in,load=e,address=address[3..8],out=oute);
RAM64(in=in,load=f,address=address[3..8],out=outf);
RAM64(in=in,load=g,address=address[3..8],out=outg);
RAM64(in=in,load=h,address=address[3..8],out=outh);
Mux8Way16(a=outa,b=outb,c=outc,d=outd,e=oute,f=outf,g=outg,h=outh,sel=address[0..2],out=out);
}
+28
View File
@@ -0,0 +1,28 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/03/a/RAM64.hdl
/**
* Memory of 64 registers, each 16 bit-wide. Out holds the value
* stored at the memory location specified by address. If load==1, then
* the in value is loaded into the memory location specified by address
* (the loaded value will be emitted to out from the next time step onward).
*/
CHIP RAM64 {
IN in[16], load, address[6];
OUT out[16];
PARTS:
DMux8Way(in=load,sel=address[0..2],a=a,b=b,c=c,d=d,e=e,f=f,g=g,h=h);
RAM8(in=in,load=a,address=address[3..5],out=outa);
RAM8(in=in,load=b,address=address[3..5],out=outb);
RAM8(in=in,load=c,address=address[3..5],out=outc);
RAM8(in=in,load=d,address=address[3..5],out=outd);
RAM8(in=in,load=e,address=address[3..5],out=oute);
RAM8(in=in,load=f,address=address[3..5],out=outf);
RAM8(in=in,load=g,address=address[3..5],out=outg);
RAM8(in=in,load=h,address=address[3..5],out=outh);
Mux8Way16(a=outa,b=outb,c=outc,d=outd,e=oute,f=outf,g=outg,h=outh,sel=address[0..2],out=out);
}
+29
View File
@@ -0,0 +1,29 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/03/a/RAM8.hdl
/**
* Memory of 8 registers, each 16 bit-wide. Out holds the value
* stored at the memory location specified by address. If load==1, then
* the in value is loaded into the memory location specified by address
* (the loaded value will be emitted to out from the next time step onward).
*/
CHIP RAM8 {
IN in[16], load, address[3];
OUT out[16];
PARTS:
DMux8Way(in=load,sel=address,a=a,b=b,c=c,d=d,e=e,f=f,g=g,h=h);
Register(in=in,load=a,out=outa);
Register(in=in,load=b,out=outb);
Register(in=in,load=c,out=outc);
Register(in=in,load=d,out=outd);
Register(in=in,load=e,out=oute);
Register(in=in,load=f,out=outf);
Register(in=in,load=g,out=outg);
Register(in=in,load=h,out=outh);
Mux8Way16(a=outa,b=outb,c=outc,d=outd,e=oute,f=outf,g=outg,h=outh,sel=address,out=out);
}
+34
View File
@@ -0,0 +1,34 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/03/a/Register.hdl
/**
* 16-bit register:
* If load[t] == 1 then out[t+1] = in[t]
* else out does not change
*/
CHIP Register {
IN in[16], load;
OUT out[16];
PARTS:
Bit(in=in[0],load=load,out=out[0]);
Bit(in=in[1],load=load,out=out[1]);
Bit(in=in[2],load=load,out=out[2]);
Bit(in=in[3],load=load,out=out[3]);
Bit(in=in[4],load=load,out=out[4]);
Bit(in=in[5],load=load,out=out[5]);
Bit(in=in[6],load=load,out=out[6]);
Bit(in=in[7],load=load,out=out[7]);
Bit(in=in[8],load=load,out=out[8]);
Bit(in=in[9],load=load,out=out[9]);
Bit(in=in[10],load=load,out=out[10]);
Bit(in=in[11],load=load,out=out[11]);
Bit(in=in[12],load=load,out=out[12]);
Bit(in=in[13],load=load,out=out[13]);
Bit(in=in[14],load=load,out=out[14]);
Bit(in=in[15],load=load,out=out[15]);
}
+97
View File
@@ -0,0 +1,97 @@
@END //check if button is pressed
0;JMP
(BLACK)
//start= 16384 the start of the screen memory
@SCREEN
D=A
@start
M=D
//n=8,192 this is the memory for the display =addreass of the keyboard - address of the screen
@8192
D=A
@n
M=D
//i=0 this is the index for each group of pixels
@i
M=0
(LOOP1)
//if i==n goto end
@i
D=M
@n
D=D-M
@END
D;JEQ
//start+1=-1 set each group of pixels to -1 which is = 111111111111
@start
D=M
@i
A=D+M
M=-1
// increment i by 1
@i
M=M+1
// go back to the start of the loop
@LOOP1
0;JMP
(WHITE)
//start= 16384 the start of the screen memory
@SCREEN
D=A
@start
M=D
//n=8,192 this is the memory for the display =addreass of the keyboard - address of the screen
@8192
D=A
@n
M=D
//i=0 this is the index for each group of pixels
@i
M=0
(LOOP2)
//if i==n goto end
@i
D=M
@n
D=D-M
@END
D;JEQ
//start+1=-1 set each group of pixels to 0 which is = 00000000
@start
D=M
@i
A=D+M
M=0
// increment i by 1
@i
M=M+1
// go back to the start of the loop
@LOOP2
0;JMP
//check if button is pressed
(END)
@KBD
D=M
@WHITE
D;JEQ
@KBD
D=M
@BLACK
D;JNE
@END
0;JMP
+24
View File
@@ -0,0 +1,24 @@
@R2
M=0
@sum
M=0
(LOOP)
@1
D=M
@END
D;JEQ // if R1==0 goto end
@R0
D=M // D=R0
@sum
M=M+D // sum=sum+R0
@R1
M=M-1 //R1=R1-1
@sum
D=M
@R2
M=D
@LOOP
0;JMP
(END)
@END
0;JMP
+115
View File
@@ -0,0 +1,115 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/05/CPU.hdl
/**
* The Hack CPU (Central Processing unit), consisting of an ALU,
* two registers named A and D, and a program counter named PC.
* The CPU is designed to fetch and execute instructions written in
* the Hack machine language. In particular, functions as follows:
* Executes the inputted instruction according to the Hack machine
* language specification. The D and A in the language specification
* refer to CPU-resident registers, while M refers to the external
* memory location addressed by A, i.e. to Memory[A]. The inM input
* holds the value of this location. If the current instruction needs
* to write a value to M, the value is placed in outM, the address
* of the target location is placed in the addressM output, and the
* writeM control bit is asserted. (When writeM==0, any value may
* appear in outM). The outM and writeM outputs are combinational:
* they are affected instantaneously by the execution of the current
* instruction. The addressM and pc outputs are clocked: although they
* are affected by the execution of the current instruction, they commit
* to their new values only in the next time step. If reset==1 then the
* CPU jumps to address 0 (i.e. pc is set to 0 in next time step) rather
* than to the address resulting from executing the current instruction.
*/
CHIP CPU {
IN inM[16], // M value input (M = contents of RAM[A])
instruction[16], // Instruction for execution
reset; // Signals whether to re-start the current
// program (reset==1) or continue executing
// the current program (reset==0).
OUT outM[16], // M value output
writeM, // Write to M?
addressM[15], // Address in data memory (of M)
pc[15]; // address of next instruction
PARTS:
Mux16(a=instruction ,b=ALUout ,sel=instruction[15] ,out=outToAreg );
ARegister(in=outToAreg ,load=loadAreg ,out=outAreg,out[0..14]=addressM );
DRegister(in=ALUout ,load=loadDreg ,out=outDreg );
Mux16(a=outAreg ,b=inM ,sel=instruction[12] ,out=outToALU );
ALU(x=outDreg ,y=outToALU ,zx=instruction[11] ,nx=instruction[10] ,zy=instruction[9] ,ny=instruction[8] ,f=instruction[7] ,no=instruction[6] ,out=ALUout,out=outM ,zr=zr ,ng=ng );
And(a=instruction[3],b=instruction[15],out=writeM);
//when to load A reg
Not(in=instruction[5],out=notd5);
Nand(a=instruction[15],b=notd5,out=loadAreg);
Not(in=ng,out=notNg);
Not(in=zr,out=notZr);
//when to load D reg
And(a=instruction[4],b=instruction[15],out=loadDreg);
//checking if instruction is a or c before jump decision is made
And(a=instruction[2],b=instruction[15],out=J1);
And(a=instruction[1],b=instruction[15],out=J2);
And(a=instruction[0],b=instruction[15],out=J3);
//NULL
Nand(a=J1,b=J2,out=NandJ1J2);
Nand(a=NandJ1J2,b=J3,out=NoJump);
//JGT
And(a=J3,b=J3,out=AndJ3J3);
Or(a=zr,b=ng,out=orZrNg);
Not(in=orZrNg,out=NorZrNg);
And(a=AndJ3J3,b=NorZrNg,out=JGT);
//JEQ
And(a=J2,b=J2,out=AndJ2J2);
And(a=zr,b=zr,out=AndZrZr);
And(a=AndZrZr,b=AndJ2J2,out=JEQ);
//JGE
And(a=J3,b=J2,out=AndJ3J2);
Or(a=zr,b=notNg,out=AndZrNotNg);
And(a=AndZrNotNg,b=AndJ3J2,out=JGE);
//JLT
And(a=J1,b=J1,out=AndJ1J1);
And(a=ng,b=ng,out=AndNgNg);
And(a=AndJ1J1,b=AndNgNg,out=JLT);
//JNE
And(a=J3,b=J1,out=AndJ3J1);
And(a=notZr,b=notZr,out=AndNotZrNotZr);
And(a=AndNotZrNotZr,b=AndJ3J1,out=JNE);
//JLE
And(a=J2,b=J1,out=AndJ2J1);
And(a=AndJ2J1,b=orZrNg,out=JLE);
//JMP
And(a=AndJ3J1,b=J2,out=JMP);
Not(in=outToLoad,out=outToLoad1); // once needted to know when to increes but also needed to not it so it dosent load the reg when J1J2J3=000
//4wayMux one
Mux(a=JMP,b=JGT,sel=instruction[0] ,out=out1);
Mux(a=JEQ,b=JGE,sel=instruction[0] ,out=out2);
Mux(a=out1,b=out2, sel=instruction[1] ,out=out5);
//4wayMux two
Mux(a=JLT,b=JNE,sel=instruction[0] ,out=out3);
Mux(a=JLE,b=JMP,sel=instruction[0] ,out=out4);
Mux(a=out3,b=out4,sel=instruction[1] ,out=out6);
//2wayMux
Mux(a=out5,b=out6,sel= instruction[2],out=outToLoad);
PC(in=outAreg ,load=outToLoad ,inc=outToLoad1 ,reset=reset ,out[0..14]=pc);
}
+25
View File
@@ -0,0 +1,25 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/05/Computer.hdl
/**
* The HACK computer, including CPU, ROM and RAM.
* When reset is 0, the program stored in the computer's ROM executes.
* When reset is 1, the execution of the program restarts.
* Thus, to start a program's execution, reset must be pushed "up" (1)
* and "down" (0). From this point onward the user is at the mercy of
* the software. In particular, depending on the program's code, the
* screen may show some output and the user may be able to interact
* with the computer via the keyboard.
*/
CHIP Computer {
IN reset;
PARTS:
CPU(inM=inM ,instruction=inst ,reset=reset ,outM=outM ,writeM=writeM ,addressM=addressM ,pc=pc );
Memory(in=outM ,load=writeM ,address= addressM,out=inM );
ROM32K(address=pc ,out=inst );
}
+36
View File
@@ -0,0 +1,36 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/05/Memory.hdl
/**
* The complete address space of the Hack computer's memory,
* including RAM and memory-mapped I/O.
* The chip facilitates read and write operations, as follows:
* Read: out(t) = Memory[address(t)](t)
* Write: if load(t-1) then Memory[address(t-1)](t) = in(t-1)
* In words: the chip always outputs the value stored at the memory
* location specified by address. If load==1, the in value is loaded
* into the memory location specified by address. This value becomes
* available through the out output from the next time step onward.
* Address space rules:
* Only the upper 16K+8K+1 words of the Memory chip are used.
* Access to address>0x6000 is invalid. Access to any address in
* the range 0x4000-0x5FFF results in accessing the screen memory
* map. Access to address 0x6000 results in accessing the keyboard
* memory map. The behavior in these addresses is described in the
* Screen and Keyboard chip specifications given in the book.
*/
CHIP Memory {
IN in[16], load, address[15];
OUT out[16];
PARTS:
DMux4Way(in=load,sel[0]=address[13],sel[1]=address[14] ,a=ram16k ,b=ram16k2,c=ramScreen);
Or(a=ram16k ,b=ram16k2 ,out=ram16end);
RAM16K(in=in ,load=ram16end ,address=address[0..13] ,out=out1);
Screen(in=in ,load=ramScreen ,address=address[0..12] ,out=out2);
Keyboard(out=outKey);
Mux4Way16(a=out1 ,b=out1 ,c=out2 ,d=outKey ,sel[0]=address[13],sel[1]=address[14] ,out=out);
}
+230
View File
@@ -0,0 +1,230 @@
def a_instruct(string): # covert the A instruction to bits
string = string.strip('@\n')
x = "{0:b}".format(int(string)) # convert the number to binary, problem if the number is too big
while len(x) < 16: # need to be 16 bits and 1 for \n
x = "0" + x
return x # return th 16 bit value
def c_instruct(string): # priema edna liniq koeto e edna instrukciq i q prevryshta v bit kod
string = string + "\n"
flag1, flag2, p = 0, 0, 0
dest_s = ''
comp_s = ''
jump_s = ''
for c in range(len(string)):
if string[c] == '=': # ako ima ravno znachi predi nego ima destination
i = 0
flag1 = 1 # diga flag za destination
while i < c:
p = c
dest_s += string[i]
i += 1
dest_s = destDic.get(dest_s) # convert t to Destination
if string[c] == ';': # ako ima ; znachi predi nego ima computation
flag2 = 1 # diga flag za Jump
if flag1 == 0: # ako flaga za destination ne e dignat zapochvame ot nachaloto na liniqta
p = 0
else: # ako e zapochvame ot kydeto e ravnoto koeto se pazi vyv var i
p = i
while p < c:
comp_s += string[p]
p += 1
comp_s = compDic.get(comp_s) # convert t1 to Computation
if string[c] == '\n':
if flag2 == 1: # ako ima flag za jump to vzimame stoinosta na jumpa
j = p + 1
while j < c:
jump_s += string[j]
j += 1
jump_s = jumpDic.get(jump_s)
else: # ako nqma togava vzima stoinosta na computationa
j = i + 1
while j < c:
comp_s += string[j]
j += 1
comp_s = compDic.get(comp_s)
final_result = '111' + comp_s # dobavqme 111 koeto e standart za C instrukt i computation bez koeto nqma instrukciq
if dest_s != '': # ako e imalo dest go dobavqme
final_result = final_result + dest_s
else: # inache dobavqme 3 nuli
final_result = final_result + '000'
if jump_s != '': # ako e imalo jump go dobavqme
final_result = final_result + jump_s
else: # inache dobavqme 3 nuli
final_result = final_result + '000'
return final_result
def check_a_or_c(temp_string):
line = ''
temp_string1 = ''
for j in temp_string: # zapisva liniqta v string koito posle se obrabotva
if j != '\n':
line += j
else:
for index in range(len(line)): # proverqva vseki simvol ot liniqta
if line[index] == "@": # ako liniqta zapochva s @ znachi e a instrukciq
temp_string1 += a_instruct(line) + '\n'
line = ''
break
else: # ako ne zapochva s @ znachi e C instrukciq
temp_string1 += c_instruct(line) + '\n'
line = ''
break
return temp_string1
def clear_file(temp_string_cf): # clears the empty lines, comments and spaces and writes them in a string
for line in asmfile:
f = 0
if line == '\n': # removes empty lines
continue
for index in range(len(line)):
if line[index] == "/" and line[index + 1] == '/': # checks if it is comment
if f == 1: # maybe a problem if the last element of a line is / since it will stay
temp_string_cf += '\n'
break
if line[index] != ' ': # removes all of the whitespaces except newlines
temp_string_cf += line[index]
f = 1
return temp_string_cf
def label(temp_string): # removes the labels and adds them to the dictionary writes all in a string
line = ''
temp_string_l = ''
global rowasm
for j in temp_string: # zapisva liniqta v string koito posle se obrabotva
if j != '\n':
line += j
else:
f = 0
for index in range(len(line)): # loops through the lines char by char
if line[index] == "(":
# checks if it is a label, will be a problem if there is only "(" and no closing bracket alse need to check label syntax
if bool(labelDic.get(line.strip('()'))) == False: # check if label is already in the Dictionary
labelDic[line.strip("()")] = str(rowasm) # adds the label to the dictionary
rowasm -= 1 # need to pay attention to the counting cause im not sure
f = 1
break # brake so i don't write this line in the string since it needs to be removed
if f != 1:
temp_string_l += line
temp_string_l += '\n'
rowasm += 1
line = ''
return temp_string_l
def variable(temp_string): # replaces the variables with the correct address
global variableCount
line = ''
temp_string_v = ''
for j in temp_string: # zapisva liniqta v string koito posle se obrabotva
if j != '\n':
line += j
else:
for index in range(len(line)):
if line[index] == '@' and numbers.find(line[index + 1]) < 0: # checks if the line holds a variable
if bool(labelDic.get(line.strip('@'))): # check if variable is already in the Dictionary
line = '@' + labelDic[line.strip('@')] # replaces the variable with address i hope
else:
labelDic[line.strip('@')] = str(variableCount) # if isn't it adds it
line = '@' + str(variableCount) # replaces the variable with address i hope
variableCount += 1 # increases the variable counter so i don't write them all in address 16
break
temp_string_v += line + '\n' # appends the line to the string
line = ''
return temp_string_v
destDic = {'None': '000',
'M': '001',
'D': '010',
'MD': '011',
'A': '100',
'AM': '101',
'AD': '110',
'AMD': '111', } # contains all destinations and their bit equivalent
jumpDic = {'None': '000',
'JGT': '001',
'JQE': '010',
'JGE': '011',
'JLT': '100',
'JNE': '101',
'JLE': '110',
'JMP': '111', } # contains all jumps and their bit equivalent
compDic = {'0': '0101010',
'1': '0111111',
'-1': '0111010',
'D': '0001100',
'A': '0110000',
'!D': '0001101',
'!A': '0110001',
'-D': '0001111',
'-A': '0110011',
'D+1': '0011111',
'A+1': '0110111',
'D-1': '0001110',
'A-1': '0110010',
'D+A': '0000010',
'D-A': '0010011',
'A-D': '0000111',
'D&A': '0000000',
'D|A': '0010101',
'M': '1110000',
'!M': '1110001',
'-M': '1110011',
'M+1': '1110111',
'M-1': '1110010',
'D+M': '1000010',
'D-M': '1010011',
'M-D': '1000111',
'D&M': '1000000',
'D|M': '1010101',
} # contains all computations and their bit equivalent
tempString = '' # create empty string
rowasm = 0
numbers = '0123456789' # used to check if given instruction calls to variable
variableCount = 16 # keeps count of the variable address
labelDic = {'SP': '0',
'LCL': '1',
'ARG': '2',
'THIS': '3',
'THAT': '4',
'SCREEN': '16384',
'KBD': '24576',
'R0': '0',
'R1': '1',
'R2': '2',
'R3': '3',
'R4': '4',
'R5': '5',
'R6': '6',
'R7': '7',
'R8': '8',
'R9': '9',
'R10': '10',
'R11': '11',
'R12': '12',
'R13': '13',
'R14': '14',
'R15': '15',
} # dictionary containing Labels and Variables in format: AddressNumber : LabelName/ VariableName
with open("C:/Users/AGrudev/Desktop/n2t/nand2tetris/projects/06/pong/Pong.asm", "r+") as asmfile:
tempString = clear_file(tempString)
print(tempString + '----------')
tempString = label(tempString)
print(tempString + '----------')
tempString = variable(tempString)
print(tempString + '----------')
tempString = check_a_or_c(tempString)
print(tempString + '----------')
with open("C:/Users/AGrudev/Desktop/n2t/nand2tetris/projects/06/pong/Pong.hack", "w+") as destfile:
destfile.write(tempString)
+160
View File
@@ -0,0 +1,160 @@
import os
import sys
from pathlib import Path
trueCounter = 0
falseCounter = 0
staticCounter = 16
def clear_file(temp_string_cf, asmfile): # clears the empty lines, comments and spaces and writes them in a string
for line in asmfile:
f = 0
if line == '\n': # removes empty lines
continue
for index in range(len(line)):
if line[index] == "/" and line[index + 1] == '/': # checks if it is comment
if f == 1: # maybe a problem if the last element of a line is / since it will stay
temp_string_cf += '\n'
break
if line[index] != ' ': # removes all of the whitespaces except newlines
temp_string_cf += line[index]
f = 1
return temp_string_cf
def push(line):
global tempString1
if line[4:8] == 'this':
number = int(line[8:])
line = '@' + str(number) + '\nD=A\n@THIS\nA=M+D\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n'
elif line[4:8] == 'that':
number = int(line[8:])
line = '@' + str(number) + '\nD=A\n@THAT\nA=M+D\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n'
elif line[4:8] == 'temp':
number = int(line[8:])
number += 5
line = '@' + str(number) + '\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n'
elif line[4:9] == 'local':
number = int(line[9:])
line = '@' + str(number) + '\nD=A\n@LCL\nA=M+D\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n'
elif line[4:10] == 'static':
number = int(line[10:])
line = '@' + name1 + '.' + str(number) + '\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n'
elif line[4:11] == 'pointer':
number = int(line[11:])
number += 3
line = '@' + str(number) + '\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n'
elif line[4:12] == 'argument':
number = int(line[12:])
line = '@' + str(number) + '\nD=A\n@ARG\nA=M+D\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n'
elif line[4:12] == 'constant':
number = line[12:]
line = '@' + str(number) + '\nD=A\n@SP\nA=M\nM=D\n@SP\nM=M+1\n'
tempString1 += line
def pop(line):
global SP
global tempString1
if line[3:7] == 'this':
number = int(line[7:])
line = '@' + str(number) + '\nD=A\n@THIS\nM=M+D\n@SP\nM=M-1\nA=M\nD=M\n@THIS\nA=M\nM=D\n' + '@' + str(
number) + '\nD=A\n@THIS\nM=M-D\n'
elif line[3:7] == 'that':
number = int(line[7:])
line = '@' + str(number) + '\nD=A\n@THAT\nM=M+D\n@SP\nM=M-1\nA=M\nD=M\n@THAT\nA=M\nM=D\n' + '@' + str(
number) + '\nD=A\n@THAT\nM=M-D\n'
elif line[3:7] == 'temp':
number = int(line[7:])
number = number + 5
line = '@SP\nM=M-1\nA=M\nD=M\n@' + str(number) + '\nM=D\n'
elif line[3:8] == 'local':
number = int(line[8:])
line = '@' + str(number) + '\nD=A\n@LCL\nM=M+D\n@SP\nM=M-1\nA=M\nD=M\n@LCL\nA=M\nM=D\n' + '@' + str(
number) + '\nD=A\n@LCL\nM=M-D\n'
elif line[3:9] == 'static':
number = int(line[9:])
line = '@SP\nM=M-1\nA=M\nD=M\n@' + name1 + '.' + str(number) + '\nM=D\n'
elif line[3:10] == 'pointer':
number = int(line[10:])
number = number + 3
line = '@SP\nM=M-1\nA=M\nD=M\n@' + str(number) + '\nM=D\n'
elif line[3:11] == 'argument':
number = int(line[11:])
line = '@' + str(number) + '\nD=A\n@ARG\nM=M+D\n@SP\nM=M-1\nA=M\nD=M\n@ARG\nA=M\nM=D\n' + '@' + str(
number) + '\nD=A\n@ARG\nM=M-D\n'
tempString1 += line
def aritmetic(line):
global trueCounter
global falseCounter
global tempString1
if line == 'add':
line = "@SP\nM=M-1\nA=M\nD=M\nA=A-1\nM=M+D\n"
elif line == 'sub':
line = "@SP\nM=M-1\nA=M\nD=M\nA=A-1\nM=M-D\n"
elif line == 'neg':
line = "@SP\nA=M\nA=A-1\nM=-M\n"
elif line == 'eq':
line = '@SP\nM=M-1\nA=M\nD=M\nA=A-1\nD=M-D\n@TRUE' + str(
trueCounter) + '\nD;JEQ\n@SP\nA=M\nA=A-1\nM=0\n@FALSE' + str(
falseCounter) + '\n0;JMP\n(TRUE' + str(trueCounter) + ')\n@SP\nA=M\nA=A-1\nM=-1\n(FALSE' + str(
falseCounter) + ')\n'
trueCounter += 1
falseCounter += 1
elif line == 'gt':
line = '@SP\nM=M-1\nA=M\nD=M\nA=A-1\nD=M-D\n@TRUE' + str(
trueCounter) + '\nD;JGT\n@SP\nA=M\nA=A-1\nM=0\n@FALSE' + str(
falseCounter) + '\n0;JMP\n(TRUE' + str(trueCounter) + ')\n@SP\nA=M\nA=A-1\nM=-1\n(FALSE' + str(
falseCounter) + ')\n'
trueCounter += 1
falseCounter += 1
elif line == 'lt':
line = '@SP\nM=M-1\nA=M\nD=M\nA=A-1\nD=M-D\n@TRUE' + str(
trueCounter) + '\nD;JLT\n@SP\nA=M\nA=A-1\nM=0\n@FALSE' + str(
falseCounter) + '\n0;JMP\n(TRUE' + str(trueCounter) + ')\n@SP\nA=M\nA=A-1\nM=-1\n(FALSE' + str(
falseCounter) + ')\n'
trueCounter += 1
falseCounter += 1
elif line == 'and':
line = "@SP\nM=M-1\nA=M\nD=M\nA=A-1\nM=M&D\n"
elif line == 'or':
line = "@SP\nM=M-1\nA=M\nD=M\nA=A-1\nM=M|D\n"
elif line == 'not':
line = "@SP\nA=M\nA=A-1\nM=!M\n"
tempString1 += line
name1 = None
line, tempString = '', ''
tempString1 = ''
aritmeticList3 = ['add', 'sub', 'neg', 'and', 'not']
aritmeticList2 = ['or', 'gt', 'lt', 'eq']
yourpath = os.getcwd()
for root, dirs, files in os.walk(yourpath, topdown=False):
nam1 = ''
for name in files:
if name[-3:] == '.vm':
name1 = name
tempString1 = ''
tempString = ''
with open(Path(root, name), "r+") as vmfile:
tempString = clear_file(tempString, vmfile)
for j in tempString: # zapisva liniqta v string koito posle se obrabotva
if j != '\n':
line += j
else:
if line[:4] == 'push':
push(line)
line = ''
elif line[:3] == 'pop':
pop(line)
line = ''
elif line[:2] in aritmeticList2 or line[:3] in aritmeticList3:
aritmetic(line)
line = ''
if name1 == name:
with open(Path(root, f'{name1[:-3]}.asm'), 'w+') as newfile:
newfile.write(tempString1)
+246
View File
@@ -0,0 +1,246 @@
import os
from pathlib import Path
def clear_file(clearfile):
temp_string_cf = '' # clears the empty lines, comments and spaces and writes them in a string
for vmline in clearfile:
flag = 0
if vmline == '\n':
continue
for index in range(len(vmline)):
if vmline[index:index + 2] == '//':
if flag == 1:
temp_string_cf += '\n'
break
if flag == 1 and vmline[index:index + 2] == ' ':
temp_string_cf += '\n'
break
temp_string_cf += vmline[index]
flag = 1
return temp_string_cf
def push(pushline, funcname):
if 'this' in pushline:
number = int(pushline[10:])
pushline = '@' + str(number) + '\nD=A\n@THIS\nA=M+D\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n//push THIS\n'
elif 'that' in pushline:
number = int(pushline[10:])
pushline = '@' + str(number) + '\nD=A\n@THAT\nA=M+D\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n//push THAT\n'
elif 'temp' in pushline:
number = int(pushline[10:])
number += 5
pushline = '@' + str(number) + '\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n//push TMP\n'
elif 'local' in pushline:
number = int(pushline[11:])
pushline = '@' + str(number) + '\nD=A\n@LCL\nA=M+D\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n//push LOCAL\n'
elif 'static' in pushline:
number = int(pushline[12:])
pushline = '@' + funcname + '.' + str(number) + '\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n//push STATIC\n'
elif 'pointer' in pushline:
number = int(pushline[13:])
number += 3
pushline = '@' + str(number) + '\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n//push POINTER\n'
elif 'argument' in pushline:
number = int(pushline[14:])
pushline = '@' + str(number) + '\nD=A\n@ARG\nA=M+D\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n//push ARGUMENT\n'
elif 'constant' in pushline:
number = pushline[14:]
pushline = '@' + str(number) + '\nD=A\n@SP\nA=M\nM=D\n@SP\nM=M+1\n//push CONSTANT\n'
return pushline
def pop(popline, funcname):
if 'this' in popline:
number = int(popline[9:])
popline = '@' + str(number) + '\nD=A\n@THIS\nM=M+D\n@SP\nM=M-1\nA=M\nD=M\n@THIS\nA=M\nM=D\n' + '@' + str(
number) + '\nD=A\n@THIS\nM=M-D\n//pop THIS\n'
elif 'that' in popline:
number = int(popline[9:])
popline = '@' + str(number) + '\nD=A\n@THAT\nM=M+D\n@SP\nM=M-1\nA=M\nD=M\n@THAT\nA=M\nM=D\n' + '@' + str(
number) + '\nD=A\n@THAT\nM=M-D\n//pop THAT\n'
elif 'temp' in popline:
number = int(popline[9:])
number = number + 5
popline = '@SP\nM=M-1\nA=M\nD=M\n@' + str(number) + '\nM=D\n//pop TMP\n'
elif 'local' in popline:
number = int(popline[10:])
popline = '@' + str(number) + '\nD=A\n@LCL\nM=M+D\n@SP\nM=M-1\nA=M\nD=M\n@LCL\nA=M\nM=D\n' + '@' + str(
number) + '\nD=A\n@LCL\nM=M-D\n//pop LOCAL\n'
elif 'static' in popline:
number = int(popline[11:])
popline = '@SP\nM=M-1\nA=M\nD=M\n@' + funcname + '.' + str(number) + '\nM=D\n//pop STATIC\n'
elif 'pointer' in popline:
number = int(popline[12:])
number = number + 3
popline = '@SP\nM=M-1\nA=M\nD=M\n@' + str(number) + '\nM=D\n//pop POINTER\n'
elif 'argument' in popline:
number = int(popline[13:])
popline = '@' + str(number) + '\nD=A\n@ARG\nM=M+D\n@SP\nM=M-1\nA=M\nD=M\n@ARG\nA=M\nM=D\n' + '@' + str(
number) + '\nD=A\n@ARG\nM=M-D\n//pop ARG\n'
return popline
def aritmetic(armline):
global trueCounter
global falseCounter
if armline == 'add':
armline = "@SP\nM=M-1\nA=M\nD=M\nA=A-1\nM=M+D\n//ADD\n"
elif armline == 'sub':
armline = "@SP\nM=M-1\nA=M\nD=M\nA=A-1\nM=M-D\n//SUB\n"
elif armline == 'neg':
armline = "@SP\nA=M\nA=A-1\nM=-M\n//NEG\n"
elif armline == 'eq':
armline = '@SP\nM=M-1\nA=M\nD=M\nA=A-1\nD=M-D\n@TRUE' + str(
trueCounter) + '\nD;JEQ\n@SP\nA=M\nA=A-1\nM=0\n@FALSE' + str(
falseCounter) + '\n0;JMP\n(TRUE' + str(trueCounter) + ')\n@SP\nA=M\nA=A-1\nM=-1\n(FALSE' + str(
falseCounter) + ')\n//EQ\n'
trueCounter += 1
falseCounter += 1
elif armline == 'gt':
armline = '@SP\nM=M-1\nA=M\nD=M\nA=A-1\nD=M-D\n@TRUE' + str(
trueCounter) + '\nD;JGT\n@SP\nA=M\nA=A-1\nM=0\n@FALSE' + str(
falseCounter) + '\n0;JMP\n(TRUE' + str(trueCounter) + ')\n@SP\nA=M\nA=A-1\nM=-1\n(FALSE' + str(
falseCounter) + ')\n//GT\n'
trueCounter += 1
falseCounter += 1
elif armline == 'lt':
armline = '@SP\nM=M-1\nA=M\nD=M\nA=A-1\nD=M-D\n@TRUE' + str(
trueCounter) + '\nD;JLT\n@SP\nA=M\nA=A-1\nM=0\n@FALSE' + str(
falseCounter) + '\n0;JMP\n(TRUE' + str(trueCounter) + ')\n@SP\nA=M\nA=A-1\nM=-1\n(FALSE' + str(
falseCounter) + ')\n//LT\n'
trueCounter += 1
falseCounter += 1
elif armline == 'and':
armline = "@SP\nM=M-1\nA=M\nD=M\nA=A-1\nM=M&D\n//AND\n"
elif armline == 'or':
armline = "@SP\nM=M-1\nA=M\nD=M\nA=A-1\nM=M|D\n//OR\n"
elif armline == 'not':
armline = "@SP\nA=M\nA=A-1\nM=!M\n//NOT\n"
return armline
def label(labelline):
labelline = '(' + func_label_name + '$' + labelline[6:] + ')\n//LABEL\n'
return labelline
def goto(gotoline):
gotoline = '@' + func_label_name + '$' + gotoline[5:] + '\n0;JMP\n//GOTO\n'
return gotoline
def if_goto(ifline):
ifline = '@SP\nM=M-1\nA=M\nD=M\n@' + func_label_name + '$' + ifline[8:] + '\nD;JNE\n//IFGOTO\n'
return ifline
def define_func(funcline):
global func_label_name
def_func_list = funcline.rsplit(' ')
func_label_name = def_func_list[1]
funcline = '(' + def_func_list[1] + ')\n'
for ind in range(int(def_func_list[2])):
funcline += '@0\nD=A\n@SP\nA=M\nM=D\n@SP\nM=M+1\n//DEFINEFUNC\n'
return funcline
def call_func(callline):
global f
call_func_list = callline.rsplit(' ')
callline = '@' + call_func_list[1] + str(f) + 'RA\nD=A\n@SP\nA=M\nM=D\n@SP\nM=M+1\n'
callline += '@LCL\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n'
callline += '@ARG\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n'
callline += '@THIS\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n'
callline += '@THAT\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\n'
callline += '@SP\nD=M\n@' + call_func_list[2] + '\nD=D-A\n@5\nD=D-A\n@ARG\nM=D\n'
callline += '@SP\nD=M\n@LCL\nM=D\n'
callline += '@' + call_func_list[1] + '\n0;JMP\n'
callline += '(' + call_func_list[1] + str(f) + 'RA)\n//CALLFUNC\n'
f += 1
return callline
def return_func(returnline):
returnline = '@LCL\nD=M\n@R13\nM=D\n'
returnline += '@5\nD=A\n@R13\nD=M-D\nA=D\nD=M\n@R14\nM=D\n'
returnline += '@SP\nA=M-1\nD=M\n@ARG\nA=M\nM=D\n'
returnline += '@ARG\nD=M+1\n@SP\nM=D\n'
returnline += '@R13\nM=M-1\nA=M\nD=M\n@THAT\nM=D\n'
returnline += '@R13\nM=M-1\nA=M\nD=M\n@THIS\nM=D\n'
returnline += '@R13\nM=M-1\nA=M\nD=M\n@ARG\nM=D\n'
returnline += '@R13\nM=M-1\nA=M\nD=M\n@LCL\nM=D\n'
returnline += '@R14\nA=M\n0;JMP\n//RETURN\n'
return returnline
def iterate(name_iterate, yourpath_iterate):
line = ''
new_string = ''
with open(Path(yourpath_iterate, name_iterate + '.vm'), "r+") as vmfile:
string_iterate = clear_file(vmfile)
for j in string_iterate: # zapisva liniqta v string koito posle se obrabotva
if j != '\n':
line += j
else:
if line[:4] == 'push':
new_string += push(line, name_iterate)
line = ''
elif line[:3] == 'pop':
new_string += pop(line, name_iterate)
line = ''
elif line[:2] in aritmeticList2 or line[:3] in aritmeticList3:
new_string += aritmetic(line)
line = ''
elif line[:5] == 'label':
new_string += label(line)
line = ''
elif line[:4] == 'goto':
new_string += goto(line)
line = ''
elif line[:7] == 'if-goto':
new_string += if_goto(line)
line = ''
elif line[:8] == 'function':
new_string += define_func(line)
line = ''
elif line[:4] == 'call':
new_string += call_func(line)
line = ''
elif line[:6] == 'return':
new_string += return_func(line)
line = ''
return new_string
trueCounter = falseCounter = f = 0
staticCounter = 16
func_label_name = ''
aritmeticList3 = ['add', 'sub', 'neg', 'and', 'not']
aritmeticList2 = ['or', 'gt', 'lt', 'eq']
yourpath = os.getcwd()
bootstrap = '''@256\nD=A\n@SP\nM=D\n@MainLoopXYZRA\nD=A\n@SP\nA=M\nM=D\n@SP\nM=M+1\n@LCL\nD=M\n@SP\nA=M\nM=D\n@SP
M=M+1\n@ARG\nD=M\n@SP\nA=M\nM=D\n@SP\nM=M+1\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
M=M+1\n@SP\nD=M\n@0\nD=D-A\n@5\nD=D-A\n@ARG\nM=D\n@SP\nD=M\n@LCL\nM=D\n@Sys.init\n0;JMP\n(MainLoopXYZRARA)
//CALLFUNC\n'''
for root, dirs, files in os.walk(yourpath, topdown=False):
nameslist = []
sysstring, functstring = '', ''
for name in files:
tempString = ''
if name[-3:] == '.vm':
nameslist += [name[:-3]]
for i in nameslist:
if i == 'Sys':
sysstring = bootstrap
sysstring += iterate(i, root)
else:
functstring += iterate(i, root)
if nameslist:
with open(Path(root, f'{os.path.split(root)[1]}.asm'), 'w+') as newfile:
newfile.write(sysstring + functstring)
+19
View File
@@ -0,0 +1,19 @@
class Main {
function void main (){
var int s;
let s = -1;
do Output.moveCursor(0,20);
do Output.printString("Welcome to Tetris");
do Sys.wait(2000);
do Output.println();
do Output.println();
do Output.println();
while ((s < 0) | (s > 100)){ // gets a number used for seed for the random function
let s = Keyboard.readInt("Enter a number between 0 and 100:");
do Screen.clearScreen();
}
do Sys.wait(2000);
do Tetris.tetris(s);
return;
}
}
+473
View File
@@ -0,0 +1,473 @@
class Piece {
static int lBorder, rBorder, uBorder, dBorder, st;
field int x1, y1, x2, y2, x3, y3, x4, y4, piece, direction;
field bool move;
static Array st;
constructor Piece new(int Ax1, int Ay1, int Ax2, int Ay2, int Ax3, int Ay3, int Ax4, int Ay4, int p) {
let x1 = Ax1;
let y1 = Ay1;
let x2 = Ax2;
let y2 = Ay2;
let x3 = Ax3;
let y3 = Ay3;
let x4 = Ax4;
let y4 = Ay4;
let piece = p;
let direction = 0;
let move = true;
return this;
}
function void init(){
var int a;
let lBorder = 0;
let rBorder = 511;
let uBorder = 0;
let dBorder = 255;
let st = Array.new(16);
let st[0] = 1;
while (a < 15){
let a = a + 1;
let st[a] = st[a - 1] + st[a - 1];
}
return;
}
method void dispose() {
do Memory.deAlloc(this);
return;
}
/** draws 2 rectangles also checks if there is a piece at the spawn which will indicate end of the game. */
method bool draw() {
var bool finish;
let finish = true;
let finish = Piece.sample(x1,y1) & finish;
let finish = Piece.sample(x2,y2) & finish;
let finish = Piece.sample(x3,y3) & finish;
let finish = Piece.sample(x4,y4) & finish;
if (finish){
do Screen.setColor(true);
do Screen.drawRectangle(x1, y1, x2, y2);
do Screen.drawRectangle(x3, y3, x4, y4);
return true;
}
return false;
}
/** Erases the square from the screen. */
method void erase() {
do Screen.setColor(false);
do Screen.drawRectangle(x1, y2, x2, y2);
do Screen.drawRectangle(x3, y3, x4, y4);
return;
}
/** checks if those coodinates hold any value > 0. */
function bool sample(int x, int y){
var int value, address, bit, memBlock;
let memBlock = x / 16;
let address = (32 * y) + memBlock + 16384;
if (address > 24576){
return false;
}
let value = Memory.peek(address);
if (value = 0){
return true;
}
return false;
}
method bool getMove(){
return move;
}
/** Checks if the piece can move in the given direction(dir). */
method bool fullSample(int dir){
var int size1, size2, i, j;
var bool result, flagUpon;
if (dir = 1){ //down
let size1 = x2 - x1;
let size2 = x4 - x3;
let result = true;
while (i < size1){ // for each block of the first rectangle
let j = 0;
let flagUpon = false;
while (j < size2){ // for each block of the second rectangle
if ((x1 + i) = (x3 + j)){ // if this block of the first rectangle sits upon a block of the second rectangle
let flagUpon = true;
}
let result = result & Piece.sample(x3 + j, y4 + 1); // if there is a block under the second rectangle
let j = j + 16; // sets the coords for the next block of the second rectangle
}
if (~(flagUpon)){
let result = result & Piece.sample(x1 + i, y2 + 1); // if there is a block under the first rectangle
}
let i = i + 16; // sets the coords for the next block of the firs rectangle
}
return result;
}
else{
if (dir = 2){ //right
let size1 = y2 - y1;
let size2 = y4 - y3;
let result = true;
while (i < size1){
let j = 0;
let flagUpon = false;
while (j < size2){
if ((y1 + i) = (y3 + j)){
let flagUpon = true;
}
let result = result & Piece.sample(x4 + 1, (y3 + j));
let j = j + 16;
}
if (~(flagUpon)){
let result = result & Piece.sample(x2 + 1, (y1 + i));
}
let i = i +16;
}
return result;
}
else{ // left
let size1 = y2 - y1;
let size2 = y4 - y3;
let result = true;
while (i < size2){
let j = 0;
let flagUpon = false;
while (j < size1){
if ((y3 + i) = (y1 + j)){
let flagUpon = true;
}
let result = result & Piece.sample(x1 - 1, (y1 + j));
let j = j + 16;
}
if (~(flagUpon)){
let result = result & Piece.sample(x3 - 1, (y3 + i));
}
let i = i + 16;
}
return result;
}
}
}
/** Moves the game piece 16 pixels down. */
method void moveDown() {
var int i;
if ((y2 < dBorder) & (y4 < dBorder) & (move) & fullSample(1)) {
while (i < 16){
do Screen.setColor(false);
do Screen.drawRectangle(x1, y1, x2, y1);
do Screen.drawRectangle(x3, y3, x4, y3);
let y1 = y1 + 1;
let y2 = y2 + 1;
let y3 = y3 + 1;
let y4 = y4 + 1;
do Screen.setColor(true);
do Screen.drawRectangle(x1, y2, x2, y2);
do Screen.drawRectangle(x3, y4, x4, y4);
let i = i + 1;
do Sys.wait(10);
}
}
else{
let move = false;
}
return;
}
/** Moves the game piece 16 pixels to the left. */
method void moveLeft() {
var int i;
if ((x1 + 15 > lBorder) & (move) & (x3 + 15 > lBorder)& fullSample(0)){
while (i < 16){
do Screen.setColor(false);
do Screen.drawRectangle(x2, y1, x2, y2);
do Screen.drawRectangle(x4, y3, x4, y4);
let x1 = x1 - 1;
let x2 = x2 - 1;
let x3 = x3 - 1;
let x4 = x4 - 1;
do Screen.setColor(true);
do Screen.drawRectangle(x1, y1, x2, y2);
do Screen.drawRectangle(x3, y3, x4, y4);
let i = i + 1;
do Sys.wait(10);
}
}
return;
}
/** Moves the game piece 16 pixels to the right. */
method void moveRight() {
var int i;
if ((x4 < rBorder) & (move) & (x2 < rBorder) & fullSample(2)){
while (i < 16){
do Screen.setColor(false);
do Screen.drawRectangle(x1, y1, x1, y2);
do Screen.drawRectangle(x3, y3, x3, y4);
let x1 = x1 + 1;
let x2 = x2 + 1;
let x3 = x3 + 1;
let x4 = x4 + 1;
do Screen.setColor(true);
do Screen.drawRectangle(x1, y1, x2, y2);
do Screen.drawRectangle(x3, y3, x4, y4);
let i = i + 1;
do Sys.wait(10);
}
}
return;
}
/** Deletes the piece and draws it at the new coodinates. */
method void reDraw(int Ax1, int Ay1, int Ax2, int Ay2, int Ax3, int Ay3, int Ax4, int Ay4){
var int absTmp;
if((Ax1 < 175) | (Ax3 < 175) | (Ax2 > 336) | (Ax4 > 336)){
return;
}
if((Ay2 > 255) | (Ay4 > 255) | (Ay1 < 0) | (Ay3 < 0)){
return;
}
if((Ax1 > Ax2) | (Ax3 > Ax4) | (Ay1 > Ay2) | (Ay3 > Ay4)){
return;
}
do Screen.setColor(false);
do Screen.drawRectangle(x1, y1, x2, y2);
do Screen.drawRectangle(x3, y3, x4, y4);
do Screen.setColor(true);
let x1 = Ax1;
let y1 = Ay1;
let x2 = Ax2;
let y2 = Ay2;
let x3 = Ax3;
let y3 = Ay3;
let x4 = Ax4;
let y4 = Ay4;
do Screen.drawRectangle(x1, y1, x2, y2);
do Screen.drawRectangle(x3, y3, x4, y4);
return;
}
/** Rotates the piece clockwise. */
method void rotate(){
var bool samp;
let samp = true;
if (direction = 0){ // starting position
if (piece = 0){ // arrow
let samp = Piece.sample(x4, y1) & samp; // checks if the place at which the new piece will be drawn are free
let samp = Piece.sample(x4, y1 - 1) & samp;
if (samp){
do reDraw(x1, y1, x2, y2, x4 - 15, y4 - 47, x4, y4); // redraws it at the new location
let direction = 1;
}
}
if (piece = 1){
let samp = Piece.sample(x1 + 16, y1) & samp;
let samp = Piece.sample(x1 + 16, y1 - 16) & samp;
let samp = Piece.sample(x4, y1 - 16) & samp;
if(samp){
do reDraw(x1 + 16, y1 - 16, x4 - 16, y4, x4 - 15, y1 - 16, x4, y1 - 1);
let direction = 1;
}
}
if (piece = 2){
let samp = Piece.sample(x1 - 16, y1 - 16) & samp;
let samp = Piece.sample(x1 - 16, y1) & samp;
if (samp){
do reDraw(x1 - 16, y1 - 16, x2 - 16, y2 + 16, x3 + 32, y3, x4, y4);
let direction = 1;
}
}
if (piece = 3){
let samp = Piece.sample(x3 + 16, y3 - 32) & samp;
let samp = Piece.sample(x4, y4 - 16) & samp;
if (samp){
do reDraw(x1 + 16, y1, x2, y2 + 16, x3 + 16, y3 - 32, x4, y4 - 16);
let direction = 1;
}
}
if (piece = 4){
let samp = Piece.sample(x3 + 32, y3 - 32) & samp;
if (samp){
do reDraw(x1, y1, x2 - 16, y2 + 16, x3 + 32, y3 - 32, x4 + 16, y4 - 16);
let direction = 1;
}
}
if (piece = 5){
let samp = Piece.sample(x1 + 32, y1 - 32) & samp;
let samp = Piece.sample(x2 + 16, y2 - 16) & samp;
let samp = Piece.sample(x4 - 16, y4 + 16) & samp;
if (samp){
do reDraw(x1 + 32, y1 - 32, x2 + 16, y2 - 16, x3, y3, x4 - 16, y4 + 16);
let direction = 1;
}
}
}
else{
if (direction = 1){
if (piece = 0){
let samp = Piece.sample(x1, y3) & samp;
let samp = Piece.sample(x1 - 1, y3) & samp;
if (samp){
do reDraw(x1 - 16, y3, x4, y3 + 15, x1, y1, x2, y2);
let direction = 2;
}
}
if (piece = 1){
let samp = Piece.sample(x1 - 16, y1 + 16) & samp;
let samp = Piece.sample(x3, y3 + 16) & samp;
let samp = Piece.sample(x3, y3 + 32) & samp;
if (samp){
do reDraw(x1 - 16, y1 + 16, x4, y4 + 16, x3, y3 + 32, x4, y2);
let direction = 2;
}
}
if (piece = 2){
let samp = Piece.sample(x1 - 16, y1 + 16) & samp;
let samp = Piece.sample(x2 + 16, y2 - 16) & samp;
let samp = Piece.sample(x3 - 32, y3) & samp;
if (samp){
do reDraw(x1 - 16, y1 + 16, x2 + 16, y2 - 16, x3 - 32, y3, x4 - 32, y4);
let direction = 2;
}
}
if (piece = 3){
let samp = Piece.sample(x1 - 16, y1) & samp;
let samp = Piece.sample(x4, y4 + 16) & samp;
if (samp){
do reDraw(x1 - 16, y1, x2, y2 - 16, x3 - 16, y3 +32, x4, y4 + 16);
let direction = 2;
}
}
if (piece = 4){
let samp = Piece.sample(x3 - 32, y3 + 32) & samp;
if (samp){
do reDraw(x1, y1, x2 + 16, y2 - 16, x3 - 32, y3 + 32, x4 - 16, y4 + 16);
let direction = 2;
}
}
if (piece = 5){
let samp = Piece.sample(x1 - 16, y1 + 16) & samp;
let samp = Piece.sample(x3 + 16, y3 - 16) & samp;
let samp = Piece.sample(x4 + 32, y4 - 32) & samp;
if (samp){
do reDraw(x1 - 32, y1 + 16, x2 - 16, y2, x3, y3 - 16, x4 + 16, y4 - 32);
let direction = 2;
}
}
}
else{
if (direction = 2){
if (piece = 0){
let samp = Piece.sample(x1, y1+16) & samp;
let samp = Piece.sample(x1, y1+32) & samp;
if (samp){
do reDraw(x1, y1, x1 + 15, y1 + 47, x3, y3, x4, y4);
let direction = 3;
}
}
if (piece = 1){
let samp = Piece.sample(x1 - 16, y1 + 16) & samp;
let samp = Piece.sample(x3, y3 + 16) & samp;
let samp = Piece.sample(x3, y3 + 32) & samp;
if (samp){
do reDraw(x1, y1 + 16, x1 + 15, y1 + 31, x1 + 16, y1 - 16, x4 - 16, y4);
let direction = 3;
}
}
if (piece = 2){
let samp = Piece.sample(x1, y1 - 16) & samp;
let samp = Piece.sample(x2 + 32, y2 + 16) & samp;
let samp = Piece.sample(x4 + 16, y4) & samp;
if (samp){
do reDraw(x1, y1 - 16, x2 - 32, y2 - 16, x3 + 16, y3 - 32, x4 + 16, y4);
let direction = 3;
}
}
if (piece = 3){
let samp = Piece.sample(x2 - 16, y2 + 16) & samp;
let samp = Piece.sample(x3, y3 - 32) & samp;
if (samp){
do reDraw(x1, y1, x2 - 16, y2 + 16, x3, y3 - 32, x4 - 16, y4 - 16);
let direction = 3;
}
}
if (piece = 4){
let samp = Piece.sample(x1 - 16, y1 - 16) & samp;
let samp = Piece.sample(x2 - 32, y2) & samp;
if (samp){
do reDraw(x1 - 16, y1 - 16, x2 - 32, y2, x3 + 16, y3 - 16, x4, y4);
let direction = 3;
}
}
if (piece = 5){
let samp = Piece.sample(x1 + 16, y1 - 16) & samp;
let samp = Piece.sample(x3 - 16, y3 - 16) & samp;
let samp = Piece.sample(x4 - 32, y4 + 32) & samp;
if (samp){
do reDraw(x1 + 16, y1 - 16, x2, y2, x3 - 16, y3 + 16, x4 - 32, y4 + 32);
let direction = 3;
}
}
}
else{
if (piece = 0){
let samp = Piece.sample(x4 + 16, y4) & samp;
let samp = Piece.sample(x4 + 32, y4) & samp;
if (samp){
do reDraw(x3, y3, x4, y4, x1, y1 + 32, x1 + 47, y1 + 47);
let direction = 0;
}
}
if (piece = 1){
let samp = Piece.sample(x1, y1 - 16) & samp;
let samp = Piece.sample(x4 + 16, y4) & samp;
if (samp){
do reDraw(x1, y1 - 16, x2, y2 -16, x1, y1, x4 + 16, y4);
let direction = 0;
}
}
if (piece = 2){
let samp = Piece.sample(x1 + 32, y1 + 16) & samp;
let samp = Piece.sample(x3 - 16, y3 + 32) & samp;
let samp = Piece.sample(x4 + 16, y4) & samp;
if (samp){
do reDraw(x1 + 32, y1 + 16, x2 + 32, y2 + 16, x3 - 16, y3 + 32, x4 + 16, y4);
let direction = 0;
}
}
if (piece = 3){
let samp = Piece.sample(x3, y3 + 32) & samp;
let samp = Piece.sample(x4 + 16, y4 + 16) & samp;
if (samp){
do reDraw(x1, y1, x2 + 16, y2 - 16, x3, y3 + 32, x4 + 16, y4 + 16);
let direction = 0;
}
}
if (piece = 4){
let samp = Piece.sample(x3 - 16, y3 + 16) & samp;
let samp = Piece.sample(x2 + 32, y2) & samp;
if (samp){
do reDraw(x1 + 16, y1 + 16, x2 + 32, y2, x3 - 16, y3 + 16, x4, y4);
let direction = 0;
}
}
if (piece = 5){
let samp = Piece.sample(x1 - 16, y1 + 32) & samp;
let samp = Piece.sample(x3 + 16, y3) & samp;
let samp = Piece.sample(x4 + 32, y4 - 16) & samp;
if (samp){
do reDraw(x1 - 16, y1 + 32, x2, y2 + 16, x3 + 16, y3, x4 + 32, y4 - 16);
let direction = 0;
}
}
}
}
}
return;
}
}
+203
View File
@@ -0,0 +1,203 @@
class Tetris {
static int points, seed, next_seed;
function void tetris(int z){
var Piece p, nextPiece;
var int i, x1, y1, x2, y2, x3, y3, x4, y4, key, j, randTmp, piece_number, moves;
var Array left_g, right_g, box, stick, left_z, right_z,dick, all_piece, tmp;
do Piece.init();
do Tetris.border();
let points = 0;
let all_piece = Array.new(25);
let all_piece[0] = Tetris.newPiece(16,0,31,15, 0,16,47,31, 0); // arrow
let all_piece[1] = Tetris.newPiece(0,0,15,15, 0,16,47,31, 1); // right_L
let all_piece[2] = Tetris.newPiece(32,16,47,31, 0,32,47,47, 2); // left_L
let all_piece[3] = Tetris.newPiece(0,0,31,15, 16,16,47,31, 3); // left_z
let all_piece[4] = Tetris.newPiece(16,0,47,15, 0,16,31,31, 4); // right_z
let all_piece[5] = Tetris.newPiece(0,0,31,15, 32,0,63,15, 5); //stick
let all_piece[6] = Tetris.newPiece(0,0,15,31, 16,0,31,31, 6); //box
let seed = z * 3; // multiply by 3, because it gets in a loop on some even numbers
let next_seed = Tetris.randomNumber();
do Output.moveCursor(0,0);
do Output.printString("Point: ");
do Output.printInt(points);
do Output.println();
do Output.printString("Next Piece: ");
while (true){ // The main game loop
let j = next_seed;
let next_seed = Tetris.randomNumber();
let tmp = all_piece[j]; // initializes the coords of the game piece
let x1 = tmp[0];
let y1 = tmp[1];
let x2 = tmp[2];
let y2 = tmp[3];
let x3 = tmp[4];
let y3 = tmp[5];
let x4 = tmp[6];
let y4 = tmp[7];
let piece_number = tmp[8];
let p = Piece.new(x1 + 240, y1, x2 + 240, y2, x3 + 240, y3, x4 + 240, y4, piece_number);
if (~(p.draw())){ // if a piece tries to spawn above a limit the game ends
if (~(Tetris.finish())){
return;
}
}
let tmp = all_piece[next_seed];
let x1 = tmp[0]; // initializes the coords of the next game piece that is being displayed
let y1 = tmp[1];
let x2 = tmp[2];
let y2 = tmp[3];
let x3 = tmp[4];
let y3 = tmp[5];
let x4 = tmp[6];
let y4 = tmp[7];
let piece_number = tmp[8];
let nextPiece = Piece.new(x1 + 16, y1 + 32, x2+16, y2 + 32, x3+16, y3 + 32, x4 + 16, y4 + 32, piece_number);
do nextPiece.draw();
while (p.getMove()){
let moves = 0;
while (moves < 3){ // one can move its piece 3 times before it moves down automatically
let key = Keyboard.keyPressed();
if (key = 130){
do p.moveLeft();
do Sys.wait(80);
}
if (key = 132){
do p.moveRight();
do Sys.wait(80);
}
if (key = 131){
do p.rotate();
}
if (key = 133){
do p.moveDown();
do p.moveDown();
}
let moves = moves +1;
}
do p.moveDown();
let i = i + 1;
do Sys.wait(80);
}
let i = 0;
do p.dispose();
do Tetris.completeRow();
do Output.moveCursor(0,7);
do Output.printInt(points);
do Screen.setColor(false);
do Screen.drawRectangle(16,32,80,96);
do Screen.setColor(true);
do nextPiece.dispose();
}
return;
}
function void completeRow(){ // checks if a row has been completed
var int adddress, row, colloum;
var bool complete;
let adddress = 16384 + 11;
let row = 15;
while (row > 0){ // for each row
let complete = true;
let colloum = 0;
while ((colloum < 10) & (complete)){ // for each collum
let complete = Memory.peek(adddress + colloum + (row * 512)) & complete;
let colloum = colloum + 1;
}
if (complete){ // removes the row
do Screen.setColor(false);
do Screen.drawRectangle(176, row * 16, 335, ((row * 16)+ 15) );
let points = points + 1;
do Tetris.shift(row);
}
let row = row - 1;
}
return;
}
function void shift(int rowShift){ // shifts all rows above the completed one
var int j, val, adddress, tmp, k;
let adddress = 16384 + 11;
while (rowShift > 1){ // each row
let j = 0;
while (j < 10){ // collum in the game field
let k = 0;
while (k < 16){ // each line a in 16 x 16 box
let tmp = adddress + j + (((rowShift - 1) * 512) + (k * 32));
let val = Memory.peek(tmp);
do Memory.poke(adddress + j + ((rowShift * 512) + (k * 32)), val);
do Memory.poke(tmp,0);
let k = k+ 1;
}
let j = j + 1;
}
let rowShift = rowShift - 1;
}
return;
}
function void border(){ // draws a border
do Screen.drawLine(175,0,175,255);
do Screen.drawLine(336,0,336,255);
return;
}
function Array newPiece(int Ax1, int Ay1, int Ax2, int Ay2, int Ax3, int Ay3, int Ax4, int Ay4,int p){
var Array gamepice;
let gamepice = Array.new(9);
let gamepice[0] = Ax1;
let gamepice[1] = Ay1;
let gamepice[2] = Ax2;
let gamepice[3] = Ay2;
let gamepice[4] = Ax3;
let gamepice[5] = Ay3;
let gamepice[6] = Ax4;
let gamepice[7] = Ay4;
let gamepice[8] = p;
return gamepice;
}
function int randomNumber(){ // radom number generator
var int multiplier,additor,moduler,toBeModulated;
let multiplier = 7;
let additor = 13;
let moduler = 1133;
let toBeModulated = (multiplier * seed) + additor;
let seed = Tetris.mod(toBeModulated,moduler);
return Tetris.mod(seed,7);
}
function bool finish(){ // after finishing the game the player has 2 options to start onether or to end the game
var char c;
do Screen.clearScreen();
do Output.moveCursor(10,24);
do Output.printString("Your score: ");
do Output.printInt(points);
do Sys.wait(10000);
do Screen.clearScreen();
do Output.moveCursor(10,0);
do Output.printString("Would you like to play again, for yes click 'Y' and for no 'N':");
let c = Keyboard.readChar();
if (c = 89){
do Screen.clearScreen();
return false;
}
if (c = 78){
do Screen.clearScreen();
do Sys.halt();
}
return true;
}
function int mod(int tbm, int mo){ //simple moduler devision
var int val, tmp2;
if (tbm < mo){
return tbm;
}
let tmp2 = (tbm / mo) * mo;
let val = tbm - tmp2;
return val;
}
}
+410
View File
@@ -0,0 +1,410 @@
import re
import os
from pathlib import Path
class Tokenizer:
def __init__(self):
self.i = 0
self.file = ''
self.symbols = ('(', ')', '[', ']', '}', '{', '>', '<', '=', '*', '+', '-', '/', '.', ';', ',', '&', '|',
'~', '&gt;', '&lt;', '&amp;')
self.key_word = (
'class', 'method', 'function', 'constructor', 'int', 'boolean', 'char', 'void', 'var', 'static', 'field',
'let', 'do', 'if', 'else', 'while', 'return', 'true', 'false', 'null', 'this')
self.token = ''
def token_type(self):
if self.token is None or self.token == '':
return None
if self.token in self.key_word:
return 'keyword'
elif self.token[0] == '"':
return 'stringConstant'
elif re.match(r"\d+", self.token):
return 'integerConstant'
elif self.token in self.symbols:
return 'symbol'
else:
return 'identifier'
def advance(self):
token = ''
i = self.i
while i < len(self.file):
if re.match(r'\s', self.file[i]):
i = i + 1
continue
else:
if self.file[i] in self.symbols:
if self.file[i] == '>':
self.token = '&gt;'
elif self.file[i] == '<':
self.token = '&lt;'
elif self.file[i] == '&':
self.token = '&amp;'
else:
self.token = self.file[i]
# self.token = self.file[i]
self.i = i + 1
return
elif self.file[i] == '"':
i += 1
while self.file[i] != '"':
token += self.file[i]
i += 1
self.i = i + 1
self.token = '"' + token + '"'
return
else:
while re.match(r'\w', self.file[i]):
token += self.file[i]
if i + 1 > len(self.file) - 1:
break
i += 1
self.i = i
self.token = token
return
def clear_file(self, directory):
with open(directory, "r") as my_file:
txt = my_file.read()
txt = re.sub(r"//.*", "", txt)
txt = re.sub(r"/[*][*].*[*]/", "", txt)
txt = re.sub(r"/[*][*][\w*\W*]*[*]/", "", txt)
self.file = txt
class CompilationEngine:
def __init__(self):
self.string = ''
self.tab = 0
def write_token(self, tokenizer):
if tokenizer.token_type() == 'stringConstant':
self.string += ' ' * self.tab + '<' + tokenizer.token_type() + '> ' + tokenizer.token.strip('"') + ' </' \
+ tokenizer.token_type() + '>\n'
else:
self.string += ' ' * self.tab + '<' + tokenizer.token_type() + '> ' + tokenizer.token + ' </' \
+ tokenizer.token_type() + '>\n'
def compile_class(self, tokenizer):
tokenizer.advance()
self.string += '<class>\n' + ' ' * self.tab
self.tab += 2
self.write_token(tokenizer)
tokenizer.advance()
self.write_token(tokenizer)
tokenizer.advance()
self.write_token(tokenizer)
tokenizer.advance()
while tokenizer.token != '}':
if tokenizer.token in ['static', 'field']:
self.compile_class_var_dec(tokenizer)
if tokenizer.token in ['constructor', 'function', 'method']:
self.compile_subroutine(tokenizer)
self.write_token(tokenizer)
tokenizer.advance()
self.tab -= 2
self.string += ' ' * self.tab + '</class>\n'
def compile_class_var_dec(self, tokenizer):
self.string += ' ' * self.tab + '<classVarDec>\n'
self.tab += 2
self.write_token(tokenizer)
tokenizer.advance()
self.write_token(tokenizer)
tokenizer.advance()
self.write_token(tokenizer)
tokenizer.advance()
while tokenizer.token == ',':
self.write_token(tokenizer)
tokenizer.advance()
self.write_token(tokenizer)
tokenizer.advance()
self.write_token(tokenizer)
tokenizer.advance()
self.tab -= 2
self.string += ' ' * self.tab + '</classVarDec>\n'
def compile_subroutine(self, tokenizer):
self.string += ' ' * self.tab + '<subroutineDec>\n'
self.tab += 2
self.write_token(tokenizer)
tokenizer.advance()
self.write_token(tokenizer)
tokenizer.advance()
self.write_token(tokenizer)
tokenizer.advance()
self.write_token(tokenizer)
tokenizer.advance()
self.compile_parameter_list(tokenizer)
self.string += ' ' * self.tab + '<subroutineBody>\n'
self.tab += 2
self.write_token(tokenizer)
tokenizer.advance()
while tokenizer.token != '}':
if tokenizer.token == 'var':
self.compile_var_dec(tokenizer)
elif tokenizer.token in ['let', 'if', 'while', 'do', 'return']:
self.compile_statements(tokenizer)
self.write_token(tokenizer)
self.tab -= 2
self.string += ' ' * self.tab + '</subroutineBody>\n'
tokenizer.advance()
self.tab -= 2
self.string += ' ' * self.tab + '</subroutineDec>\n'
def compile_parameter_list(self, tokenizer):
self.string += ' ' * self.tab + '<parameterList>\n'
self.tab += 2
while tokenizer.token != ')':
self.write_token(tokenizer)
tokenizer.advance()
self.write_token(tokenizer)
tokenizer.advance()
while tokenizer.token == ',':
self.write_token(tokenizer)
tokenizer.advance()
self.write_token(tokenizer)
tokenizer.advance()
self.tab -= 2
self.string += ' ' * self.tab + '</parameterList>\n'
self.write_token(tokenizer)
tokenizer.advance()
def compile_var_dec(self, tokenizer):
self.string += ' ' * self.tab + '<varDec>\n'
self.tab += 2
self.write_token(tokenizer)
tokenizer.advance()
self.write_token(tokenizer)
tokenizer.advance()
self.write_token(tokenizer)
tokenizer.advance()
while tokenizer.token == ',':
self.write_token(tokenizer)
tokenizer.advance()
self.write_token(tokenizer)
tokenizer.advance()
self.write_token(tokenizer)
tokenizer.advance()
self.tab -= 2
self.string += ' ' * self.tab + '</varDec>\n'
def compile_statements(self, tokenizer):
self.string += ' ' * self.tab + '<statements>\n'
self.tab += 2
while True:
if tokenizer.token == 'let':
self.compile_let(tokenizer)
elif tokenizer.token == 'if':
self.compile_if(tokenizer)
elif tokenizer.token == 'while':
self.compile_while(tokenizer)
elif tokenizer.token == 'do':
self.compile_do(tokenizer)
elif tokenizer.token == 'return':
self.compile_return(tokenizer)
else:
self.tab -= 2
self.string += ' ' * self.tab + '</statements>\n'
break
def compile_do(self, tokenizer):
self.string += ' ' * self.tab + '<doStatement>\n'
self.tab += 2
self.write_token(tokenizer)
tokenizer.advance()
self.write_token(tokenizer)
tokenizer.advance()
if tokenizer.token == '(':
self.write_token(tokenizer)
tokenizer.advance()
self.compile_expression_list(tokenizer)
self.write_token(tokenizer)
tokenizer.advance()
elif tokenizer.token == '.':
self.write_token(tokenizer)
tokenizer.advance()
self.write_token(tokenizer)
tokenizer.advance()
self.write_token(tokenizer)
tokenizer.advance()
self.compile_expression_list(tokenizer)
self.write_token(tokenizer)
tokenizer.advance()
self.write_token(tokenizer)
tokenizer.advance()
self.tab -= 2
self.string += ' ' * self.tab + '</doStatement>\n'
def compile_let(self, tokenizer):
self.string += ' ' * self.tab + '<letStatement>\n'
self.tab += 2
self.write_token(tokenizer)
tokenizer.advance()
self.write_token(tokenizer)
tokenizer.advance()
if tokenizer.token == '[':
self.write_token(tokenizer)
tokenizer.advance()
self.compile_expression(tokenizer)
self.write_token(tokenizer)
tokenizer.advance()
self.write_token(tokenizer)
tokenizer.advance()
self.compile_expression(tokenizer)
self.write_token(tokenizer)
tokenizer.advance()
self.tab -= 2
self.string += ' ' * self.tab + '</letStatement>\n'
def compile_while(self, tokenizer):
self.string += ' ' * self.tab + '<whileStatement>\n'
self.tab += 2
self.write_token(tokenizer)
tokenizer.advance()
self.write_token(tokenizer)
tokenizer.advance()
self.compile_expression(tokenizer)
self.write_token(tokenizer)
tokenizer.advance()
self.write_token(tokenizer)
tokenizer.advance()
self.compile_statements(tokenizer)
self.write_token(tokenizer)
tokenizer.advance()
self.tab -= 2
self.string += ' ' * self.tab + '</whileStatement>\n'
def compile_return(self, tokenizer):
self.string += ' ' * self.tab + '<returnStatement>\n'
self.tab += 2
self.write_token(tokenizer)
tokenizer.advance()
if tokenizer.token != ';':
self.compile_expression(tokenizer)
self.write_token(tokenizer)
tokenizer.advance()
self.tab -= 2
self.string += ' ' * self.tab + '</returnStatement>\n'
def compile_if(self, tokenizer):
self.string += ' ' * self.tab + '<ifStatement>\n'
self.tab += 2
self.write_token(tokenizer)
tokenizer.advance()
self.write_token(tokenizer)
tokenizer.advance()
self.compile_expression(tokenizer)
self.write_token(tokenizer)
tokenizer.advance()
self.write_token(tokenizer)
tokenizer.advance()
self.compile_statements(tokenizer)
self.write_token(tokenizer)
tokenizer.advance()
while tokenizer.token == 'else':
self.write_token(tokenizer)
tokenizer.advance()
self.write_token(tokenizer)
tokenizer.advance()
self.compile_statements(tokenizer)
self.write_token(tokenizer)
tokenizer.advance()
self.tab -= 2
self.string += ' ' * self.tab + '</ifStatement>\n'
def compile_expression(self, tokenizer):
if tokenizer.token in ['(', '~', '-'] or tokenizer.token_type() != 'symbol':
self.string += ' ' * self.tab + '<expression>\n'
self.tab += 2
self.compile_term(tokenizer)
while tokenizer.token in ['+', '-', '*', '/', '&amp;', '|', '&lt;', '&gt;', '=']:
self.write_token(tokenizer)
tokenizer.advance()
self.compile_term(tokenizer)
self.tab -= 2
self.string += ' ' * self.tab + '</expression>\n'
def compile_term(self, tokenizer):
if tokenizer.token == '(':
self.string += ' ' * self.tab + '<term>\n'
self.tab += 2
self.write_token(tokenizer)
tokenizer.advance()
self.compile_expression(tokenizer)
self.write_token(tokenizer)
tokenizer.advance()
self.tab -= 2
self.string += ' ' * self.tab + '</term>\n'
elif tokenizer.token in ['~', '-']:
self.string += ' ' * self.tab + '<term>\n'
self.tab += 2
self.write_token(tokenizer)
tokenizer.advance()
self.compile_term(tokenizer)
self.tab -= 2
self.string += ' ' * self.tab + '</term>\n'
elif tokenizer.token_type() != 'symbol':
self.string += ' ' * self.tab + '<term>\n'
self.tab += 2
self.write_token(tokenizer)
tokenizer.advance()
if tokenizer.token == '[':
self.write_token(tokenizer)
tokenizer.advance()
self.compile_expression(tokenizer)
self.write_token(tokenizer)
tokenizer.advance()
self.tab -= 2
self.string += ' ' * self.tab + '</term>\n'
elif tokenizer.token == '(':
self.write_token(tokenizer)
tokenizer.advance()
self.compile_expression_list(tokenizer)
self.write_token(tokenizer)
tokenizer.advance()
self.tab -= 2
self.string += ' ' * self.tab + '</term>\n'
elif tokenizer.token == '.':
self.write_token(tokenizer)
tokenizer.advance()
self.write_token(tokenizer)
tokenizer.advance()
self.write_token(tokenizer)
tokenizer.advance()
self.compile_expression_list(tokenizer)
self.write_token(tokenizer)
tokenizer.advance()
self.tab -= 2
self.string += ' ' * self.tab + '</term>\n'
else:
self.tab -= 2
self.string += ' ' * self.tab + '</term>\n'
def compile_expression_list(self, tokenizer):
self.string += ' ' * self.tab + '<expressionList>\n'
self.tab += 2
self.compile_expression(tokenizer)
while tokenizer.token == ',':
self.write_token(tokenizer)
tokenizer.advance()
self.compile_expression(tokenizer)
self.tab -= 2
self.string += ' ' * self.tab + '</expressionList>\n'
path = os.getcwd()
for root, dirs, files in os.walk(path, topdown=False):
for name in files:
if name[-4:] == 'jack':
tok = Tokenizer()
tok.clear_file(Path(root, name))
ce = CompilationEngine()
ce.compile_class(tok)
with open(Path(root, name[:-4] + 'xml'), "w+") as my_xml:
my_xml.write(ce.string)
+350
View File
@@ -0,0 +1,350 @@
import os
from pathlib import Path
from tokenizer import Tokenizer
from vmwriter import VMWriter
from symbol_table import SymbolTable
# TODO add names to variables when you call for them, aka current_vm_append(thingtobeappended=blablac)
class CompilationEngine:
def __init__(self, tokenizer, full_path_vm):
self.string = self.sub_type = self.class_name = self.function_type = ''
self.tab = self.recursion_index = 0
self.tokenizer = tokenizer
self.sym_table = []
self.vmwriter = VMWriter(full_path_vm)
self.current_vm = [] # used to reverse some of the commands, eg a+b need to be a b +
def search_kind_of_sym(self, current_vm):
if self.sym_table[-1].kind_of(current_vm) is not None:
return self.sym_table[-1].kind_of(current_vm), self.sym_table[-1].index_of(current_vm)
for i in range(len(self.sym_table) - 2, -1,
-1): # start from the amount of sym_tables -2 so it starts from one below the current,
# until it is bigger than -1, walking it backwards
if self.sym_table[i].kind_of(current_vm) in ('static', 'this'):
return self.sym_table[i].kind_of(current_vm), self.sym_table[i].index_of(current_vm)
def search_type_of_sym(self, current_vm):
for i in range(len(self.sym_table) - 1, -1, -1):
if self.sym_table[i].type_of(current_vm) is not None:
return self.sym_table[i].type_of(current_vm)
def write_token(self):
if self.tokenizer.token_type() == 'stringConstant':
self.string += ' ' * self.tab + '<' + self.tokenizer.token_type() + '> ' + self.tokenizer.token.strip(
'"') + ' </' + self.tokenizer.token_type() + '>\n'
else:
self.string += ' ' * self.tab + '<' + self.tokenizer.token_type() + '> ' + self.tokenizer.token + ' </' \
+ self.tokenizer.token_type() + '>\n'
def compile_class(self):
self.sym_table.append(SymbolTable())
self.tokenizer.advance() # class ->
self.tokenizer.advance() # type ->
self.class_name = self.tokenizer.token
self.tokenizer.advance() # name ->
self.tokenizer.advance() # { ->
while self.tokenizer.token != '}':
if self.tokenizer.token in ['static', 'field']:
self.compile_class_var_dec()
if self.tokenizer.token in ['constructor', 'function', 'method']:
self.compile_subroutine()
self.tokenizer.advance()
self.sym_table.pop()
self.vmwriter.close_vm_file()
def compile_class_var_dec(self):
var_kind = tokenizer_main.token
self.tokenizer.advance()
var_type = tokenizer_main.token
self.tokenizer.advance()
var_name = tokenizer_main.token
self.sym_table[-1].define(var_name, var_type, var_kind)
self.tokenizer.advance()
while self.tokenizer.token == ',':
self.tokenizer.advance()
var_name = tokenizer_main.token
self.sym_table[-1].define(var_name, var_type, var_kind)
self.tokenizer.advance()
self.tokenizer.advance()
def compile_subroutine(self):
self.sym_table.append(SymbolTable())
self.sub_type = self.tokenizer.token
self.tokenizer.advance() # subroutine type(function|method|constructor) ->
self.function_type = self.tokenizer.token
self.tokenizer.advance() # subroutine kind(int|void|etc..) ->
sub_name = self.tokenizer.token
self.tokenizer.advance() # subroutine name ->
self.tokenizer.advance() # ( ->
if self.sub_type == 'method':
self.sym_table[-1].start_subroutine('this', self.class_name)
self.compile_parameter_list()
self.tokenizer.advance() # { ->
while self.tokenizer.token == 'var': # create only symbol teable entries
self.compile_var_dec()
if self.sub_type == 'constructor':
self.vmwriter.write_function(f'{self.class_name}.{sub_name}', self.sym_table[-1].var_count('var'))
self.vmwriter.write_push('constant', self.sym_table[-2].var_count('field'))
self.vmwriter.write_call('Memory.alloc', 1)
self.vmwriter.write_pop('pointer', 0)
elif self.sub_type == 'method':
self.vmwriter.write_function(f'{self.class_name}.{sub_name}', self.sym_table[-1].var_count('var'))
self.vmwriter.write_push('argument', 0)
self.vmwriter.write_pop('pointer', 0)
else:
self.vmwriter.write_function(f'{self.class_name}.{sub_name}', self.sym_table[-1].var_count('var'))
while self.tokenizer.token != '}':
self.compile_statements()
self.tokenizer.advance()
self.sym_table.pop()
def compile_parameter_list(self):
if self.tokenizer.token != ')':
var_type = self.tokenizer.token
self.tokenizer.advance() # var ype ->
var_name = self.tokenizer.token
self.sym_table[-1].define(var_name, var_type, 'argument')
self.tokenizer.advance() # var name ->
while self.tokenizer.token == ',':
self.tokenizer.advance() # , ->
var_type = self.tokenizer.token
self.tokenizer.advance() # type ->
var_name = self.tokenizer.token
self.sym_table[-1].define(var_name, var_type, 'argument')
self.tokenizer.advance() # name ->
self.tokenizer.advance() # )->
def compile_var_dec(self):
var_kind = tokenizer_main.token
self.tokenizer.advance()
var_type = tokenizer_main.token
self.tokenizer.advance()
var_name = tokenizer_main.token
self.sym_table[-1].define(var_name, var_type, var_kind)
self.tokenizer.advance()
while self.tokenizer.token == ',':
self.tokenizer.advance()
var_name = tokenizer_main.token
self.sym_table[-1].define(var_name, var_type, var_kind)
self.tokenizer.advance()
self.tokenizer.advance()
def compile_statements(self):
while True:
if self.tokenizer.token == 'let':
self.compile_let()
elif self.tokenizer.token == 'if':
self.compile_if()
elif self.tokenizer.token == 'while':
self.compile_while()
elif self.tokenizer.token == 'do':
self.compile_do()
elif self.tokenizer.token == 'return':
self.compile_return()
else:
break
def compile_do(self):
self.tokenizer.advance() # do ->
class_name = self.tokenizer.token
self.tokenizer.advance() # name ->
if self.tokenizer.token == '(': # method
self.vmwriter.write_push('pointer', 0)
self.tokenizer.advance() # ( ->
count = self.compile_expression_list()
self.tokenizer.advance() # ) ->
self.vmwriter.write_call(f'{self.class_name}.{class_name}', count + 1)
elif self.tokenizer.token == '.': # method or function
self.tokenizer.advance() # . ->
fname = f'{class_name}.{self.tokenizer.token}'
sname = f'{self.search_type_of_sym(class_name)}.{self.tokenizer.token}'
self.tokenizer.advance() # name ->
if self.search_kind_of_sym(class_name) is not None:
self.vmwriter.write_push(*self.search_kind_of_sym(class_name))
self.tokenizer.advance() # ( ->
count = self.compile_expression_list()
self.tokenizer.advance() # ) ->
if self.search_kind_of_sym(class_name) is not None:
self.vmwriter.write_call(f'{sname}', count + 1)
else:
self.vmwriter.write_call(f'{fname}', count)
self.vmwriter.write_pop('temp', '0')
self.tokenizer.advance() # ; ->
def compile_let(self):
flag_array = 0
self.tokenizer.advance() # let ->
self.current_vm.append(self.tokenizer.token)
self.tokenizer.advance() # var_name ->
if self.tokenizer.token == '[':
self.vmwriter.write_push(*self.search_kind_of_sym(self.current_vm[-1]))
self.tokenizer.advance() # [ ->
self.compile_expression()
self.tokenizer.advance() # ] ->
flag_array = 1
self.tokenizer.advance() # = ->
self.compile_expression()
self.tokenizer.advance() # ; ->
if flag_array == 0:
self.vmwriter.write_pop(*self.search_kind_of_sym(self.current_vm[-1]))
else:
self.vmwriter.write_pop('temp', 1)
self.vmwriter.write_arithmetic('+')
self.vmwriter.write_pop('pointer', 1)
self.vmwriter.write_push('temp', 1)
self.vmwriter.write_pop('that', 0)
self.current_vm.pop()
def compile_while(self):
self.tokenizer.advance() # while ->
label1 = self.vmwriter.label_index
self.vmwriter.write_lable(self.vmwriter.label_index)
self.vmwriter.label_index += 1
self.tokenizer.advance() # ( ->
self.compile_expression()
self.tokenizer.advance() # ) ->
label2 = self.vmwriter.label_index
self.vmwriter.write_if(self.vmwriter.label_index)
self.vmwriter.label_index += 1
self.tokenizer.advance() # { ->
self.compile_statements()
self.tokenizer.advance() # } ->
self.vmwriter.write_goto(label1)
self.vmwriter.write_lable(label2)
def compile_return(self):
self.tokenizer.advance() # return ->
if self.tokenizer.token != ';':
self.compile_expression()
self.vmwriter.write_return(self.function_type)
self.tokenizer.advance() # ; ->
def compile_if(self):
self.tokenizer.advance() # if ->
self.tokenizer.advance() # ( ->
self.compile_expression()
self.tokenizer.advance() # ) ->
label1 = self.vmwriter.label_index
self.vmwriter.write_if(self.vmwriter.label_index)
self.vmwriter.label_index += 1
self.tokenizer.advance() # { ->
self.compile_statements()
self.tokenizer.advance() # } ->
label2 = self.vmwriter.label_index
self.vmwriter.write_goto(self.vmwriter.label_index)
self.vmwriter.label_index += 1
self.vmwriter.write_lable(label1)
if self.tokenizer.token == 'else':
self.tokenizer.advance() # else ->
self.tokenizer.advance() # { ->
self.compile_statements()
self.tokenizer.advance() # } ->
self.vmwriter.write_lable(label2)
def compile_expression(self):
self.compile_term()
while self.tokenizer.token in ['+', '-', '*', '/', '|', '=', '>', '<', '&']:
self.current_vm.append(self.tokenizer.token)
self.tokenizer.advance() # symbol ->
self.compile_term()
self.vmwriter.write_arithmetic(self.current_vm[-1])
self.current_vm.pop()
def compile_term(self):
if self.tokenizer.token == '(': # expression ()
self.tokenizer.advance() # ( ->
self.compile_expression()
self.tokenizer.advance() # ) ->
elif self.tokenizer.token in ['~', '-']: # uniry op
self.current_vm.append(self.tokenizer.token)
tmp = 'neg' if self.tokenizer.token == '-' else self.tokenizer.token
self.tokenizer.advance() # ~ or - ->
self.compile_term()
self.vmwriter.write_arithmetic(tmp)
self.current_vm.pop()
elif self.tokenizer.token_type() != 'symbol':
self.current_vm.append(self.tokenizer.token)
self.tokenizer.advance() # integer, string, keyword, varnname, subroutine_name, class_name, var_name ->
if self.tokenizer.token == '[': # Array
self.tokenizer.advance() # [ ->
self.vmwriter.write_push(*self.search_kind_of_sym(self.current_vm[-1]))
self.current_vm.pop()
self.compile_expression()
self.vmwriter.write_arithmetic('+')
self.vmwriter.write_pop('pointer', 1)
self.vmwriter.write_push('that', 0)
self.tokenizer.advance() # ] ->
elif self.tokenizer.token == '(': # subroutine_name ()
self.tokenizer.advance() # ( ->
count = self.compile_expression_list()
self.tokenizer.advance() # ) ->
self.vmwriter.write_call(f'{self.class_name}.{self.current_vm[-1]}', count)
self.current_vm.pop()
elif self.tokenizer.token == '.': # method
if self.search_type_of_sym(self.current_vm[-1]) is not None:
flag = 1
self.vmwriter.write_push(*self.search_kind_of_sym(self.current_vm[-1]))
else:
flag = 0
self.tokenizer.advance() # . ->
fname = self.tokenizer.token
self.tokenizer.advance() # subroutine name ->
self.tokenizer.advance() # ( ->
count = self.compile_expression_list()
self.tokenizer.advance() # ) ->
if flag == 1:
self.vmwriter.write_call(f'{self.search_type_of_sym(self.current_vm[-1])}.{fname}', count + 1)
else:
self.vmwriter.write_call(f'{self.current_vm[-1]}.{fname}', count)
self.current_vm.pop()
elif self.tokenizer.token_type(self.current_vm[-1]) == 'stringConstant':
self.vmwriter.write_push('constant', len(self.current_vm[-1].strip('"')))
self.vmwriter.write_call('String.new', 1)
for index, item in enumerate(self.current_vm[-1].strip('"')):
self.vmwriter.write_push('constant', ord(item))
self.vmwriter.write_call('String.appendChar', 2)
self.current_vm.pop()
elif self.tokenizer.token_type(self.current_vm[-1]) == 'integerConstant':
self.vmwriter.write_push('constant', self.current_vm[-1])
self.current_vm.pop()
elif self.tokenizer.token_type(self.current_vm[-1]) == 'identifier':
self.vmwriter.write_push(*self.search_kind_of_sym(self.current_vm[-1]))
self.current_vm.pop()
elif self.current_vm[-1] == 'true':
self.vmwriter.write_push('constant', '1')
self.vmwriter.write_arithmetic('neg')
self.current_vm.pop()
elif self.current_vm[-1] == 'false' or self.current_vm[-1] == 'null':
self.vmwriter.write_push('constant', '0')
self.current_vm.pop()
elif self.current_vm[-1] == 'this':
self.vmwriter.write_push('pointer', '0')
self.current_vm.pop()
elif self.current_vm[-1] == 'that':
self.vmwriter.write_push('pointer', '1')
self.current_vm.pop()
def compile_expression_list(self):
count_exp = 0
if self.tokenizer.token in ['(', '~', '-'] or self.tokenizer.token_type() != 'symbol':
count_exp += 1
self.compile_expression()
while self.tokenizer.token == ',':
count_exp += 1
self.tokenizer.advance() # ,
self.compile_expression()
return count_exp
if __name__ == '__main__':
path = os.getcwd()
for root, dirs, files in os.walk(path, topdown=False):
for name in files:
if name[-4:] == 'jack':
tokenizer_main = Tokenizer()
tokenizer_main.clear_file(Path(root, name))
full_path = Path(root, name[:-4] + 'vm')
comp_eng_main = CompilationEngine(tokenizer_main, full_path)
comp_eng_main.compile_class()
+62
View File
@@ -0,0 +1,62 @@
class Symbol:
def __init__(self):
self.s_name = ''
self.s_kind = ''
self.s_type = ''
self.s_index = 0
class SymbolTable:
def __init__(self):
self.sym = []
def define(self, s_name, s_type, s_kind):
self.sym.append(Symbol())
self.sym[-1].s_name = s_name
self.sym[-1].s_type = s_type
self.sym[-1].s_kind = s_kind
self.sym[-1].s_index = self.var_count(s_kind) - 1
def start_subroutine(self, s_name, s_type):
self.sym.append(Symbol())
self.sym[-1].s_name = s_name
self.sym[-1].s_type = s_type
self.sym[-1].s_kind = 'argument'
self.sym[-1].s_index = 0
def start_class(self, s_name, s_type):
self.sym.append(Symbol())
self.sym[-1].s_name = 'this'
self.sym[-1].s_type = s_type
self.sym[-1].s_kind = 'field'
self.sym[-1].s_index = 0
def var_count(self, s_kind):
count = 0 # it is -1 so the first index is 0
for i in self.sym:
if i.s_kind == s_kind:
count += 1
return count
def kind_of(self, s_name):
for i in self.sym:
if i.s_name == s_name:
if i.s_kind == 'var':
return 'local'
elif i.s_kind == 'field':
return 'this'
else:
return i.s_kind
return None
def type_of(self, s_name):
for i in self.sym:
if i.s_name == s_name:
return i.s_type
return None
def index_of(self, s_name):
for i in self.sym:
if i.s_name == s_name:
return i.s_index
return None
+78
View File
@@ -0,0 +1,78 @@
import re
class Tokenizer:
def __init__(self):
self.i = 0
self.file = ''
self.symbols = ('(', ')', '[', ']', '}', '{', '>', '<', '=', '*', '+', '-', '/', '.', ';', ',', '&', '|',
'~')
self.key_word = (
'class', 'method', 'function', 'constructor', 'int', 'boolean', 'char', 'void', 'var', 'static', 'field',
'let', 'do', 'if', 'else', 'while', 'return', 'true', 'false', 'null', 'this')
self.token = ''
def token_type(self, token=None):
if token is None:
token = self.token
if token is None or token == '':
return None
if token in self.key_word:
return 'keyword'
elif token[0] == '"':
return 'stringConstant'
elif re.match(r"\d+", token):
return 'integerConstant'
elif token in self.symbols:
return 'symbol'
else:
return 'identifier'
def advance(self):
token = ''
i = self.i
while i < len(self.file):
if re.match(r'\s', self.file[i]):
i = i + 1
continue
else:
if self.file[i] in self.symbols:
self.token = self.file[i]
self.i = i + 1
return
elif self.file[i] == '"':
i += 1
while self.file[i] != '"':
token += self.file[i]
i += 1
self.i = i + 1
self.token = '"' + token + '"'
return
else:
while re.match(r'\w', self.file[i]):
token += self.file[i]
if i + 1 > len(self.file) - 1:
break
i += 1
self.i = i
self.token = token
return
def clear_file(self, directory):
with open(directory, "r") as my_file:
txt = my_file.read()
txt = re.sub(r"//.*", "", txt)
txt = re.sub(r"/[*][*].*[*]/", "", txt)
i = 0
# TODO this should be a regex
while i < len(txt):
if txt[i] == '/' and txt[i + 1] == '*' and txt[i + 2] == '*':
start = i
while txt[i] != '*' or txt[i + 1] != '/':
i += 1
stop = i + 2
txt = txt[:start] + txt[stop:len(txt)]
i = start - 1
i += 1
self.file = txt
+75
View File
@@ -0,0 +1,75 @@
class VMWriter:
def __init__(self, vm_path):
self.my_vm = open(vm_path, "w+")
self.label_index = 0
def write_push(self, segment, index):
self.my_vm.write(f'push {segment} {index}\n')
print(f'push {segment} {index}')
def write_lable(self, label):
self.my_vm.write(f'label L{label}\n')
print(f'label L{label}')
def write_arithmetic(self, command):
if command == '+':
self.my_vm.write('add\n')
print('add')
elif command == '-':
self.my_vm.write('sub\n')
print('sub')
elif command == 'neg':
self.my_vm.write('neg\n')
print('neg')
elif command == '=':
self.my_vm.write('eq\n')
print('eq')
elif command == '>':
self.my_vm.write('gt\n')
print('gt')
elif command == '<':
self.my_vm.write('lt\n')
print('lt')
elif command == '&':
self.my_vm.write('and\n')
print('and')
elif command == '|':
self.my_vm.write('or\n')
print('or')
elif command == '~':
self.my_vm.write('not\n')
print('not')
elif command == '*':
self.write_call('Math.multiply', 2)
elif command == '/':
self.write_call('Math.divide', 2)
def write_pop(self, segment, index):
print(f'pop {segment} {index}')
self.my_vm.write(f'pop {segment} {index}\n')
def write_goto(self, label):
self.my_vm.write(f'goto L{label}\n')
print(f'goto L{label}')
def write_if(self, label):
self.write_arithmetic('~')
self.my_vm.write(f'if-goto L{label}\n')
print(f'if-goto L{label}')
def write_call(self, label, num_args):
self.my_vm.write(f'call {label} {num_args}\n')
print(f'call {label} {num_args}')
def write_function(self, label, num_locals):
self.my_vm.write(f'function {label} {num_locals}\n')
print(f'function {label} {num_locals}')
def write_return(self, func_type):
if func_type == 'void':
self.write_push('constant', '0')
self.my_vm.write('return\n')
print(f'return')
def close_vm_file(self):
self.my_vm.close()
+29
View File
@@ -0,0 +1,29 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/Array.jack
/**
* Represents an array.
* In the Jack language, arrays are instances of the Array class.
* Once declared, the array entries can be accessed using the usual
* syntax arr[i]. Each array entry can hold a primitive data type as
* well as any object type. Different array entries can have different
* data types.
*/
class Array {
/** Constructs a new Array of the given size. */
function Array new(int size) {
if(size < 0){
do Sys.error(7);
}
return Memory.alloc(size);
}
/** Disposes this array. */
method void dispose() {
do Memory.deAlloc(this);
return;
}
}
+102
View File
@@ -0,0 +1,102 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/Keyboard.jack
/**
* A library for handling user input from the keyboard.
*/
class Keyboard {
static Array mem;
/** Initializes the keyboard. */
function void init() {
let mem = 0;
return;
}
/**
* Returns the character of the currently pressed key on the keyboard;
* if no key is currently pressed, returns 0.
*
* Recognizes all ASCII characters, as well as the following keys:
* new line = 128 = String.newline()
* backspace = 129 = String.backspace()
* left arrow = 130
* up arrow = 131
* right arrow = 132
* down arrow = 133
* home = 134
* End = 135
* page up = 136
* page down = 137
* insert = 138
* delete = 139
* ESC = 140
* F1 - F12 = 141 - 152
*/
function char keyPressed() {
return mem[24576];
}
/**
* Waits until a key is pressed on the keyboard and released,
* then echoes the key to the screen, and returns the character
* of the pressed key.
*/
function char readChar() {
var char a, b;
do Output.printChar(0);
while ((b = 0) | (a > 0)){
let a = Keyboard.keyPressed();
if (a > 0){
let b = a;
}
}
do Output.printChar(String.backSpace());
do Output.printChar(b);
return b;
}
/**
* Displays the message on the screen, reads from the keyboard the entered
* text until a newline character is detected, echoes the text to the screen,
* and returns its value. Also handles user backspaces.
*/
function String readLine(String message) {
var String s, b;
var char c;
let s = String.new(100);
do Output.printString(message);
while (true){
let c = Keyboard.readChar();
if (c = 128){
return s;
}
else{
if (c = 129){
do s.eraseLastChar();
}
else{
do s.appendChar(c);
}
}
}
return s;
}
/**
* Displays the message on the screen, reads from the keyboard the entered
* text until a newline character is detected, echoes the text to the screen,
* and returns its integer value (until the first non-digit character in the
* entered text is detected). Also handles user backspaces.
*/
function int readInt(String message) {
var starting a;
var int b;
let a = Keyboard.readLine(message);
let b = String.intValue(a);
do String.dispose(a);
return b;
}
}
+83
View File
@@ -0,0 +1,83 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/StringTest/Main.jack
/** Test program for the OS String class. */
class Main {
/** Performs various string manipulations and displays their results. */
function void main() {
var String s;
var String i;
let s = String.new(0); // a zero-capacity string should be supported
do s.dispose();
let s = String.new(6); // capacity 6, make sure that length 5 is displayed
let s = s.appendChar(97);
let s = s.appendChar(98);
let s = s.appendChar(99);
let s = s.appendChar(100);
let s = s.appendChar(101);
do Output.printString("new: ");
do Output.printString(s); // new, appendChar: abcde
do Output.println();
let i = String.new(6);
do i.setInt(12345);
do Output.printString("setInt: ");
do Output.printString(i); // setInt: 12345
do Output.println();
do i.setInt(-32767);
do Output.printString("setInt: ");
do Output.printString(i); // setInt: -32767
do Output.println();
do Output.printString("length: ");
do Output.printInt(s.length()); // length: 5
do Output.println();
do Output.printString("charAt[2]: ");
do Output.printInt(s.charAt(2)); // charAt[2]: 99
do Output.println();
do s.setCharAt(2, 45);
do Output.printString("setCharAt(2,'-'): ");
do Output.printString(s); // setCharAt(2,'-'): ab-de
do Output.println();
do s.eraseLastChar();
do Output.printString("eraseLastChar: ");
do Output.printString(s); // eraseLastChar: ab-d
do Output.println();
let s = "456";
do Output.printString("intValue: ");
do Output.printInt(s.intValue()); // intValue: 456
do Output.println();
let s = "-32123";
do Output.printString("intValue: ");
do Output.printInt(s.intValue()); // intValue: -32123
do Output.println();
do Output.printString("backSpace: ");
do Output.printInt(String.backSpace()); // backSpace: 129
do Output.println();
do Output.printString("doubleQuote: ");
do Output.printInt(String.doubleQuote());// doubleQuote: 34
do Output.println();
do Output.printString("newLine: ");
do Output.printInt(String.newLine()); // newLine: 128
do Output.println();
do i.dispose();
do s.dispose();
return;
}
}
+143
View File
@@ -0,0 +1,143 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/Math.jack
/**
* A library of commonly used mathematical functions.
* Note: Jack compilers implement multiplication and division using OS method calls.
*/
class Math {
static Array st;
static int division_tmp, f;
/** Initializes the library. */
function void init() {
var int a;
let st = Array.new(16);
let st[0] = 1;
while (a < 15){
let a = a + 1;
let st[a] = st[a - 1] + st[a - 1];
}
return;
}
/** Returns the absolute value of x. */
function int abs(int x) {
if (x > 0){
return x;
}
return -x;
}
/** Returns the product of x and y.
* When a Jack compiler detects the multiplication operator '*' in the
* program's code, it handles it by invoking this method. In other words,
* the Jack expressions x*y and multiply(x,y) return the same value.
*/
function int multiply(int x, int y) {
var int sum, temp, y_comp, i, neg;
let neg = ((x < 0) & (y > 0)) | ((x > 0) & (y < 0));
let x = Math.abs(x);
let y = Math.abs(y);
if (x < y){
let temp = x;
let x = y;
let y = temp;
}
if (y = 1){
if(neg){
return -x;
}
return x;
}
while((y_comp - 1) < (y - 1)){
if ((st[i] & y) > 0) {
let sum = sum + x;
let y_comp = y_comp + st[i];
}
let x = x + x;
let i = i + 1;
}
if(neg){
let sum = -sum;
}
return sum;
}
/** Returns the integer part of x/y.
* When a Jack compiler detects the multiplication operator '/' in the
* program's code, it handles it by invoking this method. In other words,
* the Jack expressions x/y and divide(x,y) return the same value.
*/
function int divide(int x, int y) {
var int q, neg;
if (f = 0){
let division_tmp = 0;
let neg = ((x < 0) & (y > 0)) | ((x > 0) & (y < 0));
let x = Math.abs(x);
let y = Math.abs(y);
if (y = 0){
do Sys.error(3);
}
let f = 1;
}
if ((y > x) | (y < 0)){
return 0;
}
let q = Math.divide(x, y + y);
let f = 0;
let q = Math.abs(q);
if ((q & 1) = 1){
let division_tmp = division_tmp + y + y;
}
if (x - division_tmp < y){
if (neg){
return -(q + q);
}
return q + q;
}
else{
if (neg){
return -(q + q + 1);
}
return q + q + 1;
}
}
/** Returns the integer part of the square root of x. */
function int sqrt(int x) {
var int j, b, d, y;
if (x < 0){
do Sys.error(4);
}
let j = 7;
while (j > -1){
let d = y + st[j];
let b = d * d;
if ((~(b > x)) & (b > 0)){
let y = d;
}
let j = j - 1;
}
return y;
}
/** Returns the greater number. */
function int max(int a, int b) {
if (a > b){
return a;
}
return b;
}
/** Returns the smaller number. */
function int min(int a, int b) {
if (a < b){
return a;
}
return b;
}
}
+63
View File
@@ -0,0 +1,63 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/Memory.jack
/**
* This library provides two services: direct access to the computer's main
* memory (RAM), and allocation and recycling of memory blocks. The Hack RAM
* consists of 32,768 words, each holding a 16-bit binary number.
*/
class Memory {
static Array mem;
/** Initializes the class. */
function void init() {
let mem = 0;
let mem[2048] = 14334;
let mem[2049] = -1;
return;
}
/** Returns the RAM value at the given address. */
function int peek(int address) {
return mem[address];
}
/** Sets the RAM value at the given address to the given value. */
function void poke(int address, int value) {
let mem[address] = value;
return;
}
/** Finds an available RAM block of the given size and returns
* a reference to its base address. */
function int alloc(int size) {
var Array current_block;
var int tmp;
let current_block = 2048;
if (size < 0){
do Sys.error(5);
}
if (size = 0){
let size = 1;
}
while (current_block[0] < (size + 2)) {
let current_block = current_block[1];
}
let current_block[0] = current_block[0] - size - 2;
let current_block = current_block + current_block[0] + 2;
let current_block[0] = size;
return current_block + 2;
}
/** De-allocates the given object (cast as an array) by making
* it available for future allocations. */
function void deAlloc(Array o) {
var Array current_block;
let current_block = 2048;
let o[1]= current_block[1];
let current_block[1] = o;
return;
}
}
+299
View File
@@ -0,0 +1,299 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/Output.jack
/**
* A library of functions for writing text on the screen.
* The Hack physical screen consists of 512 rows of 256 pixels each.
* The library uses a fixed font, in which each character is displayed
* within a frame which is 11 pixels high (including 1 pixel for inter-line
* spacing) and 8 pixels wide (including 2 pixels for inter-character spacing).
* The resulting grid accommodates 23 rows (indexed 0..22, top to bottom)
* of 64 characters each (indexed 0..63, left to right). The top left
* character position on the screen is indexed (0,0). A cursor, implemented
* as a small filled square, indicates where the next character will be displayed.
*/
class Output {
// Character map for displaying characters
static Array charMaps;
static int address;
static bool half;
/** Initializes the screen, and locates the cursor at the screen's top-left. */
function void init() {
do Output.initMap();
do Output.moveCursor(0, 0);
return;
}
// Initializes the character map array
function void initMap() {
var int i;
let charMaps = Array.new(127);
// Black square, used for displaying non-printable characters.
do Output.create(0,63,63,63,63,63,63,63,63,63,0,0);
// Assigns the bitmap for each character in the charachter set.
// The first parameter is the character index, the next 11 numbers
// are the values of each row in the frame that represents this character.
do Output.create(32,0,0,0,0,0,0,0,0,0,0,0); //
do Output.create(33,12,30,30,30,12,12,0,12,12,0,0); // !
do Output.create(34,54,54,20,0,0,0,0,0,0,0,0); // "
do Output.create(35,0,18,18,63,18,18,63,18,18,0,0); // #
do Output.create(36,12,30,51,3,30,48,51,30,12,12,0); // $
do Output.create(37,0,0,35,51,24,12,6,51,49,0,0); // %
do Output.create(38,12,30,30,12,54,27,27,27,54,0,0); // &
do Output.create(39,12,12,6,0,0,0,0,0,0,0,0); // '
do Output.create(40,24,12,6,6,6,6,6,12,24,0,0); // (
do Output.create(41,6,12,24,24,24,24,24,12,6,0,0); // )
do Output.create(42,0,0,0,51,30,63,30,51,0,0,0); // *
do Output.create(43,0,0,0,12,12,63,12,12,0,0,0); // +
do Output.create(44,0,0,0,0,0,0,0,12,12,6,0); // ,
do Output.create(45,0,0,0,0,0,63,0,0,0,0,0); // -
do Output.create(46,0,0,0,0,0,0,0,12,12,0,0); // .
do Output.create(47,0,0,32,48,24,12,6,3,1,0,0); // /
do Output.create(48,12,30,51,51,51,51,51,30,12,0,0); // 0
do Output.create(49,12,14,15,12,12,12,12,12,63,0,0); // 1
do Output.create(50,30,51,48,24,12,6,3,51,63,0,0); // 2
do Output.create(51,30,51,48,48,28,48,48,51,30,0,0); // 3
do Output.create(52,16,24,28,26,25,63,24,24,60,0,0); // 4
do Output.create(53,63,3,3,31,48,48,48,51,30,0,0); // 5
do Output.create(54,28,6,3,3,31,51,51,51,30,0,0); // 6
do Output.create(55,63,49,48,48,24,12,12,12,12,0,0); // 7
do Output.create(56,30,51,51,51,30,51,51,51,30,0,0); // 8
do Output.create(57,30,51,51,51,62,48,48,24,14,0,0); // 9
do Output.create(58,0,0,12,12,0,0,12,12,0,0,0); // :
do Output.create(59,0,0,12,12,0,0,12,12,6,0,0); // ;
do Output.create(60,0,0,24,12,6,3,6,12,24,0,0); // <
do Output.create(61,0,0,0,63,0,0,63,0,0,0,0); // =
do Output.create(62,0,0,3,6,12,24,12,6,3,0,0); // >
do Output.create(64,30,51,51,59,59,59,27,3,30,0,0); // @
do Output.create(63,30,51,51,24,12,12,0,12,12,0,0); // ?
do Output.create(65,12,30,51,51,63,51,51,51,51,0,0); // A ** TO BE FILLED **
do Output.create(66,31,51,51,51,31,51,51,51,31,0,0); // B
do Output.create(67,28,54,35,3,3,3,35,54,28,0,0); // C
do Output.create(68,15,27,51,51,51,51,51,27,15,0,0); // D
do Output.create(69,63,51,35,11,15,11,35,51,63,0,0); // E
do Output.create(70,63,51,35,11,15,11,3,3,3,0,0); // F
do Output.create(71,28,54,35,3,59,51,51,54,44,0,0); // G
do Output.create(72,51,51,51,51,63,51,51,51,51,0,0); // H
do Output.create(73,30,12,12,12,12,12,12,12,30,0,0); // I
do Output.create(74,60,24,24,24,24,24,27,27,14,0,0); // J
do Output.create(75,51,51,51,27,15,27,51,51,51,0,0); // K
do Output.create(76,3,3,3,3,3,3,35,51,63,0,0); // L
do Output.create(77,33,51,63,63,51,51,51,51,51,0,0); // M
do Output.create(78,51,51,55,55,63,59,59,51,51,0,0); // N
do Output.create(79,30,51,51,51,51,51,51,51,30,0,0); // O
do Output.create(80,31,51,51,51,31,3,3,3,3,0,0); // P
do Output.create(81,30,51,51,51,51,51,63,59,30,48,0);// Q
do Output.create(82,31,51,51,51,31,27,51,51,51,0,0); // R
do Output.create(83,30,51,51,6,28,48,51,51,30,0,0); // S
do Output.create(84,63,63,45,12,12,12,12,12,30,0,0); // T
do Output.create(85,51,51,51,51,51,51,51,51,30,0,0); // U
do Output.create(86,51,51,51,51,51,30,30,12,12,0,0); // V
do Output.create(87,51,51,51,51,51,63,63,63,18,0,0); // W
do Output.create(88,51,51,30,30,12,30,30,51,51,0,0); // X
do Output.create(89,51,51,51,51,30,12,12,12,30,0,0); // Y
do Output.create(90,63,51,49,24,12,6,35,51,63,0,0); // Z
do Output.create(91,30,6,6,6,6,6,6,6,30,0,0); // [
do Output.create(92,0,0,1,3,6,12,24,48,32,0,0); // \
do Output.create(93,30,24,24,24,24,24,24,24,30,0,0); // ]
do Output.create(94,8,28,54,0,0,0,0,0,0,0,0); // ^
do Output.create(95,0,0,0,0,0,0,0,0,0,63,0); // _
do Output.create(96,6,12,24,0,0,0,0,0,0,0,0); // `
do Output.create(97,0,0,0,14,24,30,27,27,54,0,0); // a
do Output.create(98,3,3,3,15,27,51,51,51,30,0,0); // b
do Output.create(99,0,0,0,30,51,3,3,51,30,0,0); // c
do Output.create(100,48,48,48,60,54,51,51,51,30,0,0); // d
do Output.create(101,0,0,0,30,51,63,3,51,30,0,0); // e
do Output.create(102,28,54,38,6,15,6,6,6,15,0,0); // f
do Output.create(103,0,0,30,51,51,51,62,48,51,30,0); // g
do Output.create(104,3,3,3,27,55,51,51,51,51,0,0); // h
do Output.create(105,12,12,0,14,12,12,12,12,30,0,0); // i
do Output.create(106,48,48,0,56,48,48,48,48,51,30,0); // j
do Output.create(107,3,3,3,51,27,15,15,27,51,0,0); // k
do Output.create(108,14,12,12,12,12,12,12,12,30,0,0); // l
do Output.create(109,0,0,0,29,63,43,43,43,43,0,0); // m
do Output.create(110,0,0,0,29,51,51,51,51,51,0,0); // n
do Output.create(111,0,0,0,30,51,51,51,51,30,0,0); // o
do Output.create(112,0,0,0,30,51,51,51,31,3,3,0); // p
do Output.create(113,0,0,0,30,51,51,51,62,48,48,0); // q
do Output.create(114,0,0,0,29,55,51,3,3,7,0,0); // r
do Output.create(115,0,0,0,30,51,6,24,51,30,0,0); // s
do Output.create(116,4,6,6,15,6,6,6,54,28,0,0); // t
do Output.create(117,0,0,0,27,27,27,27,27,54,0,0); // u
do Output.create(118,0,0,0,51,51,51,51,30,12,0,0); // v
do Output.create(119,0,0,0,51,51,51,63,63,18,0,0); // w
do Output.create(120,0,0,0,51,30,12,12,30,51,0,0); // x
do Output.create(121,0,0,0,51,51,51,62,48,24,15,0); // y
do Output.create(122,0,0,0,63,27,12,6,51,63,0,0); // z
do Output.create(123,56,12,12,12,7,12,12,12,56,0,0); // {
do Output.create(124,12,12,12,12,12,12,12,12,12,0,0); // |
do Output.create(125,7,12,12,12,56,12,12,12,7,0,0); // }
do Output.create(126,38,45,25,0,0,0,0,0,0,0,0); // ~
return;
}
// Creates the character map array of the given character index, using the given values.
function void create(int index, int a, int b, int c, int d, int e,
int f, int g, int h, int i, int j, int k) {
var Array map;
let map = Array.new(11);
let charMaps[index] = map;
let map[0] = a;
let map[1] = b;
let map[2] = c;
let map[3] = d;
let map[4] = e;
let map[5] = f;
let map[6] = g;
let map[7] = h;
let map[8] = i;
let map[9] = j;
let map[10] = k;
return;
}
// Returns the character map (array of size 11) of the given character.
// If the given character is invalid or non-printable, returns the
// character map of a black square.
function Array getMap(char c) {
if ((c < 32) | (c > 126)) {
let c = 0;
}
return charMaps[c];
}
/** Moves the cursor to the j-th column of the i-th row,
* and erases the character displayed there. */
function void moveCursor(int i, int j) {
var int co,display;
var Array r,ch;
if (j = 0){
let half = true;
}
else{
let half = (j / 2) * 2 = j; // chetno true, 1vaa chast
}
let address = (352 * i) + (j / 2) + 16384;
let ch = Output.getMap(32);
while (co < 11){
if (half){
let display = r[address] & (-256);
let r[address] = ch[co] | display;
}
else{
let display = r[address] & 255;
let r[address] = (ch[co]*256) | display;
}
let co = co + 1;
let address = address + 32;
}
let address = address - 352;
return;
}
/** Displays the given character at the cursor location,
* and advances the cursor one column forward. */
function void printChar(char c) {
var Array ch;
var Array r;
var int co;
var int ds;
let ch = Output.getMap(c);
while (co < 11){
if (half){
let ds = r[address] & (-256);
let r[address] = ch[co] | ds;
}
else{
let ds = r[address] & 255;
let r[address] = (ch[co]*256) | ds;
}
let co = co + 1;
let address = address + 32;
}
if (half){
let address = address - 352;
let half = false;
}
else{
if (address > 24480){
let address = 16384;
let half = true;
}
else{
let address = address - 351;
let half = true;
}
}
return;
}
/** displays the given string starting at the cursor location,
* and advances the cursor appropriately. */
function void printString(String s) {
var int i, length;
let length = s.length();
while (i < length){
do Output.printChar(s.charAt(i));
let i = i + 1;
}
return;
}
/** Displays the given integer starting at the cursor location,
* and advances the cursor appropriately. */
function void printInt(int i) {
var String s;
let s = String.new(6);
do s.setInt(i);
do Output.printString(s);
return;
}
/** Advances the cursor to the beginning of the next line. */
function void println() {
var int row;
let row = (((address - 16384) / 32)/11) + 1;
if (row > 32){
let row = 0;
}
do Output.moveCursor(row, 0);
return;
}
/** Moves the cursor one column back. */
function void backSpace() {
if (address = 16384){
let address = 24191;
let half = true;
return;
}
if (half){
let address = address - 1;
let half = false;
}
else{
let half = true;
}
return;
}
}
+206
View File
@@ -0,0 +1,206 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/Screen.jack
/**
* A library of functions for displaying graphics on the screen.
* The Hack physical screen consists of 256 rows (indexed 0..255, top to bottom)
* of 512 pixels each (indexed 0..511, left to right). The top left pixel on
* the screen is indexed (0,0).
*/
class Screen {
static Array mem;
static Array st;
static boolean color;
/** Initializes the Screen. */
function void init() {
var int a;
let st = Array.new(16);
let st[0] = 1;
while (a < 15){
let a = a + 1;
let st[a] = st[a - 1] + st[a - 1];
}
let color = true;
return;
}
/** Erases the entire screen. */
function void clearScreen() {
var int a;
let a = 16384;
while (a < 24575){
let mem[a] = 0;
let a = a + 1;
}
return;
}
/** Sets the current color, to be used for all subsequent drawXXX commands.
* Black is represented by true, white by false. */
function void setColor(boolean b) {
let color = b;
return;
}
/** Draws the (x,y) pixel, using the current color. */
function void drawPixel(int x, int y) {
var int value, address, bit, mem_block;
if ((x > 511) | (x < 0) | (y > 255) | (y < 0)){
do Sys.error(7);
}
let mem_block = x / 16;
let address = (32 * y) + mem_block + 16384;
let value = mem[address];
let bit = x - (mem_block * 16);
if (color){
let mem[address] = st[bit] | value;
}
else{
let mem[address] = (~st[bit])& value;
}
return;
}
/** Draws a line from pixel (x1,y1) to pixel (x2,y2), using the current color. */
function void drawLine(int x1, int y1, int x2, int y2) {
var int diff, dx, dy, a, b;
if((x1 < 0) | (x2 > 511) | (y1 < 0) | (y2 > 255)){
do Sys.error(8);
}
let dx = x2 - x1;
let dy = y2 - y1;
if (dx = 0){
if (dy > 0){
while(~(b > dy)){
do Screen.drawPixel(x1, y1 + b);
let b = b + 1;
}
return;
}
else{
while(~(b < dy)){
do Screen.drawPixel(x1, y1 + b);
let b = b - 1;
}
return;
}
}
if (dy = 0){
if (dx > 0){
while(~(a > dx)){
do Screen.drawPixel(x1 + a, y1);
let a = a + 1;
}
return;
}
else{
while(~(a < dx)){
do Screen.drawPixel(x1 + a, y1);
let a = a - 1;
}
return;
}
}
if (dx < 0){
if (dy < 0){
while ((~(a < dx)) & (~(b < dy))){
do Screen.drawPixel(x1 + a, y1 + b);
if (diff < 0){
let a = a - 1;
let diff = diff - dy;
}
else{
let b = b - 1;
let diff = diff + dx;
}
}
}
else{
while ((~(a < dx)) & (~(b > dy))){
do Screen.drawPixel(x1 + a, y1 + b);
if (diff < 0){
let a = a - 1;
let diff = diff + dy;
}
else{
let b = b + 1;
let diff = diff + dx;
}
}
}
}
else{
if (dy < 0){
while ((~(a > dx)) & (~(b < dy))){
do Screen.drawPixel(x1 + a, y1 + b);
if (diff < 0){
let a = a + 1;
let diff = diff - dy;
}
else{
let b = b - 1;
let diff = diff - dx;
}
}
}
else{
while ((~(a > dx)) & (~(b > dy))){
do Screen.drawPixel(x1 + a, y1 + b);
if (diff < 0){
let a = a + 1;
let diff = diff + dy;
}
else{
let b = b + 1;
let diff = diff - dx;
}
}
}
}
return;
}
/** Draws a filled rectangle whose top left corner is (x1, y1)
* and bottom right corner is (x2,y2), using the current color. */
function void drawRectangle(int x1, int y1, int x2, int y2) {
var int a, tmp;
if (x1 > x2){
let tmp = x1;
let x1 = x2;
let x2 = tmp;
}
if (y1 > y2){
let tmp = y1;
let y1 = y2;
let y2 = tmp;
}
if((x1 < 0) | (x2 > 511) | (y1 < 0) | (y2 > 255)){
do Sys.error(8);
}
let tmp = y2 - y1;
while(a < tmp){
do Screen.drawLine(x1, y1 + a, x2, y1 + a);
let a = a + 1;
}
return;
}
/** Draws a filled circle of radius r<=181 around (x,y), using the current color. */
function void drawCircle(int x, int y, int r) {
var int dy, dx, tmp;
if(r > 181){
do Sys.error(7);
}
let dy = - r;
while (dy < r){
let tmp = Math.sqrt((r * r) - (dy * dy));
do Screen.drawLine(x - tmp, y + dy, x + tmp, y + dy);
let dy = dy + 1;
}
return;
}
}
+154
View File
@@ -0,0 +1,154 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/String.jack
/**
* Represents character strings. In addition for constructing and disposing
* strings, the class features methods for getting and setting individual
* characters of the string, for erasing the string's last character,
* for appending a character to the string's end, and more typical
* string-oriented operations.
*/
class String {
field Array str;
field int length;
field int strLength;
/** constructs a new empty string with a mavalimum length of mavalLength
* and initial length of 0. */
constructor String new(int mavalLength) {
if (mavalLength > 0){
let str = Array.new(mavalLength);
}
let strLength = mavalLength;
let length = 0;
return this;
}
/** Disposes this string. */
method void dispose() {
if(length > 0){
do str.dispose();
}
do Memory.deAlloc(this);
return;
}
/** Returns the current length of this string. */
method int length() {
return length;
}
/** Returns the character at the j-th location of this string. */
method char charAt(int j) {
if(j > length){
do Sys.error(7);
}
return str[j];
}
/** Sets the character at the j-th location of this string to c. */
method void setCharAt(int j, char c) {
if(j > length){
do Sys.error(7);
}
let str[j] = c;
return;
}
/** Appends c to this string's end and returns this string. */
method String appendChar(char c) {
if(strLength = length){
do Sys.error(7);
}
let str[length] = c;
let length = length + 1;
return this;
}
/** Erases the last character from this string. */
method void eraseLastChar() {
if (length = 0){
do Sys.error(7);
}
let str[length] = 0;
let length = length - 1;
return;
}
/** Returns the integer value of this string,
* until a non-digit character is detected. */
method int intValue() {
var int d, sum, i;
var bool f;
while(i < length){
let d = str[i];
if ((d > 47) & (d < 58)){
let sum = (sum * 10) + (d - 48);
}
else{
if((i = 0) & (d = 45)){
let f = true;
}
else{
let i = length;
}
}
let i = i + 1;
}
if (f){
return -sum;
}
return sum;
}
/** Sets this string to hold a representation of the given value. */
method void setInt(int val) {
var Array c;
var int d, b, a;
let c = Array.new(6);
if (val < 0){
let d = ~0;
let val = -val;
}
let b = val;
while(b > 0){
let b = val / 10;
let c[a] = 48 + val - (b * 10);
let a = a + 1;
let val = b;
}
if (d){
let c[a] = 45;
let a = a + 1;
}
if (a = 0){
let str[0] = 48;
let length = 1;
}
else{
let length = 0;
while (length < a){
let str[length] = c[a - 1 - length];
let length = length + 1;
}
}
do Array.dispose(c);
return;
}
/** Returns the new line character. */
function char newLine() {
return 128;
}
/** Returns the backspace character. */
function char backSpace() {
return 129;
}
/** Returns the double quote (") character. */
function char doubleQuote() {
return 34;
}
}
+53
View File
@@ -0,0 +1,53 @@
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/12/Sys.jack
/**
* A library that supports various program execution services.
*/
class Sys {
/** Performs all the initializations required by the OS. */
function void init() {
do Memory.init();
do Math.init();
do Output.init();
do Screen.init();
do Keyboard.init();
do Main.main();
do Sys.halt();
return;
}
/** Halts the program execution. */
function void halt() {
while(true){
}
return;
}
/** Waits approximately duration milliseconds and returns. */
function void wait(int duration) {
var int i;
while (duration > 0){
let i = 100;
while(i > 0){
let i = i -1;
}
let duration = duration - 1;
}
return;
}
/** Displays the given error code in the form "ERR<errorCode>",
* and halts the program's execution. */
function void error(int errorCode) {
var String s;
let s = String.new(3);
do s.setInt(errorCode);
do Output.printString("ERR");
do Output.printString(s);
return;
}
}