📄 semant.java
字号:
package Semant;import java.util.Vector;public class Semant { Env env; public int debflag; public String recout; // per il debug dei campi del record // variabile per il controllo del livello annidamento // dei cicli while o for (per individuare le break legali!) private int loopDepth = 0; // LIVELLO CORRENTE Translate.Level level; // LIVELLO INIZIALE Translate.Level levin; // PER CONVERSIONE IN CODICE INTERMEDIO public Translate.Translate trans; // etichetta globale che rappresenta l'etichetta "done" // del ciclo corrente (se esiste, altrimenti rimane = null) // a cui saltera' l'istruzione break. Temp.Label current_done = null; // TIPI BASE Types.Type INT; Types.Type STRING; Types.Type VOID; Types.Type NIL; // costruttori public Semant(ErrorMsg.ErrorMsg err, Translate.Level lvl,int dflag) { this(new Env(err,lvl), dflag); trans = new Translate.Translate(err,lvl.frame,dflag); } Semant(Env e, int df) { env=e; debflag=df; INT=e.inttemp; STRING=e.stringtemp; VOID=new Types.VOID(); NIL=new Types.NIL(); level=e.lev; levin=e.lev; } // PROGRAMMA // analisi semantica public ExpTy transProg(Absyn.Exp exp) { //stampaDeb(0,"Indirizzo del tipo INT: " + INT); //stampaDeb(0,"Indirizzo del tipo STRING: " + STRING); //stampaDeb(0,"Indirizzo del tipo VOID: " + VOID); //stampaDeb(0,"Indirizzo del tipo NIL: " + NIL ); //stampaDeb(0,"Tabella dei tipi: " + env.tenv); //stampaDeb(0,"Tabella delle variabili: " + env.venv + "\n"); ExpTy prg = transExp(exp); if(debflag == 1) { System.out.println("> Tipo finale del programma: " + nomeClasse(prg.ty)); } // aggiunge un piccolo pezzo d'albero (utilizza il livello iniziale) if(env.errorMsg.num_error == 0) prg.exp = trans.transProg(prg.exp, levin, (prg.ty == VOID) ); return prg; } /******************************* * VARIABILI * *******************************/ ExpTy transVar(Absyn.Var v) { if(v instanceof Absyn.SimpleVar) return transVar((Absyn.SimpleVar)v); if(v instanceof Absyn.SubscriptVar) return transVar((Absyn.SubscriptVar)v); if(v instanceof Absyn.FieldVar) return transVar((Absyn.FieldVar)v); throw new Error("transVar"); // da vedere se mantenere o no. } // SimpleVar ExpTy transVar(Absyn.SimpleVar v) { Entry x = (Entry)env.venv.get(v.name); if (x instanceof VarEntry) { // controlla se e' una variabile VarEntry ent = (VarEntry)x; stampaDeb(v.pos,"SimpleVar: " + v.name + ": " + nomeClasse(ent.ty.actual()) + " isFor = " + ent.isFor); // se non ci sono errori esegue Translate if (env.errorMsg.num_error==0) { // x.isFor serve per controllare se la variabile e' utilizzata // come variabile di controlla all'interno di un ciclo for return new ExpTy(trans.simpleVar(ent.access,level), ent.ty, ent.isFor); } else return new ExpTy(null,ent.ty); } else { String out= "Variabile \"" + v.name + "\" indefinita"; env.errorMsg.error(v.pos, out); return new ExpTy(null, INT); } } // SubscriptVar ExpTy transVar(Absyn.SubscriptVar v) { Types.ARRAY temp=new Types.ARRAY(null); boolean ok=true; ExpTy i = transExp(v.index); checkInt(i, v.index.pos); // l'exp tra [] deve essere intera ExpTy vtemp = transVar(v.var); // analizza la variabile (ExpTy) if(!(vtemp.ty.actual() instanceof Types.ARRAY)) { env.errorMsg.error(v.pos, "Variabile di tipo ARRAY richiesta"); ok=false; } else { // deve restituire il tipo degli elementi dell'array! temp=(Types.ARRAY)vtemp.ty.actual(); } stampaDeb(v.pos,"SubscriptVar: " + nomeClasse(temp.element)); if (ok) { if (env.errorMsg.num_error==0) { return new ExpTy(trans.subscriptVar(vtemp.exp,i.exp),temp.element); } else return new ExpTy(null,temp.element); } else return new ExpTy(null,INT); } // FieldVar ExpTy transVar(Absyn.FieldVar v) { Types.Type fieldtemp=INT; boolean ok = false; // usato per contare in che posizione si trova il campo int fieldpos = -1; ExpTy vtemp = transVar(v.var); // legge la variabile (ExpTy) if (!(vtemp.ty.actual() instanceof Types.RECORD)) env.errorMsg.error(v.var.pos, "Variabile di tipo RECORD richiesta"); else { // controlla, scorrendo il record, se esiste il campo for (Types.RECORD temp=(Types.RECORD)vtemp.ty.actual(); temp !=null; temp=temp.tail) { // incrementa la posizione del campo fieldpos++; if (v.field.toString().equals(temp.fieldName.toString())) { ok = true; fieldtemp = temp.fieldType.actual(); break; } } if (!ok) env.errorMsg.error(v.var.pos, "Campo \"" + v.field.toString() +"\" del record indefinito"); } if (env.errorMsg.num_error==0) { return new ExpTy(trans.fieldVar(vtemp.exp,fieldpos),fieldtemp); } else return new ExpTy(null, fieldtemp); } /****************************** * ESPRESSIONI * ******************************/ ExpTy transExp(Absyn.Exp e) { if(e instanceof Absyn.LetExp) return transExp((Absyn.LetExp)e); if(e instanceof Absyn.AssignExp) return transExp((Absyn.AssignExp)e); if(e instanceof Absyn.OpExp) return transExp((Absyn.OpExp)e); if(e instanceof Absyn.IfExp) return transExp((Absyn.IfExp)e); if(e instanceof Absyn.ForExp) return transExp((Absyn.ForExp)e); if(e instanceof Absyn.WhileExp) return transExp((Absyn.WhileExp)e); if(e instanceof Absyn.NilExp) return transExp((Absyn.NilExp)e); if(e instanceof Absyn.IntExp) return transExp((Absyn.IntExp)e); if(e instanceof Absyn.StringExp) return transExp((Absyn.StringExp)e); if(e instanceof Absyn.BreakExp) return transExp((Absyn.BreakExp)e); if(e instanceof Absyn.CallExp) return transExp((Absyn.CallExp)e); if(e instanceof Absyn.RecordExp) return transExp((Absyn.RecordExp)e); if(e instanceof Absyn.VarExp) return transExp((Absyn.VarExp)e); if(e instanceof Absyn.SeqExp) return transExp((Absyn.SeqExp)e); if(e instanceof Absyn.ArrayExp) return transExp((Absyn.ArrayExp)e); throw new Error("transExp: " + e); // mantenere ???. } // LetExp ExpTy transExp(Absyn.LetExp e) { if(debflag==1) System.out.println(""); // per lasciare una riga di spazio stampaDeb(e.pos,"Inizio costrutto LET ... IN ... END\n"); // utilizzato per mantenere la lista delle dichiarazioni Vector decs = new Vector(); env.venv.beginScope(); env.tenv.beginScope(); for(Absyn.DecList p=e.decs; p!=null; p=p.tail) { decs.addElement(transDec(p.head)); } ExpTy et = transExp(e.body); // prima di chiudere lo scope stampa gli ambienti (in mod. debug) if ((debflag == 1) && (env.errorMsg.num_error == 0)) { System.out.println("\n\n***** Stampa degli ambienti (in uscita dallo 'scope' attuale) *****"); stampaTenv(); stampaVenv(); } env.venv.endScope(); env.tenv.endScope(); stampaDeb(e.pos,"Fine costrutto LET ... IN ... END\n"); if (env.errorMsg.num_error==0) { return new ExpTy(trans.letExp(decs,et.exp), et.ty); } else return new ExpTy(null, et.ty); } // AssignExp ExpTy transExp(Absyn.AssignExp e) { ExpTy vt = transVar(e.var); ExpTy et = transExp(e.exp); // controlla se i due tipi coincidono if (!(vt.ty.actual()==et.ty.actual())) { // caso RECORD ---> NIL if (!((vt.ty.actual() instanceof Types.RECORD)&&(et.ty.actual()==NIL))) { String out="Non puoi assegnare alla var. di tipo \"" + nomeClasse(vt.ty.actual()) + "\" il tipo \"" + nomeClasse(et.ty.actual())+ "\""; env.errorMsg.error(e.pos, out); } } // bisogna evitare che la variabile di controllo di un ciclo for // vegna assegnata nel corpo del ciclo stesso. if (vt.isFor) { Absyn.SimpleVar v=(Absyn.SimpleVar)e.var; String out="La variabile \"" + v.name + "\" non puo' essere assegnata nel corpo del ciclo FOR."; env.errorMsg.error(v.pos+1, out); } // restituisce un tipo VOID. (cosi' (a:=b)+c e' illegale!) if (env.errorMsg.num_error==0) { stampaDeb(e.pos,"AssignExp: " + nomeClasse(vt.ty.actual()) + ":=" + nomeClasse(et.ty.actual()) ); return new ExpTy(trans.assignExp(vt.exp, et.exp), VOID); } else return new ExpTy(null, VOID); } // OpExp ExpTy transExp(Absyn.OpExp e) { ExpTy left=transExp(e.left); ExpTy right=transExp(e.right); switch(e.oper) { // Plus, Minus, Mul, Div case Absyn.OpExp.PLUS: case Absyn.OpExp.MINUS: case Absyn.OpExp.MUL: case Absyn.OpExp.DIV: { checkInt(left, e.left.pos); checkInt(right, e.right.pos); if(env.errorMsg.num_error==0) { return new ExpTy( trans.opExp(e.oper, left.exp, right.exp, ((left.ty.actual() instanceof Types.STRING)&&(right.ty.actual() instanceof Types.STRING)) ), INT ); } else return new ExpTy(null, INT ); } // EQ, NE case Absyn.OpExp.EQ: case Absyn.OpExp.NE: { checkEq(e.pos,left,right,"="); if(env.errorMsg.num_error==0) { return new ExpTy( trans.opExp(e.oper, left.exp, right.exp, ((left.ty.actual() instanceof Types.STRING)&&(right.ty.actual() instanceof Types.STRING)) ), INT ); } else return new ExpTy(null, INT ); } // LT,LE,GT,GE case Absyn.OpExp.LT: case Absyn.OpExp.LE: case Absyn.OpExp.GT: case Absyn.OpExp.GE: { checkComp(e.pos,left,right,"<"); if(env.errorMsg.num_error==0) { return new ExpTy( trans.opExp(e.oper, left.exp, right.exp, ((left.ty.actual() instanceof Types.STRING)&&(right.ty.actual() instanceof Types.STRING)) ), INT ); } else return new ExpTy(null, INT ); } } throw new Error("OpExp"); // mantenere ??? } // ForExp ExpTy transExp(Absyn.ForExp e) { // crea una nuova etichetta e la salva in old_done // il valore di current_done. Temp.Label new_done = new Temp.Label(); Temp.Label old_done = current_done; // aggiorna current_done alla nuova etichetta current_done = new_done; // incrementa il contatore dei cicli loopDepth++; env.venv.beginScope(); Absyn.VarDec lo=(Absyn.VarDec)e.var; // controlla "lo" ExpTy loexp = transExp(lo.init); // memorizza l'accesso alla variabile Translate.Access acc = level.allocLocal(lo.escape); env.venv.put(lo.name, new VarEntry(acc,loexp.ty,true)); if (!(loexp.ty==INT)) { env.errorMsg.error(e.var.pos,"La variabile di controllo del ciclo FOR deve essere di tipo INT"); } // controlla "hi" ExpTy hiexp = transExp(e.hi); if (!(hiexp.ty==INT)) env.errorMsg.error(e.hi.pos,"Exp di uscita ciclo FOR deve essere di tipo INT"); // processa il corpo e ripristina il valore precedente di current_done ExpTy et = transExp(e.body); current_done = old_done; // controlla che il corpo della FOR abbia Tipo restituito VOID if (!(et.ty==VOID)) { env.errorMsg.error(e.body.pos,"Il corpo della FOR deve essere ti tipo VOID"); } env.venv.endScope(); // decrementa il contatore dei cicli loopDepth--; if (env.errorMsg.num_error==0) { stampaDeb(e.pos,"ForExp: Frame/Livello = " + level.frame.name ); return new ExpTy(trans.forExp(acc,level,loexp.exp,hiexp.exp,et.exp,new_done),et.ty); } return new ExpTy(null,et.ty); } // IfExp ExpTy transExp(Absyn.IfExp e) { ExpTy elsec=null; // controlla il tipo della exp di test ... ExpTy check=transExp(e.test); if (!(check.ty==INT)) env.errorMsg.error(e.test.pos,"Il test dell'IF deve essere di tipo INT"); ExpTy thenc = transExp(e.thenclause); String out = "IfExp: " + nomeClasse(check.ty.actual()) + " then " + nomeClasse(thenc.ty.actual()); // controlla il tipo di then ed else (deve essere lo stesso) if (e.elseclause != null) { elsec = transExp(e.elseclause); out = out + " else " + nomeClasse(elsec.ty.actual()); // ricava i tipi del then e dell'else if (!(thenc.ty.actual()==elsec.ty.actual())) { if (!( ((thenc.ty.actual() instanceof Types.RECORD) && (elsec.ty.actual()==NIL)) || ((thenc.ty.actual()==NIL) && (elsec.ty.actual() instanceof Types.RECORD)) )) { String err="Tipo then \"" + nomeClasse(thenc.ty.actual()) + "\" diverso dal tipo else \"" + nomeClasse(elsec.ty.actual())+ "\""; env.errorMsg.error(e.elseclause.pos,err); } } } else { // se e' della forma corta (if-then) // controlla che l'if-then abbia Tipo restituito VOID if (!(thenc.ty==VOID)) { env.errorMsg.error(e.thenclause.pos,"If-then deve avere tipo VOID"); } else { if (env.errorMsg.num_error==0) { return new ExpTy(trans.ifExp(check.exp,thenc.exp,trans.nullInstr()), thenc.ty); } else return new ExpTy(null, thenc.ty); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -