【问题标题】:EBNF grammar to ANTLR3?EBNF语法到ANTLR3?
【发布时间】:2013-03-01 00:33:03
【问题描述】:

我有这个 Jass 脚本语言的 EBNF 语法。
需要做什么才能将其转换为与 ANTLR 3.5 一起使用?
此外,是否有任何工具可以帮助我这样做?

//----------------------------------------------------------------------
// Global Declarations
//----------------------------------------------------------------------
program  ::= file+
file     ::= newline? ( declr newline )* func*
declr    ::= typedef
           | globals
           | native_func
typedef  ::= 'type' id 'extends' ( 'handle' | id )
globals  ::= 'globals' newline global_var_list 'endglobals'
global_var_list
         ::= ( 'constant' type id '=' expr newline | var_declr newline )*
native_func
         ::= 'constant'? 'native' func_declr
func_declr
         ::= id 'takes' ( 'nothing' | param_list ) 'returns' ( type | 'nothing' )
param_list
         ::= type id ( ',' type id )*
func     ::= 'constant'? 'function' func_declr newline local_var_list statement_list 'endfunction' newline

//----------------------------------------------------------------------
// Local Declarations
//----------------------------------------------------------------------
local_var_list
         ::= ( 'local' var_declr newline )*
var_declr
         ::= type id ( '=' expr )?
           | type 'array' id
statement_list
         ::= ( statement newline )*
statement
         ::= set
           | call
           | ifthenelse
           | loop
           | exitwhen
           | return
           | debug
set      ::= 'set' id '=' expr
           | 'set' id '[' expr ']' '=' expr
call     ::= 'call' id '(' args? ')'
args     ::= expr ( ',' expr )*
ifthenelse
         ::= 'if' expr 'then' newline statement_list else_clause? 'endif'
else_clause
         ::= 'else' newline statement_list
           | 'elseif' expr 'then' newline statement_list else_clause?
loop     ::= 'loop' newline statement_list 'endloop'
exitwhen ::= 'exitwhen' expr
return   ::= 'return' expr?
debug    ::= 'debug' ( set | call | ifthenelse | loop )

//----------------------------------------------------------------------
// Expressions
//----------------------------------------------------------------------
expr     ::= binary_op
           | unary_op
           | func_call
           | array_ref
           | func_ref
           | id
           | const
           | parens
binary_op
         ::= expr ( [+-*/><] | '==' | '!=' | '>=' | '<=' | 'and' | 'or' ) expr
unary_op ::= ( '+' | '-' | 'not' ) expr
func_call
         ::= id '(' args? ')'
array_ref
         ::= id '[' expr ']'
func_ref ::= 'function' id
const    ::= int_const
           | real_const
           | bool_const
           | string_const
           | 'null'
int_const
         ::= decimal
           | octal
           | hex
           | fourcc
decimal  ::= [1-9] [0-9]*
octal    ::= '0' [0-7]*
hex      ::= '$' [0-9a-fA-F]+
           | '0' [xX] [0-9a-fA-F]+
fourcc   ::= '' ' .{4} ' ''
real_const
         ::= [0-9]+ '.' [0-9]*
           | '.' [0-9]+
bool_const
         ::= 'true'
           | 'false'
string_const
         ::= '"' .* '"'
parens   ::= '(' expr ')'

//----------------------------------------------------------------------
// Base RegEx
//----------------------------------------------------------------------
type     ::= id
           | 'code'
           | 'handle'
           | 'integer'
           | 'real'
           | 'boolean'
           | 'string'
id       ::= [a-zA-Z] ( [a-zA-Z0-9_]* [a-zA-Z0-9] )?
newline  ::= '\n'+


提前感谢您提供的任何建议!

【问题讨论】:

标签: parsing antlr converter grammar ebnf


【解决方案1】:

免责声明:我实际上并没有使用 ANTLR,因此使用过的人可能会提供更详细的信息。

ANTLR 生成递归下降解析器,因此必须重构您的语法以消除左递归,例如在expr:

expr     ::= binary_op
...
binary_op
         ::= expr ( [+-*/><] | '==' | '!=' | '>=' | '<=' | 'and' | 'or' ) expr

