python简易实现自定义参数的argparser

  对参数解析这一块挺感兴趣,想用之前了解到的知识来处理命令行参数,想到了解释器的工作原理,于是便简单实现了一个以解释的思想来处理命令行参数的方法。很早就想学习编译原理相关的知识不过一直没有付诸于实践,导致无法清晰的理顺命令及参数之间的逻辑,ParameterInterpreter处理参数的逻辑没有想好。

 

# -*- coding:utf-8 -*-
EOF, COMMAND, PARAMETER = "EOF", "COMMAND", "PARAMETER"
import sys


class Token(object):
    def __init__(self, type, value):
        self.type = type
        self.value = value

    def __str__(self):
        return 'Token({type}, {value})'.format(
            type=self.type,
            value=repr(self.value)
        )

    def __repr__(self):
        return self.__str__()


class Lexer(object):
    def __init__(self, text):
        self.text = text
        self.pos = 0
        self.current_char = self.text[self.pos] if len(text) > 1 else None

    def error(self):
        raise Exception("Error parsing input")

    def advance(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]

    def skip_whitespace(self):
        while self.current_char is not None and self.current_char.isspace():
            self.advance()

    def check_whitespace(self):
        if self.current_char is not None and self.current_char.isspace():
            self.advance()
        elif self.current_char is None:
            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
    def command(self):
        result = ""
        result += self.current_char
        self.advance()
        if self.current_char is None:
            self.error()
        result += self.current_char
        self.advance()
        self.check_whitespace()
        return result

    def parameter(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()
        return result

    def get_next_token(self):

        while self.current_char is not None:

            if self.current_char.isspace():
                self.skip_whitespace()

            if self.current_char == "-":
                return Token(COMMAND, self.command())

            if self.current_char.isalpha() or self.current_char.isdigit():
                return Token(PARAMETER, self.parameter())

            self.error()

        return Token(EOF, None)


class ParameterInterpreter(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 not self.commands.get(command, None):
            self.commands[command] = {"p": None, "h": _help, "r": required, "rp": require_parameter, "t": False}
        else:
            raise Exception("command already exists!")

    def error(self):
        raise Exception('Invalid syntax')

    def eat(self, type):
        if self.current_token.type == type:
            self.current_token = self.lexer.get_next_token()
        else:
            self.error()

    def base(self):
        """COMMAND"""
        # to handle the prefix of a command
        token = self.current_token
        if token.value in self.commands.keys():
            self.eat(COMMAND)
            self.commands[token.value]["t"] = True
        else:
            raise Exception("{} command not defined".format(token.value))
        return token

    def combination(self):
        """COMMAND ARGUMENT"""
        command_token = self.base()
        token = self.current_token
        if self.commands[command_token.value]["rp"] and token.type == PARAMETER:
            self.eat(PARAMETER)
            self.commands[command_token.value]["p"] = token.value
        elif 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))

    def handle_argument(self):
        """(COMMAND ARGUMENT)*

            :return result dictionary
        """
        while self.current_token.type == COMMAND:
            self.combination()

        if self.current_token.type != EOF:
            self.error()
        return self.commands


def main():
    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()

  测试结果:

现在正在将该argparser用C语言重写,打算学习了编译原理过后将代码重构一下,顺着这个思路写一个argparser的工具模块。

转载于:https://www.cnblogs.com/hollin/p/9790915.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值