# Stephanie Taylor # CS333 # Spring 2026 # Demonstrate parser for LL language (with BNF as grammar) # Demonstrate parser for similar language with EBNF as grammar, enforcing left-associativitys import simple_tokenizer as tokenizer # Whenever we enter a parseX function, we have already retrieved the first token in that statement. class E_Node: def __init__( self, left, op, right ): self.left = left self.op = op self.right = right def printTree( self, spaces = "" ): print( spaces + "E_Node with op", self.op ) self.left.printTree( spaces + " " ) self.right.printTree( spaces + " " ) class T_Node: def __init__( self, val ): self.val = val def printTree( self, spaces = "" ): print( spaces + "T_Node", self.val ) # Parse enforcing left-associativity # Start Symbol: E # Non-terminals: 0 | ... | 9, +, - # E -> T Op E | T # Op -> + | - # T -> 0 | ... | 9 class BNF_LL_Parser: def __init__( self, filename=None, lines=None ): self.tokenizer = tokenizer.Tokenizer( filename, lines ) self.ast = None self.token = None def getToken(self): self.token = self.tokenizer.getToken() #print "Getting Token: ", self.token def parseT( self ): t = T_Node( self.token.value ) self.getToken() return t def parseE(self): subtree = self.parseT() if self.token is not None: op = self.token.value self.getToken() # move into first token of next expression subtree = E_Node( subtree, op, self.parseE() ) return subtree def buildTree( self ): self.getToken() self.root = self.parseE() # Parse enforcing left-associativity # Start Symbol: E # Non-terminals: 0...9, +, - # E -> T { Op T } # Op -> + | - # T -> 0 | ... | 9 class EBNF_Parser: def __init__( self, filename=None, lines=None ): self.tokenizer = tokenizer.Tokenizer( filename, lines ) self.ast = None self.token = None def getToken(self): self.token = self.tokenizer.getToken() #print "Getting Token: ", self.token def parseT( self ): t = T_Node( self.token.value ) self.getToken() return t def parseE(self): subtree = self.parseT() while self.token is not None and self.token.value in "+-": op = self.token.value self.getToken() # move into first token of next expression # and return a Tree that puts any other +/- operations we have already # seen in the left kid, so they are evaluated first. subtree = E_Node( subtree, op, self.parseT() ) return subtree def buildTree( self ): self.getToken() self.root = self.parseE() if __name__ == "__main__": # p = EBNF_Parser( lines=["3-4+5"] ) p = BNF_LL_Parser( lines=["3-4+5"] ) p.buildTree() p.root.printTree( "" )