Browse Source

added grammar class ; added first set

pull/2/head
Tom 6 years ago
parent
commit
8f9fbf28bd
6 changed files with 281 additions and 9 deletions
  1. +8
    -0
      lab/testGrNul.grm
  2. +80
    -0
      src/grammar.py
  3. +41
    -7
      src/grammarParser.py
  4. +117
    -0
      src/nonTerminal.py
  5. +24
    -0
      src/terminal.py
  6. +11
    -2
      src/testParser.py

+ 8
- 0
lab/testGrNul.grm View 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
- 0
src/grammar.py View 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();

+ 41
- 7
src/grammarParser.py View File

@ -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()
@ -10,13 +13,14 @@ class GrammarParser:
def parse(self, grammarFile):
lines = grammarFile.readlines()
for line in lines:
self.__lxr.processLine(line)
tokenLine = self.__lxr.getParsedLine()
if self.__lineIsValid(tokenLine):
leftSide = tokenLine.popleft().getLexeme()
tokenLine.popleft()
@ -30,8 +34,38 @@ 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):
if len(tokenLine) < 3:
@ -42,7 +76,7 @@ class GrammarParser:
if tokenLine[1].getClass() != T_TOKEN.ARROW:
return False;
return True;
def __isNewNonTerm(self, token):
@ -54,7 +88,8 @@ class GrammarParser:
def printGrammar(self):
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
- 0
src/nonTerminal.py View 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
- 0
src/terminal.py View 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() + " }")

+ 11
- 2
src/testParser.py View File

@ -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();

Loading…
Cancel
Save