📄 translate.java
字号:
package Translate;import java.util.Hashtable;import java.util.Vector;public class Translate { ErrorMsg.ErrorMsg errorMsg; Frame.Frame frame; // Serve per evitare di creare tramite new Label(s) tante etichette s // tutte con lo stesso significato: sarebbero dei duplicati potenzialmente // in grado di confondere altre parti del compilatore (Appel [2nd Ed.] p.153) public static Hashtable string_to_label = new Hashtable(); // Lista di tutte le stringhe (DataFrag) e le funzioni con relativo // corpo in codice intermedio e frame (ProcFrag) incontrate private static Frag frags; int debflag; // per il debug public Translate(ErrorMsg.ErrorMsg err, Frame.Frame fr,int db) { errorMsg = err; frame = fr; debflag = db; } /******************************* * VARIABILI * *******************************/ // ----- simpleVar ----- public Exp simpleVar(Access access, Level level) { // Puntatore allo stack frame corrente Tree.TEMP static_link = new Tree.TEMP(frame.FP()); return new Ex( access.acc.exp(trovaFrame(access.home, level, static_link)) ); } // ----- subscriptVar ----- /* Poiche' l'array viene inizializzato inserendo al primo elemento la dimensione dell'array (utile per controllare l'index out of bounds) e di seguito gli altri elementi, a questo livello occorre controllare che l'indice i dato nella subscriptVar a[i] non superi la dimensione dell'array e non sia < 0. Quindi la parte di codice intermedio sara' un'istruzione di controlla per verificare quanto appena detto, seguita dai rami ramoOK e ramoErr. */ public Exp subscriptVar(Exp v,Exp index) { // pseudo-registro per l'indice Temp.Temp r = new Temp.Temp(); // istruzioni per caricare index nel registro Tree.MOVE caricaregIndex = new Tree.MOVE(new Tree.TEMP(r),index.unEx()); // per poterlo utilizzare anche con RelCx... Exp regIndex = new Ex(new Tree.TEMP(r)); // costruzione dei due rami per il controlla dell'indice... // caso senza errore "index out ot bounds" Tree.Exp ramoOK = new Tree.MEM( new Tree.BINOP( Tree.BINOP.PLUS, v.unEx(), new Tree.BINOP( Tree.BINOP.MUL, new Tree.BINOP( Tree.BINOP.PLUS, regIndex.unEx(), new Tree.CONST(1)), new Tree.CONST(frame.wordSize())))); // caso con errore "index out of bounds" Tree.SEQ ramoErr = new Tree.SEQ( new Ex( frame.externalCall("print", new Tree.ExpList( stringExp("Runtime error: indice dell'array fuori dai limiti").unEx(), null)) ).unNx(), new Ex(frame.externalCall("exit", new Tree.ExpList(intExp(-1).unEx(), null))).unNx() ); // condizione della If Exp cond = intOp( Tree.BINOP.OR, new RelCx(regIndex, intExp(0), Tree.CJUMP.LT), new RelCx(regIndex, new Ex(new Tree.MEM(v.unEx())), Tree.CJUMP.GT) ); // codice finale per subscriptVar return new Ex(new Tree.ESEQ(caricaregIndex, ifExp(cond, new Nx(ramoErr), new Ex(ramoOK)).unEx())); } // ----- fieldVar ----- /* Bisogna individuare l'errore runtime di riferimento ad un campo di una variabile record con valore nil. nil corrisponde a CONST(0) basta quindi controllare che v non punti a nil e quindi a 0. */ public Exp fieldVar(Exp v, int fieldpos) { // caso ok Tree.Exp ramoOK = new Tree.MEM( new Tree.BINOP( Tree.BINOP.PLUS, v.unEx(), new Tree.BINOP( Tree.BINOP.MUL, new Tree.CONST(fieldpos), new Tree.CONST(frame.wordSize())))); // caso con errore Tree.SEQ ramoErr = new Tree.SEQ( new Ex( frame.externalCall( "print", new Tree.ExpList( stringExp("Runtime error: riferemento ad un campo di una var. record con valore nil").unEx(), null)) ).unNx(), new Ex(frame.externalCall("exit", new Tree.ExpList(intExp(-1).unEx(), null))).unNx()); // condizione della If // ( v == nil ) ? Exp cond = new RelCx(v, nilExp(), Tree.CJUMP.EQ); // codice finale per fieldVar return new Ex(ifExp(cond, new Nx(ramoErr), new Ex(ramoOK)).unEx()); } /******************************** * ESPRESSIONI * ********************************/ // ----- intOp ----- public Exp intOp(int op, Exp sx, Exp dx) { // distingue il caso della divisione dagli altri casi (per poter gestire la div per 0) if(op != Tree.BINOP.DIV ) { return new Ex(new Tree.BINOP(op, sx.unEx(), dx.unEx())); } // se e' una divisione controlla che non sia una divisione per 0 // restituendo errore se div per 0 o il risultato altrimenti. else { // prepara lo stm per la div per 0 Tree.Stm div0 = new Tree.SEQ( new Ex( frame.externalCall( "print", new Tree.ExpList( stringExp("Runtime error: divisione per 0").unEx(), null)) ).unNx(), new Ex(frame.externalCall("exit", new Tree.ExpList( intExp(-1).unEx(), null))).unNx()); // prepara lo stm per il calcolo (non div 0) Tree.Exp nondiv0 = new Tree.BINOP(op, sx.unEx(), dx.unEx()); // restituisce la IF con il controlla e i due "cammini" possibili return new IfThenElseExp(new RelCx(dx, intExp(0), Tree.CJUMP.EQ), new Nx(div0), new Ex(nondiv0)); } } // ---- compOp ---- /* converteamo l'Absyn.OpExp nella rispettiva costante di CJUMP TABELLA DI CONVERSIONE Tree.CJUMP 0 1 2 3 4 5 operatore EQ NE LT GT LE GE Absyn.OpExp 4 5 6 8 7 9 */ public Exp compOp(int op, Exp sx, Exp dx, boolean str) { int opCJUMP=-1; switch(op) { case 4: case 5: case 6: case 9: opCJUMP=op-4; break; case 8: opCJUMP=op-5; break; case 7: opCJUMP=op-3; break; default: errorMsg.error(-1,"Conversione degli interi di comparazione non riuscita."); } // se sono stringhe... if (str) { return new RelCx( new Ex( frame.externalCall( "stringEqual", new Tree.ExpList(sx.unEx(), new Tree.ExpList(dx.unEx(), null)))), intExp(1), Tree.CJUMP.EQ); } // ...altrimenti else return new RelCx(sx,dx,opCJUMP); } // ----- intExp ----- public Exp intExp(int x) { return new Ex(new Tree.CONST(x)); } // ----- stringExp ----- public Exp stringExp(String s) { Temp.Label label; // se e' gia' stata definita prende l'etichetta dalla Hashtable if(string_to_label.containsKey(s)) { label = (Temp.Label)string_to_label.get(s); } // altrimenti crea una nuova etichetta e la inserisce nella Hashtable // in corrispondenza della stringa s else { label= new Temp.Label(); string_to_label.put(s,label); // RICORDARSI DI INVOCARE FRAME.STRING! insFrag(new DataFrag( frame.string(label,s))); } // restituisce cmq un Ex con un NAME return new Ex(new Tree.NAME(label)); } // ----- assignExp ----- public Exp assignExp(Exp e1, Exp e2) { return new Nx(new Tree.MOVE(e1.unEx(), e2.unEx())); } // ----- opExp ----- // In opExp gli operatori sono identificati dai seguenti numeri interi: // PLUS=0, MINUS=1, MUL=2, DIV=3, EQ=4, NE=5, LT=6, GT=8, LE=7, GE=9 // str serve per vedere se i parametri sono stringhe o no public Exp opExp(int op,Exp e1, Exp e2,boolean str) { switch(op) { case 0: case 1: case 2: case 3: return intOp(op,e1,e2); case 4: case 5: case 6: case 7: case 8: case 9: return compOp(op,e1,e2,str); } return null; } // ----- whileExp ---- // vedere pag. 156 A.W.Appel "Modern Compiler Implementation in Java" public Exp whileExp(Temp.Label done,Exp test,Exp body) { Temp.Label bodyLabel = new Temp.Label(); Temp.Label testLabel = new Temp.Label(); return new Nx( new Tree.SEQ( new Tree.SEQ( new Tree.SEQ( new Tree.LABEL(testLabel), new Tree.CJUMP( Tree.CJUMP.EQ, test.unEx(), intExp(0).unEx(), bodyLabel, done)), new Tree.SEQ( new Tree.LABEL(bodyLabel), body.unNx())), new Tree.SEQ( new Tree.JUMP(testLabel), new Tree.LABEL(done)))); } // ---- breakExp ---- public Exp breakExp(Temp.Label done) { return new Nx(new Tree.JUMP(done)); } // ---- forExp ---- /* fatta in modo da evitare il caso in cui limit=MAXINT come descritto a pag. 174 di A.W.Appel "Modern Compiler Implementation in Java" In particolare e' stata apportata una piccola modifica per gestire il caso i=MAXINT. Il ciclo FOR viene percio' tradotto nel seguente codice: La traduzione in pseudocodice di "for i:=lo to hi", riscritto in termini di ciclo while e' la seguente: let var i:=lo in if(i<=hi) then { do { body; i=i+1; } while (i<hi) } end NOTA: se LO=MAXINT l'overflow rimane, ma chi inizializza un ciclo con maxint merita questo e altro... */ public Exp forExp(Access acc, Level lev,Exp lo,Exp hi,Exp body,Temp.Label done) { Temp.Label t1=new Temp.Label(); Nx a = (Nx)assignExp(simpleVar(acc,lev),lo); Nx c = (Nx)assignExp(simpleVar(acc,lev),new Ex(new Tree.BINOP(Tree.BINOP.PLUS,simpleVar(acc,lev).unEx(),intExp(1).unEx()))); return new Nx( new Tree.SEQ( new Tree.SEQ( a.unNx(), new Tree.SEQ( new Tree.CJUMP(Tree.CJUMP.LE,a.unEx(),hi.unEx(),t1,done), new Tree.LABEL(t1))), new Tree.SEQ( new Tree.SEQ(body.unNx(), c.unNx()), new Tree.SEQ( new Tree.CJUMP(Tree.CJUMP.LT,c.unEx(),hi.unEx(),t1,done), new Tree.LABEL(done))))); } // ----- nilExp ---- // in questo caso non c'e' bisogno di allocare niente per il record // si usa una semplice CONST(0) public Exp nilExp() { return intExp(0); } // ----- ifExp ----- public Exp ifExp(Exp test,Exp thenc, Exp elsec ) { return new IfThenElseExp(test,thenc,elsec); } // ----- callExp ----- /* bisogna semplicemente mettere una CALL, dove pero' il primo parametro e' lo static link (da ricercare) Inoltre se la chiamata e' ad una funzione di libreria (es. print"ciao") lo static link non va messo come primo parametro! */ public Exp callExp(Level curr,Level levf,Vector Vargs,boolean isVoid) { // costruisco l'Explist ( el ) per gli argomenti della funzione Tree.ExpList el = null; // primo caso
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -