I know how to make YACC generate an AST, but how do you actaully get it? I mean, how do you actaully get t开发者_运维技巧he value of the root node from YACC?
Yacc only gives you back one node at a time, and it's always something that you just gave yacc at some earlier time, i.e., whatever you wanted to return from a reduced production or whatever you wanted to return from a terminal symbol. (Sorry, you said you knew that, but some people reading this might not.)
So, take whatever you woud have returned from the root or top rule, and save it (in your attached C reduction code) any way you like.
What Yacc gives you is a parse tree, which is different than an AST. You'd need to construct your AST by yourselves while going through each node of the parse tree (through yacc).
This is how I did it:
in the yacc file (your_grammar.y):
%parse-param {AstNode **pproot}
%parse-param {char **errmsg}
in the calling program (your_program.c):
res = yyparse(&pAst, &errmsg);
AST nodes are allocated and linked as a tree inside yyparse() (you make the logic) and the address of root node is passed back in the pAst pointer.
It's not as elegant as having the parser return an AST directly, but the best way that I've come up with to do this is to have a global data structure (e.g. a vector or linked list), with threadsafe insertion methods if thread safety is needed, and have the top-level yacc rule add its result (a.k.a. $$
) to that data structure. Then you can access this result in other functions. Of course, if you're only going to output a single AST, it's probably only necessary to have a single global pointer to that AST, rather than a data structure full of them.
精彩评论