if self lex token ='num'leaf numnode(self lex match('num')return leaf elif self lex token ='var'leaf varnode(self lex valueself lex startself lex scan(return leaf elif self lex token ='('self lex scan(tree self expr(self lex match(')'return tree elseraise syntaxerror(################################################################################self-test codeuse my parserparser ' tester ################################################################################if __name__ ='__main__'import testparser testparser test(parser'parser 'run with parser class here notice the way we handle undefined name exceptions in errorcheck when exceptions are derived from the built-in exception classtheir instances automatically return the arguments passed to the exception constructor call as tuple in their args attribute-convenient for use in string formatting here also notice that the new parser reuses the same scanner module as well to catch errors raised by the scannerit also imports the specific classes that identify the scanner' exceptions both the scanner and the parser can raise exceptions on errors (lexical errorssyntax errorsand undefined name errorsthey're caught at the top level of the parserand they end the current parse there' no need to set and check status flags to terminate the recursion since math is done using integersfloating-point numbersand python' operatorsthere' usually no need to trap numeric overflow or underflow errors but as isthe parser doesn' handle errors such as division by zero--such python exceptions make the parser system exit with python stack trace and message uncovering the cause and fix for this is left as suggested exercise when parser is run as top-level programwe get the same test code output as for parser in factit reuses the very same test code--both parsers pass in their parser class object to testparser test and since classes are also objectswe can also pass this version of the parser to testparser' interactive looptestparser interact(parser parserthe new parser' external behavior is identical to that of the originalso won' repeat all its output here (run this live for firsthand lookof notethoughthis parser supports both use as top-level scriptand package imports from other directoriessuch as the pytree viewer we'll use in moment python no longer searches module' custom language parsers