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