How does the LALR (1) yacc / bison algorithm handle empty rules?

In the LALR analyzer (1), the rules in the grammar are converted to a parser table, which effectively says: "If you still have this input and the token to view is X, then go to state Y or reduce by rule R".

I successfully built the LALR (1) parser in an interpreted language (ruby), not using a generator, but computing a syntax table at runtime and evaluating the input using this parsing table. This works surprisingly well, and table generation is pretty trivial (which surprised me somewhat), supporting self-referencing rules and associations on the left and right.

One thing that I find difficult to understand, however, is how yacc / bison conceptually handles empty rule definitions. My analyzer cannot cope with them, because when generating a table, it looks at each character in each rule, recursively, and "empty" is simply not what comes from lexer, and does not decrease by the rule. So, how then do the LALR (1) handlers handle the empty rule? Do they specifically consider this, or is it a “natural” concept with which an effective algorithm should work, without even needing a special awareness of such a concept?

Say a rule that can match any number of pair parentheses that have nothing:

expr:   /* empty */
      | '(' expr ')'
      ;

Input similar to the following will follow this rule:

((((()))))

, '(' ')' , :

  • ')' ()
  • - ()
  • - ...

"" "". , "" expr, ')', '(' expr ')', , , expr ..

" ", . ​​? , , $$ , , '(' ')' lookahead , '(' expr ')', '(' ')'.

+5
2

, , , , - .

: X- , X - , , .

, "" - . , " '(' " "-, '(' lookahead, " "". , , , , , , , , .

Stack       Lookahead    Remaining Input      Action
--------------------------------------------------------------
$           (            ())$                 Shift '('
$(          (            ))$                  Shift '('
$((         )            )$                   Reduce by /* empty */
$((expr     )            )$                   Shift ')'
$((expr)    )            $                    Reduce by '(' expr ')'
$(expr      )            $                    Shift ')'
$(expr)     $                                 Reduce by '(' expr ')'
$expr                                         Accept

, " ", , .

+6

, , d11wtq , :

FOLLOW(X) FIRST(X) ( ε). , A -> B x, B ε, x , FIRST(A). FOLLOW(B).

, LR(1).

- , $, .

:

S -> X | ϵ
X -> id

LR(1) LR(0) lookahead '$':

S -> . X   , '$'
S -> .     , '$'
X -> . id  , '$'

id:

S -> . X   , 'id'
S -> .     , 'id
X -> . id  , 'id'

FIRST FOLLOW:

S -> . X   , '$'

" " , , FIRST(X) $. , .

:

S -> .     , '$'

" " , . , FOLLOW(S): , , , ? . $ FOLLOW(S), . , . S, accept: . accept.

lookahead id. S-geting-empty:

S -> .     , 'id'

S id? . . .

, , . LR(0) LR(1) ( ) , , .

+2

All Articles