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