【问题标题】:How do I implement a lexer given that I have already implemented a basic regular expression matcher?鉴于我已经实现了基本的正则表达式匹配器,如何实现词法分析器?
【发布时间】:2012-08-28 09:48:07
【问题描述】:

我正在尝试实现一个词法分析器来取乐。我已经实现了一个基本的正则表达式匹配器(首先将模式转换为 NFA,然后再转换为 DFA)。现在我对如何继续一无所知。

我的词法分析器将获取标记列表及其相应的正则表达式。用于创建词法分析器的一般算法是什么?

我考虑过(或)对所有正则表达式进行运算,但后来我无法确定匹配了哪个特定令牌。即使我扩展我的正则表达式模块以在匹配成功时返回匹配的模式,我如何在匹配器中实现前瞻?

【问题讨论】:

    标签: regex algorithm lexer


    【解决方案1】:

    假设您有一个工作正则表达式,regex_match 返回一个布尔值(如果字符串满足正则表达式则为真)。首先,您需要有一个有序的标记列表(每个都带有正则表达式)tokens_regex,顺序很重要,因为顺序将规定优先级

    一种算法可以是(这不一定是唯一的)

    1. 编写一个过程next_token,它接受一个字符串,并返回第一个标记、它的值和剩余的字符串(或者 - 如果是非法/忽略字符 - 无,有问题的字符和剩余的字符串)。 注意:这必须尊重优先级,并且应该找到最长的标记。
    2. 编写一个过程lex,递归调用next_token

    .

    类似这样的东西(用 Python 编写):

    tokens_regex = [ (TOKEN_NAME, TOKEN_REGEX),...] #order describes precedence
    
    def next_token( remaining_string ):
        for t_name, t_regex in tokens_regex: # check over in order of precedence
            for i in xrange( len(remaining_string), 0, -1 ): #check longest possibilities first (there may be a more efficient method).
                if regex_match( remaining_string[:i], t_regex ):
                    return t_name, remaining_string[:i], remaining_string[i:]
        return None, remaining_string[0], remaining_string[1:] #either an ignore or illegal character
    
    def lex( string ):
        tokens_so_far = []
        remaining_string = string
        while len(remaining_string) > 0:
            t_name, t_value, string_remaining = next_token(remaining_string)
            if t_name is not None:
                tokens_so_far.append(t_name, t_value)
            #elif not regex_match(t_value,ignore_regex):
                #check against ignore regex, if not in it add to an error list/illegal characters
       return tokens_so_far
    

    添加一些东西来改进您的词法分析器:忽略正则表达式、错误列表和位置/行号(针对这些错误或标记)。

    玩得开心!祝你制作解析器好运:)。

    【讨论】:

    • 我对这种方法的关注是它的效率。对字符串的子字符串运行 regex_match 不会花费很多时间吗?
    • 另外,我认为 next_token 中的 return 语句应该是 return t_name, remaining_string[:i], remaining_string[i:]。是的,解析器将是我的下一个练习。
    • 效率低下,但这是我想出的第一件事,对不起!...更好的方法是尝试更短的字符串,看看你能走多远,直到它不可能是一个标记,这将不得不使用另一个正则表达式函数(类似于“考虑前 n 个字符可能是一个标记”)......这有什么意义吗?这样的效率应该会好很多。
    • @Likhit 感谢您的接受,我正在对这一行进行改进(我在上面暗示过)。玩得开心!
    【解决方案2】:

    我也做过几乎相同的事情。我这样做的方法是将所有表达式组合在一个非常大的 NFA 中,并将相同的东西转换为一个 DFA。这样做时,请跟踪每个相应的原始 DFA 中先前接受状态的状态及其优先级。

    生成的 DFA 将有许多处于接受状态的状态。您运行此 DFA,直到它接收到一个没有相应转换的角色。如果 DFA 处于接受状态,那么您将查看您的哪些原始 NFA 具有该接受状态。具有最高优先级的是您要返回的令牌。

    这不处理正则表达式前瞻。无论如何,这些通常并不是词法分析器工作真正需要的。那将是解析器的工作。

    这种词法分析器的运行速度与单个正则表达式几乎相同,因为它基本上只有一个 DFA 可以运行。您可以完全省略转换 NFA 以获得更快构建的算法,但运行速度更慢。算法基本相同。

    我写的词法分析器的源代码是github上的freely available,如果你想看看我是怎么做到的。

    【讨论】:

    • 谢谢,我去看看。不幸的是,我认为我需要重写我的 DFA 和 NFA 类来实现一种机制来跟踪哪个 DFA 与字符串匹配。
    猜你喜欢
    • 2013-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-15
    • 2012-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多