#-*- coding:utf-8 -*-
EOF, COMMAND, PARAMETER = "EOF", "COMMAND", "PARAMETER"
importsysclassToken(object):def __init__(self, type, value):
self.type=type
self.value=valuedef __str__(self):return 'Token({type}, {value})'.format(
type=self.type,
value=repr(self.value)
)def __repr__(self):return self.__str__()classLexer(object):def __init__(self, text):
self.text=text
self.pos=0
self.current_char= self.text[self.pos] if len(text) > 1 elseNonedeferror(self):raise Exception("Error parsing input")defadvance(self):
self.pos+= 1
if self.pos > len(self.text) - 1:
self.current_char= None #Indicates end of input
else:
self.current_char=self.text[self.pos]defskip_whitespace(self):while self.current_char is not None andself.current_char.isspace():
self.advance()defcheck_whitespace(self):if self.current_char is not None andself.current_char.isspace():
self.advance()elif self.current_char isNone:pass
else:raise Exception("Must separate commands with whitespace")#assume command is always two char form and have to be separated by space at the end of command
defcommand(self):
result= ""result+=self.current_char
self.advance()if self.current_char isNone:
self.error()
result+=self.current_char
self.advance()
self.check_whitespace()returnresultdefparameter(self):
result= ""
while self.current_char is not None and(
self.current_char.isalpha()or self.current_char.isdigit() or self.current_char == "."):
result+=self.current_char
self.advance()returnresultdefget_next_token(self):while self.current_char is notNone:ifself.current_char.isspace():
self.skip_whitespace()if self.current_char == "-":returnToken(COMMAND, self.command())if self.current_char.isalpha() orself.current_char.isdigit():returnToken(PARAMETER, self.parameter())
self.error()returnToken(EOF, None)classParameterInterpreter(object):def __init__(self, lexer):
self.lexer=lexer
self.current_token=self.lexer.get_next_token()
self.commands={}#p:parameter h:help r:required rp:required_parameter t:triggered
def put_command(self, command, required=False, require_parameter=False, _help=None):"""customize commands"""
if notself.commands.get(command, None):
self.commands[command]= {"p": None, "h": _help, "r": required, "rp": require_parameter, "t": False}else:raise Exception("command already exists!")deferror(self):raise Exception('Invalid syntax')defeat(self, type):if self.current_token.type ==type:
self.current_token=self.lexer.get_next_token()else:
self.error()defbase(self):"""COMMAND"""
#to handle the prefix of a command
token =self.current_tokenif token.value inself.commands.keys():
self.eat(COMMAND)
self.commands[token.value]["t"] =Trueelse:raise Exception("{} command not defined".format(token.value))returntokendefcombination(self):"""COMMAND ARGUMENT"""command_token=self.base()
token=self.current_tokenif self.commands[command_token.value]["rp"] and token.type ==PARAMETER:
self.eat(PARAMETER)
self.commands[command_token.value]["p"] =token.valueelif not self.commands[command_token.value]["rp"] and token.type ==PARAMETER:raise Exception("{} does not take a parameter".format(command_token.value))elif not self.commands[command_token.value]["rp"]:return
else:raise Exception("{} requires a parameter".format(command_token.value))defhandle_argument(self):"""(COMMAND ARGUMENT)*
:return result dictionary"""
while self.current_token.type ==COMMAND:
self.combination()if self.current_token.type !=EOF:
self.error()returnself.commandsdefmain():try:
args=sys.argv
text= " ".join(args[1:])except:
EOFError()
text= ""l=Lexer(text)
pi=ParameterInterpreter(l)
pi.put_command("-s", require_parameter=True, required=True)
pi.put_command("-l", require_parameter=False)
pi.put_command("-w", require_parameter=False)
pi.put_command("-a", require_parameter=False)
result=pi.handle_argument()print(result)if __name__ == '__main__':
main()