2

私は自分の小さな言語をやっていて、ブロックを作ろうとしていますが、現在のブロックを追跡する方法にかなりこだわっています(変数がどのブロックで作成されたかを知る必要があるためなど-何とか何とか)。

私の文法ファイルは次のようになります (簡単にするために、コード全体ではありません)。

%{
    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ですか?

または、それが本当に不可能な場合は、どうすればこれを実現できるかについてのメモ/ヒントを教えていただけますか?

4

1 に答える 1

1

ルール内のアクション コードは、ルールが縮小されたときに実行されるため、プロセスの早い段階でアクションが必要な場合は、以前に縮小されたルールにそれらを配置する必要があります。yacc と bison の両方で、ルールの右側に追加のアクションを追加するだけで、匿名のイプシロン ルールを導入できます。したがって、次のようなことができます:

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 }
;
于 2012-11-28T22:50:29.953 に答える