/**
 * MicroJava Symbol Table
 */
package ppdz;

public class Tab {
	public static final Struct
		noType = new Struct(Struct.None),
		intType = new Struct(Struct.Int),
		charType = new Struct(Struct.Char),
		nullType = new Struct(Struct.Class);
		
	public static final Obj noObj = new Obj(Obj.Var, "noObj", noType);

	public static Obj chrObj, ordObj, lenObj;

	public static Scope topScope;  // current scope
private static int level;      // nesting level of current scope

	public static boolean duplicate=false;
	public static boolean error=false;
 	public static int errnum=0;
	
	
	public static void init () {
                     topScope=null;
                     Scope s=new Scope();
	              s.outer=topScope;
	              topScope=s;
	              int k=Obj.Type;
	              String n="int";
	              Struct t=intType;
	              Obj node=new Obj(k, n, t);
	              topScope.locals=node;
	              node.next=new Obj(Obj.Type, "char", charType);
	              node=node.next;
	              node.next=new Obj(Obj.Con, "eol", charType);
	              node=node.next;
	              node.adr=10;
	              node.next=new Obj(Obj.Con, "null", nullType);
	              node=node.next;
	              node.adr=0;
	              node.next=new Obj(Obj.Meth, "chr", charType);
	              node=node.next;
	              node.level=1;
	              node.locals=new Obj(Obj.Var, "i", intType);
	              (node.locals).adr=0;
	              (node.locals).level=1;
	              (node.locals).next=null;
	              chrObj=node;
	              node.next=new Obj(Obj.Meth, "ord", intType);
	              node=node.next;
	              node.level=1;
	              node.locals=new Obj(Obj.Var, "ch", charType);
	              (node.locals).adr=0;
	              (node.locals).level=1;
	              (node.locals).next=null;
	              ordObj=node;
	              node.next=new Obj(Obj.Meth, "len", intType);
	              node=node.next;
	              node.level=1;
	              node.next=null;
	              node.locals=new Obj(Obj.Var, "arr", new Struct(Struct.Arr, noType));
	              (node.locals).adr=0;
	              (node.locals).level=1;
	              (node.locals).next=null;
	              lenObj=node;
	              topScope.nVars=7;
                     level=-1;
	}
	
	public static void openScope () {
        Scope s = new Scope();
        s.outer = topScope; topScope = s;
        level++;
	}
	
	public static void closeScope () {
		topScope = topScope.outer;
		level--;
	}
	
	public static Obj insert (int kind, String name, int line, Struct type) {
        // check for duplicate
        for (Obj p = topScope.locals; p != null; p = p.next)
            if (p.name.equals(name)) {
                error("Greska u "+line+"("+name + ") vec deklarisano");
		    duplicate=true;
                return p;
            }
	    duplicate=false;
	    // create a new Object node with kind, name, type
	    Obj newObj = new Obj(kind, name, type);
	    newObj.adr = 0;
	    if ( level != 0 ) 
	        newObj.level = 1; // local
	    else
	        newObj.level = 0; // global
		// append the node to the end of the symbol list
		if ( topScope.locals == null )
		   topScope.locals = newObj;
		else {
		   Obj p;
           for (p = topScope.locals; p.next != null; p = p.next)
              ;
           p.next = newObj; 
		}
		topScope.nVars++;
		return newObj;    
	}
	
	/** Retrieves the object with <code>name</code> from the innermost scope. */
	public static Obj find (String name, int line) {
        for (Scope s = topScope; s != null; s = s.outer)
            for (Obj p = s.locals; p != null; p = p.next)
                if (p.name.equals(name)) return p;
        error("Greska u "+line+"("+name + ") nije nadjeno");
        return noObj;
	}

	/**	Retrieves the field <code>name</code> from the fields of <code>type</code>. */
	public static Obj findField (String name, int line, Struct type) {
		if ( type.kind != Struct.Class ) {
		    error("Greska u "+line+": nije instanca klase, polje nije nadjeno");
		    return noObj;
		}
        for (Obj p = type.fields; p != null; p = p.next)
            if (p.name.equals(name)) return p;
        error("Greska u"+line+"("+name + ") polje nije nadjeno");
        return noObj;
	}

      /** prints error */
	public static void error (String err) {
        System.err.println(err);
        Tab.error=true;
        Tab.errnum++;
	}


    /** prints contents of the symbol table for testing purposes */
	public static void dump() {
        int l=level;
        System.out.println("=====================SADRZAJ TABELE SIMBOLA=========================");
        for (Scope s = topScope; s != null; s = s.outer) {
            System.out.println("(Level "+l+")");
            for (Obj p = s.locals; p != null; p = p.next) {
                System.out.println(p.toString());
            }
            l--;
        }
	}
}
