如何在ANTLR中构造干净的、类似Python的语法?

如何在ANTLR中构造干净的、类似Python的语法?,antlr,grammar,Antlr,Grammar,再见 如何构造一个简单的ANTLR语法来处理多行表达式,而不需要分号或反斜杠 我正在尝试为表达式编写一个简单的DSL: # sh style comments ThisValue = 1 ThatValue = ThisValue * 2 ThisOtherValue = (1 + 2 + ThisValue * ThatValue) YetAnotherValue = MAX(ThisOtherValue, ThatValue) 总的来说,我希望我的应用程序为脚本提供一些初始命名值,并提取最

再见

如何构造一个简单的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
exprlist
    : ( assignment_statement | empty_line )* EOF!
    ;
assignment_statement
    : assignment NL
    ;
empty_line
    : NL
    ;
assignment
    : ID '=' expr
    ;
这看起来很简单,但我已经在为新词烦恼了:

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中:

我已经违反了语法,但最终总是违反预期行为:

  • 文件末尾不需要换行符
  • 空行是可以接受的
  • 从英镑符号开始的一行中的所有内容都将作为注释丢弃
  • 赋值以行尾结束,而不是分号
  • 如果用括号括起来,表达式可以跨多行
我可以找到具有许多这些特征的ANTLR语法示例。我发现,当我把他们的表达能力限制在我所需要的范围内时,我最终破坏了一些东西。其他的太简单了,我在添加表现力时打破了它们


我应该从哪个角度来看待这个语法?你能指出任何不是平凡或完全图灵完全语言的例子吗

我会让您的标记器来完成繁重的工作,而不是将您的新行规则混合到语法中:

  • 计算括号、括号和大括号,并且在存在未关闭的组时不生成NL标记。这样你就可以免费进行连续剧,而不会让你的语法变得更聪明

  • 始终在文件末尾生成NL标记,无论最后一行是否以
    '\n'
    字符结尾,都不必担心没有NL的语句的特殊情况。语句总是以NL结尾

第二点可以让你把语法简化成这样:

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

// ... and so on
exprlist
    : ( assignment_statement | empty_line )* EOF!
    ;
assignment_statement
    : assignment NL
    ;
empty_line
    : NL
    ;
assignment
    : ID '=' expr
    ;
这个怎么样

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

我假设您选择将NL设置为可选,因为输入代码中的最后一条语句不必以换行符结尾

虽然这很有道理,但您让解析器的生活变得更加艰难。分隔符标记(如NL)应该受到重视,因为它们可以消除歧义并减少冲突的可能性

在您的例子中,解析器不知道是应该解析“赋值NL”还是“赋值空行”。有很多方法可以解决这个问题,但大多数都只是一个不明智的设计选择的创可贴

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


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

现在我需要弄清楚如何让标记器完成这项繁重的工作。我想回到文档上来。:)约翰,我还是不明白。什么是ANTLR语法,让标记器在EOF之前插入NL?+1总是以新行结尾,这让事情变得更加清晰。谢谢