简单的解析器,但不是计算器

时间:2018-01-09 23:53:51

标签: python parsing compiler-construction

我正在尝试编写一个非常简单的解析器。我在SO和互联网上阅读了类似的问题,但我能找到的只限于"算术类似于"的东西。

我有一个非常简单的DSL,例如:

ELEMENT TYPE<TYPE> elemName {
    TYPE<TYPE> memberName;
}

<TYPE>部分是可选的,仅对某些类型有效。

根据我的阅读,我尝试在Python中编写一个递归下降解析器,但有些事情我似乎无法理解:

  1. 如何查找超过1个字符的令牌?
  2. 如何分解不同部分的文字?例如,在TYPE之后我可以有一个空格或<或一个空格后面跟<。我该如何解决这个问题?

2 个答案:

答案 0 :(得分:3)

简短回答

所有问题归结为您在解析字符串之前没有对字符串进行标记。

答案很长

解析过程实际上分为两个不同的部分: lexing 解析

乐星

您对解析的看法似乎缺少的是令牌化或lexing。它是将字符串转换为标记流(即单词)的过程。在询问如何分解不同部分的文本时,您正在寻找的是什么?

您可以通过使用re检查字符串与正则表达式列表来自行完成,或者您可以使用一些众所周知的库,例如PLY。虽然如果你使用Python3,我会偏向于我写的一个lexing-parsing librairy,这是ComPyl

所以继续使用ComPyl,您正在寻找的语法似乎如下。

from compyl.lexer import Lexer

rules = [
    (r'\s+', None),
    (r'\w+', 'ID'),
    (r'< *\w+ *>', 'TYPE'), # Will match your <TYPE> token with inner whitespaces
    (r'{', 'L_BRACKET'),
    (r'}', 'R_BRACKET'),
]

lexer = Lexer(rules=rules, line_rule='\n')
# See ComPyl doc to figure how to proceed from here

请注意,第一条规则(r'\s+', None)实际上解决了有关空白的问题。它基本上告诉词法分析器匹配任何空白字符并忽略它们。当然,如果您不想使用lexing工具,只需在自己的re实现中添加类似的规则。

解析

您似乎想编写自己的 LL(1)解析器,因此我将简要介绍该部分。只知道有很多工具可以为你做(PLY和ComPyl librairies提供LR(1)解析器,它更强大但更难手写,看看LL(1)和LR(1)之间的区别here)。

只需注意,既然您知道如何对字符串进行标记,那么如何查找超过1个字符的标记?的问题已经解决。您现在正在解析,而不是字符流,而是一个封装匹配的的标记流。

答案 1 :(得分:2)

Olivier关于lexing / tokenizing然后解析的答案是有帮助的。

但是,对于相对简单的情况,一些解析工具能够处理您的需求,而无需单独的标记步骤。 parsy就是其中之一。您可以从较小的构建块构建解析器 - 有很好的文档可以提供帮助。

使用parsy完成语法类型的解析器示例如下:http://parsy.readthedocs.io/en/latest/howto/other_examples.html#proto-file-parser。 它比你的复杂得多,但展示了可能的东西。在允许空格(但不是必需的)的情况下,它使用lexeme实用程序(在顶部定义)来使用可选的空格。

您可能需要加强对空白是否必要的位置以及可选位置的理解,以及您真正意味着什么样的空白。