HyperDbg/hyperdbg/script-engine/python/ll1_parser.py

1038 lines
36 KiB
Python

"""
* @file ll1_parse_table_generator.py
* @author M.H. Gholamrezei (mh@hyperdbg.org)
* @author Sina Karvandi (sina@hyperdbg.org)
* @brief Script engine LL(1) Parse table generator
* @details This program reads grammar from Greammar.txt file
* placed in the same directory of the program
* and creates parse_table.h and parse_table.c which is
* used by the parser of script engine.
* @version 0.1
* @date 2020-10-24
*
* @copyright This project is released under the GNU Public License v3.
"""
from util import *
from lalr1_parser import *
class LL1Parser:
def __init__(self, SourceFile, HeaderFile, CommonHeaderFile, CommonHeaderFileScala):
# The file which contains the grammar of the language
self.GrammarFile = open("Grammar.txt", "r")
# The file which is used by parser for parsing the input
self.SourceFile = SourceFile
self.HeaderFile = HeaderFile
self.CommonHeaderFile = CommonHeaderFile
self.CommonHeaderFileScala = CommonHeaderFileScala
# Lists which used for storing the rules:
# Right Hand Side(Rhs)
self.RhsList = []
# Left Hand Side(Lhs)
self.LhsList = []
# Set of all terminals and noneterminals
self.TerminalSet = set()
self.NonTerminalSet = set()
# Start variable
self.Start = ""
# maximum of "Right Hand Side(Rhs)" length
self.MAXIMUM_RHS_LEN = 0
self.SPECIAL_TOKENS = ['%', '+', '~', '++', '-', '--', "*", "/", "=", "==", "!=", ",", ";", "(", ")", "{", "}", "|", "||", ">>", ">=", "<<", "<=", "&", "&&", "^",
"+=", "-=", "*=", "/=", "%=", "<<=", ">>=", "&=", "^=", "|=" ]
# INVALID rule indicator
self.INVALID = 0x80000000
self.FunctionsDict = dict()
self.OperatorsTwoOperand = []
self.OperatorsOneOperand = []
self.RegistersList = []
self.PseudoRegistersList = []
self.VariableTypeList = []
self.keywordList = []
self.SemantiRulesList = []
self.AssignmentOperator = []
# Dictionaries used for storing first and follow sets
self.FirstDict = dict()
self.FollowDict = dict()
def Run(self):
# Read grammar from input file and initialize grammar related variables
self.ReadGrammar()
# Calculate "First Set" for all nonterminals and print it
self.FindAllFirsts()
# print("Firsts:")
# self.PrintFirsts()
# print("________________________________________________________________________________")
# Calculate "Follow Set" for all nonterminals and print it
self.FindAllFollows()
# print("Follows:")
# self.PrintFollows()
# print("________________________________________________________________________________")
# Calculate "Prdicted Set" for each rule and print it
self.FindAllPredicts()
# print("Predicts:")
# self.print_predicts()
# print("________________________________________________________________________________")
# Fills "Parse Table" according to calculated "Predicted Set" and print "Parse Table"
self.FillParseTable()
# print("Parse Table:")
# self.PrintParseTable()
# print()
# Prints variables that are needed for parser for parsing into the output file
self.HeaderFile.write("#pragma once\n")
self.HeaderFile.write("#ifndef PARSE_TABLE_H\n")
self.HeaderFile.write("#define PARSE_TABLE_H\n")
self.HeaderFile.write("#define RULES_COUNT " + str(len(self.LhsList)) + "\n")
self.HeaderFile.write("#define TERMINAL_COUNT " + str(len(list(self.TerminalSet))) + "\n")
self.HeaderFile.write("#define NONETERMINAL_COUNT " + str(len(list(self.NonTerminalList))) + "\n")
self.HeaderFile.write("#define START_VARIABLE " + "\"" + self.Start +"\"\n")
self.HeaderFile.write("#define MAX_RHS_LEN " + str(self.MAXIMUM_RHS_LEN) +"\n")
self.HeaderFile.write("#define KEYWORD_LIST_LENGTH " + str(len(self.keywordList)) +"\n")
self.HeaderFile.write("#define OPERATORS_ONE_OPERAND_LIST_LENGTH " + str(len(self.OperatorsOneOperand)) + "\n")
self.HeaderFile.write("#define OPERATORS_TWO_OPERAND_LIST_LENGTH " + str(len(self.OperatorsTwoOperand)) + "\n")
self.HeaderFile.write("#define REGISTER_MAP_LIST_LENGTH " + str(len(self.RegistersList))+ "\n")
self.HeaderFile.write("#define PSEUDO_REGISTER_MAP_LIST_LENGTH " + str(len(self.PseudoRegistersList))+ "\n")
self.HeaderFile.write("#define SCRIPT_VARIABLE_TYPE_LIST_LENGTH " + str(len(self.VariableTypeList))+ "\n")
self.HeaderFile.write("#define ASSIGNMENT_OPERATOR_LIST_LENGTH " + str(len(self.AssignmentOperator)) + "\n")
self.HeaderFile.write("#define SEMANTIC_RULES_MAP_LIST_LENGTH " + str(len(self.keywordList) + len(self.OperatorsOneOperand) + len(self.OperatorsTwoOperand) + len(self.SemantiRulesList) + len(self.AssignmentOperator))+ "\n")
for Key in self.FunctionsDict:
self.HeaderFile.write("#define "+ Key[1:].upper() + "_LENGTH "+ str(len(self.FunctionsDict[Key]))+"\n")
self.SourceFile.write("#include \"pch.h\"\n")
# Prints Rules into output files
self.WriteLhsList()
self.WriteRhsList()
# Prints size of each Rhs into output files
self.WriteRhsSize()
# Prints noneterminals and Terminal into output files
self.WriteNoneTermianlList()
self.WriteTerminalList()
# Prints "Parse Table" into output files
self.WriteParseTable()
# Prints Keywords list into output files
self.WriteKeywordList()
# Prints Operators List into output files
self.WriteOperatorsList()
# Prints Maps into output files
self.WriteMaps()
self.WriteSemanticMaps()
self.WriteRegisterMaps()
self.WritePseudoRegMaps()
self.WriteVariableTypeList()
# Closes Grammar Input File
self.GrammarFile.close()
def SetLalr(self, Lalr, LalrParseTable):
self.Lalr = Lalr
self.LalrParseTable = LalrParseTable
# This function simulates of script engine parser in ScriptEngine.C in
# order to test the generated "Parse Table"
def Parse(self, Tokens):
# Initialize Parse Stack
Stack = []
# Initialize Match Stack
MatchedStack = []
# Push the end of stack indicator into stack
Stack.append("$")
# Push start variable into stack
Stack.append(self.Start)
# Assign top variale an invalid value
Top = ""
# Read input
Tokens, CurrentIn = Read(Tokens)
# Temporary values counter initialized with 0 value
TempCounter = 0
# While Stack is not empty repeat
while Top != "$":
# Read top of stack
Top = GetTop(Stack)
# print(Stack)
# print("Top:", Top)
# print("CurrentIn:", CurrentIn, "\n\n")
# x = input()
if self.IsNoneTerminal(Top):
if Top == "BOOLEAN_EXPRESSION":
print("Top == BOOLEAN_EXPRESSION:")
print(Stack)
print(Tokens)
print(CurrentIn)
print("=====================================\n\n")
Stack.pop()
#------------------------------------------------------
# Get BE Tokens
BETokensSize = 0
OpenParanthesesCount = 1
i = 0
while True:
TempToken = Tokens[i]
i +=1
if TempToken == '(' :
OpenParanthesesCount += 1
BETokensSize += 1
elif TempToken == ')':
OpenParanthesesCount -= 1
if OpenParanthesesCount == 0:
break
else:
BETokensSize +=1
else:
BETokensSize +=1
print("TempToken: ", end = "")
print(TempToken)
print("BETokensSize: ", end = "")
print(BETokensSize)
# BETokens.append("$end")
print("BETokensSize: ", end = "")
print(BETokensSize)
y = input()
NewTokens = [CurrentIn]
for x in Tokens:
NewTokens.append(x)
#------------------------------------------------------
Tokens = self.Lalr.Parse(NewTokens, BETokensSize + 1)
# x = input()
print("after lalr parsing:")
print(Stack)
print(Tokens)
print("=====================================\n\n")
CurrentIn = Tokens[0]
if (len(Tokens) > 1):
Tokens = Tokens[1:]
# x = input()
else:
Id = self.ParseTable[self.GetNoneTerminalId(Top)][self.GetTerminalId(CurrentIn)]
# Error Handling
if Id == -1:
print("1)Error in input!")
print(Tokens)
print(Stack)
print("Top: ", Top)
print("CurrentIn: ", CurrentIn)
print("\n\n")
exit()
Stack.pop()
Rhs = self.RhsList[Id]
if Rhs != ["eps"]:
for Symbol in reversed(Rhs):
Stack.append(Symbol)
elif self.IsSemanticRule(Top):
if Top == "@PUSH":
Stack.pop()
Top = GetTop(Stack)
if Top == CurrentIn:
MatchedStack.append(Top)
Tokens, CurrentIn = Read(Tokens)
else:
print("2)Error in input!")
exit()
elif Top == "@JZ":
print("JZ:")
print(Stack)
print(Tokens)
print("\n\n")
y = input()
elif Top == "@JZCMPL":
print("JZCOMPELETED:")
print(Stack)
print(Tokens)
print("\n\n")
y = input()
else:
Op0 = MatchedStack.pop()
if Top == "@PRINT":
print(Top,"\t", Op0 )
elif Top == "@MOV":
Op1 = MatchedStack.pop()
print(Top,"\t", Op1, ", ", Op0 )
else:
pass
Op1 = MatchedStack.pop()
MatchedStack.append("t" + str(TempCounter))
print(Top, "\t", "t"+ str(TempCounter), ", ", Op1, ",", Op0 )
TempCounter += 1
Stack.pop()
else: # Terminal
CurrentIn = Tokens[0]
if (len(Tokens) > 1):
Tokens = Tokens[1:]
Stack.pop()
return MatchedStack
def ReadGrammar(self):
Flag = 1
Counter = -1
for Line in self.GrammarFile:
Counter += 1
Line = Line.strip()
if Line == "" or Line[0] == "#":
continue
elif Line[0] == ".":
L = Line.split("->")
Elements = L[1].split(" ")
if L[0][1:] == "OperatorsTwoOperand":
self.OperatorsTwoOperand += Elements
continue
elif L[0][1:] == "OperatorsOneOperand":
self.OperatorsOneOperand += Elements
continue
elif L[0][1:] == "SemantiRules":
self.SemantiRulesList += Elements
continue
elif L[0][1:] == "Registers":
self.RegistersList += Elements
continue
elif L[0][1:] == "PseudoRegisters":
self.PseudoRegistersList += Elements
continue
elif L[0][1:] == "ScriptVariableType":
self.VariableTypeList += Elements
continue
elif L[0][1:] == "AssignmentOperator":
self.AssignmentOperator += Elements
continue
self.FunctionsDict[L[0]] = Elements
continue
L = Line.split("->")
Lhs = L[0]
Rhs = L[1].split(" ")
HasMapKeyword = False
MapKeywordIdx1 = 0
MapKeywordIdx2 = 0
Idx = 0
for X in Rhs:
if X[0] == ".":
HasMapKeyword = True
MapKeywordIdx1 = Idx
elif X[0] == "@":
if X[1] == ".":
MapKeywordIdx2 = Idx
Idx += 1
if not HasMapKeyword:
self.NonTerminalSet.add(Lhs)
self.LhsList.append(Lhs)
self.RhsList.append(Rhs)
for X in Rhs:
if not self.IsNoneTerminal(X) and not self.IsSemanticRule(X) and not X=="eps":
self.TerminalSet.add(X)
if self.IsSemanticRule(X):
pass
else:
for value in self.FunctionsDict[Rhs[MapKeywordIdx1]]:
RhsTemp =list(Rhs)
RhsTemp[MapKeywordIdx1] = value
RhsTemp[MapKeywordIdx2] = "@" + value.upper()
self.keywordList.append(value)
self.NonTerminalSet.add(Lhs)
self.LhsList.append(Lhs)
self.RhsList.append(RhsTemp)
for X in RhsTemp:
if not self.IsNoneTerminal(X) and not self.IsSemanticRule(X) and not X=="eps":
self.TerminalSet.add(X)
if Flag:
Flag = 0
self.Start = Lhs
self.MAXIMUM_RHS_LEN = max(self.MAXIMUM_RHS_LEN, len(Rhs))
self.TerminalSet.add("$")
self.NonTerminalList = list(self.NonTerminalSet)
self.TerminalList = list(self.TerminalSet)
def WriteSemanticMaps(self):
self.CommonHeaderFileScala.write("object ScriptEvalFunc {\n object ScriptOperators extends ChiselEnum {\n val ")
Counter = 0
CheckForDuplicateList = []
self.CommonHeaderFile.write("#define " + "FUNC_UNDEFINED " + str(Counter) + "\n")
self.CommonHeaderFileScala.write("sFunc" + "Undefined")
Counter += 1
for X in self.OperatorsOneOperand:
if X not in CheckForDuplicateList:
self.CommonHeaderFile.write("#define " + "FUNC_" + X.upper() + " " + str(Counter) + "\n")
self.CommonHeaderFileScala.write(", sFunc" + X.capitalize())
CheckForDuplicateList.append(X)
Counter += 1
for X in self.OperatorsTwoOperand:
if X not in CheckForDuplicateList:
self.CommonHeaderFile.write("#define " + "FUNC_" + X.upper() + " " + str(Counter) + "\n")
self.CommonHeaderFileScala.write(", sFunc" + X.capitalize())
CheckForDuplicateList.append(X)
Counter += 1
for X in self.SemantiRulesList:
if X not in CheckForDuplicateList:
self.CommonHeaderFile.write("#define " + "FUNC_" + X.upper() + " " + str(Counter) + "\n")
self.CommonHeaderFileScala.write(", sFunc" + X.capitalize())
CheckForDuplicateList.append(X)
Counter += 1
for X in self.keywordList:
if X not in CheckForDuplicateList:
self.CommonHeaderFile.write("#define " + "FUNC_" + X.upper() + " " + str(Counter) + "\n")
#
# Check if it's the last item
#
self.CommonHeaderFileScala.write(", sFunc" + X.capitalize() + "")
CheckForDuplicateList.append(X)
Counter += 1
self.CommonHeaderFileScala.write(" = Value\n }\n} ")
self.SourceFile.write("const SYMBOL_MAP SemanticRulesMapList[]= {\n")
self.HeaderFile.write("extern const SYMBOL_MAP SemanticRulesMapList[];\n")
for X in self.OperatorsOneOperand:
self.SourceFile.write("{\"@" + X.upper() + "\", "+ "FUNC_" + X.upper() + "},\n")
for X in self.OperatorsTwoOperand:
self.SourceFile.write("{\"@" + X.upper() + "\", "+ "FUNC_" + X.upper() + "},\n")
for X in self.SemantiRulesList:
self.SourceFile.write("{\"@" + X.upper() + "\", "+ "FUNC_" + X.upper() + "},\n")
for X in self.keywordList:
self.SourceFile.write("{\"@" + X.upper() + "\", "+ "FUNC_" + X.upper() + "},\n")
for X in self.AssignmentOperator:
self.SourceFile.write("{\"@" + X.upper() + "\", "+ "FUNC_" + X.upper().replace("_ASSIGNMENT", "") + "},\n")
self.SourceFile.write("};\n")
CheckForDuplicateList = []
self.CommonHeaderFile.write("\nstatic const char *const FunctionNames[] = {")
self.CommonHeaderFile.write("\n\"FUNC_UNDEFINED\""+ ",\n")
for X in self.OperatorsOneOperand:
if X not in CheckForDuplicateList:
self.CommonHeaderFile.write("\"" + "FUNC_" + X.upper() + "\"" + ",\n")
CheckForDuplicateList.append(X)
for X in self.OperatorsTwoOperand:
if X not in CheckForDuplicateList:
self.CommonHeaderFile.write("\"" + "FUNC_" + X.upper() + "\"" + ",\n")
CheckForDuplicateList.append(X)
for X in self.SemantiRulesList:
if X not in CheckForDuplicateList:
self.CommonHeaderFile.write("\"" + "FUNC_" + X.upper() + "\"" + ",\n")
CheckForDuplicateList.append(X)
for X in self.keywordList:
if X not in CheckForDuplicateList:
self.CommonHeaderFile.write("\"" + "FUNC_" + X.upper() + "\"" + ",\n")
CheckForDuplicateList.append(X)
self.CommonHeaderFile.write("};\n")
def WriteRegisterMaps(self):
self.CommonHeaderFile.write("\ntypedef enum REGS_ENUM {\n")
Counter = 0
for X in self.RegistersList:
if Counter == len(self.RegistersList)-1:
self.CommonHeaderFile.write("\t" + "REGISTER_" + X.upper() + " = " + str(Counter) + "\n")
else:
self.CommonHeaderFile.write("\t" + "REGISTER_" + X.upper() + " = " + str(Counter) + ",\n")
Counter += 1
self.CommonHeaderFile.write("\n} REGS_ENUM;\n\n")
self.CommonHeaderFile.write("static const char *const RegistersNames[] = {\n")
Counter = 0
for X in self.RegistersList:
if Counter == len(self.RegistersList)-1:
self.CommonHeaderFile.write("\t" + "\"" + X + "\"")
else:
if (Counter + 1) % 8 == 0:
self.CommonHeaderFile.write("" + "\"" + X + "\",\n")
else:
self.CommonHeaderFile.write("" + "\"" + X + "\", ")
Counter += 1
self.CommonHeaderFile.write("\n};\n\n")
self.SourceFile.write("const SYMBOL_MAP RegisterMapList[]= {\n")
self.HeaderFile.write("extern const SYMBOL_MAP RegisterMapList[];\n")
Counter = 0
for X in self.RegistersList:
if Counter == len(self.RegistersList)-1:
self.SourceFile.write("{\"" + X + "\", "+ "REGISTER_" + X.upper() + "}\n")
else:
self.SourceFile.write("{\"" + X + "\", "+ "REGISTER_" + X.upper() + "},\n")
Counter +=1
self.SourceFile.write("};\n")
def WritePseudoRegMaps(self):
Counter = 0
for X in self.PseudoRegistersList:
self.CommonHeaderFile.write("#define " + "PSEUDO_REGISTER_" + X.upper() + " " + str(Counter) + "\n")
Counter += 1
self.CommonHeaderFile.write("\n")
self.SourceFile.write("const SYMBOL_MAP PseudoRegisterMapList[]= {\n")
self.HeaderFile.write("extern const SYMBOL_MAP PseudoRegisterMapList[];\n")
Counter = 0
for X in self.PseudoRegistersList:
if Counter == len(self.PseudoRegistersList)-1:
self.SourceFile.write("{\"" + X + "\", "+ "PSEUDO_REGISTER_" + X.upper() + "}\n")
else:
self.SourceFile.write("{\"" + X + "\", "+ "PSEUDO_REGISTER_" + X.upper() + "},\n")
Counter +=1
self.SourceFile.write("};\n")
def WriteVariableTypeList(self):
self.SourceFile.write("const char* ScriptVariableTypeList[]= {\n")
self.HeaderFile.write("extern const char* ScriptVariableTypeList[];\n")
Counter = 0
for X in self.VariableTypeList:
if Counter == len(self.VariableTypeList)-1:
self.SourceFile.write("\"" + X + "\"" + "\n")
else:
self.SourceFile.write("\"" + X + "\"" + ",\n")
Counter +=1
self.SourceFile.write("};\n")
def WriteKeywordList(self):
self.SourceFile.write("const char* KeywordList[]= {\n")
self.HeaderFile.write("extern const char* KeywordList[];\n")
Counter = 0
for X in self.keywordList:
if Counter == len(self.keywordList)-1:
self.SourceFile.write("\"" + X + "\"" + "\n")
else:
self.SourceFile.write("\"" + X + "\"" + ",\n")
Counter +=1
self.SourceFile.write("};\n")
def WriteOperatorsList(self):
self.SourceFile.write("const char* OperatorsTwoOperandList[]= {\n")
self.HeaderFile.write("extern const char* OperatorsTwoOperandList[];\n")
Counter = 0
for X in self.OperatorsTwoOperand:
if Counter == len(self.OperatorsTwoOperand)-1:
self.SourceFile.write("\"" + "@"+ X.upper() + "\"" + "\n")
else:
self.SourceFile.write("\"" + "@"+ X.upper() + "\"" + ",\n")
Counter +=1
self.SourceFile.write("};\n")
self.SourceFile.write("const char* OperatorsOneOperandList[]= {\n")
self.HeaderFile.write("extern const char* OperatorsOneOperandList[];\n")
Counter = 0
for X in self.OperatorsOneOperand:
if Counter == len(self.OperatorsOneOperand)-1:
self.SourceFile.write("\"" + "@"+ X.upper() + "\"" + "\n")
else:
self.SourceFile.write("\"" + "@"+ X.upper() + "\"" + ",\n")
Counter +=1
self.SourceFile.write("};\n")
self.SourceFile.write("const char* AssignmentOperatorList[]= {\n")
self.HeaderFile.write("extern const char* AssignmentOperatorList[];\n")
Counter = 0
for X in self.AssignmentOperator:
if Counter == len(self.AssignmentOperator)-1:
self.SourceFile.write("\"" + "@"+ X.upper() + "\"" + "\n")
else:
self.SourceFile.write("\"" + "@"+ X.upper() + "\"" + ",\n")
Counter +=1
self.SourceFile.write("};\n")
def WriteMaps(self):
for Key in self.FunctionsDict:
print(Key)
self.HeaderFile.write("extern const char* "+ Key[1:]+ "[];\n")
self.SourceFile.write("const char* "+ Key[1:]+ "[] = {\n")
Counter = 0
for X in self.FunctionsDict[Key]:
if Counter == len(self.FunctionsDict[Key])-1:
self.SourceFile.write("\"" + "@"+ X.upper() + "\"" + "\n")
else:
self.SourceFile.write("\"" +"@"+ X.upper() + "\"" + ",\n")
Counter +=1
self.SourceFile.write("};\n")
def WriteLhsList(self):
self.SourceFile.write("const struct _SCRIPT_ENGINE_TOKEN Lhs[RULES_COUNT]= \n{\n")
self.HeaderFile.write("extern const struct _SCRIPT_ENGINE_TOKEN Lhs[RULES_COUNT];\n")
Counter = 0
for Lhs in self.LhsList:
if Counter == len(self.LhsList)-1:
self.SourceFile.write("\t{NON_TERMINAL, " + "\"" + Lhs + "\"}" + "\n")
else:
self.SourceFile.write("\t{NON_TERMINAL, " + "\"" + Lhs + "\"}" + ",\n")
Counter +=1
self.SourceFile.write("};\n")
def GetType(self,Var):
if self.IsNoneTerminal(Var):
return "NON_TERMINAL"
elif self.IsSemanticRule(Var):
return "SEMANTIC_RULE"
elif Var == "eps":
return "EPSILON"
elif Var in self.SPECIAL_TOKENS:
return "SPECIAL_TOKEN"
elif Var[0] == "_":
return Var[1:].upper()
else:
return "KEYWORD"
def WriteRhsList(self):
self.SourceFile.write("const struct _SCRIPT_ENGINE_TOKEN Rhs[RULES_COUNT][MAX_RHS_LEN]= \n{\n")
self.HeaderFile.write("extern const struct _SCRIPT_ENGINE_TOKEN Rhs[RULES_COUNT][MAX_RHS_LEN];\n")
Counter =0
for Rhs in self.RhsList:
self.SourceFile.write("\t{")
C = 0
for Var in Rhs:
if C == len(Rhs) -1:
self.SourceFile.write("{"+self.GetType(Var) +", "+"\"" + Var + "\"}" )
else:
self.SourceFile.write("{"+self.GetType(Var) +", "+"\"" + Var + "\"}," )
C += 1
if Counter == len(self.RhsList)-1:
self.SourceFile.write("}\n")
else:
self.SourceFile.write("},\n")
Counter+= 1
self.SourceFile.write("};\n")
def WriteRhsSize(self):
self.SourceFile.write("const unsigned int RhsSize[RULES_COUNT]= \n{\n")
self.HeaderFile.write("extern const unsigned int RhsSize[RULES_COUNT];\n")
Counter =0
for Rhs in self.RhsList:
if Counter == len(self.RhsList)-1:
self.SourceFile.write( str(len(Rhs)) + "\n" )
else:
self.SourceFile.write( str(len(Rhs)) + ",\n" )
Counter+= 1
self.SourceFile.write("};\n")
def WriteTerminalList(self):
self.SourceFile.write("const char* TerminalMap[TERMINAL_COUNT]= \n{\n")
self.HeaderFile.write("extern const char* TerminalMap[TERMINAL_COUNT];\n")
Counter = 0
for X in self.TerminalList:
if Counter == len(self.TerminalList)-1:
self.SourceFile.write("\"" + X + "\"" + "\n")
else:
self.SourceFile.write("\"" + X + "\"" + ",\n")
Counter +=1
self.SourceFile.write("};\n")
def WriteNoneTermianlList(self):
self.SourceFile.write("const char* NoneTerminalMap[NONETERMINAL_COUNT]= \n{\n")
self.HeaderFile.write("extern const char* NoneTerminalMap[NONETERMINAL_COUNT];\n")
Counter = 0
for X in self.NonTerminalList:
if Counter == len(self.NonTerminalList)-1:
self.SourceFile.write("\"" + X + "\"" + "\n")
else:
self.SourceFile.write("\"" + X + "\"" + ",\n")
Counter +=1
self.SourceFile.write("};\n")
def WriteParseTable(self):
self.SourceFile.write("const int ParseTable[NONETERMINAL_COUNT][TERMINAL_COUNT]= \n{\n")
self.HeaderFile.write("extern const int ParseTable[NONETERMINAL_COUNT][TERMINAL_COUNT];\n")
i = 0
for X in self.NonTerminalList:
j = 0
self.SourceFile.write("\t{")
for y in self.TerminalList:
self.SourceFile.write(str(self.ParseTable[i][j]))
if j != len(self.TerminalList)-1:
self.SourceFile.write("\t\t,")
j += 1
if i == len(self.NonTerminalList)-1:
self.SourceFile.write("\t}\n")
else:
self.SourceFile.write("\t},\n")
i +=1
self.SourceFile.write("};\n")
def FindAllFirsts(self):
self.FirstDict = {}
for Symbol in self.NonTerminalList:
self.FirstDict[Symbol] = set()
t = 0
while True:
Updated = False
i = 0
for Lhs in self.LhsList:
Rhs = self.RhsList[i]
Temp = set(self.FirstDict[Lhs])
if Rhs[0] == "eps":
pass
elif self.IsNoneTerminal(Rhs[0]):
self.FirstDict[Lhs] = self.FirstDict[Lhs].union(self.FirstDict[Rhs[0]])
p = 0
while self.IsNullable(Rhs[p]):
self.FirstDict[Lhs] = self.FirstDict[Lhs].union(self.FirstDict[Rhs[p+1]])
p += 1
elif self.IsSemanticRule(Rhs[0]):
if self.IsNoneTerminal(Rhs[0]):
self.FirstDict[Lhs] = self.FirstDict[Lhs].union(self.FirstDict[Rhs[1]])
else:
self.FirstDict[Lhs].add(Rhs[1])
else:
self.FirstDict[Lhs].add(Rhs[0])
i += 1
if Temp != self.FirstDict[Lhs]:
Updated = True
p += 1
if not Updated:
break;
def PrintFirsts(self):
for Id in self.FirstDict:
print(Id, end=": ")
for X in self.FirstDict[Id]:
print(X,end = " ")
print()
def GetNoneTerminalId(self, nonterminal):
for i in range(len(self.NonTerminalList)):
if nonterminal == self.NonTerminalList[i]:
return i
return -1
def GetTerminalId(self, Terminal):
for i in range(len(self.TerminalList)):
if Terminal == self.TerminalList[i]:
return i
return -1
def FillParseTable(self):
self.ParseTable = [[self.INVALID for y in range(len(self.TerminalList))] for X in range(len(self.NonTerminalList))]
RuleId = 0
for Lhs in self.LhsList:
i = self.GetNoneTerminalId(Lhs)
j = 0
for Terminal in self.TerminalList:
if Terminal in self.PredictDict[RuleId]:
if i ==34 and j ==3:
dccc=3
if self.ParseTable[i][j] == self.INVALID:
self.ParseTable[i][j] = RuleId
else:
print("Error! Input grammar is not LL1.")
exit()
j += 1
RuleId += 1
def PrintParseTable(self):
print("\t", end = "")
for j in range(len(self.TerminalList)):
print(self.TerminalList[j], end= "\t")
print()
for i in range(len(self.NonTerminalList)):
print(self.NonTerminalList[i], end= "\t")
for j in range(len(self.TerminalList)):
if self.ParseTable[i][j] == self.INVALID:
print(".", end= "\t")
else:
print(self.ParseTable[i][j], end= "\t")
print()
def FindAllPredicts(self):
self.PredictDict = {}
for i in range(len(self.LhsList)):
self.PredictDict[i] = set()
i = 0
for Lhs in self.LhsList:
Rhs = self.RhsList[i]
IsRightNullable = True
for Symbol in Rhs:
if self.IsSemanticRule(Symbol):
pass
elif Symbol == "eps":
IsRightNullable = True
break
elif self.IsNoneTerminal(Symbol):
self.PredictDict[i] |= self.FirstDict[Symbol]
if not self.IsNullable(Symbol):
IsRightNullable = False
break
else:
self.PredictDict[i].add(Symbol)
IsRightNullable = False
break
if IsRightNullable:
self.PredictDict[i] |= self.FollowDict[Lhs]
i += 1
def print_predicts(self):
for Key in self.PredictDict:
print(Key, end=": ")
for X in self.PredictDict[Key]:
print(X,end = " ")
print()
def FindAllFollows(self):
self.FollowDict = {}
for Symbol in self.NonTerminalList:
self.FollowDict[Symbol] = set()
if Symbol == self.Start:
self.FollowDict[Symbol].add('$')
t = 0
while True:
Updated = False
i = 0
for Lhs in self.LhsList:
Rhs = self.RhsList[i]
p = 0
for Symbol in Rhs:
if self.IsNoneTerminal(Symbol):
Temp = set(self.FollowDict[Symbol])
if p == len(Rhs)-1:
self.FollowDict[Symbol] = self.FollowDict[Symbol].union(self.FollowDict[Lhs])
else:
NextVar = self.GetNextVar(Rhs, p)
if self.IsNoneTerminal(NextVar):
self.FollowDict[Symbol] = self.FollowDict[Symbol].union(self.FirstDict[NextVar])
if self.IsNullable(NextVar):
self.FollowDict[Symbol] = self.FollowDict[Symbol].union(self.FollowDict[NextVar])
elif self.IsSemanticRule(NextVar):
pass
else:
self.FollowDict[Symbol].add(NextVar)
if p == len(Rhs)-2:
NextVar = self.GetNextVar(Rhs, p)
if self.IsNullable(NextVar):
self.FollowDict[Symbol] = self.FollowDict[Symbol].union(self.FollowDict[Lhs])
self.FollowDict[Lhs] = self.FollowDict[Lhs].union(self.FollowDict[NextVar])
if Temp != self.FollowDict[Symbol]:
Updated = True
p += 1
i += 1
t += 1
if not Updated:
break
def GetNextVar(self, Rhs, p):
if p == len(Rhs)-1:
return None
X = p +1
while self.IsSemanticRule(Rhs[X]) and X + 1 < len(Rhs):
X+=1
return Rhs[X]
def PrintFollows(self):
for Key in self.FollowDict:
print(Key, end=": ")
for X in self.FollowDict[Key]:
print(X,end = " ")
print()
def IsNoneTerminal(self,X):
if X[0].isupper():
return True
else:
return False
def IsSemanticRule(self, X):
if X[0] == '@':
return True
else:
return False
def IsNullable(self, s):
if not s[0].isupper():
return False
i = 0
for Lhs in self.LhsList:
Rhs = self.RhsList[i]
if Lhs == s:
if Rhs[0] == "eps":
return True
p = 0
while True:
if self.IsNullable(Rhs[p]):
return True
else:
break
p += 1
i +=1
return False