Back Next

Observations

It is common for the grammar in a .y file to be visually overwhelmed by the amount of C code in the grammar. The grammar can be made more visable compared to the C code by moving the production bodies into functions.

Here is an example fragment from gcc-2.95 And here is the same code from gcc-3.4.6
 primary:
    IDENTIFIER
        {
          $$ = lastiddecl;
          if (!$$ || $$ == error_mark_node)
            {
              if (yychar == YYEMPTY)
                yychar = YYLEX;
              if (yychar == '(')
                {
                  /* Ordinary implicit function declaration.
                  $$ = implicitly_declare ($1);
                  assemble_external ($$);
                  TREE_USED ($$) = 1;
                }
              else if (current_function_decl == 0)
                {
                  error ("`%s' undeclared here (not in a fun
                         IDENTIFIER_POINTER ($1));
                  $$ = error_mark_node;
                }
              else
                {
                  if (IDENTIFIER_GLOBAL_VALUE ($1) != error_
                      || IDENTIFIER_ERROR_LOCUS ($1) != curr
                  {
                      error ("`%s' undeclared (first use in
                              IDENTIFIER_POINTER ($1));

                      if (! undeclared_variable_notice)
                      {
                    error ("(Each undeclared identifier is r
                          error ("for each function it appea
                          undeclared_variable_notice = 1;
                      }
                  }
                  $$ = error_mark_node;
                  /* Prevent repeated error messages.  */
                  IDENTIFIER_GLOBAL_VALUE ($1) = error_mark_
                  IDENTIFIER_ERROR_LOCUS ($1) = current_func
                }
            }
          else if (TREE_TYPE ($$) == error_mark_node)
            $$ = error_mark_node;
          else if (C_DECL_ANTICIPATED ($$))
            {
              /* The first time we see a build-in function u
                 if it has not been declared.  */
              C_DECL_ANTICIPATED ($$) = 0;
              if (yychar == YYEMPTY)
                yychar = YYLEX;
              if (yychar == '(')
                {
                  /* Omit the implicit declaration we
                     would ordinarily do, so we don't lose
                     the actual built in type.
                     But print a diagnostic for the mismatch
                    if (TREE_CODE ($$) != FUNCTION_DECL)
                      error ("`%s' implicitly declared as fu
                             IDENTIFIER_POINTER (DECL_NAME (
                  else if ((TYPE_MODE (TREE_TYPE (TREE_TYPE
                            != TYPE_MODE (integer_type_node)
                           && (TREE_TYPE (TREE_TYPE ($$))
                               != void_type_node))
                    pedwarn ("type mismatch in implicit decl
                             IDENTIFIER_POINTER (DECL_NAME (
                  /* If it really returns void, change that
                  if (TREE_TYPE (TREE_TYPE ($$)) == void_typ
                    TREE_TYPE ($$)
                      = build_function_type (integer_type_no
                                             TYPE_ARG_TYPES
                }
              else
                pedwarn ("built-in function `%s' used withou
                         IDENTIFIER_POINTER (DECL_NAME ($$))

              /* Do what we would ordinarily do when a fn is
              assemble_external ($$);
              TREE_USED ($$) = 1;
            }
          else
            {
              assemble_external ($$);
              TREE_USED ($$) = 1;
            }

          if (TREE_CODE ($$) == CONST_DECL)
            {
              $$ = DECL_INITIAL ($$);
              /* This is to prevent an enum whose value is 0
                 from being considered a null pointer consta
              $$ = build1 (NOP_EXPR, TREE_TYPE ($$), $$);
              TREE_CONSTANT ($$) = 1;
            }
        } 
primary:
    IDENTIFIER
        {
          if (yychar == YYEMPTY)
            yychar = YYLEX;
          $$ = build_external_ref ($1, yychar == '(');
        }
    | CONSTANT
    | STRING
    | FUNC_NAME
        { $$ = fname_decl (C_RID_CODE ($$), $$); }
    | '(' typename ')' '{'
        {
          start_init (NULL_TREE, NULL, 0);
          $2 = groktypename ($2);
          really_start_incremental_init ($2);
        }
      initlist_maybe_comma '}'  %prec UNARY
        {
          tree constructor = pop_init_level (0);
          tree type = $2;
          finish_init ();

          if (pedantic && ! flag_isoc99)
            pedwarn ("ISO C90 forbids compound literals");
          $$ = build_compound_literal (type, constructor);
        }
    | '(' expr ')'
        {
          char class = TREE_CODE_CLASS (TREE_CODE ($2));
          if (IS_EXPR_CODE_CLASS (class))
            C_SET_EXP_ORIGINAL_CODE ($2, ERROR_MARK);
          $$ = $2;
        }
    | '(' error ')'
        { $$ = error_mark_node; }
    | compstmt_primary_start compstmt_nostart ')'
        {
          tree saved_last_tree;

          if (pedantic)
            pedwarn ("ISO C forbids braced-groups within exp
          saved_last_tree = COMPOUND_BODY ($1);
          RECHAIN_STMTS ($1, COMPOUND_BODY ($1));
          last_tree = saved_last_tree;
          TREE_CHAIN (last_tree) = NULL_TREE;
          if (!last_expr_type)
            last_expr_type = void_type_node;
          $$ = build1 (STMT_EXPR, last_expr_type, $1);
          TREE_SIDE_EFFECTS ($$) = 1;
        }
    | compstmt_primary_start error ')'
        {
          last_tree = COMPOUND_BODY ($1);
          TREE_CHAIN (last_tree) = NULL_TREE;
          $$ = error_mark_node;
        }
    | primary '(' exprlist ')'   %prec '.'
        { $$ = build_function_call ($1, $3); }
    | VA_ARG '(' expr_no_commas ',' typename ')'
        { $$ = build_va_arg ($3, groktypename ($5)); }
    | CHOOSE_EXPR '(' expr_no_commas ',' expr_no_commas ','
        {
          tree c;

          c = fold ($3);
          STRIP_NOPS (c);
          if (TREE_CODE (c) != INTEGER_CST)
            error ("first argument to __builtin_choose_expr
          $$ = integer_zerop (c) ? $7 : $5;
        }
    | TYPES_COMPATIBLE_P '(' typename ',' typename ')'
        {
          tree e1, e2;

          e1 = TYPE_MAIN_VARIANT (groktypename ($3));
          e2 = TYPE_MAIN_VARIANT (groktypename ($5));

          $$ = comptypes (e1, e2, COMPARE_STRICT)
               ? build_int_2 (1, 0) : build_int_2 (0, 0);
        }
    | primary '[' expr ']'   %prec '.'
        { $$ = build_array_ref ($1, $3); }
    | primary '.' identifier
        {
          $$ = build_component_ref ($1, $3);
        }
    | primary POINTSAT identifier
        {
          tree expr = build_indirect_ref ($1, "->");
          $$ = build_component_ref (expr, $3);
        }
    | primary PLUSPLUS
        { $$ = build_unary_op (POSTINCREMENT_EXPR, $1, 0); }
    | primary MINUSMINUS
        { $$ = build_unary_op (POSTDECREMENT_EXPR, $1, 0); }
    ; 
/* vim: set ts=8 sw=4 et : */