解析“off-side”(基于缩进的)语言

时间:2010-02-01 16:52:18

标签: language-design indentation compiler-theory

off-side语言是

的语言
  

......该语言的声明(块)的范围由它们的缩进表示。

此类语言的示例包括Python,Boo,Nemerle,YAML等等。

所以我的问题是:我如何实际解析这些?如何解决标签与空格问题(两个标签或8个空格是否等效)?解析器生成器在这里有任何帮助,还是我必须自己手动编写词法分析器/解析器?

6 个答案:

答案 0 :(得分:8)

Python有一个 lexer ,它生成 Indent Dedent 标记,相当于花括号(“{”,“}”) 。 Stack Overflow上甚至有一个example,这个词法分析器的实现很简单。

对于制表符与空格,Python只有一个编码convention:每个缩进级别使用4个空格。标签虽然是合法的语法。

答案 1 :(得分:4)

  

如何解决标签与空格问题(两个标签或8个空格是否相等)?

这取决于编辑器的设置,如果两个标签等于八个空格。

由发起者表达的偏离规则提到了两个连续代码行的相对位置,而不是空白的绝对数量。 Here这是一个很好的阅读,可以帮助你更好地理解(和一些引用):

  

“Whitespace在Python中很重要   源代码。“

     

不,不是一般的。只有   您的陈述的缩进级别   是重要的(即在。的空白)   你的陈述的左边)。   在其他地方,空白不是   重要的,可以用作你   就像在任何其他语言中一样。   你也可以插入空行   什么都不包含(或者只是任意的   任何地方的空白。

     

另外,缩进的确切数量   根本不重要,但只有   嵌套块的相对缩进   (相对于彼此)。 [...]

答案 2 :(得分:4)

解决选项卡与空格问题的最简单方法是禁止使用空格和制表符的组合(例如,这是在F#中完成的)。任何现代编辑器都允许将标签转换为一些空格。

至于你是否需要放弃解析器生成器,可能不是,但你必须在那里破解越位识别。这可能需要您的一点创造力。在浏览F#源的基础上,看起来他们使用post-lexing步骤创建代表越位语言元素的其他标记。

答案 3 :(得分:2)

对于它的价值,Haskell也是基于缩进的,并且可选地{foo;酒吧;等等,当空白不方便时。 I wrote a simple indentation-based parser Parsec与{{3}}一样,它的内容类似于Lisp,但缩进表示操作符应用程序。括号只能在一行上使用。

(aaa bb) cc
         e fffff (ggg hhh) iii
                 jjj kkk
         ddd

此处aaa适用于bb。结果是三元函数。它适用于应用于一个参数的参数cceddd。了解应用程序如何基于列对齐,而不是X空格。

解析器也可能更简单。

答案 4 :(得分:1)

你有几个选择w.r.t.制表符和空格:禁止混合制表符和空格,假定制表符与空格的固定比例,或允许程序员根据每个项目或每个源文件决定(某种“#pragma tab(4)”样式指令到允许选项卡和/或更改它们代表的空格数。)

ANTLR 3等分析器生成器可以轻松应对这种情况;我自己一直在玩一个例子,编译它的C#目标。 DirkGently's answer中的链接解释了Python算法,该算法直接转换为代码。我的方法只是为空格和换行定义单独的标记,并覆盖词法分析器使用的“发出标记”函数,以便动态插入额外的缩进/标记标记。事实证明这比我见过的其他方法更容易实现,这些方法覆盖了“获取最后一个令牌”功能,但是效果非常好。

答案 5 :(得分:0)

我自己有一个解决方案,我就像嵌套树的块一样分析代码。对于括号中的部分,我只使用了常规方法。

这是解析器:https://github.com/jiyinyiyong/cirru-parser