越位语言是一种
...该语言中声明(块)的范围由它们的缩进表示。
此类语言的示例包括 Python、Boo、Nemerle、YAML 等等。
所以我的问题是:我如何真正解析这些?如何解决制表符与空格的问题(两个制表符或 8 个空格是否等效)?解析器生成器在这里有什么帮助吗,还是我必须自己手动编写词法分析器/解析器?
越位语言是一种
...该语言中声明(块)的范围由它们的缩进表示。
此类语言的示例包括 Python、Boo、Nemerle、YAML 等等。
所以我的问题是:我如何真正解析这些?如何解决制表符与空格的问题(两个制表符或 8 个空格是否等效)?解析器生成器在这里有什么帮助吗,还是我必须自己手动编写词法分析器/解析器?
解决制表符与空格问题的最简单方法是禁止空格和制表符的组合(例如,这是在 F# 中所做的)。任何现代编辑器都允许将制表符转换为一定数量的空格。
至于您是否需要放弃解析器生成器,可能不需要,但您将不得不在某处破解越位识别。这可能需要您发挥一些创造力。根据浏览 F# 源代码,他们似乎使用了词法分析后步骤来创建表示越位语言元素的附加标记。
如何解决制表符与空格的问题(两个制表符或 8 个空格是否等效)?
如果两个制表符等于八个空格,这取决于编辑器的设置。
正如发起者所表达的,越位规则提到了两个连续代码行的相对定位,而不是空格的绝对数量。这是一本很好的读物,可以帮助您更好地理解(和一些引用):
“空格在 Python 源代码中很重要。”
不,一般不会。只有语句的缩进级别很重要(即语句最左边的空格)。在其他任何地方,空格并不重要,可以随意使用,就像在任何其他语言中一样。您还可以在任何地方插入不包含任何内容(或仅包含任意空格)的空行。
此外,缩进的确切数量根本不重要,而只有嵌套块的相对缩进(相对于彼此)。[...]
值得一提的是,Haskell 也是基于缩进和可选的 { foo; 酒吧; 等 } 当空格不方便时。我用Parsec编写了一个简单的基于缩进的解析器,它看起来像 Lisp,但缩进表示运算符应用程序。括号只能在一行中使用。
(aaa bb) cc
e fffff (ggg hhh) iii
jjj kkk
ddd
这里aaa
适用于bb
。结果是三元函数。它应用于参数cc
,e
应用于一个参数,并且ddd
。了解应用程序如何基于列对齐,而不是 X 空格。
解析器也可能要简单得多。
您有几个选项可以选择制表符和空格:或者禁止混合制表符和空格,假设制表符与空格的比例固定,或者允许程序员根据每个项目或每个源文件来决定(某种“#pragma tab (4)" 样式指令以允许制表符和/或更改它们所代表的空格数)。
ANTLR 3 等解析器生成器可以轻松应对;我自己一直在玩弄一个例子,编译到它的 C# 目标。DirkGently 答案中的链接解释了直接转换为代码的 Python 算法。我的方法只是为空格和换行符定义单独的标记,并覆盖词法分析器使用的“发出标记”函数以动态插入额外的缩进/缩进标记。事实证明,这比我见过的其他覆盖“获取最后一个令牌”函数的方法更容易实现,但两者都运行得很好。
我自己得到了一个解决方案,我像嵌套树的块一样分析代码。对于括号的部分,我只是使用了正常的方法。