#VendingMachineParser.py import shlex,sys from cStringIO import StringIO class VendingCmd: def __init__(self,cmd,**kwargs): self.cmd = cmd self.__dict__.update(kwargs) def __repr__(self): s = '%s(' % self.cmd for item in self.__dict__.items(): if item[0] != 'cmd': s += ' %s=%s' % item return s + ' )' class Parser: def __init__(self,aStream=sys.stderr): self.outstream=aStream def next_token(self): tok = self.lexer.get_token() if not tok: self.err('Unexpected end of file') return tok def next_number(self,func=int): tok = self.next_token() if tok: try: tok = func(tok) except ValueError: return self.err('Expected a number, not '+tok) return tok def next_money(self): num=self.next_number() if num not in (10,50,100,500,1000): return self.err('Unexpected money type') return num def next_button(self): tok=self.lexer.get_token() if tok not in ('black','white','sugar_black','sugar_white'): return self.err('Unexpected button type') return tok def err(self,msg): self.outstream.write(self.lexer.error_leader()+msg+'\n') def parse_put(self): money = self.next_money() if money: return VendingCmd('put',arg=money) def parse_push(self): button=self.next_button() if button: return VendingCmd('push',arg=button) def parse(self,aString=None,aStream=None,aName=None): if aString: aStream=StringIO(aString) lexer=shlex.shlex(aStream,aName) lexer.source = 'include' lexer.wordchars += '.,-' self.lexer=lexer cmds = [] while 1: tok = lexer.get_token() if not tok: break try: parser = getattr(self,'parse_%s'%tok) except: self.err('Unknown command: '+tok) continue cmd=parser() if cmd is None: continue cmds.append(cmd) return cmds if __name__=='__main__': err=StringIO() p=Parser(err) cmds=p.parse("put 30 put 50 put 1000") print cmds print `err.getvalue()`