diff --git a/AST.py b/AST.py
new file mode 100644
index 0000000000000000000000000000000000000000..a7a89fed65861278355bfebee0e79bff53fea223
--- /dev/null
+++ b/AST.py
@@ -0,0 +1,76 @@
+import pprint
+
+class ASTNode():
+    # Base class for a node in the AST
+    # Default fields:
+    #   children : a list of child nodes, these nodes might
+    #       be stored in other fields of the object, we double store the pointers
+    #       for easier recursion
+    #   parseTree: stores the parse tree that corresponds to this AST node
+    #        This is a redundancy that can be cleaned up after the AST construction,
+    #        but we will keep it for easier debugging, since effeciency is not a concern here
+    def __init__(self, parseTree):
+        self.parseTree = parseTree
+
+    # Do certains actions on every node of the AST tree
+    #   call the same method in each class and its children recursively
+    #   the methods that represent an action would return arguments to be used in
+    #   the child nodes' method if neccessary
+    def recurseAction(self, actionName, args):
+        func = self.getattr(actionName)
+        result = None
+        if func:
+            result = func(args)
+        for c in self.children:
+            c.recurseAction(result)
+
+    # use the parse tree to populate current AST node and construct child AST nodes
+    def buildASTNodeRecursive(self):
+        pass
+
+    def printNodePretty(self, prefix=0):
+        pp = pprint.PrettyPrinter(indent=prefix)
+
+        pp.pprint(self.__class__.__name__)
+        pp.pprint(vars(self))
+        pp.pprint("-----children-----")
+        prefix += 1
+        for c in self.children:
+            c.printNodePretty(prefix)
+
+# Utils ######################################################
+
+#   given a parseTree and a list of names, traverse the tree
+#        to return a list of tree nodes(on the same level) that
+#        has one of those names. A termination list can also be supplied
+#        to stop the recursive search at the specified nodes
+def getParseTreeNodes(names, tree, terminateList = []):
+    result = []
+    if tree.name in names:
+        return result.append(tree)
+    if not tree.children:
+        return []
+    for n in tree.children:
+        if n.name in names:
+            result.append(n)
+        elif n.name in terminateList:
+            continue
+        else:
+            result.extend(getParseTreeNodes(names, n))
+    return result
+
+
+# input: a parse tree node with its name == 'type'
+# output: (isPrimitiveType: Bool, typeName: String) of a type
+def getTypeName(node):
+    isPrimType = False
+    typeName = ''
+    nameNodes = getParseTreeNodes(['BOOLEAN', 'BYTE', 'CHAR', 'INT', 'SHORT'], node)
+    if nameNodes:
+        isPrimType = True
+    else:
+        # get refType
+        nameNodes = getParseTreeNodes(['ID', 'COMPID'], node)
+    for n in nameNodes:
+        typeName = n.lex
+    return (isPrimType, typeName)
diff --git a/AstBuilding.py b/AstBuilding.py
index 8a5987808da7570b7c072c1a06277c8b5a9aaca3..5b96449bfc59f896fcb3755db9590b3c2218cedc 100644
--- a/AstBuilding.py
+++ b/AstBuilding.py
@@ -1,69 +1,15 @@
-import string
-from AstNodes import *
-
-##################### Build AST ##########################################
-# go through parse tree
-# determine what nodes are going to be converted into specific type of node
-# condense tree (a->b->c => a->c)
-
-# node: Node
-def astbuildNode(node):
-    newNode = None
-    if (node.name == 'classDcl'):
-        newNode = ClassDcl(node)
-    else:
-        newNode = Node(node.name, node.lex, [])
-
-    childs = node.children
-    newChilds    = []
-
-    for c in childs:
-        newChilds.append(astbuildNode(c))
-
-    newNode.children = newChilds
-
-    return newNode
-
-# tree: Node
-def astbuild(tree):
-    try:
-        ast = astbuildNode(tree)
-    except:
-        return (None, 'Couldn\'t build AST')
-
-    return (ast, 'success')
-
-# ast: Node
-def weed(ast):
-    res = ast.weed()
-    for c in ast.children:
-        res += weed(c)
-    return res
-
-##################### Tests ##########################################
-
-x = Node('start', '', [
-    Node('BOF', 'BOF', []),
-    Node('packageDcl', '', []),
-    Node('importDcls', '', []),
-    Node('topDcls', '', [
-        Node('topDcl', '', [
-            Node('classDcl', '', [
-                Node('classMod', '', [
-                    Node('PUBLIC', 'public', []),
-                ]),
-                Node('CLASS', 'class', []),
-                Node('ID', 'MyClass', []),
-                Node('superclass', '', []),
-                Node('superInterface', '', []),
-                Node('classBody', '', [
-                    Node('LBRACK', '(', []),
-                    Node('classBodyDcls', '', []),
-                    Node('RBRACK', ')', [])
-                ]),
-            ])
-        ]),
-        Node('topDcls', '', [])
-    ])
-])
-# print(astbuild(x))
\ No newline at end of file
+from CompNode import CompNode
+
+# tree: (filename, parseTree)
+def astBuild(trees):
+    ASTs = []
+    for (n, t) in trees:
+        ASTs.append((n, CompNode(t)))
+    return ASTs
+
+# # ast: Node
+# def weed(ast):
+#     res = ast.weed()
+#     for c in ast.children:
+#         res += weed(c)
+#     return res
diff --git a/AstNodes.py b/AstNodes.py
deleted file mode 100644
index aff1885e12d4572687eef20f6526283ac55b3bb7..0000000000000000000000000000000000000000
--- a/AstNodes.py
+++ /dev/null
@@ -1,65 +0,0 @@
-import string
-import sys
-
-##################### Nodes ##########################################
-
-# children: Node[]
-# name:     string
-# lex:      string
-class Node():
-    def __init__(self, name, lex, children):
-        self.name     = name
-        self.lex      = lex
-        self.children = children
-    def __str__(self):
-        return printNodePretty(self)
-    def weed(self):
-        return ''
-
-# node: Node
-class ClassDcl(Node):
-    def __init__(self, node):
-        self.name           = node.name
-        self.lex            = node.lex
-        self.children       = node.children
-        self.classMod       = node.children[0]
-        self.ID             = node.children[2].lex
-        self.superClass     = node.children[3]
-        self.superInterface = node.children[4]
-        self.classBody      = node.children[5]
-    def weed(self):
-        # Every class must contain at least one explicit constructor
-        if not checkConstructor(self.classBody.children[1]):
-            return 'Class ' + self.ID + ' does not contain a constructor.'
-        
-        return ''
-
-# Every class must contain at least one explicit constructor
-# classBodyDcls: Node
-# cfgrules:
-#  classBodyDcls classBodyDcl classBodyDcls
-#  classBodyDcls
-def checkConstructor(classBodyDcls):
-    if classBodyDcls.children:
-        classBodyDcl = classBodyDcls.children[0]
-        if classBodyDcl.children[0].name == 'constructorDcl':
-            return True
-        return checkConstructor(classBodyDcls.children[1])
-    return False
-
-
-##################### Helpers ##########################################
-
-# node:   Node
-# prefix: string
-# last:   boolean
-def printNodePretty(node, prefix='', last=True):
-    res = prefix
-    res += '`- ' if last else '|- '
-    res += node.name + ' ' + node.lex + '\n'
-    prefix += '   ' if last else '|  '
-    num = len(node.children)
-    for i, child in enumerate(node.children):
-        last = i == (num - 1)
-        res += printNodePretty(child, prefix, last)
-    return res
\ No newline at end of file
diff --git a/CompNode.py b/CompNode.py
new file mode 100644
index 0000000000000000000000000000000000000000..2a74f598047c19cbebbc3cb0e3031527586407ab
--- /dev/null
+++ b/CompNode.py
@@ -0,0 +1,33 @@
+from AST import ASTNode, getParseTreeNodes
+from TypeNodes import InterNode, ClassNode
+
+
+# compilation unit
+class CompNode(ASTNode):
+    # always list all fields in the init method to show the class structure
+    def __init__(self, parseTree):
+        self.parseTree = parseTree
+        self.packageName = ''
+        self.importNames = [] # list of strings representing names getting imported
+        self.env = None
+        self.typeDcl = None
+        self.children = []
+
+        for node in parseTree.children:
+            if node.name == 'packageDcl':
+                nameNodes = getParseTreeNodes(['ID', 'COMPID'], node)
+                for n in nameNodes:
+                    self.packageName = n.lex
+            elif node.name == 'importDcls':
+                nameNodes = getParseTreeNodes(['ID', 'COMPID', 'IMPORTALL'], node)
+                for n in nameNodes:
+                    self.importNames.append(n.lex)
+            elif node.name == 'topDcls':
+                typeNode = getParseTreeNodes('classDcl', node)
+                if not typeNode:
+                    typeNode = getParseTreeNodes('interfaceDcl', node)
+                    self.typeDcl = InterNode(typeNode[0])
+                else:
+                    self.typeDcl = ClassNode(typeNode[0])
+        # always populate the children list
+        self.children.append(self.typeDcl)
diff --git a/Environment.py b/Environment.py
new file mode 100644
index 0000000000000000000000000000000000000000..e3badd87855ff79bfa7c4ba02397b7916062dd74
--- /dev/null
+++ b/Environment.py
@@ -0,0 +1,68 @@
+from ASTNode import ScopeNode, Environment
+
+##################################################################
+
+# give a list of parseTrees, returns the global Environemnt object and
+#   a list of classNodes with globalEnv attached to them
+def buildGlobalEnv(parseTrees):
+	gEnv = Environment(None)
+	ASTs = []
+
+	for t in parseTrees:
+		# add imports
+		imports = getParseTreeNodes(['importDcl'], t)
+		for i in imports:
+			importNames = getParseTreeNodes(['ID', 'COMPID', 'IMPORTALL'], i)
+			for n in importNames:
+				gEnv.addName(n.lex, 'package', None)
+
+		# TODO: figure out package name
+		packages = getParseTreeNodes('packageDcl', t)
+		pNames = []
+		for p in packages:
+			pNames.extend(getParseTreeNodes(['ID', 'COMPID'], p))
+		if pNames:
+			pNames = pNames[0]
+		else:
+			pNames = 'no packageName'
+
+		# add class to global Env
+		classDcl = getParseTreeNodes('classDcl', t)
+		interfaceDcl = getParseTreeNodes('interfaceDcl', t)
+
+		if not classDcl:
+			intNode = ScopeNode(interfaceDcl[0], gEnv)
+			ASTs.append(intNode)
+			gEnv.addName(pNames+ " " + intNode.name, 'interface', intNode)
+		else:
+			classNode = ScopeNode(classDcl[0], gEnv)
+			ASTs.append(classNode)
+			gEnv.addName(pNames+ " " + classNode.name, 'class', classNode)
+
+	#prints
+
+	print('----------- global env ------------')
+	for g in gEnv.map:
+		print(g)
+		for gg in gEnv.map[g]:
+			print(gg)
+	print('----------- ASTs  -----------------')
+	for a in ASTs:
+		print(a.name)
+	return gEnv, ASTs
+
+# Utils: given a parseTree and a list of names, traverse the tree
+#        to return a list of tree nodes(on the same level) that
+#        has one of those names
+def getParseTreeNodes(names, tree):
+	result = []
+	if tree.name in names:
+		return result.append(tree)
+	if not tree.children:
+		return []
+	for n in tree.children:
+		if n.name in names:
+			result.append(n)
+		else:
+			result.extend(getParseTreeNodes(names, n))
+	return result
diff --git a/LineNodes.py b/LineNodes.py
new file mode 100644
index 0000000000000000000000000000000000000000..20dce6524853bbf7a180511422d1980763e1f94b
--- /dev/null
+++ b/LineNodes.py
@@ -0,0 +1,21 @@
+from AST import ASTNode, getParseTreeNodes, getTypeName
+
+# expr
+class ExprNode(ASTNode):
+    # always list all fields in the init method to show the class structure
+    def __init__(self, parseTree):
+        self.parseTree = parseTree
+        self.left = ''
+        self.op = ''
+        self.right = None  # another expr
+        self.env = None
+        self.children = []
+
+# block
+class BlockNode(ASTNode):
+    # always list all fields in the init method to show the class structure
+    def __init__(self, parseTree):
+        self.parseTree = parseTree
+        self.statements = []  # list of statements in a block
+        self.env = None
+        self.children = []
diff --git a/MemberNodes.py b/MemberNodes.py
new file mode 100644
index 0000000000000000000000000000000000000000..cb4e2951a0fbd234e3bed3c867f042d85c7a20c4
--- /dev/null
+++ b/MemberNodes.py
@@ -0,0 +1,89 @@
+from AST import ASTNode, getParseTreeNodes, getTypeName
+from LineNodes import ExprNode, BlockNode
+
+# field
+class FieldNode(ASTNode):
+    # always list all fields in the init method to show the class structure
+    def __init__(self, parseTree):
+        self.parseTree = parseTree
+        self.name = ''
+        self.fieldType = ''
+        self.fieldInit = None
+        self.mods = []
+        self.isPrimType = False # easy boolean flag, can be optimize later
+        self.env = None
+        self.children = []
+
+
+        for node in parseTree.children:
+            if node.name == 'methodMod':
+                for m in node.children:
+                    self.mods.append(m.lex)
+
+            elif node.name == 'type':
+                self.isPrimType, self.fieldType = getTypeName(node)
+
+            elif node.name == 'variableDcl':
+                nameNodes = getParseTreeNodes(['ID', 'COMPID'], node, ['variableInit'])
+                for n in nameNodes:
+                    self.name = n.lex
+
+                nameNodes = getParseTreeNodes(['variableInit'], node)
+                for n in nameNodes:
+                    self.fieldInit =  ExprNode(n)
+
+        if self.fieldInit: self.children.append(self.fieldInit)
+
+
+
+###########################################################
+
+# method
+class MethodNode(ASTNode):
+    # always list all fields in the init method to show the class structure
+    def __init__(self, parseTree):
+        self.parseTree = parseTree
+        self.name = ''
+        self.methodType = ''
+        self.params = {} # a dictionary {paramName -> (isPrimType, typeName)}, after type linking: {paramName -> typeNode}
+        self.mods = []
+        self.body = None
+        self.isPrimType = False # easy boolean flag, can be optimize later
+        self.env = None
+        self.children = []
+
+        # get method name
+        nameNodes = getParseTreeNodes(['ID'], parseTree, ['params', 'type', 'methodBody'])
+        for n in nameNodes:
+            self.name = n.lex
+
+        nameNodes = getParseTreeNodes(['param'], parseTree, ['methodBody'])
+        for n in nameNodes:
+            paramName = ''
+            paramType = ''
+            for c in n.children:
+                if c.name == 'type':
+                    paramType = getTypeName(c)
+                elif c.name == 'ID':
+                    paramName = c.lex
+            self.params[paramName] = paramType
+
+        nameNodes = getParseTreeNodes(['type', 'VOID'], parseTree, ['methodBody', 'params'])
+        for n in nameNodes:
+            if n.name == 'VOID':
+                self.isPrimType = True
+                self.methodType = n.lex
+            else:
+                self.isPrimType, self.methodType = getTypeName(n)
+
+        for node in parseTree.children:
+            if node.name == 'methodMod':
+                for m in node.children:
+                    self.mods.append(m.lex)
+
+            elif node.name == 'methodBody':
+                nameNodes = getParseTreeNodes(['block'], node)
+                for n in nameNodes:
+                    self.body = BlockNode(n)
+
+        if self.body: self.children.append(self.body)
diff --git a/ParseNode.py b/ParseNode.py
new file mode 100644
index 0000000000000000000000000000000000000000..cba3fc29765127d32e23d72b8554a40f68a96f14
--- /dev/null
+++ b/ParseNode.py
@@ -0,0 +1,65 @@
+import string
+import sys
+
+##################### Nodes ##########################################
+
+# children: Node[]
+# name:     string
+# lex:      string
+class Node():
+    def __init__(self, name, lex, children):
+        self.name     = name
+        self.lex      = lex
+        self.children = children
+    def __str__(self):
+        return printNodePretty(self)
+    def weed(self):
+        return ''
+#
+# # node: Node
+# class ClassDcl(Node):
+#     def __init__(self, node):
+#         self.name           = node.name
+#         self.lex            = node.lex
+#         self.children       = node.children
+#         self.classMod       = node.children[0]
+#         self.ID             = node.children[2].lex
+#         self.superClass     = node.children[3]
+#         self.superInterface = node.children[4]
+#         self.classBody      = node.children[5]
+#     def weed(self):
+#         # Every class must contain at least one explicit constructor
+#         if not checkConstructor(self.classBody.children[1]):
+#             return 'Class ' + self.ID + ' does not contain a constructor.'
+#
+#         return ''
+#
+# # Every class must contain at least one explicit constructor
+# # classBodyDcls: Node
+# # cfgrules:
+# #  classBodyDcls classBodyDcl classBodyDcls
+# #  classBodyDcls
+# def checkConstructor(classBodyDcls):
+#     if classBodyDcls.children:
+#         classBodyDcl = classBodyDcls.children[0]
+#         if classBodyDcl.children[0].name == 'constructorDcl':
+#             return True
+#         return checkConstructor(classBodyDcls.children[1])
+#     return False
+
+
+##################### Helpers ##########################################
+
+# node:   Node
+# prefix: string
+# last:   boolean
+def printNodePretty(node, prefix='', last=True):
+    res = prefix
+    res += '`- ' if last else '|- '
+    res += node.name + ' ' + node.lex + '\n'
+    prefix += '   ' if last else '|  '
+    num = len(node.children)
+    for i, child in enumerate(node.children):
+        last = i == (num - 1)
+        res += printNodePretty(child, prefix, last)
+    return res
diff --git a/Parsing.py b/Parsing.py
index ac82a4486f708ce6d881de18971109c109371089..c051bb5389ff5fb84876046dd2c208ffc5cbe3af 100644
--- a/Parsing.py
+++ b/Parsing.py
@@ -1,7 +1,7 @@
 import string
 import sys
 from Scanning import Token
