2009-07-23 17 views
8

G'day!如何在ANTLR中构造一个干净的,像Python一样的语法?

如何构造一个简单的ANTLR语法来处理多行表达式而不需要分号或反斜线?

我试图写一个简单的DSL的表达式:

# sh style comments 
ThisValue = 1 
ThatValue = ThisValue * 2 
ThisOtherValue = (1 + 2 + ThisValue * ThatValue) 
YetAnotherValue = MAX(ThisOtherValue, ThatValue) 

总之,我希望我的应用程序提供了一些初步命名值的脚本,然后拉出最后的结果。然而,我越来越挂在语法上。我想支持像多行表达式如下:

# Note: no backslashes required to continue expression, as we're in brackets 
# Note: no semicolon required at end of expression, either 
ThisValueWithAReallyLongName = (ThisOtherValueWithASimilarlyLongName 
           +AnotherValueWithAGratuitouslyLongName) 

我开始了与ANTLR语法是这样的:

exprlist 
    : (assignment_statement | empty_line)* EOF! 
    ; 
assignment_statement 
    : assignment NL!? 
    ; 
empty_line 
    : NL; 
assignment 
    : ID '=' expr 
    ; 

// ... and so on 

这看似简单,但我已经与烦恼换行:

warning(200): StackOverflowQuestion.g:11:20: Decision can match input such as "NL" using multiple alternatives: 1, 2 
As a result, alternative(s) 2 were disabled for that input 

图形,在org.antlr.works.IDE:

Decision Can Match NL Using Multiple Alternatives http://img.skitch.com/20090723-ghpss46833si9f9ebk48x28b82.png

我已经戒了周围的语法,但总是与违反预期的行为的结束:

  • 在文件到底是不是需要一个换行符
  • 空行是可以接受的
  • 从英镑符号开始的一行中的所有内容都将作为注释被丢弃
  • 赋值以行尾而非分号结尾
  • 如果包含在括号中,表达式可以跨越多行ets

我可以找到具有许多这些特征的示例ANTLR语法。我发现,当我削减他们的表现力,以限制他们的需求时,我最终打破了一些东西。其他人太简单了,当我添加表现力的时候我会打破他们。

这个语法应该采用哪个角度?你能指出任何既不平凡又不完整的图灵完整语言的例子吗?

回答

6

我将让你的标记生成器做繁重,而不是你的新行规则混合到你的语法:

  • 计数括号,括号和大括号,而同时也有未关闭的组不会产生NL令牌。这会给你免费的线路延续,而不会让你的语法变得更聪明。

  • 无论最后一行是否以'\n'字符结尾,都始终在文件末尾生成一个NL令牌,那么您不必担心没有NL的语句的特例。陈述总是以NL结尾。

第二点会让你简化你的语法是这样的:

exprlist 
    : (assignment_statement | empty_line)* EOF! 
    ; 
assignment_statement 
    : assignment NL 
    ; 
empty_line 
    : NL 
    ; 
assignment 
    : ID '=' expr 
    ; 
+0

现在我需要弄清楚如何让tokenizer完成那个繁重的工作。回到文档,我想。 :) – 2009-07-23 11:45:50

0

这个怎么样?

exprlist 
    : (expr)? (NL+ expr)* NL!? EOF! 
    ; 
expr 
    : assignment | ... 
    ; 
assignment 
    : ID '=' expr 
    ; 
0

我假设你选择让NL可选的,因为在你输入代码的最后声明中并没有以新行结束。

虽然它很有意义,但是对于解析器而言,生活会变得更加困难。应该珍视分隔符令牌(如NL),因为它们可以消除歧义并减少冲突的可能性。

在你的情况下,解析器不知道它是否应该解析“赋值NL”或“赋值empty_line”。有很多方法可以解决这个问题,但其中大多数只是为了一个不明智的设计选择而设立的乐队助手。

我的建议是一个无辜的黑客:使NL成为强制性的,并始终将NL附加到输入流的末尾!

这看起来可能有点令人讨厌,但实际上它会为您节省很多未来的麻烦。

相关问题