def CompFirst(self): # uses the special null production token NULLTOKEN # snarfed directly from Aho+Ullman (terminals glossed) First = kjSet.NewDG([]) # repeat the while loop until no change is made to First done = 0 while not done: done = 1 # assume we're done until a change is made to First # iterate through all rules looking for a new arc to add # indicating Terminal > possible first token derivation # for R in self.Rules: GoalNonterm = R.Nonterm Bodylength = len(R.Body) # look through the body of the rule up to the token with # no epsilon production (yet seen) Bodyindex = 0 Processindex = 1 while Processindex: # unless otherwise indicated below, don't go to next token Processindex = 0 # if index is past end of body then record # an epsilon production for this nonterminal if Bodyindex >= Bodylength: if not kjSet.HasArc(First, GoalNonterm, NULLTOKEN): kjSet.AddArc(First, GoalNonterm, NULLTOKEN) done = 0 # change made to First else: # otherwise try to add firsts of this token # to firsts of the Head of the rule. Token = R.Body[Bodyindex] (type, name) = Token if type in (KEYFLAG, TERMFLAG): # try to add this terminal to First for GoalNonterm if not kjSet.HasArc(First, GoalNonterm, Token): kjSet.AddArc(First, GoalNonterm, Token) done = 0 elif type == NONTERMFLAG: # try to add each First entry for nonterminal # to First entry for GoalNonterm for FToken in kjSet.Neighbors(First, Token): if not kjSet.HasArc(First, GoalNonterm, FToken): kjSet.AddArc(First, GoalNonterm, FToken) done = 0 # does this nonterminal have a known e production? if kjSet.HasArc(First, Token, NULLTOKEN): # if so, process next token in rule Processindex = 1 else: raise TokenError, "unknown token type in rule body" #endif Bodyindex = Bodyindex + 1 #endwhile Processindex #endfor R in self.Rules #endwhile not done self.First = First
def FirstOfTail(self, Rule, TailIndex, Token=None): ''' computing the "first" of the tail of a rule followed by an optional terminal. doesn't include NULLTOKEN requires self.First to be computed ''' Result = kjSet.NewSet( [] ) # go through all tokens in rule tail so long as there is a # null derivation for the remainder Nullprefix = 1 BodyLength = len(Rule.Body) ThisIndex = TailIndex while Nullprefix and ThisIndex < BodyLength: RToken = Rule.Body[ThisIndex] (RTtype, RTname) = RToken if RTtype == NONTERMFLAG: for FToken in kjSet.Neighbors(self.First, RToken): if FToken != NULLTOKEN: kjSet.addMember(FToken, Result) #endfor # check whether this symbol might have a null production if not kjSet.HasArc(self.First, RToken, NULLTOKEN): Nullprefix = 0 elif RTtype in [KEYFLAG, TERMFLAG]: kjSet.addMember(RToken, Result) Nullprefix = 0 else: raise TokenError, "unknown token type in rule body" ThisIndex = ThisIndex + 1 #endwhile # add the optional token if given and Nullprefix still set if Nullprefix and Token != None: kjSet.addMember(Token, Result) return Result
def compFollowRule(self, Follow, R): done = 1 # work backwards in the rule body to # avoid retesting for epsilon nonterminals Bodylength = len(R.Body) # the tail of rule may expand to null EpsilonTail = 1 # loop starts at the last for BodyIndex in range(Bodylength-1, -1, -1): Token = R.Body[BodyIndex] (Ttype,Tname) = Token if Ttype not in (KEYFLAG, TERMFLAG, NONTERMFLAG): raise TokenError, "unknown token type in rule body" if Ttype in (KEYFLAG,TERMFLAG): # keywords etc cancel epsilon tail, otherwise ignore EpsilonTail = 0 continue # if the tail expands to epsilon, map # follow for the goal nonterminal to this token # and also follow for the tail nonterms if EpsilonTail: # add follow for goal for FToken in kjSet.Neighbors(Follow,R.Nonterm): if not kjSet.HasArc(Follow, Token, FToken): kjSet.AddArc(Follow, Token, FToken) # follow changed, loop again done = 0 # add follow for tail members #for Index2 in range(BodyIndex+1, Bodylength): # TailToken = R.Body[Index2] # for FToken in kjSet.Neighbors(Follow,TailToken): # if not kjSet.HasArc(Follow,Token,FToken): # kjSet.AddArc(Follow,Token,FToken) # done = 0 #endif EpsilonTail # if we are not at the end use First set for next token if BodyIndex != Bodylength-1: NextToken = R.Body[BodyIndex+1] (NTtype, NTname) = NextToken if NTtype in (KEYFLAG,TERMFLAG): if not kjSet.HasArc(Follow, Token, NextToken): kjSet.AddArc(Follow, Token, NextToken) done = 0 elif NTtype == NONTERMFLAG: for FToken in kjSet.Neighbors(self.First, NextToken): if FToken != NULLTOKEN: if not kjSet.HasArc(Follow, Token, FToken): kjSet.AddArc(Follow, Token, FToken) done = 0 continue # next token expands to epsilon: # add its follow, unless already done above for FToken in kjSet.Neighbors(Follow, NextToken): if not kjSet.HasArc(Follow, Token, FToken): kjSet.AddArc(Follow, Token, FToken) done = 0 else: raise TokenError, "unknown token type in rule body" # finally, check whether next iteration has epsilon tail if not kjSet.HasArc(self.First, Token, NULLTOKEN): EpsilonTail = 0 return done
def CompFollow(self): Follow = kjSet.NewDG( [] ) # put end marker on follow of start nonterminal kjSet.AddArc(Follow, self.StartNonterm, kjParser.ENDOFFILETOKEN) # now compute other follows using the rules; # repeat the loop until no change to Follow. done = 0 while not done: done = 1 # assume done unless Follow changes for R in self.Rules: #print R # work backwards in the rule body to # avoid retesting for epsilon nonterminals Bodylength = len(R.Body) EpsilonTail = 1 # the tail of rule may expand to null BodyIndex = Bodylength - 1 Last = 1 # loop starts at the last from types import TupleType while BodyIndex >= 0: Token = R.Body[BodyIndex] (Ttype,Tname) = Token if Ttype in (KEYFLAG,TERMFLAG): # keywords etc cancel epsilon tail, otherwise ignore EpsilonTail = 0 elif Ttype == NONTERMFLAG: # if the tail expands to epsilon, map # follow for the goal nonterminal to this token # and also follow for the tail nonterms if EpsilonTail: # add follow for goal for FToken in kjSet.Neighbors(Follow,R.Nonterm): if not kjSet.HasArc(Follow,Token,FToken): kjSet.AddArc(Follow,Token,FToken) #if type(FToken[0])==TupleType: # raise ValueError, "bad FToken"+`FToken` #print "new", Token, FToken done = 0 # follow changed, loop again # add follow for tail members #for Index2 in range(BodyIndex+1, Bodylength): # TailToken = R.Body[Index2] # for FToken in kjSet.Neighbors(Follow,TailToken): # if not kjSet.HasArc(Follow,Token,FToken): # kjSet.AddArc(Follow,Token,FToken) # done = 0 #endif EpsilonTail # if we are not at the end use First set for next token if not Last: NextToken = R.Body[BodyIndex+1] (NTtype, NTname) = NextToken if NTtype in (KEYFLAG,TERMFLAG): if not kjSet.HasArc(Follow,Token,NextToken): kjSet.AddArc(Follow,Token,NextToken) #print "next", Token, NextToken done = 0 elif NTtype == NONTERMFLAG: for FToken in kjSet.Neighbors(self.First, NextToken): if FToken != NULLTOKEN: if not kjSet.HasArc(Follow,Token,FToken): kjSet.AddArc(Follow,Token,FToken) #print "neighbor", Token, FToken done = 0 else: # next token expands to epsilon: # add its follow, unless already done above #if not EpsilonTail: for FToken in kjSet.Neighbors(Follow,NextToken): if not kjSet.HasArc(Follow,Token,FToken): kjSet.AddArc(Follow,Token,FToken) #print "epsilon", Token, FToken done = 0 else: raise TokenError, "unknown token type in rule body" #endif not Last # finally, check whether next iteration has epsilon tail if not kjSet.HasArc(self.First, Token, NULLTOKEN): EpsilonTail = 0 else: raise TokenError, "unknown token type in rule body" BodyIndex = BodyIndex - 1 Last = 0 # no longer at the last token of the rule #endwhile #endfor #endwhile self.Follow = Follow