【问题标题】:ANTLR parser and tree grammars for one simple language一种简单语言的 ANTLR 解析器和树语法
【发布时间】:2011-04-30 20:18:07
【问题描述】:

编辑:

这是更新后的树和解析器语法:

解析器语法:

    options {

language = CSharp2;

output=AST;


}
tokens {
UNARY_MINUS;
CALL;
}
program :   (function)* main_function

        ;



function:       'function' IDENTIFIER '(' (parameter (',' parameter)*)? ')' 'returns' TYPE declaration* statement* 'end' 'function'
        ->    ^('function' IDENTIFIER parameter* TYPE declaration* statement*)
    ;

main_function
    :   'function' 'main' '(' ')' 'returns' TYPE declaration* statement*  'end' 'function'
    ->    ^('function' 'main' TYPE declaration* statement*)   
    ;   

parameter
    :   'param' IDENTIFIER ':' TYPE
    ->    ^('param' IDENTIFIER TYPE)
    ;

declaration
    :       'variable' IDENTIFIER ( ',' IDENTIFIER)* ':' TYPE ';'
    ->    ^('variable' TYPE IDENTIFIER+ )
    |       'array' array  ':' TYPE ';'
    ->    ^('array' array TYPE)
    ;

statement 
    : ';'! | block | assignment | if_statement | switch_statement | while_do_statement | for_statement | call_statement | return_statement  
    ;

call_statement
    :   call ';'!
    ;

return_statement
    :   'return' expression ';'
    ->    ^('return' expression)
    ;

block   : 'begin' declaration* statement* 'end'
        -> ^('begin' declaration* statement*)
        |  '{' declaration* statement* '}'
        -> ^('{' declaration* statement*)
    ;

assignment 
    :   IDENTIFIER ':=' expression ';'
        ->      ^(':=' IDENTIFIER expression )
    |       array ':=' expression ';'
    ->     ^(':=' array expression) 
    ;

array   :   IDENTIFIER '[' expression (',' expression)* ']'
    ->  ^(IDENTIFIER expression+)
    ;

if_statement 
    :   'if' '(' expression ')' 'then' statement ('else' statement)? 'end' 'if'
    ->    ^('if' expression statement statement?)

    ;

switch_statement 
    :   'switch' '(' expression ')' case_part+ ('default' ':' statement)? 'end' 'switch'
    ->    ^('switch' expression case_part+ statement?)
    ; 

case_part
    :   'case' literal (',' literal)* ':' statement
    ->    ^('case' literal+ statement)
    ;

literal 
    :   INTEGER | FLOAT | BOOLEAN | STRING
    ; 

while_do_statement
    :   'while' '(' expression ')' 'do' statement 'end' ' while'
    ->    ^('while' expression statement)
    ;

for_statement 
    :       'for' '(' IDENTIFIER ':=' expression 'to' expression ')' 'do' statement 'end' 'for'
    ->   ^('for' IDENTIFIER expression expression statement)
    ;

expression
    :   conjuction ( 'or'^ conjuction)*
    ;

conjuction
    :       equality ('and'^ equality)* 
    ;

equality:   relation (('=' | '/=')^ relation)?
        ;

relation:   addition (('<' | '<=' | '>' | '>=')^ addition)?
    ;

addition:   multiplication (('+' | '-')^ multiplication)*   
    ;

multiplication
    :   unary_operation (('*' | '/' | '%')^ unary_operation)*
    ;
unary_operation
    :   '-' primary 
    ->   ^(UNARY_MINUS primary)
    |        'not' primary 
    ->   ^('not' primary)
    |     primary
    ;

primary :   IDENTIFIER 
        | array 
        |  literal 
        | '('! expression ')'!  
        | '(' TYPE ')'  '(' expression ')'
        -> ^(TYPE expression) 
        |  call
    ; 

call    :   IDENTIFIER '(' arguments ')'
        ->     ^(CALL IDENTIFIER arguments)
    ;

arguments
    :   (expression  (','! expression)*)? 
    ;

BOOLEAN :   'true' | 'false'
    ;   

T    YPE    : 'integer' | 'boolean' | 'float' | 'string' | 'array' | 'void'
    ;

IDENTIFIER  :   ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
    ;

INTEGER :   '0'..'9'+
    ;

FLOAT
    :   ('0'..'9')+ '.' ('0'..'9')+ 
    ;

COMMENT
    :   '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;}
    |   '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;}
    ;

WS  :   ( ' '
        | '\t'
        | '\r'
        | '\n'
        ) {$channel=HIDDEN;}
    ;

STRING
    :  '"' .* '"'
    ;

这是更新的树语法(我改变了表达式,等等......):

    options {
language = 'CSharp2';
//tokenVocab= token vocab needed
ASTLabelType=CommonTree; // what is Java type of nodes?

}
program :   (function)* main_function

        ;



function:     ^('function' IDENTIFIER parameter* TYPE declaration* statement*)
    ;

main_function
    :   ^('function' 'main' TYPE declaration* statement*)   
    ;   

parameter
    :   ^('param' IDENTIFIER TYPE)
    ;

declaration
    :     ^('variable' TYPE IDENTIFIER+)
        |     ^('array' array TYPE  )
    ;

statement 
    : block | assignment | if_statement | switch_statement | while_do_statement | for_statement | call_statement | return_statement 
    ;

call_statement
    :   call 
    ;

return_statement
    :   ^('return' expression)
    ;

