【问题标题】:Parsing blocks as Python将块解析为 Python
【发布时间】:2018-05-01 17:08:23
【问题描述】:

我正在用 JFlex + CUP 编写一个词法分析器 + 解析器,我希望在块方面具有类似 Python 的语法;也就是说,缩进标记了块级。

我不确定如何解决这个问题,以及是否应该在词汇或语法级别完成。

我目前的方法是在词法级别解决问题 - 换行符被解析为指令分隔符,当处理一个时,我将词法分析器移动到一种特殊状态,该状态检查新行前面有多少字符并记住最后一行从哪一列开始,并相应地引入和打开块或关闭块字符。

但是,我遇到了各种各样的麻烦。例如:

  1. JFlex 无法匹配空字符串,因此我的指令需要在每个换行符后至少有一个空格。
  2. 我无法使用这种方法同时关闭两个块。

我的方法正确吗?我应该做不同的事情吗?

【问题讨论】:

    标签: python grammar indentation jflex cup


    【解决方案1】:

    您在词法分析器而不是解析器中处理缩进的方法是正确的。好吧,这两种方法都可行,但这通常是更简单的方法,而且 Python 本身(或至少 CPython 和 PyPy)就是这样做的。

    我对 JFlex 了解不多,你也没有给我们任何代码,但我可以笼统地解释一下。

    对于您的第一个问题,您已经在换行符之后将词法分析器置于特殊状态,因此“抓取 0 个或更多空格”应该可以通过逃避正常的事物流并仅针对行。

    对于第二个问题,最简单的解决方案(也是 Python 使用的解决方案)是保留一堆缩进。我将演示一些比 Python 更简单的东西。

    第一:

    indents = [0]
    

    在每个换行符之后,获取 0 个或多个空格作为 spaces。那么:

    if len(spaces) == indents[-1]:
        pass
    elif len(spaces) > indents[-1]:
        indents.append(len(spaces))
        emit(INDENT_TOKEN)
    else:
        while len(spaces) != indents[-1]:
            indents.pop()
            emit(DEDENT_TOKEN)
    

    现在您的解析器只看到INDENT_TOKENDEDENT_TOKEN,它们与类似C 语言的OPEN_BRACE_TOKENCLOSE_BRACE_TOKEN 没有什么不同。

    你想要更好的错误处理——提出某种标记器错误而不是隐含的IndexError,也许使用<而不是!=,这样你就可以检测到你已经走得太远而不是筋疲力尽了堆栈(如果您想继续发出更多错误而不是在第一个错误时放弃,以便更好地恢复错误)等。

    对于现实生活中的示例代码(带有错误处理、制表符和空格、反斜杠换行符转义、处理括号表达式内的非语法缩进等),请参阅tokenize 文档和源代码标准库。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-12-31
      • 1970-01-01
      • 2018-10-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多