4

我正在尝试学习语言解析以获得乐趣......

我创建了一个 ANTLR 语法,我相信它会匹配我希望实现的简单语言。它将具有以下语法:

<FunctionName> ( <OptionalArguments>+) {
     <OptionalChildFunctions>+
 }

实际示例:

ForEach(in:[1,2,3,4,5] as:"nextNumber") {
   Print(message:{nextNumber})
}

我相信我的语法可以正常工作以匹配这个结构,现在我正在尝试为该语言构建一个抽象语法树。

首先,我必须承认我不确定这棵树应该是什么样子。其次,我完全不知道如何在我的 Antlr 语法中做到这一点......我已经尝试了几个小时但没有取得多大成功。

这是我目前对树的想法:

                   FunctionName
                  /          \
           Attributes         \
               / \          /  \ 
            ID    /\    ChildFunctions
           / \   ID etc
          /   \
  Attribute  AttributeValue
        Type

这是我当前的 Antlr 语法文件:

grammar Test;

options {output=AST;ASTLabelType=CommonTree;}

program : function ;
function : ID (OPEN_BRACKET (attribute (COMMA? attribute)*)? CLOSE_BRACKET)? (OPEN_BRACE function* CLOSE_BRACE)?;

attribute : ID COLON datatype;

datatype : NUMBER | STRING | BOOLEAN | array | lookup ;
array  :  OPEN_BOX (datatype (COMMA datatype)* )? CLOSE_BOX ;
lookup  : OPEN_BRACE (ID (PERIOD ID)*) CLOSE_BRACE;

NUMBER
 : ('+' | '-')? (INTEGER | FLOAT)
 ;

STRING
    :  '"' ( ESC_SEQ | ~('\\'|'"') )* '"'
    ;

BOOLEAN
 : 'true' | 'TRUE' | 'false' | 'FALSE'
 ;

ID  : (LETTER|'_') (LETTER | INTEGER |'_')*
    ;

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

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

COLON : ':' ;
COMMA : ',' ;
PERIOD  :  '.' ;

OPEN_BRACKET : '(' ;
CLOSE_BRACKET : ')' ;

OPEN_BRACE : '{' ; 
CLOSE_BRACE : '}' ;

OPEN_BOX : '[' ;
CLOSE_BOX : ']' ;

fragment
LETTER
 : 'a'..'z' | 'A'..'Z' 
 ;

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

fragment
FLOAT
 : INTEGER+ '.' INTEGER*
 ;

fragment
ESC_SEQ
    :   '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
    ;

任何帮助/建议都会很棒。我已经尝试阅读数十篇教程,但似乎没有任何关于 AST 生成的内容:(

4

1 回答 1

9

第 1 步是让树看起来像您发布的小图。现在,你没有任何树构造操作符,所以你最终会得到一个平面列表。

请参阅antlr.org 网站上的树构造。

您可以使用ANTLRWorks来查看解析树和 AST 得到了什么。开始添加树构造运算符并观察情况如何变化。

编辑/附加信息:

您可以按照以下流程大致了解如何操作:

  1. 下载 ANTLRWorks 并使用它的绘图工具。您肯定希望在进行更改之前和之后查看解析树和 AST。一旦你了解了一切是如何工作的,那么你就可以使用任何你想要的 IDE 或编辑器。
  2. 树构造有两个基本运算符 - 感叹号!告诉编译器不要将节点放置在 AST 中,以及 carot^告诉 ANTLR 将某些东西作为根节点。首先检查每个非终结规则并确定哪些元素不需要在 AST 中。例如,您不需要逗号或括号。获得所有信息后,您可以填充提供所有信息的结构(或创建自己的 AST 结构)。逗号不再有帮助,所以添加一个!。例如:

    function: ID (OPEN_BRACKET! (attribute (COMMA!? attribute)*)? CLOSE_BRACKET!)? (OPEN_BRACE! function* CLOSE_BRACE!)?;

  3. 看看前后在 ANTLRWorks 中的 AST。相比。

  4. 现在决定哪个元素应该是根节点。看起来你想ID成为根节点,所以在 ANTLRWorks 中添加一个^afterID和 compare。

这里有一些改变使它更接近我认为你想要的:

program : function ;
function : ID^ (OPEN_BRACKET! attributeList? CLOSE_BRACKET!)? (OPEN_BRACE! function* CLOSE_BRACE!)?;
attributeList:  (attribute (COMMA!? attribute)*);
attribute : ID COLON! datatype;
datatype : NUMBER | STRING | BOOLEAN | array | lookup ;
array  :  OPEN_BOX! (datatype^ (COMMA! datatype)* )? CLOSE_BOX!;
lookup  : OPEN_BRACE! (ID (PERIOD! ID)*) CLOSE_BRACE!;

有了这些,现在去看看一些教程

于 2010-01-14T00:02:06.933 回答