public class Tab

public static readonly Struct
noType = new Struct(Struct.Kinds.None),
intType = new Struct(Struct.Kinds.Int),
charType = new Struct(Struct.Kinds.Char),
nullType = new Struct(Struct.Kinds.Class);

/* Symbol to indicate that an error has occurred in the symbol table */ 
public static readonly Symbol noSym = new Symbol(Symbol.Kinds.Const, "noSymbol", noType);

public static Symbol chrSym, ordSym, lenSym;

internal static Scope topScope; // current scope
/* Sets up the "universe" (= predefined names). */
public static void Init () {
/*---------------------------------*/
/*----- insert your code here -----*/
/*---------------------------------*/
}

public static void OpenScope () {
/*---------------------------------*/
/*----- insert your code here -----*/
/*---------------------------------*/
}

public static void CloseScope () { 
/*---------------------------------*/
/*----- insert your code here -----*/
/*---------------------------------*/
}

public static Symbol Insert (Symbol.Kinds kind, string name, Struct type) {
/*---------------------------------*/
/*----- insert your code here -----*/
/*---------------------------------*/
}

/* Retrieves the Symbol with name from the innermost scope. */
public static Symbol Find (string name) {
/*---------------------------------*/
/*----- insert your code here -----*/
/*---------------------------------*/
}

/* Retrieves the field name from the fields of type. */
public static Symbol FindField (string name, Struct type) {
/*---------------------------------*/
/*----- insert your code here -----*/
/*---------------------------------*/
}
}
public class Scope {
public Scope outer; // reference to enclosing scope
public Symbol locals; // symbol table of this scope
public int nArgs; // # of arguments in this scope (for address asignment)
public int nLocs; // # of local variables in this scope (for address asignment)
}
/* Z# Symbol Table Nodes:
* Every named object in a program is stored in an Symbol node.
* Every scope has a list of Symbols declared within it. */
public class Symbol {
public enum Kinds { Const, Global, Field, Arg, Local, Type, Meth, Prog }

public Kinds kind;
public string name;
public Struct type;
public Symbol next; // next Symbol node in this scope
public int val; // Const: value;
public int adr; // Field, Arg, Local: order of declaration in scope
public int nArgs; // Meth: # of arguments
public int nLocs; // Meth: # of local variables
public Symbol locals; // Meth: arguments, then local variables; Prog: symbol table of program
/* these fields are necessary for the building the assembly with System.Reflection.Emit */
internal MethodBuilder meth; // Method: builder for metadata and CIL
internal FieldBuilder fld; // Field: builder for metadata
internal ConstructorBuilder ctor; // Type: builder for metadata and CIL

public Symbol (Kinds kind, string name, Struct type) {
this.kind = kind; this.name = name; this.type = type;
}

public override bool Equals (object o) {
if (this == o) return true; // same object
Symbol sym = o as Symbol;
if (sym == null) return false;
return Equals(sym);
}

public bool Equals (Symbol sym) {
if (kind != sym.kind || name != sym.name || !type.Equals(sym.type)) 
return false;
switch (kind) {
case Kinds.Const: return val == sym.val;
case Kinds.Arg: case Kinds.Local: return adr == sym.adr;
case Kinds.Meth:
return nArgs == sym.nArgs && nLocs == sym.nLocs && 
EqualsCompleteList(locals, sym.locals);
}
return true;
}

public override string ToString () {
StringBuilder sb = new StringBuilder();

sb.AppendFormat("{0}: {1}, {2}", name, kind, type);
switch (kind) {
case Kinds.Const: sb.AppendFormat(" ={0}", val); break;
case Kinds.Arg: case Kinds.Local: sb.AppendFormat(", {0}", adr); break;
case Kinds.Meth:
sb.AppendFormat(", {0}, {1}", nArgs, nLocs);
Symbol sym; int i;
for (sym = locals, i = 0; sym != null; sym = sym.next, i++)
sb.AppendFormat("{0}-----{3}[{1}]={2}", Environment.NewLine, i, sym,
(sym.kind == Symbol.Kinds.Arg) ? "arg" : "loc");
if (nArgs + nLocs > 0) sb.AppendFormat("{0}", Environment.NewLine);
break;
}

return sb.ToString();
}

/* Compare complete Symbol node lists. */
public static bool EqualsCompleteList (Symbol sym1, Symbol sym2) {
if (sym1 == sym2) return true; // same object

while (sym1 != null && sym1.Equals(sym2)) {
sym1 = sym1.next; sym2 = sym2.next;
}

if (sym1 != null || sym2 != null) return false;

return true;
}
}
/* Z# Type Structures:
* A type structure stores the type attributes of a declared type. */
public class Struct {
public enum Kinds { None, Int, Char, Arr, Class }

public Kinds kind; // None, Int, Char, Arr, Class
public Struct elemType; // Arr: type of array elements
public Symbol fields; // Class: reference to list of local variables
/* this field is necessary for the building the assembly with System.Reflection.Emit */ 
internal Type sysType; // CLR runtime type object

public Struct (Kinds kind) : this(kind, null) {}
public Struct (Kinds kind, Struct elemType) {
this.kind = kind;
// set CLR type of Struct instance
switch (kind) {
case Struct.Kinds.None: sysType = typeof(void); break;
case Struct.Kinds.Int: sysType = typeof(int); break;
case Struct.Kinds.Char: sysType = typeof(char); break;
case Struct.Kinds.Arr: 
sysType = Array.CreateInstance(elemType.sysType, 0).GetType(); 
this.elemType = elemType;
break;
case Struct.Kinds.Class: 
// do nothing here, type must first be defined
// sysType is set in Code.CreateMetadata before first use
break;
}

this.elemType = elemType;
}

public override bool Equals (object o) {
if (this == o) return true; // same object
Struct s = o as Struct;
if (s == null) return false;
return Equals(s);
}

public bool Equals (Struct other) {
if (kind == Kinds.Arr)
return other.kind == Kinds.Arr && elemType.Equals(other.elemType);

return this == other; // must be same type node
}

public bool IsRefType () { return kind == Kinds.Class || kind == Kinds.Arr; }

public bool CompatibleWith (Struct other) {
return this.Equals(other) ||
this == Tab.nullType && other.IsRefType() ||
other == Tab.nullType && this.IsRefType();
}

public bool AssignableTo (Struct dest) {
return this.Equals(dest) || 
this == Tab.nullType && dest.IsRefType() ||
// for predefined function len(Array of noType)
kind == Kinds.Arr && dest.kind == Kinds.Arr && dest.elemType == Tab.noType;


public override string ToString () {
StringBuilder sb = new StringBuilder();

switch (kind) {
case Struct.Kinds.Int: sb.Append("int"); break;
case Struct.Kinds.Char: sb.Append("char"); break;
case Struct.Kinds.Class: 
sb.AppendFormat("#{0}", GetHashCode());
Symbol field; int i;
for (field = fields, i = 0; field != null; field = field.next, i++)
sb.AppendFormat("{0}-----field[{1}]={2}", Environment.NewLine, i, field);
sb.AppendFormat("{0}", Environment.NewLine);
break;
case Struct.Kinds.Arr: sb.AppendFormat("{0}[]", elemType); break;
}

return sb.ToString();
}
}