-from AstNodes import Node
+from ParseNode import Node
 
 ##################### State ##########################################
 
@@ -170,5 +170,5 @@ def parse(tokens):
         result = checkSequence(tokens)
     except ValueError as err:
         return (None, err)
-        
+
     return (result, 'success')
diff --git a/Test.py b/Test.py
index ed8dac2433c30dc35384669f079c3f3b80f6beb8..c69c96d292bba1d189ce96c4f0849ed66aaa22fb 100644
--- a/Test.py
+++ b/Test.py
@@ -1,18 +1,20 @@
 import sys
-from os import listdir
+from os import listdir, scandir
 from os.path import isfile, join
 
 from Scanning import scan
 from Parsing import parse
+from AstBuilding import astBuild
 import Weeding
-import AstBuilding
 
 
+def main():
+    a2Multiple()
+
 def allFiles(testDir):
      return [testDir + f for f in listdir(testDir) if isfile(join(testDir, f)) and f.startswith('J1')]
 
-def main():
-
+def a1():
     if len(sys.argv) > 1:
         testFiles = ["./Tests/" + f for f in sys.argv[1:]]
     else:
@@ -20,6 +22,31 @@ def main():
         testDirectory = "./Tests/"
         testFiles = allFiles(testDirectory)
     print("**********************************************************")
+    run(testFiles)
+
+def a2Single():
+    # test all the single file cases in a2
+    pass
+
+def a2Multiple():
+    if len(sys.argv) > 1:
+        testCases = [f for f in sys.argv[1:]]
+    else:
+        # All files in the test directory
+        testDirectory = "./Tests/A2/"
+        testCases = [f.path for f in scandir(testDirectory) if f.is_dir()]
+
+    for c in testCases:
+        print(c)
+        print("**********************************************************")
+        testFiles = [c + '/'+  f for f in listdir(c) if isfile(join(c, f))]
+        run(testFiles)
+        print("\n \n\n ")
+
+
+
+def run(testFiles):
+    parseTrees = []
 
     for f in testFiles:
         print(f)
@@ -65,27 +92,22 @@ def main():
             print("**********************************************************")
             continue
 
-        # AST Building
-        try:
-            (ast, error) = AstBuilding.astbuild(tree)
-        except:
-            print("Exception in AstBuilding")
-        # print(ast)
+        parseTrees.append((f, tree))
 
-        # Error in AstBuilding
-        if ast is None:
-            print("ERROR in AstBuilding: " + error)
-            print("**********************************************************")
-            continue
+        print("Scan and Parse Succeeded")
+        print("**********************************************************")
 
-        # Weeding after AST
-        weeds = AstBuilding.weed(ast)
-        if weeds:
-            print("ERROR in Weeding on AST: " + weeds)
-            print("**********************************************************")
-            continue
 
-        print("Succeeded")
-        print("**********************************************************")
+    ASTs = astBuild(parseTrees)
+
+    for (n, t) in ASTs:
+        print(n)
+        print("--------------------")
+        t.printNodePretty()
+        print("\n \n\n \n")
+
+
+    print("Succeeded")
+    print("**********************************************************")
 
-main()
\ No newline at end of file
+main()
diff --git a/TestMultiple.py b/TestMultiple.py
new file mode 100644
index 0000000000000000000000000000000000000000..98b08473e5135a48a92f10b5466ff2449a717f3d
--- /dev/null
+++ b/TestMultiple.py
@@ -0,0 +1,7 @@
+# test compiling multiple files
+# for running multiple-files test cases for A2 (one case in a folder)
+
+if len(sys.argv) > 1:
+    testFiles = ["./Tests/" + f for f in sys.argv[1:]]
+
+os.system('py Test.py')
diff --git a/TypeNodes.py b/TypeNodes.py
new file mode 100644
index 0000000000000000000000000000000000000000..4a9a79f0f5075feccf5bb501a2302d9ed890dc7c
--- /dev/null
+++ b/TypeNodes.py
@@ -0,0 +1,80 @@
+from AST import ASTNode, getParseTreeNodes
+from MemberNodes import FieldNode, MethodNode
+
+# types: class , interface
+
+# class
+class ClassNode(ASTNode):
+    # always list all fields in the init method to show the class structure
+    def __init__(self, parseTree):
+        self.parseTree = parseTree
+        self.name = ''
+        self.fields = []
+        self.methods = []
+        self.constructors = []
+        self.mods = []
+        self.superClass = '' # these fields initially stores a string that represent the super
+        self.superInter = [] #    class/Interface's name, then stores a pointer to the class after type linking
+        self.env = None
+        self.children = []
+
+        for node in parseTree.children:
+            if node.name == 'classMod':
+                for m in node.children:
+                    self.mods.append(m.lex)
+            elif node.name == 'ID':
+                self.name = node.lex
+
+            elif node.name == 'superClass':
+                nameNodes = getParseTreeNodes(['ID', 'COMPID'], node)
+                for n in nameNodes:  # use for loop to handle no superclass case
+                    self.superClass = n.lex
+            elif node.name == 'superInterface':
+                nameNodes = getParseTreeNodes(['ID', 'COMPID'], node)
+                for n in nameNodes:
+                    self.superInter.append(n.lex)
+
+            elif node.name == 'classBody':
+                fieldNodes = getParseTreeNodes(['fieldDcl'], node, ['constructorDcl', 'methodDcl'])
+                for f in fieldNodes:
+                    self.fields.append(FieldNode(f))
+
+                constructorDcl = getParseTreeNodes(['constructorDcl'], node, ['fieldDcl', 'methodDcl'])
+                for c in constructorDcl:
+                    self.constructors.append(MethodNode(c))
+
+                methodNodes = getParseTreeNodes(['methodDcl'], node, ['constructorDcl', 'fieldDcl'])
+                for m in methodNodes:
+                    self.methods.append(MethodNode(m))
+
+        self.children += self.fields + self.methods + self.constructors
+
+
+
+#####################################################################
+# interface
+class InterNode(ASTNode):
+    # always list all fields in the init method to show the class structure
+    def __init__(self, parseTree):
+        self.parseTree = parseTree
+        self.name = ''
+        self.methods = []
+        self.superInter = [] # list of strings of superInterface's name, then stores a pointer to the node after type linking
+        self.env = None
+        self.children = []
+
+        for node in parseTree.children:
+            if node.name == 'ID':
+                self.name = node.lex
+
+            elif node.name == 'superInterface':
+                nameNodes = getParseTreeNodes(['ID', 'COMPID'], node)
+                for n in nameNodes:
+                    self.superInter.append(n.lex)
+
+            elif node.name == 'interfaceBody':
+                nodes = getParseTreeNodes(['interfaceMethodDcl'], node)
+                for n in nodes:
+                    self.methods.append(MethodNode(n))
+
+        self.children = self.methods
diff --git a/Weeding.py b/Weeding.py
index 61c6adca3c18b97ab3aeb4f10973e57fbbc650b9..cb91b985f711ac42c66c41868ae4f9a06af8a7e1 100644
--- a/Weeding.py
+++ b/Weeding.py
@@ -10,7 +10,10 @@ def weedTokens(tokens, file):
 
 
 def fileNameCheck(tokens, f):
