#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()`