如何使用ANTLR生成的语法文件?

时间:2009-03-12 04:16:54

标签: c antlr

我认为这是一个愚蠢的问题,但我刚刚开始使用ANTLR。我将他们的教程中的“SimpleCalc”语法放在一起,并用C作为目标语言生成它。我得到SimpleCalcParser.c / .h和SimpleCalcLexer.c / .h作为输出,我能够编译这些并成功构建。但是现在,我如何实际使用生成的代码?我很难找到有用的文档中的任何内容。

下面是我的main()函数。这也来自教程。

 #include "SimpleCalcLexer.h"

 int main(int argc, char * argv[])
 {

    pANTLR3_INPUT_STREAM           input;
    pSimpleCalcLexer               lex;
    pANTLR3_COMMON_TOKEN_STREAM    tokens;
    pSimpleCalcParser              parser;

    input  = antlr3AsciiFileStreamNew          ((pANTLR3_UINT8)argv[1]);
    lex    = SimpleCalcLexerNew                (input);
    tokens = antlr3CommonTokenStreamSourceNew  (ANTLR3_SIZE_HINT, TOKENSOURCE(lex));
    parser = SimpleCalcParserNew               (tokens);

    parser  ->expr(parser);

    // Must manually clean up
    //
    parser ->free(parser);
    tokens ->free(tokens);
    lex    ->free(lex);
    input  ->close(input);

    return 0;
 }

编辑:根据第一个回复,我应该说我运行了这样的程序:“。/ testantlr test.txt”,其中test.txt包含“4 + 1”。没有输出。

从这里开始,我将如何访问生成的语法树中的“4”,或打印出整个语法树?基本上,我如何访问ANTLR生成的语法树中的东西?

4 个答案:

答案 0 :(得分:4)

当我第一次接受攻击时,我遇到了同样的困惑。这是一个非常明显的问题/问题,这使得它更加奇怪,它似乎没有在教程中明确和直接地解决。

我找到的困惑的方法是'returns'关键字:

token returns [TreeNode value]
    :    WORD { $value = new TreeNode( "word", $WORD.Text ); }
    |    INT { $value = new TreeNode( "int", $INT.Text ); }
    ;

WORD:    ('a'..'z'|'A'..'Z')+;
INT :    ('0'..'9')+;

TreeNode是我创建的一个类。它变得棘手的是如何通过一系列说法,多个令牌来做到这一点。我提出的解决方案是递归:

expr returns [Accumulator value]
    :   a=token  (WS+ b=expr)?
    {
        if( b != null )
        {
            $value = new Accumulator( "expr", a.value, b.value );
        } else
        {
            $value = new Accumulator( "expr", a.value );
        }
    }
    ;

Accumulator是我创建的一个有两个不同构造函数的类。一个构造函数封装单个标记,另一个构造函数封装单个标记和另一个Accumulator实例。请注意,规则本身是递归定义的,b.value是一个Accumulator实例。为什么?因为b是expr,expr的定义有returns [Accumulator value]

最终生成的树是一个累积了所有标记的Accumulator实例。要实际使用该树,您需要进行一些设置,然后调用与您正在解析内容的规则同名的方法:

Antlr.Runtime.ANTLRStringStream stringstream =  new Antlr.Runtime.ANTLRStringStream( script );
TokenLexer lexer = new TokenLexer( stringstream );
Antlr.Runtime.CommonTokenStream tokenstream = new Antlr.Runtime.CommonTokenStream( lexer );
TokenParser parser = new TokenParser( tokenstream );

Accumulator grandtree = parser.expr().value;

希望这可以帮助那些遇到这种困惑的人。


更新

有一种更简单的方法可以将项目收集到列表中,因为系统允许您将目标语言代码散布在看似任意模式位置的位置。成语是:

sequence returns [String k]
    :   (e=atom { $k = $e.k; })
        (e=atom { $k += ", " + $e.k; })*
        { $k = "sequence (" + $k + ")"; } ;

字符串k初始化为第一个原子的k值,后续原子得到+=k。代码段$e.k指的是其他地方定义的atom returns [String k]规则。如果没有这样的规则,您可以使用text属性(即$e.text,这是令牌所具有的。我不确定非令牌是否具有此属性。如果没有,您可以做:

nonToken returns [String whatever] : e=TOKEN { $whatever = $e.text; } ;

然后您将在更高的规则中使用,例如

e=nonToken { System.out.println($e.whatever); }

答案 1 :(得分:0)

因此,当您运行此程序时,您在此处提供的第一个命令行参数将是要解析的文件的名称。

第一步,尝试(运行并给它一个文件)。

第二步,回来编辑你的问题但稍微改变方向。不要问“我如何使用代码”,而是尝试询问“如何使用此__________”,其中空白被您想要完成的某些描述所取代。

所以parser->expr(parser)似乎正在解析来自你的文件的令牌流,这应该产生一个AST。通过大量细节猜测我的方式,我建议看看它返回什么,尤其是。 value成员(如果有)。似乎有很多在线教程看起来与你正在做的类似,没有两个相同。

如果所有其他方法都失败了,继续阅读教程,1)它会回答你的问题,或2)它不会,你可以尝试另一个。

答案 2 :(得分:0)

看看Scott Stanchfield的第8部分视频http://vimeo.com/groups/29150/videos/8377479。他在Java中这样做,但同样的原则可以应用于C(++)。

答案 3 :(得分:-1)

我不是故意粗鲁,但似乎你真的不知道ANTLR的目的是什么。我认为您需要先了解这一点,然后才能尝试使用它生成的文件。

非常简短的答案是ANTLR是一个解析器生成器,这意味着它生成解析文本的代码。常见的用法是解析编程语言的文本。我没有阅读你所指的教程,但我猜这个解析器解析的文本是一组计算器指令,类似于

ADD 2 4
MULTIPLY 4 8

为了使用上面显示的程序,您可以像执行任何其他C程序一样执行它。第一个参数(argc)应该是参数的数量,第二个参数(argv)应该是要解析的文本。

为了从头开始学习ANTLR,我建议你阅读由ANTLR的作者Terence Parr出版的the book