for loop IR generation in Bison

165 Views Asked by At

Consider the following grammar rule:

forstmt: for openparentheses nexpr semicolon expr semicolon nexpr closeparentheses stmt {}

nexpr: expr { }
    | %empty { }

expr: .
      .
      .
      // something huge
      .
      .
      .

It is a parser rul for a for loop like below (a usual C like for loop):

for(i=0; i<10; i++){
    Print("hello world");
}

I got to generate IR for this C like for loop (forstmt).
The IR for expr is already written.
The point is that the last nexpr's IR should go after the stmt.
I know about mid-rule actions and I thought that somehow I could solve this using a stack, but my thoughts didn't lead to any conclusions.
Precisely is there a way to stop bison from generating IR for the last nexpr and make it generate after the stmt ?
In other words, how to make all action of the last nexpr go after the stmt ?
Has anyone had a problem like this ?

2

There are 2 best solutions below

0
Parsa Noori On

It must be done by hand!
Bison doesn't have or even it shouldn't have anything for that!
My solution was to some how set a bit somewhere to hold the generated IR in code generator and the release it after the for loop's stmt.

0
Chris Dodd On

Generally you generate IR (internal represention) in memory, so you can manipulate it after you're parsed your program, which allows you to analyse the whole program and reorder things as you see fit. So the order in which you generate the IR is irrelevant.

If you are instead trying to generate code directly in your actions as they are parsed, you need to set things up so that that works, generally by branching around. So you might do something like:

forexpr:
    FOR '(' expr ';' {
        $$.l1 = create_label();   // creates a unique label
        output_label($$.l1);  // the label is at this point in the code
    } expr ';' {
        $$.l1 = create_label();
        $$.l2 = create_label();
        $$.l3 = create_lable();
        output_jump_if_true($6, $$.l1);  // conditional branch
        output_jump($$.l2);              // unconditional branch
        output_label($$.l3);
    } expr ')' {
        output_jump($5.l1);
        output_label($8.l1);
    } stmt {
        output_jump($8.l3);
        output_label($8.l2);
    }

Needless to say, this is quite suboptimal.