我认为这是一个愚蠢的问题,但我刚刚开始使用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生成的语法树中的东西?
答案 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。