From 463a3db6dd86a238b686e63ca0207292c929065f Mon Sep 17 00:00:00 2001 From: Xun Yang <x299yang@uwaterloo.ca> Date: Thu, 20 Feb 2020 23:40:10 -0500 Subject: [PATCH] AST nodes, AST building, test multiple files for A2 --- AST.py | 76 ++++ AstBuilding.py | 84 +---- AstNodes.py | 65 ---- CompNode.py | 33 ++ Environment.py | 68 ++++ LineNodes.py | 21 ++ MemberNodes.py | 89 +++++ ParseNode.py | 65 ++++ Parsing.py | 4 +- Test.py | 70 ++-- TestMultiple.py | 7 + TypeNodes.py | 80 +++++ Weeding.py | 5 +- cfg/Jlr1.class | 858 -------------------------------------------- cfg/Jlr1.java | 790 ---------------------------------------- cfg/README | 5 - cfg/cfgNonTerminals | 93 ----- cfg/cfgRules | 198 ---------- cfg/cfgTerminals | 59 --- 19 files changed, 506 insertions(+), 2164 deletions(-) create mode 100644 AST.py delete mode 100644 AstNodes.py create mode 100644 CompNode.py create mode 100644 Environment.py create mode 100644 LineNodes.py create mode 100644 MemberNodes.py create mode 100644 ParseNode.py create mode 100644 TestMultiple.py create mode 100644 TypeNodes.py delete mode 100644 cfg/Jlr1.class delete mode 100644 cfg/Jlr1.java delete mode 100644 cfg/README delete mode 100644 cfg/cfgNonTerminals delete mode 100644 cfg/cfgRules delete mode 100644 cfg/cfgTerminals diff --git a/AST.py b/AST.py new file mode 100644 index 0000000..a7a89fe --- /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 8a59878..5b96449 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 aff1885..0000000 --- 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 0000000..2a74f59 --- /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 0000000..e3badd8 --- /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 0000000..20dce65 --- /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 0000000..cb4e295 --- /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 0000000..cba3fc2 --- /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 ac82a44..c051bb5 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 ed8dac2..c69c96d 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 0000000..98b0847 --- /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 0000000..4a9a79f --- /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 61c6adc..cb91b98 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 7f1ae4c..0000000 --- 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 8d34da6..0000000 --- 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 ccb6334..0000000 --- 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 1c80260..0000000 --- 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 d38563a..0000000 --- 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 ca8467d..0000000 --- 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 -- GitLab