package zinara.symtable; import java.util.ArrayList; import java.util.HashMap; import java.util.Set; import java.util.Iterator; import zinara.ast.ASTNode; import zinara.ast.Declaration; import zinara.ast.MultipleDeclaration; import zinara.ast.SingleDeclaration; import zinara.ast.Param; import zinara.ast.expression.Expression; import zinara.ast.expression.LValue; import zinara.ast.instructions.Assignation; import zinara.ast.instructions.SingleAssignation; import zinara.ast.instructions.MultipleAssignation; import zinara.exceptions.IdentifierAlreadyDeclaredException; import zinara.exceptions.IdentifierNotDeclaredException; import zinara.exceptions.InvalidAssignationException; import zinara.exceptions.TypeClashException; public class SymTable{ private HashMap table; private SymTable father; private ArrayList sons; // ArrayList of symtables public String name = ""; //@invariant table != null; //@invariant sons != null; public SymTable() { this.sons = new ArrayList(); this.father = null; this.table = new HashMap(); } public SymTable(SymTable f) { this.sons = new ArrayList(); this.father = f; this.table = new HashMap(); } public SymTable(SymTable f, String name) { this.sons = new ArrayList(); this.father = f; this.table = new HashMap(); this.name = name; } public boolean checkDoubleDeclaration(String id) throws IdentifierAlreadyDeclaredException { if (containsId(id)) throw new IdentifierAlreadyDeclaredException(id); else return false; } //@ requires decl != null; public void addDeclaration(Declaration decl) throws IdentifierAlreadyDeclaredException { SingleDeclaration current_decl; if (decl.isSingle()) { //@ assume \typeof(decl) == \type(SingleDeclaration); current_decl = (SingleDeclaration)decl; if (!currentTableContainsId(current_decl.getId())) { addSymbol(current_decl.getId(), new SymValue(current_decl.getType(), current_decl.getStatus())); } else throw new IdentifierAlreadyDeclaredException(((SingleDeclaration)decl).getId()); } else { //@ assume \typeof(decl) == \type(MultipleDeclaration); for (int i = 0; i < ((MultipleDeclaration)decl).size(); i++) { current_decl = ((MultipleDeclaration)decl).get(i); //@ assume current_decl != null; if (!currentTableContainsId(current_decl.getId())) { addSymbol(current_decl.getId(), new SymValue(current_decl.getType(), current_decl.getStatus())); } else throw new IdentifierAlreadyDeclaredException(current_decl.getId()); } } } public void addSymbol (String id, SymValue v){ this.table.put(id,v); } public SymValue deleteSymbol (String id){ return (SymValue)this.table.remove(id); } public SymValue getSymbol (String id){ //@ assume \typeof(table.get(id)) == \type(SymValue); return (SymValue)this.table.get(id); } public SymTable getFather() { return this.father; } public ArrayList getSons() { return sons; } public SymTable getSon(int i) { return (SymTable)sons.get(i); } public boolean currentTableContainsId(String id){ return this.table.containsKey(id); } public boolean containsId(String id) { if (this.table.containsKey(id)) return true; else if (father != null) return father.containsId(id); else return false; } public SymTable getSymTableForId(String id) { if (this.table.containsKey(id)) return this; else if (father != null) return father.getSymTableForId(id); else return null; } public SymTable getSymTableForIdOrDie(String id) throws IdentifierNotDeclaredException { SymTable t = getSymTableForId(id); if (t != null) return t; else throw new IdentifierNotDeclaredException(id); } public SymValue getSymValueForId(String id) { //@ assume \typeof(this.table.get(id)) == \type(SymValue); if (this.table.containsKey(id)) return (SymValue)this.table.get(id); else if (father != null) return father.getSymValueForId(id); else return null; } public SymValue getSymValueForIdOrDie(String id) throws IdentifierNotDeclaredException { SymValue sv = getSymValueForId(id); if (sv != null) return sv; else throw new IdentifierNotDeclaredException(id); } public boolean containsValue (SymValue v){ return this.table.containsValue(v); } public boolean isEmpty (){ return this.table.isEmpty(); } public String toString() { String ret = ""; for (int i = 0; i < sons.size(); i++) ret += (SymTable)sons.get(i) + ", "; if (ret.length() != 0) ret = ret.substring(0, ret.length()-2); return "<" + table.toString() + "[" + ret + "]>"; } /* Checks two things, if the id of the assignation is declared and if the types match. */ //@ requires expr != null; //@ requires lv != null; public SingleAssignation checkAssignation(LValue lv, Expression expr) throws IdentifierNotDeclaredException, TypeClashException { //SymValue idSymValue = getSymValueForIdOrDie(id); //@ assume lv.getType() != null; if (lv.isConstant()) throw new TypeClashException("El identificador " + lv + " fue declarado como constante y no puede ser usado en una asignacion"); if (!lv.getType().getType().equals(expr.getType().getType())) throw new TypeClashException("Conflicto de tipos entre el identificador " + lv + lv.getType() +" y la expresion " + expr + expr.getType()); return new SingleAssignation(lv, expr); } /* Checks if the list of ids and expressions match in number, then checks the validity of every assignation issuing `checkAssignation`. */ //@ requires ids != null; //@ requires exprs != null; //@ requires (\forall int i; i >=0 && i < ids.size(); \typeof(ids.get(i)) == \type(LValue)); //@ requires (\forall int i; i >=0 && i < ids.size(); \typeof(ids.get(i)) == \type(Expression)); public Assignation checkMultipleAssignations(ArrayList ids, ArrayList exprs) throws IdentifierNotDeclaredException, TypeClashException, InvalidAssignationException { if (ids.size() != exprs.size()) throw new InvalidAssignationException(); // FIX THIS: same as in MultipleAssignation.java if (ids.size() == 1) return checkAssignation((LValue)ids.get(0), (Expression)exprs.get(0)); else { ArrayList assignations = new ArrayList(); for (int i = 0; i < ids.size(); i++) assignations.add(checkAssignation((LValue)ids.get(i), (Expression)exprs.get(i))); return new MultipleAssignation(assignations); } } public SymTable newTable() { SymTable son = new SymTable(this); sons.add(son); return son; } //@requires son != null; public void addSon(SymTable son){ this.sons.add(son); } public Set keySet() { return table.keySet(); } public int reserve_mem_main(int offset, String area){ return reserve_mem(offset,area,"+"); } public int reserve_mem_stack(int offset, String area){ return reserve_mem(offset,area,"-"); } public int reserve_mem(int offset, String area, String direction){ Iterator keyIt = keySet().iterator(); String identifier; SymValue symValue; int total_size = offset; int aux; while(keyIt.hasNext()) { identifier = (String)keyIt.next(); symValue = getSymbol(identifier); if (symValue.isParam()|| symValue.isReturn()|| symValue.type.size() == 0) continue; symValue.setOffset(direction + total_size); symValue.setArea(area); total_size += symValue.type.size(); } for (int i = 0; i < sons.size(); i++){ aux = ((SymTable)sons.get(i)).reserve_mem(total_size,area,direction); if (aux > total_size) total_size = aux; } return total_size; } public void set_params_offset(String area, int addrSize, ArrayList params){ String identifier; SymValue symValue; Param current_param; int params_offset = 2*addrSize; /*Porque antes de los parametros esta la cadena dinamica y la direccion de retorno*/ for (int i = params.size()-1; i>=0; --i){ current_param =((Param)params.get(i)); identifier = current_param.getId(); symValue = getSymbol(identifier); if (symValue.type.size() == 0) continue; symValue.setOffset("+"+params_offset); symValue.setArea(area); if (current_param.byValue()) params_offset += symValue.type.size(); else params_offset += addrSize; } } }