我有这种用于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'+
提前感谢您提供的任何建议!
答案 0 :(得分: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
...
等等。
这不是一个简单的过程,但也不是不可能的。
答案 1 :(得分:1)
您询问了任何建议,但您的问题对于Antlr 3.5来说是特别奇怪的。您是否需要使用Antlr 3.5?这将有助于了解您将使用语法:简单的语法验证还是全面的解释器?
如果你可以考虑使用Antlr 4,你应该。它比Antlr 3更好地处理左因素规则,因为看起来你只是在学习Antlr,所以Antlr 4 IMO将更容易上手。如果你真的需要AST,那么请使用Antlr 3
不幸的是,自动转换工具充其量只能为你提供一个很好的语法开发点。
至于何处/如何开始,最好的建议是获取Java语法的副本(Antlr 3.5的java.g或Antlr 4的java.g4)作为工作示例 - Jess看起来非常相似,java语法应该让你清楚地了解如何继续。
答案 2 :(得分:1)
语法描述语言非常小。他们的语法只有十几个规则。
你能做什么(我做过的事情)是使用ANTLR为EBNF表示法编写语法,并使用它来将你所拥有的语法翻译成ANTLR语法。
应该是大约一天的工作,或者最多两天。