block   : ^('begin' declaration* statement*)
        |  ^('{' declaration* statement*)
    ;

assignment 
    :   ^(':=' IDENTIFIER expression )
    |      ^(':=' array expression) 
    ;

array   :   ^(IDENTIFIER expression+)
    ;

if_statement 
    :   ^('if' expression statement statement?)

    ;

switch_statement 
    :   ^('switch' expression case_part+ statement?)
    ; 

case_part
    :   ^('case' literal+ statement)
    ;

literal 
    :   INTEGER | FLOAT | BOOLEAN | STRING
    ; 

while_do_statement
    :   ^('while' expression statement)
    ;

for_statement 
    :    ^('for' IDENTIFIER expression expression statement)
    ;

expression
    :   ^('or' expression expression)
    |      ^('and' expression expression)
    |      ^('=' expression expression)   
    |      ^('/=' expression expression)
    |       ^('<' expression expression)
    |       ^('<=' expression expression)
    |       ^('>' expression expression)
    |       ^('>=' expression expression)
    |       ^('+' expression expression)
    |       ^('-' expression expression)
    |      ^(UNARY_MINUS expression)
    |      ^('not' expression)
    |      IDENTIFIER
    |      array
    |       literal 
        |      ^(TYPE expression) 
        |      call
    ;

call    :   ^(CALL IDENTIFIER arguments)
    ;

arguments
    :   (expression  (expression)*)? 
    ;

我成功地使用 DOTTreeGenerator 和 StringTemplate 类生成了树图,所以目前看来一切正常。但是任何建议(关于坏习惯或此语法中的其他内容)都值得赞赏,因为我在 ANTLR 或语言识别方面没有很多经验。

查看http://vladimir-radojicic.blogspot.com的更新

【问题讨论】:

  • 请同时提供树解析器规则以供您添加。否则很难判断出了什么问题。
  • 如果不查看整个解析器和树语法,就无法判断。
  • 我可以把整个语法发给你吗,因为加法规则是调用另一个,另一个和另一个规则,所以它几乎是整个语法?
  • 您可以编辑原始问题并添加解析器语法和树语法。
  • 这里是 - 解析器和树语法 我使用的是 ANTLRWorks 1.4,而不是 1.4.2,因为目前它在生成 C# 代码时存在一些错误

标签: c# parsing tree antlr


【解决方案1】:

我唯一要建议的是,除了引入虚构标记以确保您的树语法产生“唯一 AST”并简化 -语法中的 expression,你们俩已经做到了(再次:做得好!),是您不应该在解析器语法中使用文字标记。尤其是当它们可能被其他词法分析器规则匹配时。例如,您的所有保留字(如forwhileend 等)也可以通过词法分析器规则IDENTIFIER 进行匹配。最好在词法分析器中创建显式标记(并将这些规则放在IDENTIFIER 规则之前!):

...

FOR   : 'for'; 
WHILE : 'while'; 
END   : 'end';

...

IDENTIFIER  
  :  ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
  ;

...

理想情况下,树语法不包含任何带引号的标记。 AFAIK,您无法在语法Y 中正确导入语法X:语法X 中的文字标记在语法Y 中不可用。而且,当您将组合语法拆分为解析器和词法分析器语法时,这些文字标记是不允许的。对于像你这样的小语法,这些最后的评论与你无关(你可以保持你的语法“原样”),但是当你创建更大的语法时记住它们。

祝你好运!

编辑

虚构的标记不仅在没有可以作为树根的真实标记时很方便。我看待虚构标记的方式是它们使您的树“唯一”,因此树语法只能以一种可能的方式“遍历”您的树。以减法和一元减法为例。如果您没有创建一个名为UNARY_MINUS 的虚构令牌,而只是这样做:

unary_operation
  :  '-' primary   -> ^('-' primary)
  |  'not' primary -> ^('not' primary)
  |  primary
  ;

那么你的树语法中会有这样的东西:

expression
  :  ^('-' expression expression)
  |  ...
  |  ^('-' expression)
  |  ...
  ;

现在减法和一元减法都以相同的标记开头,这是树语法不喜欢的!这个-(减号)示例很容易看出,但可能有一些不那么明显的棘手案例(即使是像你这样的小语法!)。所以,总是让解析器在重写 AST 时创建“独特的树”。

希望能澄清一下(有点)。

【讨论】:

  • 非常感谢您的有用建议,我真的很感激!首先我想摆脱所有“语法糖”,所以我尝试尽可能少地引入额外的虚构标记,因为它没有它没有携带任何关于源代码的重要信息,它只是在我的语法中添加了一些额外的规则。但是现在我看到我不应该逃避它。但是想象的标记是“语法糖”,对吗?例如,这个源代码变量声明: int x,y;在我的解析器语法中,我制作了虚构的标记 VAR:^(VAR type ID+)。现在我的 AST 中的“糖”比我的源代码更多?
  • 非常感谢您的解释。接下来我打算为此制作代码生成器,它将我的语言源代码编译成通用中间语言。为此,我在vladimir-radojicic.blogspot.com 上开设了博客,所以我希望如果我成功了,我会在下个月发布这部分工作,因为这对我来说是全新的世界。 :)
猜你喜欢
  • 1970-01-01
  • 2014-05-07
  • 1970-01-01
  • 2011-01-30
  • 2016-11-09
  • 1970-01-01
  • 1970-01-01
  • 2017-09-07
  • 1970-01-01
相关资源
最近更新 更多