added grammar class ; added first set
This commit is contained in:
8
lab/testGrNul.grm
Normal file
8
lab/testGrNul.grm
Normal file
@@ -0,0 +1,8 @@
|
||||
$S -> $A$B
|
||||
$A -> $C/a
|
||||
$A -> /~
|
||||
$B -> /c$Bpr
|
||||
$Bpr -> /a$A$C$Bpr
|
||||
$Bpr -> /~
|
||||
$C -> /b
|
||||
$C -> /~
|
80
src/grammar.py
Normal file
80
src/grammar.py
Normal file
@@ -0,0 +1,80 @@
|
||||
from terminal import Terminal
|
||||
from nonTerminal import NonTerminal
|
||||
|
||||
class Grammar:
|
||||
__atomKeyMapping = []
|
||||
__productions = []
|
||||
__first = {}
|
||||
|
||||
__nonTerminals = {}
|
||||
__terminals = {}
|
||||
|
||||
def addProduction(self, nonTerminal, atoms):
|
||||
|
||||
|
||||
self.__addAtom(nonTerminal);
|
||||
|
||||
for atom in atoms:
|
||||
self.__addAtom(atom)
|
||||
|
||||
key = nonTerminal.toString()
|
||||
self.__nonTerminals[key].addProduction(atoms)
|
||||
|
||||
def __addAtom(self, atom):
|
||||
if isinstance(atom, Terminal):
|
||||
self.__addAtomToSet(self.__terminals, atom)
|
||||
elif isinstance(atom, NonTerminal):
|
||||
self.__addAtomToSet(self.__nonTerminals, atom)
|
||||
|
||||
def __addAtomToSet(self, atomSet, atom):
|
||||
key = atom.toString()
|
||||
|
||||
if atomSet.get(key) == None:
|
||||
atomSet[key] = atom
|
||||
|
||||
|
||||
def toString(self):
|
||||
retStr = ""
|
||||
|
||||
for key in self.__nonTerminals:
|
||||
nonTerminal = self.__nonTerminals[key]
|
||||
|
||||
retStr += nonTerminal.productionsToString() + "\n";
|
||||
|
||||
return retStr
|
||||
|
||||
def generateMetrics(self):
|
||||
self.__generateFirstSets()
|
||||
|
||||
|
||||
def __generateFirstSets(self):
|
||||
for key in self.__nonTerminals:
|
||||
nonTerminal = self.__nonTerminals[key]
|
||||
nonTerminal.generateFirstSet();
|
||||
|
||||
|
||||
def printNullableSet(self):
|
||||
output = "Nullable = { "
|
||||
|
||||
for key in self.__nonTerminals:
|
||||
nonTerminal = self.__nonTerminals[key]
|
||||
|
||||
if nonTerminal.isNullable():
|
||||
output += nonTerminal.toString() + " "
|
||||
|
||||
output += "}"
|
||||
|
||||
print(output)
|
||||
|
||||
def printFirstSets(self):
|
||||
print("First Sets:")
|
||||
|
||||
for key in self.__nonTerminals:
|
||||
nonTerminal = self.__nonTerminals[key]
|
||||
|
||||
nonTerminal.printFirstSet();
|
||||
|
||||
for key in self.__terminals:
|
||||
terminal = self.__terminals[key]
|
||||
|
||||
terminal.printFirstSet();
|
@@ -2,6 +2,9 @@
|
||||
|
||||
from grammarLexer import GrammarLexer
|
||||
from grammarLexer import T_TOKEN
|
||||
from grammar import Grammar
|
||||
from terminal import Terminal
|
||||
from nonTerminal import NonTerminal
|
||||
|
||||
class GrammarParser:
|
||||
__lxr = GrammarLexer()
|
||||
@@ -17,6 +20,7 @@ class GrammarParser:
|
||||
|
||||
tokenLine = self.__lxr.getParsedLine()
|
||||
|
||||
|
||||
if self.__lineIsValid(tokenLine):
|
||||
leftSide = tokenLine.popleft().getLexeme()
|
||||
tokenLine.popleft()
|
||||
@@ -30,7 +34,37 @@ class GrammarParser:
|
||||
|
||||
self.__grammar[leftSide].append(rightSide)
|
||||
|
||||
print(self.__grammar)
|
||||
def parseGrm(self, grammarFile):
|
||||
grm = Grammar()
|
||||
lines = grammarFile.readlines()
|
||||
|
||||
for line in lines:
|
||||
self.__lxr.processLine(line)
|
||||
tokenLine = self.__lxr.getParsedLine()
|
||||
|
||||
if self.__lineIsValid(tokenLine):
|
||||
leftSide = NonTerminal(tokenLine.popleft().getLexeme())
|
||||
tokenLine.popleft()
|
||||
|
||||
rightSide = []
|
||||
tmpToken = None
|
||||
|
||||
while len(tokenLine) > 0:
|
||||
tmpToken = tokenLine.popleft()
|
||||
|
||||
if tmpToken.getClass() == T_TOKEN.NON_TERMINAL:
|
||||
rightSide.append(NonTerminal(tmpToken.getLexeme()))
|
||||
elif tmpToken.getClass() == T_TOKEN.TERMINAL:
|
||||
lexeme = tmpToken.getLexeme();
|
||||
|
||||
if lexeme == "~":
|
||||
lexeme = None;
|
||||
|
||||
rightSide.append(Terminal(lexeme))
|
||||
|
||||
grm.addProduction(leftSide, rightSide)
|
||||
|
||||
return grm
|
||||
|
||||
|
||||
def __lineIsValid(self, tokenLine):
|
||||
@@ -55,6 +89,7 @@ class GrammarParser:
|
||||
for left in self.__grammar:
|
||||
self.__printRow(left, self.__grammar[left]);
|
||||
|
||||
|
||||
def __printRow(self, left, right):
|
||||
line = left + " -> "
|
||||
|
||||
@@ -67,4 +102,3 @@ class GrammarParser:
|
||||
line += str(token.getClass()) + "(" + token.getLexeme() + ")"
|
||||
|
||||
print(line)
|
||||
|
||||
|
117
src/nonTerminal.py
Normal file
117
src/nonTerminal.py
Normal file
@@ -0,0 +1,117 @@
|
||||
from terminal import Terminal
|
||||
|
||||
class NonTerminal:
|
||||
def __init__(self, string):
|
||||
self.__string = None
|
||||
self.__isNullable = False
|
||||
self.__productions = []
|
||||
self.__first = []
|
||||
self.__firstSetIsGenerated = False;
|
||||
|
||||
self.__string = string
|
||||
|
||||
def addProduction(self, rhs):
|
||||
self.__firstSetIsGenrated = False;
|
||||
|
||||
if (len(rhs) == 1 and
|
||||
isinstance(rhs[0], Terminal) and
|
||||
rhs[0].isEmptyString()):
|
||||
|
||||
self.__isNullable = True
|
||||
|
||||
self.__productions.append(rhs)
|
||||
|
||||
def productionsToString(self):
|
||||
if len(self.__productions) == 0:
|
||||
return "N/A"
|
||||
|
||||
output = self.toString() + " -> "
|
||||
|
||||
for index in range(len(self.__productions) - 1):
|
||||
production = self.__productions[index]
|
||||
|
||||
for atom in production:
|
||||
output += atom.toString()
|
||||
|
||||
output += " | "
|
||||
|
||||
for atom in self.__productions[len(self.__productions) - 1]:
|
||||
output += atom.toString()
|
||||
|
||||
return output
|
||||
|
||||
def printProductions(self):
|
||||
print(self.productionsToString())
|
||||
|
||||
def generateFirstSet(self):
|
||||
for production in self.__productions:
|
||||
self.__addFirsSetForProduction(production)
|
||||
|
||||
self.__firstSetIsGenrated = True;
|
||||
|
||||
def __addFirsSetForProduction(self, production):
|
||||
stillNullable = True
|
||||
lenProd = len(production)
|
||||
index = 0;
|
||||
|
||||
while stillNullable and index < lenProd:
|
||||
atom = production[index]
|
||||
|
||||
if isinstance(atom, Terminal):
|
||||
self.__addAtomToFirstSet(atom)
|
||||
stillNullable = False
|
||||
elif atom != self:
|
||||
if atom.isNullable():
|
||||
if index < lenProd - 1:
|
||||
self.__copyFirstSetFrom(atom, False)
|
||||
else:
|
||||
self.__copyFirstSetFrom(atom, True)
|
||||
else:
|
||||
self.__copyFirstSetFrom(atom, False)
|
||||
|
||||
|
||||
index += 1;
|
||||
|
||||
def __addAtomToFirstSet(self, newAtom):
|
||||
key = newAtom.toString()
|
||||
|
||||
for atom in self.__first:
|
||||
if atom.toString() == key:
|
||||
return
|
||||
|
||||
self.__first.append(newAtom)
|
||||
|
||||
def __copyFirstSetFrom(self, atom, includeEmptyString):
|
||||
|
||||
for innerAtom in atom.getFirstSet():
|
||||
if isinstance(innerAtom, Terminal):
|
||||
if innerAtom.isEmptyString():
|
||||
if includeEmptyString:
|
||||
self.__addAtomToFirstSet(innerAtom)
|
||||
else:
|
||||
self.__addAtomToFirstSet(innerAtom)
|
||||
|
||||
def getFirstSet(self):
|
||||
if self.__firstSetIsGenrated == False:
|
||||
self.generateFirstSet();
|
||||
|
||||
return self.__first
|
||||
|
||||
def isNullable(self):
|
||||
return self.__isNullable
|
||||
|
||||
def toString(self):
|
||||
return "N(" + self.__string + ")"
|
||||
|
||||
def getString(self):
|
||||
return self.__string
|
||||
|
||||
def printFirstSet(self):
|
||||
output = "First("+ self.toString() +") = { "
|
||||
|
||||
for atom in self.__first:
|
||||
output += atom.toString() + " ";
|
||||
|
||||
output += "}"
|
||||
|
||||
print(output)
|
24
src/terminal.py
Normal file
24
src/terminal.py
Normal file
@@ -0,0 +1,24 @@
|
||||
class Terminal:
|
||||
|
||||
def __init__(self, string):
|
||||
self.__string = None
|
||||
self.__isEmptyString = True
|
||||
|
||||
if string == "":
|
||||
self.__string = ""
|
||||
else:
|
||||
self.__string = string
|
||||
self.__isEmptyString = False
|
||||
|
||||
|
||||
def getFirstSet(self):
|
||||
return [self]
|
||||
|
||||
def isEmptyString(self):
|
||||
return self.__isEmptyString
|
||||
|
||||
def toString(self):
|
||||
return "T(" + self.__string + ")"
|
||||
|
||||
def printFirstSet(self):
|
||||
print("First("+ self.toString() +") = { " + self.toString() + " }")
|
@@ -7,7 +7,16 @@ prs = GrammarParser()
|
||||
|
||||
inp = input("grammar file: ");
|
||||
|
||||
prs.parse(open(inp, "r"));
|
||||
grm = prs.parseGrm(open(inp, "r"));
|
||||
|
||||
prs.printGrammar();
|
||||
print(grm.toString())
|
||||
|
||||
grm.generateMetrics()
|
||||
|
||||
print("----------------")
|
||||
grm.printNullableSet()
|
||||
|
||||
print("----------------")
|
||||
grm.printFirstSets()
|
||||
|
||||
#prs.printGrammar();
|
||||
|
Reference in New Issue
Block a user