5.0 Introduction

5.1 Metalanguage

5.2 LR-Family Parsing

5.3 Error Handling

5.4 Compaction of Tables

5.5 Yacc

5.6 Summary

Web References

Exercises

5.5.1 YACC Metalanguage

The YACC metalanguage has a form similar to that for LEX:

    Definitions <-- C declaration and token definitions>

    %%

    Rules <-- BNF plus associated actions>

    %%

    User-Written Procedures <-- In C>

The Definitions section can contain the typical things found at the top of a C program: constant definitions, structure declarations, include statements, and user variable definitions. Tokens may also be defined here.

The Rules section contains the BNF. The left-hand side is separated from the right-hand side by a color, ":". The actions may appear interspersed in the right-hand side; this means they will be executed when all the tokens or nonterminals to the action's left are shifted. If the action occurs after a production, it will be invoked when a reduction ( of the right-hand side to the left-hand side of a production ) is made.

Thus, a YACC input file looks like the following:

        %{
        #include 1
        #include 2
        #define ...
        %}
        %token ...
        ...
        %%
        Nonterminal: Right-Hand side {semantic action 1}
                   | Right-hand side {semantic action 2}
        ...
        %%
        C functions

Example 6 shows a YACC input file for the language consisting of sequences of assignment statements.

EXAMPLE 6 Sequences of assignment statements in YACC

        %{
        #include <stdio.h>
        %}
        %start program
        %token Id
        %token Lit
        %%

Program:        Statements              {printf("Program \n");};
Statements:     Statement Statements    {printf("Statements \n)";};
                | Statement             {printf("Statements \n");};
Statement:      AsstStmt                {printf("Statement \n");};
AsstStmt:       Id ":=" Expression      {printf("AsstStmt \n");};
Expression:     Expression "=" Term     {printf("Expression \n");};
                | Expression "-" Term   {printf("Expression \n");};
                | Term                  {printf("Expression \n");};
Term:           Term "*" Factor         {printf("Term \n");};
                | Term "/" Factor       {printf("Term \n");};
                | Factor                {printf("Term \n");};
Factor:         "(" Expression ")"      {printf("Factor \n");};
                | Id                    {printf("Factor \n");};
                | Lit                   {printf("Factor \n");};
%%
#include lex.yy.c
 
main()
{
  yyparse ();
}

In Example 6, the lexical analyzer is the one output by LEX, or users may write their own ( and call it "lex.yy.c"). Alternatively, a function called "yylex()", consisting of code to find tokens, could be written in either the definition section or the User-Written Procedures section.

YACC contain facilities for specifying precedence and associativity of operators and for specifying errors. An error production in YACC is of the form:

B error { Action }

where is an erroneous construct.

We will look at this example again in Chapter 6 when we discuss semantic analysis.


Send questions and comments to: Karen Lemone