import java.io.*; import java.util.*; public class CzeroJoos1 { public CzeroJoos1() {} public int tLPAR = 0; public int tRPAR = 1; public int tASSIGN = 2; public int tSEMI = 3; public int tCOMMA = 4; public int tEQ = 5; public int tNE = 6; public int tID = 7; public int tCONST = 8; public int tCHAR = 9; public int tADD = 10; public int tSUB = 11; public int tMUL = 12; public int tDIV = 13; public int tMOD = 14; public int tLBRACK = 15; public int tRBRACK = 16; public int tOR = 17; public int tAND = 18; public int tNOT = 19; public int tLT = 20; public int tGT = 21; public int tLEQ = 22; public int tGEQ = 23; public int tSHARP = 24; public int tDOT = 25; public int tINT = 26; public int tIF = 27; public int tELSE = 28; public int tWHILE = 29; public int tGETCHAR = 30; public int tPUTCHAR = 31; public int tINCLUDE = 32; public int tRETURN = 33; public int tMAIN = 34; public int tEOF = 35; public int tERROR = 36; public int tWHITE = 37; public String tFile; public int tLine; public int tCol; public int tIntValue; public String tIdValue; public int tKind; public FileReader in; public int c; public int nextChar() throws Exception { c = in.read(); if (c=='\n') { tLine=tLine+1; tCol = 1; } else tCol=tCol+1; return c; } public Writer out; public void code(String s) throws Exception { out.write(s+"\n"); } public boolean letter(int c) { return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); } public boolean digit(int c) { return ('0' <= c && c <= '9'); } public boolean alpha(int c) { return letter(c) || digit(c); } public int nextToken() throws Exception { if (c=='(') { tKind = tLPAR; nextChar(); return tKind; } if (c==')') { tKind = tRPAR; nextChar(); return tKind; } if (c==';') { tKind = tSEMI; nextChar(); return tKind; } if (c==',') { tKind = tCOMMA; nextChar(); return tKind; } if (c=='+') { tKind = tADD; nextChar(); return tKind; } if (c=='-') { tKind = tSUB; nextChar(); return tKind; } if (c=='*') { tKind = tMUL; nextChar(); return tKind; } if (c=='/') { tKind = tDIV; nextChar(); return tKind; } if (c=='%') { tKind = tMOD; nextChar(); return tKind; } if (c=='{') { tKind = tLBRACK; nextChar(); return tKind; } if (c=='}') { tKind = tRBRACK; nextChar(); return tKind; } if (c=='|') { tKind = tOR; nextChar(); return tKind; } if (c=='&') { tKind = tAND; nextChar(); return tKind; } if (c=='#') { tKind = tSHARP; nextChar(); return tKind; } if (c=='.') { tKind = tDOT; nextChar(); return tKind; } if (c==' ' || c=='\n') { tKind = tWHITE; nextChar(); return tKind; } if (c=='\'') { nextChar(); if (c=='\\') { nextChar(); if (c!='n') { tKind = tERROR; return tKind; } nextChar(); if (c!='\'') { tKind = tERROR; return tKind; } nextChar(); tKind = tCONST; tIntValue = 10; return tKind; } if (c==-1 || c=='\'') { tKind = tERROR; return tKind; } tKind = tCONST; tIntValue = c; nextChar(); if (c!='\'') { tKind = tERROR; return tKind; } nextChar(); return tKind; } if (c=='=') { nextChar(); if (c=='=') { nextChar(); tKind = tEQ; } else { tKind = tASSIGN; } return tKind; } if (c=='<') { nextChar(); if (c=='=') { nextChar(); tKind = tLEQ; } else { tKind = tLT; } return tKind; } if (c=='>') { nextChar(); if (c=='=') { nextChar(); tKind = tGEQ; } else { tKind = tGT; } return tKind; } if (c=='!') { nextChar(); if (c=='=') { nextChar(); tKind = tNE; } else { tKind = tNOT; } return tKind; } if (c==-1) { tKind = tEOF; return tKind; } if (letter(c)) { tKind = tID; tIdValue = ""; while (alpha(c)) { tIdValue = tIdValue+(char)c; nextChar(); } if (tIdValue.equals((Object)"int")) tKind = tINT; else if (tIdValue.equals((Object)"if")) tKind = tIF; else if (tIdValue.equals((Object)"else")) tKind = tELSE; else if (tIdValue.equals((Object)"while")) tKind = tWHILE; else if (tIdValue.equals((Object)"getchar")) tKind = tGETCHAR; else if (tIdValue.equals((Object)"putchar")) tKind = tPUTCHAR; else if (tIdValue.equals((Object)"include")) tKind = tINCLUDE; else if (tIdValue.equals((Object)"return")) tKind = tRETURN; else if (tIdValue.equals((Object)"main")) tKind = tMAIN; } else if (digit(c)) { tKind = tCONST; tIntValue = 0; while (digit(c)) { tIntValue = 10*tIntValue+c-'0'; nextChar(); } } else { tKind = tERROR; } return tKind; } public void parseError() { System.out.print("*** "+tFile+":"+tLine+":"+tCol+": unexpected token: "); printToken(); System.out.println(); System.exit(1); } public void compileError(String s) { System.out.println("*** "+tFile+":"+tLine+":"+tCol+": "+s); System.exit(1); } public void skip() throws Exception { while (tKind==tWHITE) nextToken(); } public void checkToken(int k) throws Exception { if (tKind!=k) parseError(); nextToken(); } public void skipToken(int k) throws Exception { skip(); checkToken(k); } public void checkToken(String s) throws Exception { if (tKind!=tID || !tIdValue.equals((Object)s)) parseError(); nextToken(); } public void printToken() { if (tKind==tLPAR) { System.out.print("("); } if (tKind==tRPAR) { System.out.print(")"); } if (tKind==tASSIGN) { System.out.print("="); } if (tKind==tSEMI) { System.out.print(";"); } if (tKind==tCOMMA) { System.out.print(","); } if (tKind==tEQ) { System.out.print("=="); } if (tKind==tNE) { System.out.print("!="); } if (tKind==tID) { System.out.print(tIdValue); } if (tKind==tCONST) { System.out.print(tIntValue); } if (tKind==tCHAR) { System.out.print("char"); } if (tKind==tADD) { System.out.print("+"); } if (tKind==tSUB) { System.out.print("-"); } if (tKind==tMUL) { System.out.print("*"); } if (tKind==tDIV) { System.out.print("/"); } if (tKind==tMOD) { System.out.print("%"); } if (tKind==tLBRACK) { System.out.print("{"); } if (tKind==tRBRACK) { System.out.print("}"); } if (tKind==tOR) { System.out.print("|"); } if (tKind==tAND) { System.out.print("&"); } if (tKind==tNOT) { System.out.print("!"); } if (tKind==tLT) { System.out.print("<"); } if (tKind==tGT) { System.out.print(">"); } if (tKind==tLEQ) { System.out.print("<="); } if (tKind==tGEQ) { System.out.print(">="); } if (tKind==tSHARP) { System.out.print("#"); } if (tKind==tDOT) { System.out.print("."); } if (tKind==tINT) { System.out.print("int"); } if (tKind==tIF) { System.out.print("if"); } if (tKind==tELSE) { System.out.print("else"); } if (tKind==tWHILE) { System.out.print("while"); } if (tKind==tGETCHAR) { System.out.print("getchar"); } if (tKind==tPUTCHAR) { System.out.print("putchar"); } if (tKind==tINCLUDE) { System.out.print("include"); } if (tKind==tRETURN) { System.out.print("return"); } if (tKind==tMAIN) { System.out.print("main"); } if (tKind==tEOF) { System.out.print("eof"); } if (tKind==tERROR) { System.out.print("error"); } if (tKind==tWHITE) { System.out.print(" "); } } public int nextLabel = 0; public void parseProgram() throws Exception { Map funcs = new HashMap(); Map prototypes = new HashMap(); skipToken(tSHARP); checkToken(tINCLUDE); skipToken(tLT); checkToken("stdio"); checkToken(tDOT); checkToken("h"); checkToken(tGT); parseFunctions(funcs,prototypes); parseMain(funcs,prototypes); Iterator i = prototypes.keySet().iterator(); while (i.hasNext()) { String s = (String)i.next(); if (!funcs.containsKey((Object)s)) compileError("missing implementation of "+s); } } public void parseMain(Map funcs, Map prototypes) throws Exception { Map vars = new HashMap(); skipToken(tMAIN); skipToken(tLPAR); skipToken(tRPAR); code(".method main"); code(".args 1"); parseBody(0,vars,funcs,prototypes); skipToken(tEOF); } public void parseFunctions(Map funcs, Map prototypes) throws Exception { skip(); while (tKind==tINT) { parseFunction(funcs,prototypes); skip(); } } public void parseFunction(Map funcs, Map prototypes) throws Exception { Map vars = new HashMap(); String name = ""; checkToken(tINT); skipToken(tID); name = tIdValue; skipToken(tLPAR); int args = parseFormals(vars); skipToken(tRPAR); skip(); if (tKind==tSEMI) { nextToken(); if (prototypes.containsKey((Object)name)) compileError("duplicate declaration of "+name); if (funcs.containsKey((Object)name) && args!=((Integer)funcs.get((Object)name)).intValue()) compileError("conflicting declaration of "+name); prototypes.put((Object)name,(Object)(new Integer(args))); } else { if (funcs.containsKey((Object)name)) compileError("duplicate implementation of "+name); if (prototypes.containsKey((Object)name) && args!=((Integer)prototypes.get((Object)name)).intValue()) compileError("conflicting implementation of "+name); funcs.put((Object)name,(Object)(new Integer(args))); code(".method "+name); code(".args "+(args+1)); parseBody(args,vars,funcs,prototypes); code("bipush 0"); code("ireturn"); } } public int parseFormals(Map vars) throws Exception { int offset = 0; boolean more = false; skip(); while (tKind==tINT) { nextToken(); skipToken(tID); offset=offset+1; vars.put((Object)tIdValue,(Object)(new Integer(offset))); skip(); if (tKind==tCOMMA) { nextToken(); skip(); more = true; } else more = false; } if (more) parseError(); return offset; } public void parseBody(int offset, Map vars, Map funcs, Map prototypes) throws Exception { skipToken(tLBRACK); parseDeclarations(offset,0,vars); parseStatements(vars,funcs,prototypes); skipToken(tRBRACK); } public void parseDeclarations(int offset, int locals, Map vars) throws Exception { int initValue = 0; boolean initialized = false; skip(); if (tKind==tINT) { nextToken(); skipToken(tID); offset=offset+1; vars.put((Object)tIdValue,(Object)(new Integer(offset))); skip(); if (tKind==tASSIGN) { nextToken(); skipToken(tCONST); initialized = true; initValue = tIntValue; } checkToken(tSEMI); parseDeclarations(offset,locals+1,vars); } else { if (locals>0) code(".locals "+locals); } if (initialized) { code("bipush "+initValue); code("istore "+offset); } } public void parseStatements(Map vars, Map funcs, Map prototypes) throws Exception { skip(); while (tKind!=tRBRACK) { parseStatement(vars,funcs,prototypes); skip(); } } public void parseStatement(Map vars, Map funcs, Map prototypes) throws Exception { if (tKind==tID) { String name = tIdValue; nextToken(); skipToken(tASSIGN); if (!vars.containsKey((Object)name)) compileError("undeclared variable: "+name); skip(); parseExpression(vars,funcs,prototypes); skipToken(tSEMI); code("istore "+vars.get((Object)name)); } else if (tKind==tRETURN) { nextToken(); skip(); parseExpression(vars,funcs,prototypes); skipToken(tSEMI); code("ireturn"); } else if (tKind==tIF) { int elselabel = (nextLabel=nextLabel+1); int donelabel = (nextLabel=nextLabel+1); nextToken(); skipToken(tLPAR); skip(); parseExpression(vars,funcs,prototypes); skipToken(tRPAR); code("ifeq L"+elselabel); skipToken(tLBRACK); parseStatements(vars,funcs,prototypes); skipToken(tRBRACK); code("goto L"+donelabel); code("L"+elselabel+":"); skip(); if (tKind==tELSE) { nextToken(); skipToken(tLBRACK); skip(); parseStatements(vars,funcs,prototypes); skipToken(tRBRACK); } code("L"+donelabel+":"); } else if (tKind==tWHILE) { int looplabel = (nextLabel=nextLabel+1); int donelabel = (nextLabel=nextLabel+1); code("L"+looplabel+":"); nextToken(); skipToken(tLPAR); skip(); parseExpression(vars,funcs,prototypes); skipToken(tRPAR); code("ifeq L"+donelabel); skipToken(tLBRACK); skip(); parseStatements(vars,funcs,prototypes); skipToken(tRBRACK); code("goto L"+looplabel); code("L"+donelabel+":"); } else if (tKind==tPUTCHAR) { nextToken(); skipToken(tLPAR); code("bipush 44"); skip(); parseExpression(vars,funcs,prototypes); code("invokevirtual putchar"); skipToken(tRPAR); skipToken(tSEMI); } else parseError(); } public void parseExpression(Map vars, Map funcs, Map prototypes) throws Exception { parseExp3(vars,funcs,prototypes); } public void parseExp0(Map vars, Map funcs, Map prototypes) throws Exception { if (tKind==tCONST) { code("ldc_w "+tIntValue); nextToken(); } else if (tKind==tGETCHAR) { nextToken(); skipToken(tLPAR); skipToken(tRPAR); code("bipush 44"); code("invokevirtual getchar"); } else if (tKind==tLPAR) { nextToken(); parseExpression(vars,funcs,prototypes); skipToken(tRPAR); } else if (tKind==tID) { String name = tIdValue; nextToken(); skip(); if (tKind==tLPAR) { nextToken(); skip(); code("bipush 44"); int args = parseActuals(vars,funcs,prototypes); code("invokevirtual "+name); skipToken(tRPAR); if (funcs.containsKey((Object)name)) { if (args!=((Integer)funcs.get((Object)name)).intValue()) compileError("incorrect number of arguments: "+name); } else if (prototypes.containsKey((Object)name)) { if (args!=((Integer)prototypes.get((Object)name)).intValue()) compileError("incorrect number of arguments: "+name); } else { compileError("undeclared function: "+name); } } else { if (!vars.containsKey((Object)name)) compileError("undeclared variable: "+name); code("iload "+vars.get((Object)name)); } } else if (tKind==tSUB) { nextToken(); skip(); code("bipush 0"); parseExp0(vars,funcs,prototypes); code("isub"); } else if (tKind==tNOT) { nextToken(); skip(); code("bipush 44"); parseExp0(vars,funcs,prototypes); code("invokevirtual not_"); } else parseError(); } public void parseExp1(Map vars, Map funcs, Map prototypes) throws Exception { parseExp0(vars,funcs,prototypes); skip(); while (tKind==tMUL || tKind==tDIV || tKind==tAND || tKind==tMOD) { int op = tKind; nextToken(); skip(); if (op==tMUL || op==tDIV || op==tMOD) { code("bipush 44"); code("swap"); } parseExp0(vars,funcs,prototypes); if (tKind==tMUL) code("invokevirtual mul_"); if (tKind==tDIV) code("invokevirtual div_"); if (tKind==tAND) code("iand"); if (tKind==tMOD) code("invokevirtual mod_"); } } public void parseExp2(Map vars, Map funcs, Map prototypes) throws Exception { parseExp1(vars,funcs,prototypes); skip(); while (tKind==tADD || tKind==tSUB || tKind==tOR) { int op = tKind; nextToken(); skip(); parseExp1(vars,funcs,prototypes); if (tKind==tADD) code("iadd"); if (tKind==tSUB) code("isub"); if (tKind==tOR) code("ior"); } } public void parseExp3(Map vars, Map funcs, Map prototypes) throws Exception { parseExp2(vars,funcs,prototypes); skip(); while (tKind==tEQ || tKind==tNE || tKind==tLT || tKind==tGT || tKind==tLEQ || tKind==tGEQ) { int op = tKind; nextToken(); skip(); code("bipush 44"); code("swap"); parseExp2(vars,funcs,prototypes); if (tKind==tEQ) code("invokevirtual eq_"); if (tKind==tNE) code("invokevirtual ne_"); if (tKind==tLT) code("invokevirtual lt_"); if (tKind==tGT) code("invokevirtual gt_"); if (tKind==tLEQ) code("invokevirtual leq_"); if (tKind==tGEQ) code("invokevirtual geq_"); } } public int parseActuals(Map vars, Map funcs, Map prototypes) throws Exception { boolean more = false; int args = 0; skip(); while (tKind!=tRPAR) { parseExpression(vars,funcs,prototypes); args=args+1; skip(); if (tKind==tCOMMA) { nextToken(); skip(); more = true; } else more = false; } if (more) parseError(); return args; } public void codeLibrary() throws Exception { code(".method mul_"); code(".args 3"); code(".locals 2"); code("bipush 1"); code("istore 4"); code("bipush 0"); code("iload 1"); code("isub"); code("iflt mul0"); code("bipush 0"); code("iload 1 "); code("isub"); code("istore 1"); code("bipush 0"); code("istore 4"); code("mul0:"); code("bipush 0"); code("istore 3"); code("mul1:"); code("iload 1"); code("ifeq mul2"); code("iload 1"); code("bipush 1"); code("isub"); code("istore 1"); code("iload 3"); code("iload 2"); code("iadd"); code("istore 3"); code("goto mul1"); code("mul2:"); code("bipush 1"); code("iload 4"); code("isub "); code("ifeq mul3"); code("bipush 0"); code("iload 3"); code("isub"); code("istore 3"); code("mul3:"); code("iload 3"); code("ireturn"); code(""); code(".method div_"); code(".args 3"); code(".locals 2"); code("bipush 1"); code("istore 4"); code("bipush 0"); code("iload 1"); code("isub"); code("iflt div0"); code("bipush 0"); code("iload 1 "); code("isub"); code("istore 1"); code("bipush 0"); code("istore 4"); code("div0:"); code("bipush 0"); code("iload 2"); code("isub"); code("iflt div1"); code("bipush 0"); code("iload 2 "); code("isub"); code("istore 2"); code("iload 4"); code("bipush 1"); code("iadd"); code("istore 4"); code("div1:"); code("bipush 0"); code("istore 3"); code("div2:"); code("iload 1"); code("iload 2"); code("isub"); code("iflt div3"); code("iload 1"); code("iload 2"); code("isub"); code("istore 1"); code("iload 3"); code("bipush 1"); code("iadd"); code("istore 3"); code("goto div2"); code("div3:"); code("bipush 0"); code("iload 4"); code("isub "); code("iflt div4"); code("bipush 0"); code("iload 3"); code("isub"); code("istore 3"); code("div4:"); code("iload 3"); code("ireturn"); code(""); code(".method mod_"); code(".args 3"); code(".locals 1"); code("bipush 44"); code("iload 1"); code("iload 2"); code("invokevirtual div_"); code("istore 3"); code("iload 1"); code("bipush 44"); code("iload 3"); code("iload 2"); code("invokevirtual mul_"); code("isub"); code("ireturn"); code(""); code(".method not_"); code(".args 2"); code("iload 1"); code("ifeq not1"); code("bipush 0"); code("goto not0"); code("not1:"); code("bipush 1"); code("not0:"); code(""); code(".method eq_"); code(".args 3"); code("iload 1"); code("iload 2"); code("isub"); code("ifeq eq1"); code("bipush 0"); code("ireturn"); code("eq1:"); code("bipush 1"); code("ireturn"); code(""); code(".method ne_"); code(".args 3"); code("iload 1"); code("iload 2"); code("isub"); code("ifeq ne0"); code("bipush 1"); code("ireturn"); code("ne0:"); code("bipush 0"); code("ireturn"); code(""); code(".method lt_"); code(".args 3"); code("iload 1"); code("iload 2"); code("isub"); code("iflt lt1"); code("bipush 0"); code("ireturn"); code("lt1:"); code("bipush 1"); code("ireturn"); code(""); code(".method gt_"); code(".args 3"); code("iload 1"); code("iload 2"); code("isub"); code("iflt gt0"); code("bipush 1"); code("ireturn"); code("gt0:"); code("bipush 0"); code("ireturn"); code(""); code(".method leq_"); code(".args 3"); code("iload 1"); code("iload 2"); code("isub"); code("dup"); code("ifeq leqpop1"); code("iflt leq1"); code("bipush 0"); code("ireturn"); code("leq1:"); code("bipush 1"); code("ireturn"); code("leqpop1:"); code("pop"); code("bipush 1"); code("ireturn"); code(""); code(".method geq_"); code(".args 3"); code("iload 1"); code("iload 2"); code("isub"); code("dup"); code("ifeq geqpop1"); code("iflt geq0"); code("bipush 1"); code("ireturn"); code("geq0:"); code("bipush 0"); code("ireturn"); code("geqpop1:"); code("pop"); code("bipush 1"); code("ireturn"); code(""); } public void compile(String filename) throws Exception { tFile = filename; in = new FileReader(tFile); out = new OutputStreamWriter((OutputStream)System.out); tLine = 1; tCol = 0; codeLibrary(); nextChar(); nextToken(); parseProgram(); out.close(); } public static void main(String[] args) throws Exception { new CzeroJoos1().compile(args[0]); } }