我正在做我自己的小语言而且我正试图让它有块,但我完全坚持如何跟踪当前块(因为我需要知道哪一个变量是在等等等等。等等。
我的语法文件看起来像这样(为简单起见,它不是整个代码):
%{
struct Node *nodest = NULL;
struct Node *currentblock = NULL;
%}
%start source
%%
source
: stmts { nodest = block($1); currentblock = nodest; }
;
stmts
: stmt
| stmts stmt
;
stmt
: expr_stmt
| iter_stmt
| select_stmt
| comp_stmt
;
expr_stmt
: ';'
| expr ';'
;
expr
: binary_expr
| assign_expr
| call_expr
| decl_expr
| init_expr
| VAR_IDENT
| INTEGER
| '(' expr ')'
;
comp_stmt
: '{' '}'
| '{' stmts '}' { $$ = block($2); currentblock = $$; }
;
decl_expr
: type VAR_IDENT { $$ = declaration($1, $2, currentblock) }
;
/* ... */
type
: TYPE_INT
;
这显然不会起作用,因为nodest
(作为一个包含其他所有节点的块节点)实际上在创建AST的最后给出了一些值,所以它的其余部分为NULL时间,所以currentblock
不能像decl_expr
那样使用,因为当时它是NULL。
所以我的问题是:我怎样才能在代码中获得nodest
的值(指向或指向的位置)?
或者,如果它真的不可能,你能否给我一些关于如何实现此目的的说明/提示?
答案 0 :(得分:1)
规则中的操作代码在规则减少时执行,因此如果您希望在流程的早期操作,则需要将它们放在先前减少的规则上。 yacc和bison都允许您通过在规则的右侧添加额外操作来引入匿名epsilon规则。所以你可以这样做:
source: { $$ = currentblock = nodest = empty_block(); } stmts
{ $$ = add_to_block($1, $2); }
comp_stmt:
'{' { $$ = currentblock = empty_block(); } stmts '}'
{ $$ = add_to_block($2, $3); }
;
请注意,当您像这样早创建块时,必须将它们创建为空(因为您尚未解析进入块的任何内容),然后再向其中添加内容。在解析它时将每个stmt添加到当前块可能更有意义(在这种情况下,您需要确保currentblock确实是当前块而不是最后一个块:
source: { currentblock = nodest = empty_block(); } stmts ;
stmts: /* empty*/
| stmts stmt { add_to_block(currentblock, $2; }
comp_stmt:
'{' { $$ = currentblock; currentblock = empty_block(); } stmts '}'
{ $$ = currentblock; currentblock = $2 }
;