left left self term(elseraise syntaxerror(def term(self)if self lex token ='num'val self lex match('num'return val elif self lex token ='var'if self lex value in self vars keys()val self vars[self lex valueself lex scan(return val elseraise undefinederror(self lex valueelif self lex token ='('self lex scan(val self expr(self lex match(')'return val elseraise syntaxerror(if __name__ ='__main__'import testparser testparser test(parser'parser 'numbers keys()eibtilook up name' value sub-expression self-test code test local parser if you study this code closelyyou'll notice that the parser keeps dictionary (self varsto manage variable namesthey're stored in the dictionary on set command and are fetched from it when they appear in an expression tokens are represented as stringswith an optional associated value ( numeric value for numbers and string for variable namesthe parser uses iteration (while loopsrather than recursion for the expr-tail and factor-tail rules other than this optimizationthe rules of the grammar map directly onto parser methodstokens become calls to the scannerand nested rule references become calls to other methods when the file parser py is run as top-level programits self-test code is executedwhich in turn simply runs canned test in the module shown in example - notice how the scanner converts numbers to strings with intthis ensures that all integer math invoked by the parser supports unlimited precisionsimply because it uses python integers which always provide the extra precision if needed (the separate python long type and syntax is no morealso notice that mixed integer/floating-point operations cast up to floating point since python operators are used to do the actual calculations along the way the expression language' division operator also inherits python ' true division model which retains remainders and returns floating point results regardless of operand types we custom language parsers