C 如何输出使用ANTLR构建的AST?
我正在为C做一个静态分析器。 我已经使用ANTLR完成了lexer和解析器,其中生成了Java代码 ANTLR是否通过C 如何输出使用ANTLR构建的AST?,c,antlr,static-analysis,abstract-syntax-tree,C,Antlr,Static Analysis,Abstract Syntax Tree,我正在为C做一个静态分析器。 我已经使用ANTLR完成了lexer和解析器,其中生成了Java代码 ANTLR是否通过选项{output=AST;}自动为我们构建AST?还是我必须自己做这棵树?如果有,那么如何吐出该AST上的节点 我目前认为AST上的节点将用于生成SSA,然后进行数据流分析,以生成静态分析器。我走对了吗 拉斐尔写道: antlr是否通过选项{output=AST;}自动为我们构建AST?还是我必须自己做这棵树?如果有,那么如何吐出该AST上的节点 不,解析器不知道每个解析器规则
选项{output=AST;}
自动为我们构建AST?还是我必须自己做这棵树?如果有,那么如何吐出该AST上的节点
我目前认为AST上的节点将用于生成SSA,然后进行数据流分析,以生成静态分析器。我走对了吗
拉斐尔写道:
antlr是否通过选项{output=AST;}自动为我们构建AST?还是我必须自己做这棵树?如果有,那么如何吐出该AST上的节点
不,解析器不知道每个解析器规则的根和叶是什么,因此您需要做的不仅仅是在语法中放入options{output=AST;}
例如,当使用语法生成的解析器解析源代码时,“true&&(false | | true&&(true | | false))”:
grammar ASTDemo;
options {
output=AST;
}
parse
: orExp
;
orExp
: andExp ('||' andExp)*
;
andExp
: atom ('&&' atom)*
;
atom
: 'true'
| 'false'
| '(' orExp ')'
;
// ignore white space characters
Space
: (' ' | '\t' | '\r' | '\n') {$channel=HIDDEN;}
;
将生成以下解析树:
(即,仅仅是一个扁平的一维标记列表)
您需要告诉ANTLR语法中哪些标记成为根、叶,或者干脆不在树中
创建AST的方法有两种:
foo:abcd->^(dab)
,其中foo
是与令牌a B C D
匹配的解析器规则。所以->
之后的所有内容都是实际的重写规则。如您所见,重写规则中没有使用标记C
,这意味着AST中省略了该标记。直接放置在^(
后面的令牌将成为树的根^
和!
,其中^
将使令牌成为根,而!
将从树中删除令牌。foo:abcd->^(dab);
的等价物是foo:abc!D^;
foo:abcd->^(dab);
和foo:abcc!D^;
都将生成以下AST:
现在,您可以将语法改写如下:
grammar ASTDemo;
options {
output=AST;
}
parse
: orExp
;
orExp
: andExp ('||'^ andExp)* // Make `||` root
;
andExp
: atom ('&&'^ atom)* // Make `&&` root
;
atom
: 'true'
| 'false'
| '(' orExp ')' -> orExp // Just a single token, no need to do `^(...)`,
// we're removing the parenthesis. Note that
// `'('! orExp ')'!` will do exactly the same.
;
// ignore white space characters
Space
: (' ' | '\t' | '\r' | '\n') {$channel=HIDDEN;}
;
它将从源代码“true&&(false | | true&&(true | | false))”创建以下AST:
相关ANTLR wiki链接:
import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.stringtemplate.*;
public class Main {
public static void main(String[] args) throws Exception {
String src = "true && (false || true && (true || false))";
ASTDemoLexer lexer = new ASTDemoLexer(new ANTLRStringStream(src));
ASTDemoParser parser = new ASTDemoParser(new CommonTokenStream(lexer));
CommonTree tree = (CommonTree)parser.parse().getTree();
DOTTreeGenerator gen = new DOTTreeGenerator();
StringTemplate st = gen.toDOT(tree);
System.out.println(st);
}
}
谢谢你的回答,但我仍然不知道如何决定哪些标记应该是根和叶。有什么建议吗?@Raphael,你觉得最有意义的就说吧。很自然,括号、分号等可以很容易地从树中删除,运算符成为根。
while
语句的根可能是关键字'while'
,并且可能有两个子项:expression
和statementBlock
(这是零个或多个语句
),在表达式计算结果为true时执行。再说一次:对你来说最有意义的事情:你就是那个要“走”AST并做所有艰苦工作的人。祝你好运@Samuel,请参见我的编辑(这是您想要的)。为什么示例中的解析树是扁平的?无法从平面解析树推断解析过程。@Malinda它们通常通过(我已更新链接)提供