kpo*_*zin 19
我设法通过在Manuel Abadia的文章结尾处调整示例来解决这个问题.
这是我的版本,我碰巧用它来将解析后的代码转换为C#.这些是步骤:
CommonTree.要获取节点的文字文本,请使用node.Text.要获取节点的令牌名称,请使用node.Token.Text.
请注意,node.Token.Text如果令牌是一个没有相应字符串的虚构令牌,它只会为您提供令牌的实际名称.如果它是真正的令牌,那么node.Token.Text将返回其字符串.
例如,如果您的语法中包含以下内容:
tokens { PROGRAM, FUNCDEC }
EQUALS : '==';
ASSIGN : '=';
Run Code Online (Sandbox Code Playgroud)
然后你将获得"PROGRAM","FUNCDEC"和"==",以及"="相应的访问node.Token.Text.
您可以在下面看到我的部分示例,或者您可以浏览完整版本.
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;
....
}
}
Run Code Online (Sandbox Code Playgroud)
通常,您使用递归来执行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))
Run Code Online (Sandbox Code Playgroud)
处理的种类高度依赖于语言的语义.例如,在为JVM或CLR等堆栈机器生成代码时IF,使用结构处理语句(IF <predicate> <if-true> [<if-false>])可能看起来像这样:
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)
Run Code Online (Sandbox Code Playgroud)
通常,一切都是递归完成的,具体取决于当前节点的类型等.
| 归档时间: |
|
| 查看次数: |
11138 次 |
| 最近记录: |