Search code examples
parsingcompiler-constructionbisonyacc

How to parse subnodes that depended on parents' information?


If I write grammar file in Yacc/Bison like this:

Module
    :ModuleName "=" Functions
      { $$ = Builder::concat($1, $2, ","); }

Functions
    :Functions Function
      { $$ = Builder::concat($1, $2, ","); }
    | Function
      { $$ = $1; }

Function
    : DEF ID ARGS BODY
      {
          /** Lacks module name to do name mangling for the function **/
          /** How can I obtain the "parent" node's module name here ?? **/
          module_name = ; //????

          $$ = Builder::def_function(module_name, $ID, $ARGS, $BODY); 
      }

And this parser should parse codes like this:

main_module:
    def funA (a,b,c) { ... }

In my AST, the name "funA" should be renamed as main_module.funA. But I can't get the module's information while the parser is processing Function node !

Is there any Yacc/Bison facilities can help me to handle this problem, or should I change my parsing style to avoid such embarrassing situations ?


Solution

  • There is a bison feature, but as the manual says, use it with care:

    $N with N zero or negative is allowed for reference to tokens and groupings on the stack before those that match the current rule. This is a very risky practice, and to use it reliably you must be certain of the context in which the rule is applied. Here is a case in which you can use this reliably:

     foo:      expr bar '+' expr  { ... }
             | expr bar '-' expr  { ... }
             ;
    
     bar:      /* empty */
             { previous_expr = $0; }
             ;
    

    As long as bar is used only in the fashion shown here, $0 always refers to the expr which precedes bar in the definition of foo.

    More cleanly, you could use a mid-rule action (in Module) to push the module name on a name stack (which would have to be part of the parsing context). You would then pop the stack at the end of the rule.

    For more information and examples of mid-rules actions, see the manual.