在解析expr 时,解析器会尝试binary_op 作为一个选项,遇到另一个expr,然后尝试在不消耗任何输入的情况下递归解析它,您现在将拥有无限递归。

这通常通过重新制定语法来处理

expr     ::= binary_op
...
binary_op
         ::= term ( [+-] term )

term = factor ( [*/] factor)

factor = id
         | const
         | parens
         ...

等等。

不是一个简单的过程,但也不是不可能做到的。

【讨论】:

  • ANTLR 4 (antlr.org) 允许左递归。在幕后,它在生成垂直下降解析器之前执行必要的语法重构。
【解决方案2】:

您询问了任何建议,但奇怪的是您的问题特定于 Antlr 3.5。您有使用 Antlr 3.5 的要求吗?了解您将使用语法做什么会有所帮助:简单的语法验证还是完整的解释器?

如果您可以考虑使用 Antlr 4,那么您应该这样做。它比 Antlr 3 更好地处理左因子规则,并且由于您似乎只是在学习 Antlr,Antlr 4 IMO 将更容易上手。如果你真的需要 AST,那就用 Antlr 3

不幸的是,自动转换工具充其量只会给你一个糟糕的语法开发起点。

至于从哪里/如何开始,最好的建议是获取 Java 语法的副本(java.g 用于 Antlr 3.5 或 java.g4 用于 Antlr 4)作为一个工作示例——Jess 似乎足够类似于 java 语法应该让您清楚地了解如何进行。

【讨论】:

  • 对不起,我应该指定的。我将语言重新定义为更像 C/C++,为此我首先需要能够解析原始的 Jass 语言。然后,我将为我自己的语言(基于 C)构建一个解析器和词法分析器,将两个解析器放在同一个 C++ 库中,然后将该库链接到控制台编译器应用程序,能够将我的语言解释为原始 Jass 脚本语言,由暴雪娱乐发明。 Jass 本身有很大的改进空间,我希望根据自己的喜好填补这些空白。
  • 我会使用 Antlr 4,但我已经读到它现在仅用于 Java 开发......而且我宁愿不必为了使用 Antlr 的唯一目的。另一方面,Antlr 3.5 有一个内置的 C 生成器,是 ANTLRWorks 1.5 中使用的最新版本,我宁愿不要没有这个工具。
  • 请忽略我之前的评论。事实证明,他们最近开发了使用 ANTLR4 的 ANTLRWorks2 (link)。它仍然只针对 java 开发环境,但该站点声明他们正在使用 C++ ......所以我想我会继续关注它,同时我想我可以使用 eclipse 来处理。如果我能做到那么远,甚至可能只是创建一个解释器。
【解决方案3】:

语法描述语言真的很小。他们的语法只有十几个规则。

您可以做的(我已经做过的事情)是使用 ANTLR 为 EBNF 表示法编写语法,并使用它来将您拥有的内容转换为 ANTLR 语法。

应该是一天的工作,最多两天。

【讨论】:

  • 你的意思是,构建一个将 EBNF 转换为 ANTLR 的解析器?如果我能做到这一点,那么我可能不需要一开始就发布这个问题。但是,如果您已经创建了这样的工具,您介意在这里分享吗?
  • 我已经这样做了,但是我的 EBNF 风格和你的不同,我已经从 ANTLR 搬到了 Grako。相信我,这将是一天左右的工作,然后你可以修复它以保留它,或者你可以在它产生你需要的输出后将它扔掉。
  • 我认为你错过了这里的重点(或者我可能是)......如果我明白如何做你的建议,那么 我不需要发布问题关于如何做到这一点。我是 ANTLR 的新手,所以我还没有完全理解 EBNF 和 ANTLR 语法之间的区别。
  • 对不起,我误解了。 EBNF 规则和 ANTLR 规则之间存在直接映射,因为这两种语言非常相似。这是一个到处改变符号的问题(::= 变成:)。真正的诀窍是您必须将词法规则(处理字符而不是标记的规则)移动到 ANTLR 词法分析器语法中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多