-    fileName = os.path.basename(f).split('.java')[0]
+    fileNameParts = os.path.basename(f).split('.java')
+    if len(fileNameParts) < 2:
+        fileNameParts = os.path.basename(f).split('.joos')
+    fileName = fileNameParts[0]
 
     check = False
     for t in tokens:
diff --git a/cfg/Jlr1.class b/cfg/Jlr1.class
deleted file mode 100644
index 7f1ae4cdf7ad5d4b09d873258ef12bb8b038f3fb..0000000000000000000000000000000000000000
--- a/cfg/Jlr1.class
+++ /dev/null
@@ -1,858 +0,0 @@
-package jlalr;
-
-import java.util.*;
-import java.io.*;
-
-/*
-   Copyright 2006,2008,2009 Ondrej Lhotak. All rights reserved.
-
-   Permission is granted for study use by
-   students registered in CS 444, Winter 2020
-   term.
-
-   The contents of this file may not be
-   published, in whole or in part, in print
-   or electronic form.
-
-   The contents of this file may be included
-   in work submitted for CS 444 assignments in
-   Winter 2020.  The contents of this file may
-   not be submitted, in whole or in part, for
-   credit in any other course.
-
-*/
-
-/*
- * JLALR constructs LALR(1) and SLR(1) parse tables from a grammar, using
- * the algorithms described in chapter 3 of Appel, _Modern Compiler
- * Implementation in Java, second edition_, 2002. JLALR reads a grammar
- * on standard input, and writes the generated grammar and parse tables on
- * standard output.
- *
-*/
-
-/** Represents an item (a dotted production). */
-class Item {
-    Production rule; // the production
-    int pos; // position of the dot (0 <= pos <= rule.rhs.size())
-    String lookahead; // the lookahead terminal
-    private Item( Production rule, int pos, String lookahead ) {
-        this.rule = rule;
-        this.pos = pos;
-        this.lookahead = lookahead;
-    }
-    private static Map<Pair<Production, Pair<Integer, String>>, Item> map =
-        new HashMap<Pair<Production, Pair<Integer, String>>, Item>();
-    public static Item v(Production rule, int pos, String lookahead) {
-        Pair<Production, Pair<Integer, String>> triple =
-            new Pair<Production, Pair<Integer, String>>(
-                    rule, new Pair<Integer, String>(pos, lookahead));
-        Item ret = map.get(triple);
-        if(ret == null) {
-            ret = new Item(rule, pos, lookahead);
-            map.put(triple, ret);
-        }
-        return ret;
-    }
-    public static Item v(Production rule, int pos) {
-        return v(rule, pos, "");
-    }
-    /** Returns true if the dot is not at the end of the RHS. */
-    public boolean hasNextSym() {
-        return pos < rule.rhs.length;
-    }
-    /** Returns the symbol immediately after the dot. */
-    public String nextSym() {
-        if(!hasNextSym()) throw new RuntimeException("Internal error: getting next symbol of an item with no next symbol");
-        return rule.rhs[pos];
-    }
-    /** Returns the item obtained by advancing (shifting) the dot by one
-     *  symbol. */
-    public Item advance() {
-        if(!hasNextSym()) throw new RuntimeException("Internal error: advancing an item with no next symbol");
-        return Item.v(rule, pos+1, lookahead);
-    }
-    public String toString() {
-        StringBuffer ret = new StringBuffer();
-        ret.append("(");
-        ret.append(rule.lhs);
-        ret.append(" ->");
-        int i;
-        for(i = 0; i < pos; i++) ret.append(" "+rule.rhs[i]);
-        ret.append(" ##");
-        for(; i < rule.rhs.length; i++) ret.append(" "+rule.rhs[i]);
-        ret.append(", ");
-        ret.append(lookahead);
-        ret.append(")");
-        return ret.toString();
-    }
-}
-class State {
-    public Set<Item> items;
-    private State(Set<Item> items) {
-        this.items = items;
-    }
-    private static Map<Set<Item>, State> map = new HashMap<Set<Item>, State>();
-    public static State v(Set<Item> items) {
-        State ret = map.get(items);
-        if(ret == null) {
-            ret = new State(items);
-            map.put(items, ret);
-        }
-        return ret;
-    }
-    public String toString() {
-        StringBuffer ret = new StringBuffer();
-        ret.append("\n");
-        for(Item item : items) {
-            ret.append(item);
-            ret.append("\n");
-        }
-        return ret.toString();
-    }
-}
-/** Represents a parser action (shift or reduce). */
-abstract class Action {
-}
-/** Represents a shift parser action. */
-class ShiftAction extends Action {
-    State nextState; // the automaton state to move to after the shift
-    public ShiftAction(State nextState) {
-        this.nextState = nextState;
-    }
-    public int hashCode() { return nextState.hashCode(); }
-    public boolean equals(Object other) {
-        if(!(other instanceof ShiftAction)) return false;
-        ShiftAction o = (ShiftAction) other;
-        return nextState.equals(o.nextState);
-    }
-    public String toString() {
-        return "shift " + nextState;
-    }
-}
-/** Represents a reduce parser action. */
-class ReduceAction extends Action {
-    Production rule; // the production to reduce by
-    public ReduceAction(Production rule) {
-        this.rule = rule;
-    }
-    public int hashCode() { return rule.hashCode(); }
-    public boolean equals(Object other) {
-        if(!(other instanceof ReduceAction)) return false;
-        ReduceAction o = (ReduceAction) other;
-        return rule.equals(o.rule);
-    }
-    public String toString() {
-        return "reduce " + rule;
-    }
-}
-/** Utility class representing a pair of arbitrary objects. */
-class Pair<A,B> {
-    public Pair( A o1, B o2 ) { this.o1 = o1; this.o2 = o2; }
-    public int hashCode() {
-        return o1.hashCode() + o2.hashCode();
-    }
-    public boolean equals( Object other ) {
-        if( other instanceof Pair ) {
-            Pair p = (Pair) other;
-            return o1.equals( p.o1 ) && o2.equals( p.o2 );
-        } else return false;
-    }
-    public String toString() {
-        return "Pair "+o1+","+o2;
-    }
-    public A getO1() { return o1; }
-    public B getO2() { return o2; }
-
-    protected A o1;
-    protected B o2;
-}
-
-
-/** The main LALR/SLR generator class. */
-class Generator {
-    /** The context-free grammar. */
-    Grammar grammar;
-    /** A map from each non-terminal to the productions that expand it. */
-    Map<String,List<Production>> lhsToRules = new HashMap<String,List<Production>>();
-
-    public Generator(Grammar grammar) {
-        this.grammar = grammar;
-        for(String nonterm : grammar.nonterminals) {
-            lhsToRules.put(nonterm, new ArrayList<Production>());
-        }
-        for(Production p : grammar.productions) {
-            List<Production> mapRules = lhsToRules.get(p.lhs);
-            mapRules.add(p);
-        }
-    }
-
-    /** Compute the closure of a set of items using the algorithm of
-     * Appel, p. 60 */
-    public Set<Item> closure(Set<Item> i) {
-        boolean change;
-        while(true) {
-            Set<Item> oldI = new HashSet<Item>(i);
-            for( Item item : oldI ) {
-                if(!item.hasNextSym()) continue;
-                String x = item.nextSym();
-                if(grammar.isTerminal(x)) continue;
-                for( Production r : lhsToRules.get(x)) {
-                    i.add(Item.v(r, 0));
-                }
-            }
-            if( i.equals(oldI) ) return i;
-        }
-    }
-    /** Compute the goto set for state i and symbol x, using the algorithm
-     * of Appel, p. 60 */
-    public Set<Item> goto_(Set<Item> i, String x) {
-        Set<Item> j = new HashSet<Item>();
-        for( Item item : i ) {
-            if( !item.hasNextSym() ) continue;
-            if( !item.nextSym().equals(x) ) continue;
-            j.add(item.advance());
-        }
-        return closure(j);
-    }
-    private Map<List<String>, Set<String>> generalFirstCache = new HashMap<List<String>, Set<String>>();
-    /** Compute the generalized first using the definition of Appel, p. 50. */
-    public Set<String> generalFirst(List<String> l) {
-        Set<String> ret = generalFirstCache.get(l);
-        if(ret == null) {
-            ret = new HashSet<String>();
-            if(l.isEmpty()) {
-                return ret;
-            } else {
-                ret.addAll(first.get(l.get(0)));
-                int i = 0;
-                while(i < l.size()-1 && nullable.contains(l.get(i))) {
-                    ret.addAll(first.get(l.get(i+1)));
-                    i++;
-                }
-            }
-            generalFirstCache.put(l, ret);
-        }
-        return ret;
-    }
-
-    private Map<Set<Item>, Set<Item>> closureCache = new HashMap<Set<Item>, Set<Item>>();
-    /** Compute the closure of a set of LR(1) items using the algorithm of
-     * Appel, p. 63 */
-    public Set<Item> lr1_closure(Set<Item> i) {
-        boolean change;
-        Set<Item> ret = closureCache.get(i);
-        if(ret == null) {
-            Set<Item> origI = new HashSet<Item>(i);
-            Queue<Item> q = new LinkedList<Item>(i);
-            while(!q.isEmpty()) {
-                Item item = q.remove();
-                if(!item.hasNextSym()) continue;
-                String x = item.nextSym();
-                if(grammar.isTerminal(x)) continue;
-                List<String> betaz = new ArrayList<String>();
-                for(int p = item.pos+1; p < item.rule.rhs.length; p++) {
-                    betaz.add(item.rule.rhs[p]);
-                }
-                betaz.add(item.lookahead);
-                Collection<String> ws = generalFirst(betaz);
-                for( Production r : lhsToRules.get(x)) {
-                    for( String w : ws ) {
-                        Item newItem = Item.v(r, 0, w);
-                        if(i.add(newItem)) q.add(newItem);
-                    }
-                }
-            }
-            closureCache.put(origI, i);
-            ret = i;
-        }
-        return ret;
-    }
-
-
-    private Map<Pair<State, String>, State> gotoCache = new HashMap<Pair<State, String>, State>();
-    /** Compute the LR(1) goto set for state i and symbol x, using the algorithm
-     * of Appel, p. 63 */
-    public State lr1_goto_(State i, String x) {
-        Pair<State, String> pair = new Pair<State, String>(i, x);
-        State ret = gotoCache.get(pair);
-        if(ret == null) {
-            Set<Item> j = new HashSet<Item>();
-            for( Item item : i.items ) {
-                if( !item.hasNextSym() ) continue;
-                if( !item.nextSym().equals(x) ) continue;
-                j.add(item.advance());
-            }
-            ret = State.v(lr1_closure(j));
-            gotoCache.put(pair, ret);
-        }
-        return ret;
-    }
-    /** Add the action a to the parse table for the state state and
-     * symbol sym. Report a conflict if the table already contains
-     * an action for the same state and symbol. */
-    private boolean addAction( State state, String sym, Action a ) {
-        boolean ret = false;
-        Pair<State,String> p = new Pair<State,String>(state, sym);
-        Action old = table.get(p);
-        if(old != null && !old.equals(a)) {
-            throw new Error(
-                "Conflict on symbol "+sym+" in state "+state+"\n"+
-                "Possible actions:\n"+
-                old+"\n"+a);
-        }
-        if(old == null || !old.equals(a)) ret = true;
-        table.put(p, a);
-        return ret;
-    }
-    /** Return true if all the symbols in l are in the set nullable. */
-    private boolean allNullable(String[] l) {
-        return allNullable(l, 0, l.length);
-    }
-    /** Return true if the symbols start..end in l are in the set nullable. */
-    private boolean allNullable(String[] l, int start, int end) {
-        boolean ret = true;
-        for(int i = start; i < end; i++) {
-            if(!nullable.contains(l[i])) ret = false;
-        }
-        return ret;
-    }
-    // The NULLABLE, FIRST, and FOLLOW sets. See Appel, pp. 47-49
-    Set<String> nullable = new HashSet<String>();
-    Map<String,Set<String>> first = new HashMap<String,Set<String>>();
-    Map<String,Set<String>> follow = new HashMap<String,Set<String>>();
-    /** Computes NULLABLE, FIRST, and FOLLOW sets using the algorithm
-     * of Appel, p. 49 */
-    public void computeFirstFollowNullable() {
-        for( String z : grammar.syms() ) {
-            first.put(z, new HashSet<String>());
-            if(grammar.isTerminal(z)) first.get(z).add(z);
-            follow.put(z, new HashSet<String>());
-        }
-        boolean change;
-        do {
-            change = false;
-            for( Production rule : grammar.productions ) {
-                if(allNullable(rule.rhs)) {
-                    if( nullable.add(rule.lhs) ) change = true;
-                }
-                int k = rule.rhs.length;
-                for(int i = 0; i < k; i++) {
-                    if(allNullable(rule.rhs, 0, i)) {
-                        if( first.get(rule.lhs).addAll(
-                                first.get(rule.rhs[i])))
-                            change = true;
-                    }
-                    if(allNullable(rule.rhs, i+1,k)) {
-                        if( follow.get(rule.rhs[i]).addAll(
-                                follow.get(rule.lhs)))
-                            change = true;
-                    }
-                    for(int j = i+1; j < k; j++) {
-                        if(allNullable(rule.rhs, i+1,j)) {
-                            if( follow.get(rule.rhs[i]).addAll(
-                                    first.get(rule.rhs[j])))
-                                change = true;
-                        }
-                    }
-                }
-            }
-        } while(change);
-    }
-    /** The computed parse table. */
-    Map<Pair<State,String>,Action> table =
-        new HashMap<Pair<State,String>,Action>();
-    State initialState;
-
-    /** Generates the LR(0) parse table using the algorithms on
-     * pp. 60 of Appel. */
-    public void generateLR0Table() {
-        Set<Item> startRuleSet = new HashSet<Item>();
-        for(Production r : lhsToRules.get(grammar.start)) {
-            startRuleSet.add(Item.v(r, 0));
-        }
-        initialState = State.v(closure(startRuleSet));
-        Set<State> t = new HashSet<State>();
-        t.add(initialState);
-        boolean change;
-        // compute goto actions
-        do {
-            change = false;
-            for( State i : new ArrayList<State>(t) ) {
-                for( Item item : i.items ) {
-                    if(!item.hasNextSym()) continue;
-                    String x = item.nextSym();
-                    State j = State.v(goto_(i.items, x));
-                    if(t.add(j)) change = true;
-                    if(addAction(i, x, new ShiftAction(j))) change = true;
-                }
-            }
-        } while(change);
-        // compute reduce actions
-        for( State i : t ) {
-            for( Item item : i.items ) {
-                if( item.hasNextSym() ) continue;
-                for( String x : grammar.syms() ) {
-                    addAction(i, x, new ReduceAction(item.rule));
-                }
-            }
-        }
-    }
-
-    /** Generates the SLR(1) parse table using the algorithms on
-     * pp. 60 and 62 of Appel. */
-    public void generateSLR1Table() {
-        Set<Item> startRuleSet = new HashSet<Item>();
-        for(Production r : lhsToRules.get(grammar.start)) {
-            startRuleSet.add(Item.v(r, 0));
-        }
-        initialState = State.v(closure(startRuleSet));
-        Set<State> t = new HashSet<State>();
-        t.add(initialState);
-        boolean change;
-        // compute goto actions
-        do {
-            change = false;
-            for( State i : new ArrayList<State>(t) ) {
-                for( Item item : i.items ) {
-                    if(!item.hasNextSym()) continue;
-                    String x = item.nextSym();
-                    State j = State.v(goto_(i.items, x));
-                    if(t.add(j)) change = true;
-                    if(addAction(i, x, new ShiftAction(j))) change = true;
-                }
-            }
-        } while(change);
-        // compute reduce actions
-        for( State i : t ) {
-            for( Item item : i.items ) {
-                if( item.hasNextSym() ) continue;
-                for( String x : follow.get(item.rule.lhs) ) {
-                    addAction(i, x, new ReduceAction(item.rule));
-                }
-            }
-        }
-    }
-
-    /** Generates the LR(1) parse table using the algorithms on
-     * pp. 60, 62, and 64 of Appel. */
-    public void generateLR1Table() {
-        Set<Item> startRuleSet = new HashSet<Item>();
-        System.err.println("Computing start state");
-        for(Production r : lhsToRules.get(grammar.start)) {
-            startRuleSet.add(Item.v(r, 0, grammar.terminals.iterator().next()));
-        }
-        initialState = State.v(lr1_closure(startRuleSet));
-        Set<State> t = new HashSet<State>();
-        t.add(initialState);
-        Queue<State> q = new LinkedList<State>();
-        q.add(initialState);
-        // compute goto actions
-        System.err.println("Computing goto actions");
-        while(!q.isEmpty()) {
-            State i = q.remove();
-            for( Item item : i.items ) {
-                if(!item.hasNextSym()) continue;
-                String x = item.nextSym();
-                State j = lr1_goto_(i, x);
-                if(t.add(j)) {
-                    System.err.print(".");
-                    q.add(j);
-                }
-                addAction(i, x, new ShiftAction(j));
-            }
-        }
-        // compute reduce actions
-        System.err.println("Computing reduce actions");
-        for( State i : t ) {
-            for( Item item : i.items ) {
-                if( item.hasNextSym() ) continue;
-                addAction(i, item.lookahead, new ReduceAction(item.rule));
-            }
-        }
-    }
-    public Set<Item> core(Set<Item> items) {
-        Set<Item> ret = new HashSet<Item>();
-        for(Item item : items) {
-            ret.add(Item.v(item.rule, item.pos));
-        }
-        return ret;
-    }
-    /** Generates the LALR(1) parse table using the algorithms on
-     * pp. 60, 62, and 64 of Appel. */
-    public void generateLALR1Table() {
-        Set<Item> startRuleSet = new HashSet<Item>();
-        System.err.println("Computing start state");
-        for(Production r : lhsToRules.get(grammar.start)) {
-            startRuleSet.add(Item.v(r, 0, grammar.terminals.iterator().next()));
-        }
-        initialState = State.v(lr1_closure(startRuleSet));
-        Set<State> t = new HashSet<State>();
-        t.add(initialState);
-        Queue<State> q = new LinkedList<State>();
-        q.add(initialState);
-        System.err.println("Computing states");
-        while(!q.isEmpty()) {
-            State i = q.remove();
-            for( Item item : i.items ) {
-                if(!item.hasNextSym()) continue;
-                String x = item.nextSym();
-                State j = lr1_goto_(i, x);
-                if(t.add(j)) {
-                    System.err.print(".");
-                    q.add(j);
-                }
-            }
-        }
-        System.err.println("Merging states");
-        Map<Set<Item>, Set<Item>> coreToState = new HashMap<Set<Item>, Set<Item>>();
-        for(State state : t) {
-            Set<Item> items = state.items;
-            Set<Item> core = core(items);
-            Set<Item> accum = coreToState.get(core);
-            if(accum == null) {
-                System.err.print(".");
-                accum = new HashSet<Item>(items);
-                coreToState.put(core, accum);
-            } else accum.addAll(items);
-        }
-        Map<Set<Item>, State> coreToStateState = new HashMap<Set<Item>, State>();
-        for(State state : t) {
-            Set<Item> core = core(state.items);
-            coreToStateState.put(core, State.v(coreToState.get(core)));
-        }
-        // compute goto actions
-        System.err.println("Computing goto actions");
-        t.clear();
-        initialState = State.v(coreToState.get(core(initialState.items)));
-        t.add(initialState);
-        q.add(initialState);
-        while(!q.isEmpty()) {
-            State i = q.remove();
-            for( Item item : i.items ) {
-                if(!item.hasNextSym()) continue;
-                String x = item.nextSym();
-                State j = lr1_goto_(i, x);
-                j = coreToStateState.get(core(j.items));
-                if(t.add(j)) {
-                    System.err.print(".");
-                    q.add(j);
-                }
-                addAction(i, x, new ShiftAction(j));
-            }
-        }
-        // compute reduce actions
-        System.err.println("Computing reduce actions");
-        for( State i : t ) {
-            for( Item item : i.items ) {
-                if( item.hasNextSym() ) continue;
-                addAction(i, item.lookahead, new ReduceAction(item.rule));
-            }
-        }
-    }
-    /** Print the elements of a list separated by spaces. */
-    public static String listToString(List l) {
-        StringBuffer ret = new StringBuffer();
-        boolean first = true;
-        for( Object o : l ) {
-            if( !first ) ret.append(" ");
-            first = false;
-            ret.append(o);
-        }
-        return ret.toString();
-    }
-    /** Produce output according to the output specification. */
-    public void generateOutput() {
-        Map<Production,Integer> ruleMap = new HashMap<Production,Integer>();
-        int i = 0;
-        for(Production r : grammar.productions) {
-            ruleMap.put(r, i++);
-        }
-        Map<State,Integer> stateMap = new HashMap<State,Integer>();
-        i = 0;
-        stateMap.put(initialState, i++);
-        for(Action a : table.values()) {
-            if(!(a instanceof ShiftAction)) continue;
-            State state = ((ShiftAction)a).nextState;
-            if(!stateMap.containsKey(state)) {
-                stateMap.put(state, i++);
-            }
-        }
-        for(Pair<State,String> key : table.keySet()) {
-            State state = key.getO1();
-            if(!stateMap.containsKey(state)) {
-                stateMap.put(state, i++);
-            }
-        }
-        System.out.println(i);
-        System.out.println(table.size());
-        for(Map.Entry<Pair<State,String>,Action> e : table.entrySet()) {
-            Pair<State,String> p = e.getKey();
-            System.out.print(stateMap.get(p.getO1())+" "+p.getO2()+" ");
-            Action a = e.getValue();
-            if(a instanceof ShiftAction) {
-                System.out.println("shift "+
-                        stateMap.get(((ShiftAction)a).nextState));
-            } else if(a instanceof ReduceAction) {
-                System.out.println("reduce "+
-                        ruleMap.get(((ReduceAction)a).rule));
-            } else throw new Error("Internal error: unknown action");
-        }
-    }
-}
-
-class Jlr1 {
-    public static final void main(String[] args) {
-        Grammar grammar;
-        try {
-            grammar = Util.readGrammar(new Scanner(System.in));
-            Util.writeGrammar(grammar);
-        } catch(Error e) {
-            System.err.println("Error reading grammar: "+e);
-            System.exit(1);
-            return;
-        }
-        Generator jlr = new Generator(grammar);
-        try {
-            jlr.computeFirstFollowNullable();
-            jlr.generateLR1Table();
-            jlr.generateOutput();
-        } catch(Error e) {
-            System.err.println("Error performing LR(1) construction: "+e);
-            System.exit(1);
-            return;
-        }
-    }
-}
-class Jlr0 {
-    public static final void main(String[] args) {
-        Grammar grammar;
-        try {
-            grammar = Util.readGrammar(new Scanner(System.in));
-            Util.writeGrammar(grammar);
-        } catch(Error e) {
-            System.err.println("Error reading grammar: "+e);
-            System.exit(1);
-            return;
-        }
-        Generator jlr = new Generator(grammar);
-        try {
-            jlr.computeFirstFollowNullable();
-            jlr.generateLR0Table();
-            jlr.generateOutput();
-        } catch(Error e) {
-            System.err.println("Error performing LR(0) construction: "+e);
-            System.exit(1);
-            return;
-        }
-    }
-}
-class Jslr1 {
-    public static final void main(String[] args) {
-        Grammar grammar;
-        try {
-            grammar = Util.readGrammar(new Scanner(System.in));
-            Util.writeGrammar(grammar);
-        } catch(Error e) {
-            System.err.println("Error reading grammar: "+e);
-            System.exit(1);
-            return;
-        }
-        Generator jslr = new Generator(grammar);
-        try {
-            jslr.computeFirstFollowNullable();
-            jslr.generateSLR1Table();
-            jslr.generateOutput();
-        } catch(Error e) {
-            System.err.println("Error performing SLR(1) construction: "+e);
-            System.exit(1);
-            return;
-        }
-    }
-}
-public class Jlalr1 {
-    public static final void main(String[] args) {
-        Grammar grammar;
-        try {
-            grammar = Util.readGrammar(new Scanner(System.in));
-            Util.writeGrammar(grammar);
-        } catch(Error e) {
-            System.err.println("Error reading grammar: "+e);
-            System.exit(1);
-            return;
-        }
-        Generator jlalr = new Generator(grammar);
-        try {
-            jlalr.computeFirstFollowNullable();
-            jlalr.generateLALR1Table();
-            jlalr.generateOutput();
-        } catch(Error e) {
-            System.err.println("Error performing LALR(1) construction: "+e);
-            System.exit(1);
-            return;
-        }
-    }
-}
-/** A production in the grammar. */
-class Production {
-    public String lhs;
-    public String[] rhs;
-    private Production(String lhs, String[] rhs) {
-        this.lhs = lhs; this.rhs = rhs;
-    }
-    private static Map<Pair<String, String[]>, Production> map =
-        new HashMap<Pair<String, String[]>, Production>();
-    public static Production v(String lhs, String[] rhs) {
-        Pair<String, String[]> pair = new Pair<String, String[]>(lhs, rhs);
-        Production ret = map.get(pair);
-        if(ret == null) {
-            ret = new Production(lhs, rhs);
-            map.put(pair, ret);
-        }
-        return ret;
-    }
-    public String toString() {
-        StringBuffer ret = new StringBuffer();
-        ret.append(lhs);
-        //ret.append(" ->");
-        for(String sym : rhs) {
-            ret.append(" "+sym);
-        }
-        return ret.toString();
-    }
-}
-/** Representation of a context-free grammar. */
-class Grammar {
-    Set<String> terminals = new LinkedHashSet<String>();
-    Set<String> nonterminals = new LinkedHashSet<String>();
-    Set<Production> productions = new LinkedHashSet<Production>();
-    String start;
-
-    public boolean isTerminal(String s) {
-        return terminals.contains(s);
-    }
-    public boolean isNonTerminal(String s) {
-        return nonterminals.contains(s);
-    }
-    public List<String> syms() {
-        List<String> ret = new ArrayList<String>();
-        ret.addAll(terminals);
-        ret.addAll(nonterminals);
-        return ret;
-    }
-}
-class Error extends RuntimeException {
-    public Error(String s) { super(s); }
-}
-class Util {
-    public static String readLine(Scanner in, String msg) {
-        if(!in.hasNextLine()) throw new Error(msg+" but input file ended");
-        return in.nextLine();
-    }
-    public static int toInt(String line, String msg) {
-        try {
-            return new Integer(line);
-        } catch(NumberFormatException e) {
-            throw new Error("Expecting "+msg+" but the line is not a number:\n"+line);
-        }
-    }
-    public static Grammar readGrammar(Scanner in) {
-        Grammar grammar = new Grammar();
-        String line = readLine(in, "Expecting number of non-terminals");
-        int nterm = toInt(line, "number of non-terminals");
-        for(int i = 0; i < nterm; i++) {
-            String term = readLine(in, "Expecting a non-terminal").intern();
-            if(!grammar.terminals.add(term))
-                throw new Error("Duplicate terminal: "+term);
-        }
-
-        line = readLine(in, "Expecting number of non-terminals");
-        int nnonterm = toInt(line, "number of non-terminals");
-        for(int i = 0; i < nnonterm; i++) {
-            String nonterm = readLine(in, "Expecting a non-terminal").intern();
-            if(!grammar.nonterminals.add(nonterm))
-                throw new Error("Duplicate non-terminal: "+nonterm);
-            if(grammar.isTerminal(nonterm))
-                throw new Error("Cannot be both terminal and non-terminal: "+nonterm);
-        }
-
-        grammar.start = readLine(in, "Expecting start symbol").intern();
-        if(!grammar.nonterminals.contains(grammar.start)) throw new Error(
-            "Start symbol "+grammar.start+" was not declared as a non-terminal.");
-
-        line = readLine(in, "Expecting number of productions");
-        int nprods = toInt(line, "number of productions");
-        for(int i = 0; i < nprods; i++) {
-            Production prod = readProduction(readLine(in, "Expecting production"), grammar);
-            if(!grammar.productions.add(prod)) {
-                throw new Error("Duplicate production: "+prod);
-            }
-        }
-        if(in.hasNextLine()) {
-            System.err.println("Warning: extra input lines after grammar; maybe your production count is wrong.");
-        }
-        return grammar;
-    }
-    public static Production readProduction(String line, Grammar grammar) {
-        Scanner s = new Scanner(line);
-        if(!s.hasNext()) throw new Error("Empty line instead of a production");
-        String lhs = s.next().intern();
-        if(!grammar.isNonTerminal(lhs)) throw new Error("Symbol "+lhs+" was not declared as a non-terminal, but appears on the LHS of production "+line);
-        List<String> rhs = new ArrayList<String>();
-        while(s.hasNext()) {
-            String sym = s.next().intern();
-            if(!grammar.isNonTerminal(sym) && !grammar.isTerminal(sym)) {
-                throw new Error("Symbol "+sym+" is not a part of the grammar");
-            }
-            rhs.add(sym);
-        }
-        return Production.v(lhs,
-                (String[]) rhs.toArray(new String[rhs.size()]));
-    }
-    static String checkIndent(String line, int indent) {
-        for(int i = 0; i < indent; i++) {
-            if(line.length() <= i) throw new Error("Expecting production but got empty line.");
-            if(line.charAt(i) != ' ') throw new Error("Production "+line.substring(i)+" should be indented "+indent+" space(s), but it is indented "+i+" spaces");
-        }
-        if(line.length() <= indent) throw new Error("Expecting production but got empty line.");
-        if(line.charAt(indent) == ' ') throw new Error("Production "+line+" should be indented "+indent+" spaces, but it is indented more than that.");
-        return line.substring(indent);
-    }
-    static void printGrammar(Grammar grammar) {
-        System.out.println("Terminals:");
-        for(String s : grammar.terminals) {
-            System.out.println("   "+s);
-        }
-        System.out.println();
-
-        System.out.println("Nonterminals:");
-        for(String s : grammar.nonterminals) {
-            System.out.println("   "+s);
-        }
-        System.out.println();
-
-        System.out.println("Start Symbol:");
-        System.out.println("   "+grammar.start);
-        System.out.println();
-
-        System.out.println("Production Rules:");
-        for(Production s : grammar.productions) {
-            System.out.println("   "+s);
-        }
-    }
-    static void writeGrammar(Grammar grammar) {
-        System.out.println(grammar.terminals.size());
-        for(String s : grammar.terminals) {
-            System.out.println(s);
-        }
-        System.out.println(grammar.nonterminals.size());
-        for(String s : grammar.nonterminals) {
-            System.out.println(s);
-        }
-        System.out.println(grammar.start);
-        System.out.println(grammar.productions.size());
-        for(Production s : grammar.productions) {
-            System.out.println(s);
-        }
-    }
-}
diff --git a/cfg/Jlr1.java b/cfg/Jlr1.java
deleted file mode 100644
index 8d34da6f5daee4be4da832f563ef39a258e87e1d..0000000000000000000000000000000000000000
--- a/cfg/Jlr1.java
+++ /dev/null
@@ -1,790 +0,0 @@
-package jlalr;
-
-import java.util.*;
-import java.io.*;
-
-/*
-   Copyright 2006,2008,2009 Ondrej Lhotak. All rights reserved.
-
-   Permission is granted for study use by
-   students registered in CS 444, Winter 2020
-   term.
-
-   The contents of this file may not be
-   published, in whole or in part, in print
-   or electronic form.
-
-   The contents of this file may be included
-   in work submitted for CS 444 assignments in
-   Winter 2020.  The contents of this file may
-   not be submitted, in whole or in part, for
-   credit in any other course.
-
-*/
-
-/*
- * JLALR constructs LALR(1) and SLR(1) parse tables from a grammar, using
- * the algorithms described in chapter 3 of Appel, _Modern Compiler
- * Implementation in Java, second edition_, 2002. JLALR reads a grammar
- * on standard input, and writes the generated grammar and parse tables on
- * standard output.
- *
-*/
-
-/** Represents an item (a dotted production). */
-class Item {
-    Production rule; // the production
-    int pos; // position of the dot (0 <= pos <= rule.rhs.size())
-    String lookahead; // the lookahead terminal
-    private Item( Production rule, int pos, String lookahead ) {
-        this.rule = rule;
-        this.pos = pos;
-        this.lookahead = lookahead;
-    }
-    private static Map<Pair<Production, Pair<Integer, String>>, Item> map =
-        new HashMap<Pair<Production, Pair<Integer, String>>, Item>();
-    public static Item v(Production rule, int pos, String lookahead) {
-        Pair<Production, Pair<Integer, String>> triple =
-            new Pair<Production, Pair<Integer, String>>(
-                    rule, new Pair<Integer, String>(pos, lookahead));
-        Item ret = map.get(triple);
-        if(ret == null) {
-            ret = new Item(rule, pos, lookahead);
-            map.put(triple, ret);
-        }
-        return ret;
-    }
-    public static Item v(Production rule, int pos) {
-        return v(rule, pos, "");
-    }
-    /** Returns true if the dot is not at the end of the RHS. */
-    public boolean hasNextSym() {
-        return pos < rule.rhs.length;
-    }
-    /** Returns the symbol immediately after the dot. */
-    public String nextSym() {
-        if(!hasNextSym()) throw new RuntimeException("Internal error: getting next symbol of an item with no next symbol");
-        return rule.rhs[pos];
-    }
-    /** Returns the item obtained by advancing (shifting) the dot by one
-     *  symbol. */
-    public Item advance() {
-        if(!hasNextSym()) throw new RuntimeException("Internal error: advancing an item with no next symbol");
-        return Item.v(rule, pos+1, lookahead);
-    }
-    public String toString() {
-        StringBuffer ret = new StringBuffer();
-        ret.append("(");
-        ret.append(rule.lhs);
-        ret.append(" ->");
-        int i;
-        for(i = 0; i < pos; i++) ret.append(" "+rule.rhs[i]);
-        ret.append(" ##");
-        for(; i < rule.rhs.length; i++) ret.append(" "+rule.rhs[i]);
-        ret.append(", ");
-        ret.append(lookahead);
-        ret.append(")");
-        return ret.toString();
-    }
-}
-class State {
-    public Set<Item> items;
-    private State(Set<Item> items) {
-        this.items = items;
-    }
-    private static Map<Set<Item>, State> map = new HashMap<Set<Item>, State>();
-    public static State v(Set<Item> items) {
-        State ret = map.get(items);
-        if(ret == null) {
-            ret = new State(items);
-            map.put(items, ret);
-        }
-        return ret;
-    }
-    public String toString() {
-        StringBuffer ret = new StringBuffer();
-        ret.append("\n");
-        for(Item item : items) {
-            ret.append(item);
-            ret.append("\n");
-        }
-        return ret.toString();
-    }
-}
-/** Represents a parser action (shift or reduce). */
-abstract class Action {
-}
-/** Represents a shift parser action. */
-class ShiftAction extends Action {
-    State nextState; // the automaton state to move to after the shift
-    public ShiftAction(State nextState) {
-        this.nextState = nextState;
-    }
-    public int hashCode() { return nextState.hashCode(); }
-    public boolean equals(Object other) {
-        if(!(other instanceof ShiftAction)) return false;
-        ShiftAction o = (ShiftAction) other;
-        return nextState.equals(o.nextState);
-    }
-    public String toString() {
-        return "shift " + nextState;
-    }
-}
-/** Represents a reduce parser action. */
-class ReduceAction extends Action {
-    Production rule; // the production to reduce by
-    public ReduceAction(Production rule) {
-        this.rule = rule;
-    }
-    public int hashCode() { return rule.hashCode(); }
-    public boolean equals(Object other) {
-        if(!(other instanceof ReduceAction)) return false;
-        ReduceAction o = (ReduceAction) other;
-        return rule.equals(o.rule);
-    }
-    public String toString() {
-        return "reduce " + rule;
-    }
-}
-/** Utility class representing a pair of arbitrary objects. */
-class Pair<A,B> {
-    public Pair( A o1, B o2 ) { this.o1 = o1; this.o2 = o2; }
-    public int hashCode() {
-        return o1.hashCode() + o2.hashCode();
-    }
-    public boolean equals( Object other ) {
-        if( other instanceof Pair ) {
-            Pair p = (Pair) other;
-            return o1.equals( p.o1 ) && o2.equals( p.o2 );
-        } else return false;
-    }
-    public String toString() {
-        return "Pair "+o1+","+o2;
-    }
-    public A getO1() { return o1; }
-    public B getO2() { return o2; }
-
-    protected A o1;
-    protected B o2;
-}
-
-
-/** The main LALR/SLR generator class. */
-class Generator {
-    /** The context-free grammar. */
-    Grammar grammar;
-    /** A map from each non-terminal to the productions that expand it. */
-    Map<String,List<Production>> lhsToRules = new HashMap<String,List<Production>>();
-
-    public Generator(Grammar grammar) {
-        this.grammar = grammar;
-        for(String nonterm : grammar.nonterminals) {
-            lhsToRules.put(nonterm, new ArrayList<Production>());
-        }
-        for(Production p : grammar.productions) {
-            List<Production> mapRules = lhsToRules.get(p.lhs);
-            mapRules.add(p);
-        }
-    }
-
-    /** Compute the closure of a set of items using the algorithm of
-     * Appel, p. 60 */
-    public Set<Item> closure(Set<Item> i) {
-        boolean change;
-        while(true) {
-            Set<Item> oldI = new HashSet<Item>(i);
-            for( Item item : oldI ) {
-                if(!item.hasNextSym()) continue;
-                String x = item.nextSym();
-                if(grammar.isTerminal(x)) continue;
-                for( Production r : lhsToRules.get(x)) {
-                    i.add(Item.v(r, 0));
-                }
-            }
-            if( i.equals(oldI) ) return i;
-        }
-    }
-    /** Compute the goto set for state i and symbol x, using the algorithm
-     * of Appel, p. 60 */
-    public Set<Item> goto_(Set<Item> i, String x) {
-        Set<Item> j = new HashSet<Item>();
-        for( Item item : i ) {
-            if( !item.hasNextSym() ) continue;
-            if( !item.nextSym().equals(x) ) continue;
-            j.add(item.advance());
-        }
-        return closure(j);
-    }
-    private Map<List<String>, Set<String>> generalFirstCache = new HashMap<List<String>, Set<String>>();
-    /** Compute the generalized first using the definition of Appel, p. 50. */
-    public Set<String> generalFirst(List<String> l) {
-        Set<String> ret = generalFirstCache.get(l);
-        if(ret == null) {
-            ret = new HashSet<String>();
-            if(l.isEmpty()) {
-                return ret;
-            } else {
-                ret.addAll(first.get(l.get(0)));
-                int i = 0;
-                while(i < l.size()-1 && nullable.contains(l.get(i))) {
-                    ret.addAll(first.get(l.get(i+1)));
-                    i++;
-                }
-            }
-            generalFirstCache.put(l, ret);
-        }
-        return ret;
-    }
-
-    private Map<Set<Item>, Set<Item>> closureCache = new HashMap<Set<Item>, Set<Item>>();
-    /** Compute the closure of a set of LR(1) items using the algorithm of
-     * Appel, p. 63 */
-    public Set<Item> lr1_closure(Set<Item> i) {
-        boolean change;
-        Set<Item> ret = closureCache.get(i);
-        if(ret == null) {
-            Set<Item> origI = new HashSet<Item>(i);
-            Queue<Item> q = new LinkedList<Item>(i);
-            while(!q.isEmpty()) {
-                Item item = q.remove();
-                if(!item.hasNextSym()) continue;
-                String x = item.nextSym();
-                if(grammar.isTerminal(x)) continue;
-                List<String> betaz = new ArrayList<String>();
-                for(int p = item.pos+1; p < item.rule.rhs.length; p++) {
-                    betaz.add(item.rule.rhs[p]);
-                }
-                betaz.add(item.lookahead);
-                Collection<String> ws = generalFirst(betaz);
-                for( Production r : lhsToRules.get(x)) {
-                    for( String w : ws ) {
-                        Item newItem = Item.v(r, 0, w);
-                        if(i.add(newItem)) q.add(newItem);
-                    }
-                }
-            }
-            closureCache.put(origI, i);
-            ret = i;
-        }
-        return ret;
-    }
-
-
-    private Map<Pair<State, String>, State> gotoCache = new HashMap<Pair<State, String>, State>();
-    /** Compute the LR(1) goto set for state i and symbol x, using the algorithm
-     * of Appel, p. 63 */
-    public State lr1_goto_(State i, String x) {
-        Pair<State, String> pair = new Pair<State, String>(i, x);
-        State ret = gotoCache.get(pair);
-        if(ret == null) {
-            Set<Item> j = new HashSet<Item>();
-            for( Item item : i.items ) {
-                if( !item.hasNextSym() ) continue;
-                if( !item.nextSym().equals(x) ) continue;
-                j.add(item.advance());
-            }
-            ret = State.v(lr1_closure(j));
-            gotoCache.put(pair, ret);
-        }
-        return ret;
-    }
-    /** Add the action a to the parse table for the state state and
-     * symbol sym. Report a conflict if the table already contains
-     * an action for the same state and symbol. */
-    private boolean addAction( State state, String sym, Action a ) {
-        boolean ret = false;
-        Pair<State,String> p = new Pair<State,String>(state, sym);
-        Action old = table.get(p);
-        if(old != null && !old.equals(a)) {
-            throw new Error(
-                "Conflict on symbol "+sym+" in state "+state+"\n"+
-                "Possible actions:\n"+
-                old+"\n"+a);
-        }
-        if(old == null || !old.equals(a)) ret = true;
-        table.put(p, a);
-        return ret;
-    }
-    /** Return true if all the symbols in l are in the set nullable. */
-    private boolean allNullable(String[] l) {
-        return allNullable(l, 0, l.length);
-    }
-    /** Return true if the symbols start..end in l are in the set nullable. */
-    private boolean allNullable(String[] l, int start, int end) {
-        boolean ret = true;
-        for(int i = start; i < end; i++) {
-            if(!nullable.contains(l[i])) ret = false;
-        }
-        return ret;
-    }
-    // The NULLABLE, FIRST, and FOLLOW sets. See Appel, pp. 47-49
-    Set<String> nullable = new HashSet<String>();
-    Map<String,Set<String>> first = new HashMap<String,Set<String>>();
-    Map<String,Set<String>> follow = new HashMap<String,Set<String>>();
-    /** Computes NULLABLE, FIRST, and FOLLOW sets using the algorithm
-     * of Appel, p. 49 */
-    public void computeFirstFollowNullable() {
-        for( String z : grammar.syms() ) {
-            first.put(z, new HashSet<String>());
-            if(grammar.isTerminal(z)) first.get(z).add(z);
-            follow.put(z, new HashSet<String>());
-        }
-        boolean change;
-        do {
-            change = false;
-            for( Production rule : grammar.productions ) {
-                if(allNullable(rule.rhs)) {
-                    if( nullable.add(rule.lhs) ) change = true;
-                }
-                int k = rule.rhs.length;
-                for(int i = 0; i < k; i++) {
-                    if(allNullable(rule.rhs, 0, i)) {
-                        if( first.get(rule.lhs).addAll(
-                                first.get(rule.rhs[i])))
-                            change = true;
-                    }
-                    if(allNullable(rule.rhs, i+1,k)) {
-                        if( follow.get(rule.rhs[i]).addAll(
-                                follow.get(rule.lhs)))
-                            change = true;
-                    }
-                    for(int j = i+1; j < k; j++) {
-                        if(allNullable(rule.rhs, i+1,j)) {
-                            if( follow.get(rule.rhs[i]).addAll(
-                                    first.get(rule.rhs[j])))
-                                change = true;
-                        }
-                    }
-                }
-            }
-        } while(change);
-    }
-    /** The computed parse table. */
-    Map<Pair<State,String>,Action> table =
-        new HashMap<Pair<State,String>,Action>();
-    State initialState;
-
-    /** Generates the LR(0) parse table using the algorithms on
-     * pp. 60 of Appel. */
-    public void generateLR0Table() {
-        Set<Item> startRuleSet = new HashSet<Item>();
-        for(Production r : lhsToRules.get(grammar.start)) {
-            startRuleSet.add(Item.v(r, 0));
-        }
-        initialState = State.v(closure(startRuleSet));
-        Set<State> t = new HashSet<State>();
-        t.add(initialState);
-        boolean change;
-        // compute goto actions
-        do {
-            change = false;
-            for( State i : new ArrayList<State>(t) ) {
-                for( Item item : i.items ) {
-                    if(!item.hasNextSym()) continue;
-                    String x = item.nextSym();
-                    State j = State.v(goto_(i.items, x));
-                    if(t.add(j)) change = true;
-                    if(addAction(i, x, new ShiftAction(j))) change = true;
-                }
-            }
-        } while(change);
-        // compute reduce actions
-        for( State i : t ) {
-            for( Item item : i.items ) {
-                if( item.hasNextSym() ) continue;
-                for( String x : grammar.syms() ) {
-                    addAction(i, x, new ReduceAction(item.rule));
-                }
-            }
-        }
-    }
-
-    /** Generates the SLR(1) parse table using the algorithms on
-     * pp. 60 and 62 of Appel. */
-    public void generateSLR1Table() {
-        Set<Item> startRuleSet = new HashSet<Item>();
-        for(Production r : lhsToRules.get(grammar.start)) {
-            startRuleSet.add(Item.v(r, 0));
-        }
-        initialState = State.v(closure(startRuleSet));
-        Set<State> t = new HashSet<State>();
-        t.add(initialState);
-        boolean change;
-        // compute goto actions
-        do {
-            change = false;
-            for( State i : new ArrayList<State>(t) ) {
-                for( Item item : i.items ) {
-                    if(!item.hasNextSym()) continue;
-                    String x = item.nextSym();
-                    State j = State.v(goto_(i.items, x));
-                    if(t.add(j)) change = true;
-                    if(addAction(i, x, new ShiftAction(j))) change = true;
-                }
-            }
-        } while(change);
-        // compute reduce actions
-        for( State i : t ) {
-            for( Item item : i.items ) {
-                if( item.hasNextSym() ) continue;
-                for( String x : follow.get(item.rule.lhs) ) {
-                    addAction(i, x, new ReduceAction(item.rule));
-                }
-            }
-        }
-    }
-
-    /** Generates the LR(1) parse table using the algorithms on
-     * pp. 60, 62, and 64 of Appel. */
-    public void generateLR1Table() {
-        Set<Item> startRuleSet = new HashSet<Item>();
-        System.err.println("Computing start state");
-        for(Production r : lhsToRules.get(grammar.start)) {
-            startRuleSet.add(Item.v(r, 0, grammar.terminals.iterator().next()));
-        }
-        initialState = State.v(lr1_closure(startRuleSet));
-        Set<State> t = new HashSet<State>();
-        t.add(initialState);
-        Queue<State> q = new LinkedList<State>();
-        q.add(initialState);
-        // compute goto actions
-        System.err.println("Computing goto actions");
-        while(!q.isEmpty()) {
-            State i = q.remove();
-            for( Item item : i.items ) {
-                if(!item.hasNextSym()) continue;
-                String x = item.nextSym();
-                State j = lr1_goto_(i, x);
-                if(t.add(j)) {
-                    System.err.print(".");
-                    q.add(j);
-                }
-                addAction(i, x, new ShiftAction(j));
-            }
-        }
-        // compute reduce actions
-        System.err.println("Computing reduce actions");
-        for( State i : t ) {
-            for( Item item : i.items ) {
-                if( item.hasNextSym() ) continue;
-                addAction(i, item.lookahead, new ReduceAction(item.rule));
-            }
-        }
-    }
-    public Set<Item> core(Set<Item> items) {
-        Set<Item> ret = new HashSet<Item>();
-        for(Item item : items) {
-            ret.add(Item.v(item.rule, item.pos));
-        }
-        return ret;
-    }
-    /** Generates the LALR(1) parse table using the algorithms on
-     * pp. 60, 62, and 64 of Appel. */
-    public void generateLALR1Table() {
-        Set<Item> startRuleSet = new HashSet<Item>();
-        System.err.println("Computing start state");
-        for(Production r : lhsToRules.get(grammar.start)) {
-            startRuleSet.add(Item.v(r, 0, grammar.terminals.iterator().next()));
-        }
-        initialState = State.v(lr1_closure(startRuleSet));
-        Set<State> t = new HashSet<State>();
-        t.add(initialState);
-        Queue<State> q = new LinkedList<State>();
-        q.add(initialState);
-        System.err.println("Computing states");
-        while(!q.isEmpty()) {
-            State i = q.remove();
-            for( Item item : i.items ) {
-                if(!item.hasNextSym()) continue;
-                String x = item.nextSym();
-                State j = lr1_goto_(i, x);
-                if(t.add(j)) {
-                    System.err.print(".");
-                    q.add(j);
-                }
-            }
-        }
-        System.err.println("Merging states");
-        Map<Set<Item>, Set<Item>> coreToState = new HashMap<Set<Item>, Set<Item>>();
-        for(State state : t) {
-            Set<Item> items = state.items;
-            Set<Item> core = core(items);
-            Set<Item> accum = coreToState.get(core);
-            if(accum == null) {
-                System.err.print(".");
-                accum = new HashSet<Item>(items);
-                coreToState.put(core, accum);
-            } else accum.addAll(items);
-        }
-        Map<Set<Item>, State> coreToStateState = new HashMap<Set<Item>, State>();
-        for(State state : t) {
-            Set<Item> core = core(state.items);
-            coreToStateState.put(core, State.v(coreToState.get(core)));
-        }
-        // compute goto actions
-        System.err.println("Computing goto actions");
-        t.clear();
-        initialState = State.v(coreToState.get(core(initialState.items)));
-        t.add(initialState);
-        q.add(initialState);
-        while(!q.isEmpty()) {
-            State i = q.remove();
-            for( Item item : i.items ) {
-                if(!item.hasNextSym()) continue;
-                String x = item.nextSym();
-                State j = lr1_goto_(i, x);
-                j = coreToStateState.get(core(j.items));
-                if(t.add(j)) {
-                    System.err.print(".");
-                    q.add(j);
-                }
-                addAction(i, x, new ShiftAction(j));
-            }
-        }
-        // compute reduce actions
-        System.err.println("Computing reduce actions");
-        for( State i : t ) {
-            for( Item item : i.items ) {
-                if( item.hasNextSym() ) continue;
-                addAction(i, item.lookahead, new ReduceAction(item.rule));
-            }
-        }
-    }
-    /** Print the elements of a list separated by spaces. */
-    public static String listToString(List l) {
-        StringBuffer ret = new StringBuffer();
-        boolean first = true;
-        for( Object o : l ) {
-            if( !first ) ret.append(" ");
-            first = false;
-            ret.append(o);
-        }
-        return ret.toString();
-    }
-    /** Produce output according to the output specification. */
-    public void generateOutput() {
-        Map<Production,Integer> ruleMap = new HashMap<Production,Integer>();
-        int i = 0;
-        for(Production r : grammar.productions) {
-            ruleMap.put(r, i++);
-        }
-        Map<State,Integer> stateMap = new HashMap<State,Integer>();
-        i = 0;
-        stateMap.put(initialState, i++);
-        for(Action a : table.values()) {
-            if(!(a instanceof ShiftAction)) continue;
-            State state = ((ShiftAction)a).nextState;
-            if(!stateMap.containsKey(state)) {
-                stateMap.put(state, i++);
-            }
-        }
-        for(Pair<State,String> key : table.keySet()) {
-            State state = key.getO1();
-            if(!stateMap.containsKey(state)) {
-                stateMap.put(state, i++);
-            }
-        }
-        System.out.println(i);
-        System.out.println(table.size());
-        for(Map.Entry<Pair<State,String>,Action> e : table.entrySet()) {
-            Pair<State,String> p = e.getKey();
-            System.out.print(stateMap.get(p.getO1())+" "+p.getO2()+" ");
-            Action a = e.getValue();
-            if(a instanceof ShiftAction) {
-                System.out.println("shift "+
-                        stateMap.get(((ShiftAction)a).nextState));
-            } else if(a instanceof ReduceAction) {
-                System.out.println("reduce "+
-                        ruleMap.get(((ReduceAction)a).rule));
-            } else throw new Error("Internal error: unknown action");
-        }
-    }
-}
-
-class Jlr1 {
-    public static final void main(String[] args) {
-        Grammar grammar;
-        try {
-            grammar = Util.readGrammar(new Scanner(System.in));
-            Util.writeGrammar(grammar);
-        } catch(Error e) {
-            System.err.println("Error reading grammar: "+e);
-            System.exit(1);
-            return;
-        }
-        Generator jlr = new Generator(grammar);
-        try {
-            jlr.computeFirstFollowNullable();
-            jlr.generateLR1Table();
-            jlr.generateOutput();
-        } catch(Error e) {
-            System.err.println("Error performing LR(1) construction: "+e);
-            System.exit(1);
-            return;
-        }
-    }
-}
-
-/** A production in the grammar. */
-class Production {
-    public String lhs;
-    public String[] rhs;
-    private Production(String lhs, String[] rhs) {
-        this.lhs = lhs; this.rhs = rhs;
-    }
-    private static Map<Pair<String, String[]>, Production> map =
-        new HashMap<Pair<String, String[]>, Production>();
-    public static Production v(String lhs, String[] rhs) {
-        Pair<String, String[]> pair = new Pair<String, String[]>(lhs, rhs);
-        Production ret = map.get(pair);
-        if(ret == null) {
-            ret = new Production(lhs, rhs);
-            map.put(pair, ret);
-        }
-        return ret;
-    }
-    public String toString() {
-        StringBuffer ret = new StringBuffer();
-        ret.append(lhs);
-        //ret.append(" ->");
-        for(String sym : rhs) {
-            ret.append(" "+sym);
-        }
-        return ret.toString();
-    }
-}
-/** Representation of a context-free grammar. */
-class Grammar {
-    Set<String> terminals = new LinkedHashSet<String>();
-    Set<String> nonterminals = new LinkedHashSet<String>();
-    Set<Production> productions = new LinkedHashSet<Production>();
-    String start;
-
-    public boolean isTerminal(String s) {
-        return terminals.contains(s);
-    }
-    public boolean isNonTerminal(String s) {
-        return nonterminals.contains(s);
-    }
-    public List<String> syms() {
-        List<String> ret = new ArrayList<String>();
-        ret.addAll(terminals);
-        ret.addAll(nonterminals);
-        return ret;
-    }
-}
-class Error extends RuntimeException {
-    public Error(String s) { super(s); }
-}
-class Util {
-    public static String readLine(Scanner in, String msg) {
-        if(!in.hasNextLine()) throw new Error(msg+" but input file ended");
-        return in.nextLine();
-    }
-    public static int toInt(String line, String msg) {
-        try {
-            return new Integer(line);
-        } catch(NumberFormatException e) {
-            throw new Error("Expecting "+msg+" but the line is not a number:\n"+line);
-        }
-    }
-    public static Grammar readGrammar(Scanner in) {
-        Grammar grammar = new Grammar();
-        String line = readLine(in, "Expecting number of non-terminals");
-        int nterm = toInt(line, "number of non-terminals");
-        for(int i = 0; i < nterm; i++) {
-            String term = readLine(in, "Expecting a non-terminal").intern();
-            if(!grammar.terminals.add(term))
-                throw new Error("Duplicate terminal: "+term);
-        }
-
-        line = readLine(in, "Expecting number of non-terminals");
-        int nnonterm = toInt(line, "number of non-terminals");
-        for(int i = 0; i < nnonterm; i++) {
-            String nonterm = readLine(in, "Expecting a non-terminal").intern();
-            if(!grammar.nonterminals.add(nonterm))
-                throw new Error("Duplicate non-terminal: "+nonterm);
-            if(grammar.isTerminal(nonterm))
-                throw new Error("Cannot be both terminal and non-terminal: "+nonterm);
-        }
-
-        grammar.start = readLine(in, "Expecting start symbol").intern();
-        if(!grammar.nonterminals.contains(grammar.start)) throw new Error(
-            "Start symbol "+grammar.start+" was not declared as a non-terminal.");
-
-        line = readLine(in, "Expecting number of productions");
-        int nprods = toInt(line, "number of productions");
-        for(int i = 0; i < nprods; i++) {
-            Production prod = readProduction(readLine(in, "Expecting production"), grammar);
-            if(!grammar.productions.add(prod)) {
-                throw new Error("Duplicate production: "+prod);
-            }
-        }
-        if(in.hasNextLine()) {
-            System.err.println("Warning: extra input lines after grammar; maybe your production count is wrong.");
-        }
-        return grammar;
-    }
-    public static Production readProduction(String line, Grammar grammar) {
-        Scanner s = new Scanner(line);
-        if(!s.hasNext()) throw new Error("Empty line instead of a production");
-        String lhs = s.next().intern();
-        if(!grammar.isNonTerminal(lhs)) throw new Error("Symbol "+lhs+" was not declared as a non-terminal, but appears on the LHS of production "+line);
-        List<String> rhs = new ArrayList<String>();
-        while(s.hasNext()) {
-            String sym = s.next().intern();
-            if(!grammar.isNonTerminal(sym) && !grammar.isTerminal(sym)) {
-                throw new Error("Symbol "+sym+" is not a part of the grammar");
-            }
-            rhs.add(sym);
-        }
-        return Production.v(lhs,
-                (String[]) rhs.toArray(new String[rhs.size()]));
-    }
-    static String checkIndent(String line, int indent) {
-        for(int i = 0; i < indent; i++) {
-            if(line.length() <= i) throw new Error("Expecting production but got empty line.");
-            if(line.charAt(i) != ' ') throw new Error("Production "+line.substring(i)+" should be indented "+indent+" space(s), but it is indented "+i+" spaces");
-        }
-        if(line.length() <= indent) throw new Error("Expecting production but got empty line.");
-        if(line.charAt(indent) == ' ') throw new Error("Production "+line+" should be indented "+indent+" spaces, but it is indented more than that.");
-        return line.substring(indent);
-    }
-    static void printGrammar(Grammar grammar) {
-        System.out.println("Terminals:");
-        for(String s : grammar.terminals) {
-            System.out.println("   "+s);
-        }
-        System.out.println();
-
-        System.out.println("Nonterminals:");
-        for(String s : grammar.nonterminals) {
-            System.out.println("   "+s);
-        }
-        System.out.println();
-
-        System.out.println("Start Symbol:");
-        System.out.println("   "+grammar.start);
-        System.out.println();
-
-        System.out.println("Production Rules:");
-        for(Production s : grammar.productions) {
-            System.out.println("   "+s);
-        }
-    }
-    static void writeGrammar(Grammar grammar) {
-        System.out.println(grammar.terminals.size());
-        for(String s : grammar.terminals) {
-            System.out.println(s);
-        }
-        System.out.println(grammar.nonterminals.size());
-        for(String s : grammar.nonterminals) {
-            System.out.println(s);
-        }
-        System.out.println(grammar.start);
-        System.out.println(grammar.productions.size());
-        for(Production s : grammar.productions) {
-            System.out.println(s);
-        }
-    }
-}
diff --git a/cfg/README b/cfg/README
deleted file mode 100644
index ccb6334d73e183ac4d067507603198ddd88a1667..0000000000000000000000000000000000000000
--- a/cfg/README
+++ /dev/null
@@ -1,5 +0,0 @@
-compile Jlr1.java into it's own folder called 'jlar'
-javac Jlr1.java
-
-cat lr1GenInput.cfg | java jlalr.Jlr1
-cat cs444/cfg/lr1GenInput.cfg | java jlalr.Jlr1 > cs444/cfg/trans.txt
\ No newline at end of file
diff --git a/cfg/cfgNonTerminals b/cfg/cfgNonTerminals
deleted file mode 100644
index 1c802600a53c5963f77e11948b17879b713c04b5..0000000000000000000000000000000000000000
--- a/cfg/cfgNonTerminals
+++ /dev/null
@@ -1,93 +0,0 @@
-92
-start
-packageDcl
-importDcls
-importDcl
-importAll
-topDcls
-topDcl
-classDcl
-superClass
-superInterface
-classBody
-classMod
-classBodyDcls
-classBodyDcl
-fieldDcl
-fieldMod
-constructorDcl
-constructorMod
-methodDcl
-normalMethodDcl
-abstractMethodDcl
-methodHead
-methodMod
-methodMod2
-methodMod3
-result
-methodBody
-interfaceDcl
-extendInterface
-interfaceBody
-interfaceMemberDcls
-interfaceMemberDcl
-interfaceMod
-interfaceMod2
-interfaceTypelist
-names
-name
-compIDs
-params
-param
-type
-primitiveType
-numType
-refType
-arrayType
-variableDcl
-variableInit
-arrayInit
-args
-exprs
-block
-statements
-statement
-noTailStatement
-exprStatement
-statementExpr
-whileStatement
-ifElseStatement
-ifStatement
-forStatement
-forInit
-forupdate
-returnStatement
-statementNoShortIf
-ifElseStatementNoShortIf
-whileStatementNoShortIf
-forStatementNoShortIf
-primaryAndArray
-arrayCreationExpr
-primary
-classInstanceCreate
-unqualClassCreate
-fieldAccess
-arrayAccess
-methodInvoc
-literal
-expr
-assignment
-leftHandSide
-condOrExpr
-condAndrExpr
-inclusiveOrExpr
-exclusiveOrExpr
-andExpr
-eqExpr
-relationalExpr
-addExpr
-multExpr
-unaryExpr
-unaryNotPlusMinus
-castExpr
-postfixExpr
diff --git a/cfg/cfgRules b/cfg/cfgRules
deleted file mode 100644
index d38563ad9030a4d8d36d28c3b11ee730f3e1daa7..0000000000000000000000000000000000000000
--- a/cfg/cfgRules
+++ /dev/null
@@ -1,198 +0,0 @@
-198
-start BOF packageDcl importDcls topDcls EOF
-packageDcl PACKAGE name  SEMICO
-packageDcl
-importDcls importDcl importDcls
-importDcls
-importDcl  IMPORT name importAll SEMICO
-importAll
-importAll PERIOD STAR
-topDcls topDcl topDcls
-topDcls
-topDcl classDcl
-topDcl interfaceDcl
-topDcl SEMICO
-classDcl classMod CLASS ID superClass superInterface classBody
-superClass  EXTENDS name
-superInterface IMPLEMENTS interfaceTypelist
-classBody LBRAC classBodyDcls RBRAC
-classMod PUBLIC
-classMod ABSTRACT
-classMod FINAL
-classBodyDcls classBodyDcl classBodyDcls
-classBodyDcls
-classBodyDcl fieldDcl
-classBodyDcl methodDcl
-classBodyDcl constructorDcl
-classBodyDcl SEMICO
-fieldDcl fieldMod type variableDcl SEMICO
-fieldMod PUBLIC
-fieldMod PROTECTED
-fieldMod STATIC
-constructorDcl constructorMod ID LPAREN params RPAREN methodBody
-constructorMod PUBLIC
-constructorMod PROTECTED
-methodDcl normalMethodDcl
-methodDcl abstractMethodDcl
-normalMethodDcl methodMod methodMod2 methodHead methodBody
-abstractMethodDcl methodMod methodMod3 methodHead SEMICO
-methodHead result ID LPAREN params RPAREN (not 100% sure)
-methodMod PUBLIC
-methodMod PROTECTED
-methodMod
-methodMod2 FINAL
-methodMod2 STATIC
-methodMod2
-methodMod3 ABSTRACT
-methodMod3 STATIC NATIVE
-result type
-result VOID
-methodBody block
-methodBody SEMICO
-interfaceDcl PUBLIC interface ID extendInterface interfaceBody
-extendInterface EXTENDS interfaceTypelist
-extendInterface
-interfaceBody LBRACK interfaceMemberDcls RBRACK
-interfaceMemberDcls interfaceMemberDcl interfaceMemberDcls
-interfaceMemberDcls
-interfaceMemberDcl SEMICO
-interfaceMemberDcl interfaceMethodDcl
-interfaceMethodDcl interfaceMod interfaceMod2 methodHead SEMICO
-interfaceMod PUBLIC
-interfaceMod
-interfaceMod2 ABSTRACT
-interfaceMod2
-interfaceTypelist name names
-names COMMA name names
-names
-name ID
-name ID PERIOD name
-params param params
-params
-param type ID
-type primitiveType
-type refType
-primitiveType BOOLEAN
-primitiveType BYTE
-primitiveType CHAR
-primitiveType numType
-numType INT
-numType SHORT
-refType name
-refType arrayType
-arrayType primitiveType RSQRBRACK RSQRBRACK
-arrayType name RSQRBRACK RSQRBRACK
-variableDcl ID
-variableDcl ID ASSIGN variableInit
-variableInit arrayInit
-variableInit expr
-arrayInit LBRACK RBRACK
-args expr
-args exprs
-args
-exprs expr COMMA exprs
-exprs expr
-block LBRAC statements RBRAC
-statements statement statements
-statements
-statement noTailStatement
-statement ifStatement
-statement ifElseStatement
-statement forStatement
-statement whileStatement
-statement variableDcl
-noTailStatement block
-noTailStatement SEMICO
-noTailStatement exprStatement
-noTailStatement returnStatement
-exprStatement statementExpr SEMICO
-statementExpr assignment
-statementExpr methodInvoc
-whileStatement WHILE LPAREN expr RPAREN statement
-ifElseStatement IF LPAREN expr RPAREN statementNoShortIf ELSE statement
-ifStatement IF LPAREN expr RPAREN statement
-forStatement FOR LPAREN forInit SEMICO expr SEMICO forupdate RPAREN statement
-forInit statementExpr
-forInit variableDcl
-forupdate statementExpr
-returnStatement RETURN expr SEMICO
-returnStatement RETURN SEMICO
-statementNoShortIf noTailStatement
-statementNoShortIf ifElseStatementNoShortIf
-statementNoShortIf whileStatementNoShortIf
-statementNoShortIf forStatementNoShortIf
-ifElseStatementNoShortIf IF LPAREN expr RPAREN statementNoShortIf ELSE statementNoShortIf
-whileStatementNoShortIf WHILE LPAREN expr RPAREN statementNoShortIf
-forStatementNoShortIf FOR LPAREN forInit SEMICO expr SEMICO forupdate RPAREN statementNoShortIf
-primaryAndArray primary
-primaryAndArray arrayCreationExpr
-arrayCreationExpr NEW primitiveType LSQRBRACK expr  RSQRBRACK
-arrayCreationExpr NEW name LSQRBRACK expr RSQRBRACK
-arrayCreationExpr NEW primitiveType LSQRBRACK RSQRBRACK
-arrayCreationExpr NEW name LSQRBRACK RSQRBRACK
-primary literal
-primary THIS
-primary name PERIOD THIS
-primary LPAREN expr RPAREN
-primary classInstanceCreate
-primary fieldAccess
-primary arrayAccess
-primary methodInvoc
-classInstanceCreate unqualCreate
-classInstanceCreate name PERIOD unqualCreate
-classInstanceCreate primaryAndArray PERIOD unqualCreate
-unqualClassCreate NEW name LPAREN args RPAREN
-fieldAccess primaryAndArray PERIOD ID
-arrayAccess name LSQBRACK expr RSQBRACK
-arrayAccess primary LSQBRACK expr RSQBRACK
-methodInvoc ID LPAREN args RPAREN
-methodInvoc name LPAREN args RPAREN
-methodInvoc primaryAndArray PERIOD ID LPAREN args RPAREN
-literal LITERALBOOL
-literal LITERALCHAR
-literal LITERALSTRING
-literal NULL
-literal NUM
-literal ZERO
-expr assignment
-expr condOrExpr
-assignment leftHandSide ASSIGN expr
-leftHandSide name
-leftHandSide fieldAccess
-leftHandSide arrayAccess
-condOrExpr condAndrExpr
-condOrExpr condOrExpr OR condAndrExpr
-condAndrExpr inclusiveOrExpr
-condAndrExpr condAndrExpr AND inclusiveOrExpr
-inclusiveOrExpr exclusiveOrExpr
-inclusiveOrExpr inclusiveOrExpr BITOR exclusiveOrExpr
-exclusiveOrExpr andExpr
-exclusiveOrExpr exclusiveOrExpr EXP andExpr
-andExpr eqExpr
-andExpr andExpr BITAND eqExpr
-eqExpr relationalExpr
-eqExpr EQUAL relationalExpr
-eqExpr NE relationalExpr
-relationalExpr addExpr
-relationalExpr relationalExpr LE addExpr
-relationalExpr relationalExpr GE addExpr
-relationalExpr relationalExpr LT addExpr
-relationalExpr relationalExpr GT addExpr
-relationalExpr relationalExpr INSTANCEOF refType
-addExpr multExpr
-addExpr addExpr ADD multExpr
-addExpr addExpr SUB multExpr
-multExpr unaryExpr
-multExpr multExpr MULT unaryExpr
-multExpr multExpr DIV unaryExpr
-multExpr multExpr MOD unaryExpr
-unaryExpr ADD unaryExpr
-unaryExpr SUB unaryExpr
-unaryExpr unaryNotPlusMinus
-unaryNotPlusMinus postfixExpr
-unaryNotPlusMinus NOT unaryExpr
-unaryNotPlusMinus castExpr
-castExpr LPAREN primitiveType RPAREN unaryExpr
-castExpr LPAREN refType RPAREN unaryNotPlusMinus
-postfixExpr primaryAndArray
-postfixExpr name
diff --git a/cfg/cfgTerminals b/cfg/cfgTerminals
deleted file mode 100644
index ca8467df428089b4d44c789d7b0cc049920aa1ac..0000000000000000000000000000000000000000
--- a/cfg/cfgTerminals
+++ /dev/null
@@ -1,59 +0,0 @@
-58
-ABSTRACT
-BOOLEAN
-BYTE
-CHAR
-CLASS
-ELSE
-EXTENDS
-FINAL
-FOR
-IF
-IMPLEMENTS
-IMPORT
-INSTANCEOF
-INT
-NATIVE
-NEW
-PACKAGE
-PROTECTED
-PUBLIC
-RETURN
-SHORT
-STATIC
-THIS
-VOID
-WHILE
-ID
-NUM
-ZERO
-LITERALBOOL
-LITERALCHAR
-LITERALSTRING
-NULL
-ASSIGN
-GT
-LT
-NOT
-EQUAL
-GE
-LE
-NE
-AND
-OR
-ADD
-SUB
-MULT
-DIV
-BITAND
-BITOR
-MOD
-SEMICO
-LPAREN
-RPAREN
-LBRACK
-RBRACK
-LSQRBRACK
-RSQRBRACK
-COMMA
-PERIOD