从中间/底部的最顶层规则中获取值

时间:2012-11-28 21:42:46

标签: c bison

我正在做我自己的小语言而且我正试图让它有块,但我完全坚持如何跟踪当前块(因为我需要知道哪一个变量是在等等等等。等等。

我的语法文件看起来像这样(为简单起见,它不是整个代码):

%{
    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的值(指向或指向的位置)?

或者,如果它真的不可能,你能否给我一些关于如何实现此目的的说明/提示?

1 个答案:

答案 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 }
;