有没有人知道在C#中使用ANTLR生成的AST的教程?我能找到的最接近的是this,但这不是非常有帮助。教程在C#中走ANTLR ASTs?
我的目标是根据我正在处理的领域特定语言生成树,并使用这些树来输出生成的C#代码。
基于Java的教程也会有所帮助 - 任何可以提供有关如何遍历ANTLR ASTs的清晰示例的东西都可以。
有没有人知道在C#中使用ANTLR生成的AST的教程?我能找到的最接近的是this,但这不是非常有帮助。教程在C#中走ANTLR ASTs?
我的目标是根据我正在处理的领域特定语言生成树,并使用这些树来输出生成的C#代码。
基于Java的教程也会有所帮助 - 任何可以提供有关如何遍历ANTLR ASTs的清晰示例的东西都可以。
我设法通过修改Manuel Abadia's article末尾的例子来解决这个问题。
这是我的版本,我碰巧用它将分析后的代码转换为C#。 这些步骤如下:
CommonTree
。获取一个节点的文字文本,使用node.Text
。 要获取节点的令牌名称,请使用node.Token.Text
。
请注意,node.Token.Text
只会给你的令牌的实际名称,如果它是一个假想的令牌没有相应的字符串。如果它是一个真实的标记,那么node.Token.Text
将返回其字符串。
举例来说,如果你有在你的语法如下:
tokens { PROGRAM, FUNCDEC }
EQUALS : '==';
ASSIGN : '=';
然后你会得到"PROGRAM"
,"FUNCDEC"
,"=="
,并且"="
从node.Token.Text
相应的访问。
你可以在下面看到我的例子的一部分,或者你可以浏览full version。
public static string Convert(string input)
{
ANTLRStringStream sStream = new ANTLRStringStream(input);
MyGrammarLexer lexer = new MyGrammarLexer(sStream);
CommonTokenStream tStream = new CommonTokenStream(lexer);
MyGrammarParser parser = new MyGrammarParser (tStream);
MyGrammarParser.program_return parserResult = parser.program();
CommonTree ast = (CommonTree)parserResult.Tree;
Print(ast);
string output = header + body + footer;
return output;
}
public static void PrintChildren(CT ast)
{
PrintChildren(ast, " ", true);
}
public static void PrintChildren(CT ast, string delim, bool final)
{
if (ast.Children == null)
{
return;
}
int num = ast.Children.Count;
for (int i = 0; i < num; ++i)
{
CT d = (CT)(ast.Children[i]);
Print(d);
if (final || i < num - 1)
{
body += delim;
}
}
}
public static void Print(CommonTree ast)
{
switch (ast.Token.Text)
{
case "PROGRAM":
//body += header;
PrintChildren(ast);
//body += footer;
break;
case "GLOBALS":
body += "\r\n\r\n// GLOBALS\r\n";
PrintChildren(ast);
break;
case "GLOBAL":
body += "public static ";
PrintChildren(ast);
body += ";\r\n";
break;
....
}
}
正常情况下,您可以使用递归遍历AST,并根据节点的类型执行不同的操作。如果您使用多态树节点(即树中不同节点的不同子类),则可以适当地在访问者模式中重新分派;然而,Antlr通常不太方便。
伪代码,平时走路看起来有点像这样:
func processTree(t)
case t.Type of
FOO: processFoo t
BAR: processBar t
end
// a post-order process
func processFoo(foo)
// visit children
for (i = 0; i < foo.ChildCount; ++i)
processTree(foo.GetChild(i))
// visit node
do_stuff(foo.getText())
// a pre-order process
func processBoo(bar)
// visit node
do_stuff(bar.getText())
// visit children
for (i = 0; i < foo.ChildCount; ++i)
processTree(foo.GetChild(i))
该种处理的是高度依赖于语言的语义。例如,处理一个IF
声明,结构(IF <predicate> <if-true> [<if-false>])
,对堆栈机,如JVM或CLR生成代码时,可能看起来有点像这样:
func processIf(n)
predicate = n.GetChild(0)
processExpr(predicate) // get predicate value on stack
falseLabel = createLabel()
genCode(JUMP_IF_FALSE, falseLabel) // JUMP_IF_FALSE is called brfalse in CLR,
// ifeq in JVM
if_true = n.GetChild(1)
processStmt(if_true)
if_false = n.ChildCount > 2 ? n.GetChild(2) : null
if (if_false != null)
doneLabel = createLabel()
genCode(JUMP, doneLabel)
markLabel(falseLabel)
if (if_false != null)
processStmt(if_false) // if-false branch
markLabel(doneLabel)
一般来说一切都完成递归根据当前的类型节点等
你应该看看写一个TreeParser;它可以使解释树的工作变得更简单。
对于ANTLR 2.x中看到http://www.antlr2.org/doc/sor.html 对于ANTLR 3.x中看到http://www.antlr.org/wiki/display/ANTLR3/Tree+construction(基于Java的语法分析器和树分析器的例子)
我没有类似的东西(但不是真的),我结束了一个TreeParser。
我也建议购买ANTLR书。我发现它比任何网络资源都更有价值。它可能没有所有的答案,但它确实有助于基础知识。
树语法的为C#任何示例代码? – Kiquenet 2010-08-24 08:34:01