/****************************************************************/
/*                                                              */
/*           C Language YACC input grammar                      */
/*                                                              */
/****************************************************************/
%{

/* to show the reductions as the parse proceeds, define REDUCE. */

#define REDUCE
#undef REDUCE

/* to print the parse tree when the parse has successfully      */
/* completed, define TREE.                                      */

#undef TREE
#define TREE

#define TRUE   1
#define FALSE  0
#define EXIT_FAILURE (-1)
/*-----------------------------------*/
/*- C language includes        ------*/
#include <string.h>
#include <varargs.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <ctype.h>
#include "tree.h"
#include "types.h"
#include "symtbl.h"

int yylex();
extern int yylineno;

/** Yacc function prototype     */
int yyparse();      /* function prototype */

#ifdef REDUCE
#   define reduce(a) printf("%s\n",a)
#else
#   define reduce(a)
#endif

%}

%union {
	struct {
		struct node *tree_info;
		struct SymbolTableNode *symptr;
		struct type_info_t type_info;
	} info;
}

/*---------------------------------------------------------------------------*/
%token <info> SEMICOLON
%token <info> AUTO
%token <info> REGISTER
%token <info> STATIC
%token <info> EXTERN
%token <info> TYPEDEF
%token <info> VOID
%token <info> CHAR
%token <info> SHORT
%token <info> INT
%token <info> LONG
%token <info> FLOAT
%token <info> DOUBLE
%token <info> SIGNED
%token <info> UNSIGNED
%token <info> TYPEDEF_NAME
%token <info> CONST
%token <info> VOLATILE
%token <info> IDENTIFIER
%token <info> LEFT_BANANA
%token <info> RIGHT_BANANA
%token <info> STRUCT
%token <info> C_UNION
%token <info> COMMA
%token <info> EQUAL
%token <info> COLON
%token <info> ENUM
%token <info> LEFT_PARENTH
%token <info> RIGHT_PARENTH
%token <info> LEFT_BRACKET
%token <info> RIGHT_BRACKET
%token <info> ASTERISK
%token <info> ELLIPSIS
%token <info> CASE
%token <info> DEFAULT
%token <info> IF
%token <info> ELSE
%token <info> SWITCH
%token <info> WHILE
%token <info> DO
%token <info> FOR
%token <info> GOTO
%token <info> CONTINUE
%token <info> BREAK
%token <info> RETURN
%token <info> MULTIPLY_EQUAL
%token <info> DIVIDE_EQUAL
%token <info> REMAINDER_EQUAL
%token <info> PLUS_EQUAL
%token <info> MINUS_EQUAL
%token <info> LEFT_SHIFT_EQUAL
%token <info> RIGHT_SHIFT_EQUAL
%token <info> AND_EQUAL
%token <info> XOR_EQUAL
%token <info> OR_EQUAL
%token <info> QUESTION
%token <info> OR_OR
%token <info> AND_AND
%token <info> EXCLAMATION
%token <info> CIRCONFLEX
%token <info> AMPERSAND
%token <info> EQUAL_EQUAL
%token <info> NOT_EQUAL
%token <info> LESS
%token <info> MORE
%token <info> LESS_EQUAL
%token <info> GREATER_EQUAL
%token <info> LEFT_SHIFT
%token <info> RIGHT_SHIFT
%token <info> PLUS
%token <info> MOINUS
%token <info> SLASH
%token <info> PERCENT
%token <info> PLUS_PLUS
%token <info> MINUS_MINUS
%token <info> SIZEOF
%token <info> TILDE
%token <info> OR
%token <info> POINT
%token <info> ARROW
%token <info> STRING
%token <info> INTEGER_CONSTANT
%token <info> CHARACTER_CONSTANT
%token <info> FLOATING_CONSTANT
%token <info> ENUMERATION_CONSTANT
%token <info> NEIGHBOUR
%token <info> PLURAL
%token <info> RECEIVE
%token <info> SEND
%token <info> SHARED
%token <info> VECTOR

%type <info> constant primary_expression postfix_expression
%type <info> argument_expression_list assignment_expression
%type <info> expression unary_operator unary_expression
%type <info> cast_expression multiplicative_expression
%type <info> additive_expression shift_expression 
%type <info> relational_expression equality_expression
%type <info> AND_expression exclusive_OR_expression
%type <info> inclusive_OR_expression logical_AND_expression
%type <info> logical_OR_expression constant_expression
%type <info> conditional_expression type_name expression
%type <info> assignment_operator assignment_expression
%type <info> jump_statement opt_expr iteration_statement
%type <info> selection_statement statement_list compound_statement
%type <info> expression_statement labeled_statement statement
%type <info> direct_abstract_declarator abstract_declarator type_name
%type <info> initializer_list initializer identifier_list
%type <info> parameter_declaration parameter_list
%type <info> parameter_type_list type_qualifier_list pointer
%type <info> direct_declarator declarator enumerator
%type <info> enumerator_list enum_specifier struct_declarator
%type <info> struct_declarator_list specifier_qualifier_list
%type <info> struct_declaration init_declarator 
%type <info> init_declarator_list struct_declaration_list
%type <info> struct_or_union struct_or_union_specifier
%type <info> type_qualifier type_specifier 
%type <info> storage_class_specifier declaration_specifiers
%type <info> declaration declaration_list
%type <info> function_definition external_definition
%type <info> translation_unit

%start START

%%      /* beginning of rules section */

START
    :   translation_unit
	{
		reduce("START => translation_unit");
#ifdef TREE
		print_tree($1.tree_info,0);
#endif
	}
    ;

translation_unit
    :   external_definition
	{
		reduce("translation_unit => external_definition");
		$$.tree_info = create_node("translation_unit");
		add_child($$.tree_info,$1.tree_info);
	}
    |   translation_unit   external_definition
	{
		reduce("translation_unit => translation_unit external_definition");
		$$.tree_info = create_node("translation_unit");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    ;

external_definition
    :   function_definition
	{
		reduce("external_definition => function_definition");
		$$.tree_info = create_node("external_definition");
		add_child($$.tree_info,$1.tree_info);
	}
    |   declaration
	{
		reduce("external_definition => declaration");
		$$.tree_info = create_node("external_definition");
		add_child($$.tree_info,$1.tree_info);
	}
    ;

function_definition
    :   declaration_specifiers  declarator  declaration_list compound_statement
	{
		reduce("function_definition => decl_spec declarator decl_list comp_stmt");
		$$.tree_info = create_node("function_definition");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
		add_child($$.tree_info,$4.tree_info);
	}
    |                           declarator  declaration_list compound_statement
	{
		reduce("function_definition => declarator decl_list comp_stmt");
		$$.tree_info = create_node("function_definition");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    |   declaration_specifiers  declarator compound_statement
	{
		reduce("function_definition => decl_spec declarator comp_stmt");
		$$.tree_info = create_node("function_definition");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    |                           declarator compound_statement
	{
		reduce("function_definition => declarator comp_stmt");
		$$.tree_info = create_node("function_definition");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    ;

declaration_list
    :   declaration
	{
		reduce("declaration_list => declaration");
		$$.tree_info = create_node("declaration");
		add_child($$.tree_info,$1.tree_info);
	}
    |   declaration_list  declaration
	{
		reduce("declaration_list => decl_list declaration");
		$$.tree_info = create_node("declaration");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    ;

declaration
    :   declaration_specifiers   init_declarator_list SEMICOLON
	{
		reduce("declaration => decl_spec init_decl_list ;");
		$$.tree_info = create_node("declaration");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
		if ($1.type_info.storage_class == TYPEDEF_C) {
			$2.symptr->symtype = TYPEDEF_T;
		}
	}
    |   declaration_specifiers                        SEMICOLON
	{
		reduce("declaration => decl_spec ;");
		$$.tree_info = create_node("declaration");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    ;

declaration_specifiers
    :   storage_class_specifier   declaration_specifiers
	{
		reduce("declaration_specifiers => storage_cl_spec decl_spec");
		$$.tree_info = create_node("declaration_specifiers");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		$$.type_info.storage_class = $1.type_info.storage_class;
	}
    |   storage_class_specifier
	{
		reduce("declaration_specifiers => storage_cl_spec");
		$$.tree_info = create_node("declaration_specifiers");
		add_child($$.tree_info,$1.tree_info);
		$$.type_info.storage_class = $1.type_info.storage_class;
	}
    |   type_specifier            declaration_specifiers
	{
		reduce("declaration_specifiers => type_spec decl_spec");
		$$.tree_info = create_node("declaration_specifiers");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    |   type_specifier
	{
		reduce("declaration_specifiers => type_specifier");
		$$.tree_info = create_node("declaration_specifiers");
		add_child($$.tree_info,$1.tree_info);
	}
    |   type_qualifier            declaration_specifiers
	{
		reduce("declaration_specifiers => type_qualifier decl_spec");
		$$.tree_info = create_node("declaration_specifiers");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    |   type_qualifier
	{
		reduce("declaration_specifiers => type_qualifier");
		$$.tree_info = create_node("declaration_specifiers");
		add_child($$.tree_info,$1.tree_info);
	}
    ;

storage_class_specifier
    :   AUTO
	{
		reduce("storage_class_specifier => AUTO");
		$$.tree_info = create_node("storage_class_specifier");
		add_child($$.tree_info,$1.tree_info);
	}
    |   REGISTER
	{
		reduce("storage_class_specifier => REGISTER");
		$$.tree_info = create_node("storage_class_specifier");
		add_child($$.tree_info,$1.tree_info);
	}
    |   STATIC
	{
		reduce("storage_class_specifier => STATIC");
		$$.tree_info = create_node("storage_class_specifier");
		add_child($$.tree_info,$1.tree_info);
	}
    |   EXTERN
	{
		reduce("storage_class_specifier => EXTERN");
		$$.tree_info = create_node("storage_class_specifier");
		add_child($$.tree_info,$1.tree_info);
	}
    |   TYPEDEF
	{
		reduce("storage_class_specifier => TYPEDEF");
		$$.tree_info = create_node("storage_class_specifier");
		add_child($$.tree_info,$1.tree_info);
		$$.type_info.storage_class = TYPEDEF_C;
	}
    ;

type_specifier
    :   VOID
	{
		reduce("type_specifier => VOID");
		$$.tree_info = create_node("type_specifier");
		add_child($$.tree_info,$1.tree_info);
	}
    |   CHAR
	{
		reduce("type_specifier => CHAR");
		$$.tree_info = create_node("type_specifier");
		add_child($$.tree_info,$1.tree_info);
	}
    |   SHORT
	{
		reduce("type_specifier => SHORT");
		$$.tree_info = create_node("type_specifier");
		add_child($$.tree_info,$1.tree_info);
	}
    |   INT
	{
		reduce("type_specifier => INT");
		$$.tree_info = create_node("type_specifier");
		add_child($$.tree_info,$1.tree_info);
	}
    |   LONG
	{
		reduce("type_specifier => LONG");
		$$.tree_info = create_node("type_specifier");
		add_child($$.tree_info,$1.tree_info);
	}
    |   FLOAT
	{
		reduce("type_specifier => FLOAT");
		$$.tree_info = create_node("type_specifier");
		add_child($$.tree_info,$1.tree_info);
	}
    |   DOUBLE
	{
		reduce("type_specifier => DOUBLE");
		$$.tree_info = create_node("type_specifier");
		add_child($$.tree_info,$1.tree_info);
	}
    |   SIGNED
	{
		reduce("type_specifier => SIGNED");
		$$.tree_info = create_node("type_specifier");
		add_child($$.tree_info,$1.tree_info);
	}
    |   UNSIGNED
	{
		reduce("type_specifier => UNSIGNED");
		$$.tree_info = create_node("type_specifier");
		add_child($$.tree_info,$1.tree_info);
	}
    |   struct_or_union_specifier
	{
		reduce("type_specifier => struct_or_union_specifier");
		$$.tree_info = create_node("type_specifier");
		add_child($$.tree_info,$1.tree_info);
	}
    |   enum_specifier
	{
		reduce("type_specifier => enum_specifier");
		$$.tree_info = create_node("type_specifier");
		add_child($$.tree_info,$1.tree_info);
	}
    |   TYPEDEF_NAME
	{
		reduce("type_specifier => TYPEDEF_NAME");
		$$.tree_info = create_node("type_specifier");
		add_child($$.tree_info,$1.tree_info);
	}
    ;

type_qualifier
    :   CONST
	{
		reduce("type_qualifier => CONST");
		$$.tree_info = create_node("type_qualifier");
		add_child($$.tree_info,$1.tree_info);
	}
    |   VOLATILE
	{
		reduce("type_qualifier => VOLATILE");
		$$.tree_info = create_node("type_qualifier");
		add_child($$.tree_info,$1.tree_info);
	}
    ;

struct_or_union_specifier
    :   struct_or_union  IDENTIFIER  LEFT_BANANA  struct_declaration_list RIGHT_BANANA
	{
		reduce("struct_or_union_specifier => struct_or_union ident { struct_decl_list }");
		$$.tree_info = create_node("struct_or_union_specifier");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
		add_child($$.tree_info,$4.tree_info);
		add_child($$.tree_info,$5.tree_info);
	}
    |   struct_or_union              LEFT_BANANA  struct_declaration_list RIGHT_BANANA
	{
		reduce("struct_or_union_specifier => struct_or_union { struct_decl_list }");
		$$.tree_info = create_node("struct_or_union_specifier");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
		add_child($$.tree_info,$4.tree_info);
	}
    |   struct_or_union  IDENTIFIER
	{
		reduce("struct_or_union_specifier => struct_or_union ident");
		$$.tree_info = create_node("struct_or_union_specifier");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    ;

struct_or_union
    :   STRUCT
	{
		reduce("struct_or_union => STRUCT");
		$$.tree_info = create_node("struct_or_union");
		add_child($$.tree_info,$1.tree_info);
	}
    |   C_UNION
	{
		reduce("struct_or_union => C_UNION");
		$$.tree_info = create_node("struct_or_union");
		add_child($$.tree_info,$1.tree_info);
	}
    ;

struct_declaration_list
    :   struct_declaration
	{
		reduce("struct_declaration_list => struct_declaration");
		$$.tree_info = create_node("struct_declaration_list");
		add_child($$.tree_info,$1.tree_info);
	}
    |   struct_declaration_list   struct_declaration
	{
		reduce("struct_declaration_list => struct_decl_list struct_decl");
		$$.tree_info = create_node("struct_declaration_list");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    ;

init_declarator_list
    :   init_declarator
	{
		reduce("init_declarator_list => init_declarator");
		$$.tree_info = create_node("init_declarator_list");
		add_child($$.tree_info,$1.tree_info);
		$$.symptr = $1.symptr;
	}
    |   init_declarator_list   COMMA   init_declarator
	{
		reduce("init_declarator_list => init_decl_list , init_decl");
		$$.tree_info = create_node("init_declarator_list");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    ;

init_declarator
    :   declarator
	{
		reduce("init_declarator => declarator");
		$$.tree_info = create_node("init_declarator");
		add_child($$.tree_info,$1.tree_info);
		$$.symptr = $1.symptr;
	}
    |   declarator   EQUAL   initializer
	{
		reduce("init_declarator => declarator = initializer");
		$$.tree_info = create_node("init_declarator");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    ;

struct_declaration
    :   specifier_qualifier_list  struct_declarator_list   SEMICOLON
	{
		reduce("struct_declaration => spec_qual_list struct_decl_list ;");
		$$.tree_info = create_node("struct_declaration");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    ;

specifier_qualifier_list
    :   type_specifier  specifier_qualifier_list
	{
		reduce("specifier_qualifier_list => type_specifier spec_qual_list");
		$$.tree_info = create_node("specifier_qualifier_list");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    |   type_specifier
	{
		reduce("specifier_qualifier_list => type_specifier");
		$$.tree_info = create_node("specifier_qualifier_list");
		add_child($$.tree_info,$1.tree_info);
	}
    |   type_qualifier  specifier_qualifier_list
	{
		reduce("specifier_qualifier_list => type_qualifier spec_qual_list");
		$$.tree_info = create_node("specifier_qualifier_list");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    |   type_qualifier
	{
		reduce("specifier_qualifier_list => type_qualifier");
		$$.tree_info = create_node("specifier_qualifier_list");
		add_child($$.tree_info,$1.tree_info);
	}
    ;

struct_declarator_list
    :   struct_declarator
	{
		reduce("struct_declarator_list => struct_declarator");
		$$.tree_info = create_node("struct_declarator_list");
		add_child($$.tree_info,$1.tree_info);
	}
    |   struct_declarator_list   COMMA   struct_declarator
	{
		reduce("struct_declarator_list => struct_decl_list , struct_decl");
		$$.tree_info = create_node("struct_declarator_list");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    ;

struct_declarator
    :   declarator
	{
		reduce("struct_declarator => declarator");
		$$.tree_info = create_node("declarator");
		add_child($$.tree_info,$1.tree_info);
	}
    |   declarator   COLON   constant_expression
	{
		reduce("struct_declarator => declarator : const_expr");
		$$.tree_info = create_node("declarator");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    |                COLON   constant_expression
	{
		reduce("struct_declarator => : const_expr");
		$$.tree_info = create_node("declarator");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    ;

enum_specifier
    :   ENUM  IDENTIFIER    LEFT_BANANA  enumerator_list  RIGHT_BANANA
	{
		reduce("enum_specifier => ENUM IDENT { enum_list }");
		$$.tree_info = create_node("enum_specifier");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
		add_child($$.tree_info,$4.tree_info);
		add_child($$.tree_info,$5.tree_info);
	}
    |   ENUM                LEFT_BANANA  enumerator_list  RIGHT_BANANA
	{
		reduce("enum_specifier => ENUM { enum_list }");
		$$.tree_info = create_node("enum_specifier");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
		add_child($$.tree_info,$4.tree_info);
	}
    |   ENUM  IDENTIFIER
	{
		reduce("enum_specifier => ENUM ");
		$$.tree_info = create_node("enum_specifier");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    ;

enumerator_list
    :   enumerator
	{
		reduce("enumerator_list => enumerator");
		$$.tree_info = create_node("enumerator_list");
		add_child($$.tree_info,$1.tree_info);
	}
    |   enumerator_list  COMMA  enumerator
	{
		reduce("enumerator_list => enum_list , enumerator");
		$$.tree_info = create_node("enumerator_list");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    ;

enumerator
    :   IDENTIFIER
	{
		reduce("enumerator => IDENTIFIER");
		$$.tree_info = create_node("enumerator");
		add_child($$.tree_info,$1.tree_info);
	}
    |   IDENTIFIER   EQUAL   constant_expression
	{
		reduce("enumerator => IDENTIFIER = const_expr");
		$$.tree_info = create_node("enumerator");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    ;

declarator
    :   pointer   direct_declarator
	{
		reduce("declarator => pointer direct_declarator");
		$$.tree_info = create_node("declarator");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		$$.symptr = $1.symptr;
	}
    |             direct_declarator
	{
		reduce("declarator => direct_declarator");
		$$.tree_info = create_node("declarator");
		add_child($$.tree_info,$1.tree_info);
		$$.symptr = $1.symptr;
	}
    ;

direct_declarator
    :   IDENTIFIER
	{
		reduce("direct_declarator => IDENTIFIER");
		$$.tree_info = create_node("direct_declarator");
		add_child($$.tree_info,$1.tree_info);
		$$.symptr = $1.symptr;
	}
    |   LEFT_PARENTH  declarator  RIGHT_PARENTH
	{
		reduce("direct_declarator => ( declarator )");
		$$.tree_info = create_node("direct_declarator");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
		$$.symptr = $2.symptr;
	}
    |   direct_declarator  LEFT_BRACKET  constant_expression  RIGHT_BRACKET
	{
		reduce("direct_declarator => direct_decl [ const_expr ]");
		$$.tree_info = create_node("direct_declarator");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
		add_child($$.tree_info,$4.tree_info);
		$$.symptr = $1.symptr;
	}
    |   direct_declarator  LEFT_BRACKET                       RIGHT_BRACKET
	{
		reduce("direct_declarator => direct_declarator [ ]");
		$$.tree_info = create_node("direct_declarator");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
		$$.symptr = $1.symptr;
	}
    |   direct_declarator  LEFT_PARENTH  parameter_type_list  RIGHT_PARENTH
	{
		reduce("direct_declarator => direct_decl ( parm_type_list )");
		$$.tree_info = create_node("direct_declarator");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
		add_child($$.tree_info,$4.tree_info);
		$$.symptr = $1.symptr;
	}
    |   direct_declarator  LEFT_PARENTH  identifier_list      RIGHT_PARENTH
	{
		reduce("direct_declarator => direct_decl ( ident_list )");
		$$.tree_info = create_node("direct_declarator");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
		add_child($$.tree_info,$4.tree_info);
		$$.symptr = $1.symptr;
	}
    |   direct_declarator  LEFT_PARENTH                       RIGHT_PARENTH
	{
		reduce("direct_declarator => direct_declarator ( )");
		$$.tree_info = create_node("direct_declarator");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
		$$.symptr = $1.symptr;
	}
    ;

pointer
    :   ASTERISK  type_qualifier_list
	{
		reduce("pointer => * type_qualifier_list");
		$$.tree_info = create_node("pointer");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    |   ASTERISK
	{
		reduce("pointer => * ");
		$$.tree_info = create_node("pointer");
		add_child($$.tree_info,$1.tree_info);
	}
    |   ASTERISK  type_qualifier_list  pointer
	{
		reduce("pointer => * type_qualifier_list pointer");
		$$.tree_info = create_node("pointer");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    |   ASTERISK                       pointer
	{
		reduce("pointer => * pointer");
		$$.tree_info = create_node("pointer");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    ;

type_qualifier_list
    :   type_qualifier
	{
		reduce("type_qualifier_list => type_qualifier");
		$$.tree_info = create_node("type_qualifier_list");
		add_child($$.tree_info,$1.tree_info);
	}
    |   type_qualifier_list   type_qualifier
	{
		reduce("type_qualifier_list => type_qual_list type_qualifier");
		$$.tree_info = create_node("type_qualifier_list");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    ;

parameter_type_list
    :   parameter_list
	{
		reduce("parametery_type_list => parameter_list");
		$$.tree_info = create_node("parameter_type_list");
		add_child($$.tree_info,$1.tree_info);
	}
    |   parameter_list   COMMA   ELLIPSIS
	{
		reduce("parametery_type_list => parameter_list , ...");
		$$.tree_info = create_node("parameter_type_list");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    ;

parameter_list
    :   parameter_declaration
	{
		reduce("parameter_list => parameter_declaration");
		$$.tree_info = create_node("parameter_list");
		add_child($$.tree_info,$1.tree_info);
	}
    |   parameter_list   COMMA   parameter_declaration
	{
		reduce("parameter_list => parm_list , parameter_declaration");
		$$.tree_info = create_node("parameter_list");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    ;

parameter_declaration
    :   declaration_specifiers   declarator
	{
		reduce("parm_decl => decl_specifier declarator");
		$$.tree_info = create_node("parameter_declaration");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    |   declaration_specifiers   abstract_declarator
	{
		reduce("parm_decl => decl_specifier abstract_declarator");
		$$.tree_info = create_node("parameter_declaration");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    |   declaration_specifiers
	{
		reduce("parm_decl => decl_specifier");
		$$.tree_info = create_node("parameter_declaration");
		add_child($$.tree_info,$1.tree_info);
	}
    ;

identifier_list
    :   IDENTIFIER
	{
		reduce("identifier_list => IDENTIFIER");
		$$.tree_info = create_node("identifier_list");
		add_child($$.tree_info,$1.tree_info);
	}
    |   identifier_list   COMMA   IDENTIFIER
	{
		reduce("identifier_list => identifier_list , IDENTIFIER");
		$$.tree_info = create_node("identifier_list");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    ;
initializer
    :   assignment_expression
	{
		reduce("initializer => assignment_expression");
		$$.tree_info = create_node("initializer");
		add_child($$.tree_info,$1.tree_info);
	}
    |   LEFT_BANANA   initializer_list           RIGHT_BANANA
	{
		reduce("initializer => { initializer_list }");
		$$.tree_info = create_node("initializer");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    |   LEFT_BANANA   initializer_list   COMMA   RIGHT_BANANA
	{
		reduce("initializer => { initializer_list , }");
		$$.tree_info = create_node("initializer");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
		add_child($$.tree_info,$4.tree_info);
	}
    ;

initializer_list
    :   initializer
	{
		reduce("initializer_list => initializer");
		$$.tree_info = create_node("initializer_list");
		add_child($$.tree_info,$1.tree_info);
	}
    |   initializer_list  COMMA  initializer
	{
		reduce("initializer_list => initializer_list , initializer");
		$$.tree_info = create_node("initializer_list");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    ;

type_name
    :   specifier_qualifier_list  abstract_declarator
	{
		reduce("type_name => specifier_qual_list abstract_decl");
		$$.tree_info = create_node("type_name");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    |   specifier_qualifier_list
	{
		reduce("type_name => specifier_qual_list");
		$$.tree_info = create_node("type_name");
		add_child($$.tree_info,$1.tree_info);
	}
    ;

abstract_declarator
    :   pointer
	{
		reduce("abstract_declarator => pointer");
		$$.tree_info = create_node("abstract_declarator");
		add_child($$.tree_info,$1.tree_info);
	}
    |   pointer  direct_abstract_declarator
	{
		reduce("abstract_declarator => pointer direct_abs_decl");
		$$.tree_info = create_node("abstract_declarator");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    |            direct_abstract_declarator
	{
		reduce("abstract_declarator => direct_abs_decl");
		$$.tree_info = create_node("abstract_declarator");
		add_child($$.tree_info,$1.tree_info);
	}
    ;

direct_abstract_declarator
    :                            LEFT_PARENTH  abstract_declarator RIGHT_PARENTH
	{
		reduce("direct_abs_decl => ( abs_decl )");
		$$.tree_info = create_node("direct_abstract_declarator");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    | direct_abstract_declarator LEFT_BRACKET constant_expression  RIGHT_BRACKET
	{
		reduce("direct_abs_decl => direct_abs_decl [ const_expr ]");
		$$.tree_info = create_node("direct_abstract_declarator");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
		add_child($$.tree_info,$4.tree_info);
	}
    | direct_abstract_declarator LEFT_BRACKET                      RIGHT_BRACKET
	{
		reduce("direct_abs_decl => direct_abs_decl [ ]");
		$$.tree_info = create_node("direct_abstract_declarator");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    |                            LEFT_BRACKET constant_expression  RIGHT_BRACKET
	{
		reduce("direct_abs_decl => [ const_expr ]");
		$$.tree_info = create_node("direct_abstract_declarator");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    |                            LEFT_BRACKET                      RIGHT_BRACKET
	{
		reduce("direct_abs_decl => [ ]");
		$$.tree_info = create_node("direct_abstract_declarator");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    | direct_abstract_declarator LEFT_PARENTH parameter_type_list  RIGHT_PARENTH
	{
		reduce("direct_abs_decl => direct_abs_decl ( parm_type_list )");
		$$.tree_info = create_node("direct_abstract_declarator");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
		add_child($$.tree_info,$4.tree_info);
	}
    | direct_abstract_declarator LEFT_PARENTH                      RIGHT_PARENTH
	{
		reduce("direct_abs_decl => direct_abs_decl ( )");
		$$.tree_info = create_node("direct_abstract_declarator");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    |                            LEFT_PARENTH parameter_type_list  RIGHT_PARENTH
	{
		reduce("direct_abs_decl => ( parm_type_list )");
		$$.tree_info = create_node("direct_abstract_declarator");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    |                            LEFT_PARENTH                      RIGHT_PARENTH
	{
		reduce("direct_abs_decl => ( )");
		$$.tree_info = create_node("direct_abstract_declarator");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    ;

statement
    :   labeled_statement
	{
		reduce("statement => labeled_stmt");
		$$.tree_info = create_node("statement");
		add_child($$.tree_info,$1.tree_info);
	}
    |   expression_statement
	{
		reduce("statement => expression_stmt");
		$$.tree_info = create_node("statement");
		add_child($$.tree_info,$1.tree_info);
	}
    |   compound_statement
	{
		reduce("statement => compound_stmt");
		$$.tree_info = create_node("statement");
		add_child($$.tree_info,$1.tree_info);
	}
    |   iteration_statement
	{
		reduce("statement => iteration_stmt");
		$$.tree_info = create_node("statement");
		add_child($$.tree_info,$1.tree_info);
	}
    |   jump_statement
	{
		reduce("statement => jump_stmt");
		$$.tree_info = create_node("statement");
		add_child($$.tree_info,$1.tree_info);
	}
    |   selection_statement
	{
		reduce("statement => selection_stmt");
		$$.tree_info = create_node("statement");
		add_child($$.tree_info,$1.tree_info);
	}
    ;


labeled_statement
    :   IDENTIFIER                   COLON  statement
	{
		reduce("labeled_statement => identifier : stmt");
		$$.tree_info = create_node("labeled_statement");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    |   CASE   constant_expression   COLON  statement
	{
		reduce("labeled_statement => CASE const_expr : stmt");
		$$.tree_info = create_node("labeled_statement");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
		add_child($$.tree_info,$4.tree_info);
	}
    |   DEFAULT                      COLON  statement
	{
		reduce("labeled_statement => DEFAULT : stmt");
		$$.tree_info = create_node("labeled_statement");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    ;

expression_statement
    :   expression  SEMICOLON
	{
		reduce("expression_statement => expression ;");
		$$.tree_info = create_node("expression_statement");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    |               SEMICOLON
	{
		reduce("expression_statement => ;");
		$$.tree_info = create_node("expression_statement");
		add_child($$.tree_info,$1.tree_info);
	}
    ;

compound_statement
    :   LEFT_BANANA   declaration_list   statement_list   RIGHT_BANANA
	{
		reduce("compound_stmt => { decl_list stmt_list }");
		$$.tree_info = create_node("compound_statement");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
		add_child($$.tree_info,$4.tree_info);
	}
    |   LEFT_BANANA   declaration_list                    RIGHT_BANANA
	{
		reduce("compound_stmt => { decl_list }");
		$$.tree_info = create_node("compound_statement");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    |   LEFT_BANANA                      statement_list   RIGHT_BANANA
	{
		reduce("compound_stmt => { stmt_list }");
		$$.tree_info = create_node("compound_statement");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    |   LEFT_BANANA                                       RIGHT_BANANA
	{
		reduce("compound_stmt => { }");
		$$.tree_info = create_node("compound_statement");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    ;

statement_list
    :   statement
	{
		reduce("statement_list => statement");
		$$.tree_info = create_node("statement_list");
		add_child($$.tree_info,$1.tree_info);
	}
    |   statement_list  statement
	{
		reduce("statement_list => statement_list statement");
		$$.tree_info = create_node("statement_list");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    ;

selection_statement
    :   SWITCH LEFT_PARENTH expression RIGHT_PARENTH statement
	{
		reduce("selection_stmt => SWITCH ( exp ) stmt");
		$$.tree_info = create_node("selection_statement");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
		add_child($$.tree_info,$4.tree_info);
		add_child($$.tree_info,$5.tree_info);
	}
    |   IF     LEFT_PARENTH expression RIGHT_PARENTH statement
	{
		reduce("selection_stmt => IF ( exp ) stmt");
		$$.tree_info = create_node("selection_statement");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
		add_child($$.tree_info,$4.tree_info);
		add_child($$.tree_info,$5.tree_info);
	}
    |   IF     LEFT_PARENTH expression RIGHT_PARENTH statement ELSE statement
	{
		reduce("selection_stmt => IF ( exp ) stmt ELSE stmt");
		$$.tree_info = create_node("selection_statement");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
		add_child($$.tree_info,$4.tree_info);
		add_child($$.tree_info,$5.tree_info);
		add_child($$.tree_info,$6.tree_info);
		add_child($$.tree_info,$7.tree_info);
	}
    ;

iteration_statement
    :     WHILE   LEFT_PARENTH   expression   RIGHT_PARENTH   statement
	{
		reduce("iteration_stmt => WHILE ( exp ) stmt");
		$$.tree_info = create_node("iteration_statement");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
		add_child($$.tree_info,$4.tree_info);
		add_child($$.tree_info,$5.tree_info);
	}
    | DO   statement   WHILE   LEFT_PARENTH   expression   RIGHT_PARENTH   SEMICOLON
	{
		reduce("iteration_stmt => DO stmt WHILE ( exp ) ;");
		$$.tree_info = create_node("iteration_statement");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
		add_child($$.tree_info,$4.tree_info);
		add_child($$.tree_info,$5.tree_info);
		add_child($$.tree_info,$6.tree_info);
		add_child($$.tree_info,$7.tree_info);
	}
    | FOR LEFT_PARENTH opt_expr SEMICOLON opt_expr SEMICOLON opt_expr RIGHT_PARENTH statement
	{
		reduce("iteration_stmt => FOR ( opt_exp ; opt_exp ; opt_exp ) stmt");
		$$.tree_info = create_node("iteration_statement");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
		add_child($$.tree_info,$4.tree_info);
		add_child($$.tree_info,$5.tree_info);
		add_child($$.tree_info,$6.tree_info);
		add_child($$.tree_info,$7.tree_info);
		add_child($$.tree_info,$8.tree_info);
		add_child($$.tree_info,$9.tree_info);
	}
    ;

opt_expr
    :
	{
		reduce("opt_expr => <NULL>");
		$$.tree_info = create_node("opt_expr");
	}
    |    expression
	{
		reduce("opt_expr => expression");
		$$.tree_info = create_node("opt_expr");
		add_child($$.tree_info,$1.tree_info);
	}
    ;

jump_statement
    :   GOTO   IDENTIFIER    SEMICOLON
	{
		reduce("jump_statement => GOTO ident ;");
		$$.tree_info = create_node("jump_statement");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    |   CONTINUE             SEMICOLON
	{
		reduce("jump_statement => CONTINUE ;");
		$$.tree_info = create_node("jump_statement");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    |   BREAK                SEMICOLON
	{
		reduce("jump_statement => BREAK ;");
		$$.tree_info = create_node("jump_statement");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    |   RETURN   expression  SEMICOLON
	{
		reduce("jump_statement => RETURN expression ;");
		$$.tree_info = create_node("jump_statement");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    |   RETURN               SEMICOLON
	{
		reduce("jump_statement => RETURN ;");
		$$.tree_info = create_node("jump_statement");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    ;

expression
    :   assignment_expression
	{
		reduce("expression => assignment_expression");
		$$.tree_info = create_node("expression");
		add_child($$.tree_info,$1.tree_info);
	}
    |   expression   COMMA   assignment_expression
	{
		reduce("expression => expression , assignment_expression");
		$$.tree_info = create_node("expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    ;

assignment_expression
    :   conditional_expression
	{
		reduce("assignment_exp => cond_exp");
		$$.tree_info = create_node("assignment_expression");
		add_child($$.tree_info,$1.tree_info);
	}
    |   unary_expression assignment_operator assignment_expression
	{
		reduce("assignment_exp => unary_exp assign_op assign_exp");
		$$.tree_info = create_node("assignment_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    ;

assignment_operator
    :   EQUAL
	{
		reduce("assignment_operator => EQUAL");
		$$.tree_info = create_node("assignment_operator");
		add_child($$.tree_info,$1.tree_info);
	}
    |   MULTIPLY_EQUAL
	{
		reduce("assignment_operator => MULT_EQUAL");
		$$.tree_info = create_node("assignment_operator");
		add_child($$.tree_info,$1.tree_info);
	}
    |   DIVIDE_EQUAL
	{
		reduce("assignment_operator => DIV_EQUAL");
		$$.tree_info = create_node("assignment_operator");
		add_child($$.tree_info,$1.tree_info);
	}
    |   REMAINDER_EQUAL
	{
		reduce("assignment_operator => REM_EQUAL");
		$$.tree_info = create_node("assignment_operator");
		add_child($$.tree_info,$1.tree_info);
	}
    |   PLUS_EQUAL
	{
		reduce("assignment_operator => PLUS_EQUAL");
		$$.tree_info = create_node("assignment_operator");
		add_child($$.tree_info,$1.tree_info);
	}
    |   MINUS_EQUAL
	{
		reduce("assignment_operator => MINUS_EQUAL");
		$$.tree_info = create_node("assignment_operator");
		add_child($$.tree_info,$1.tree_info);
	}
    |   LEFT_SHIFT_EQUAL
	{
		reduce("assignment_operator => LSHIFT_EQUAL");
		$$.tree_info = create_node("assignment_operator");
		add_child($$.tree_info,$1.tree_info);
	}
    |   RIGHT_SHIFT_EQUAL
	{
		reduce("assignment_operator => RSHIFT_EQUAL");
		$$.tree_info = create_node("assignment_operator");
		add_child($$.tree_info,$1.tree_info);
	}
    |   AND_EQUAL
	{
		reduce("assignment_operator => AND_EQUAL");
		$$.tree_info = create_node("assignment_operator");
		add_child($$.tree_info,$1.tree_info);
	}
    |   XOR_EQUAL
	{
		reduce("assignment_operator => XOR_EQUAL");
		$$.tree_info = create_node("assignment_operator");
		add_child($$.tree_info,$1.tree_info);
	}
    |   OR_EQUAL
	{
		reduce("assignment_operator => OR_EQUAL");
		$$.tree_info = create_node("assignment_operator");
		add_child($$.tree_info,$1.tree_info);
	}
    ;

conditional_expression
    :   logical_OR_expression
	{
		reduce("conditional_expression => logical_OR_expression");
		$$.tree_info = create_node("conditional_expression");
		add_child($$.tree_info,$1.tree_info);
	}
    |   logical_OR_expression  QUESTION  expression  COLON conditional_expression
	{
		reduce("conditional_expression => log_OR_exp ? exp : cond_exp");
		$$.tree_info = create_node("conditional_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
		add_child($$.tree_info,$4.tree_info);
		add_child($$.tree_info,$5.tree_info);
	}
    ;

constant_expression
    :   conditional_expression
	{
		reduce("constant_expression => conditional_expression");
		$$.tree_info = create_node("constant_expression");
		add_child($$.tree_info,$1.tree_info);
	}
    ;

logical_OR_expression
    :   logical_AND_expression
	{
		reduce("logic_or_expression => logic_and_expression");
		$$.tree_info = create_node("logical_or_expression");
		add_child($$.tree_info,$1.tree_info);
	}
    |   logical_OR_expression   OR_OR   logical_AND_expression
	{
		reduce("logic_or_expression => logic_or_exp || logic_and_exp");
		$$.tree_info = create_node("logical_or_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    ;

logical_AND_expression
    :   inclusive_OR_expression
	{
		reduce("logic_and_expression => ior_expression");
		$$.tree_info = create_node("logical_and_expression");
		add_child($$.tree_info,$1.tree_info);
	}
    |   logical_AND_expression   AND_AND   inclusive_OR_expression
	{
		reduce("logic_and_expression => logic_and_exp && ior_exp");
		$$.tree_info = create_node("logical_and_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    ;

inclusive_OR_expression
    :   exclusive_OR_expression
	{
		reduce("ior_expression => xor_expression");
		$$.tree_info = create_node("ior_expression");
		add_child($$.tree_info,$1.tree_info);
	}
    |   inclusive_OR_expression   OR exclusive_OR_expression
	{
		reduce("ior_expression => ior_exp | xor_expression");
		$$.tree_info = create_node("ior_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    ;

exclusive_OR_expression
    :   AND_expression
	{
		reduce("xor_expression => and_expression");
		$$.tree_info = create_node("xor_expression");
		add_child($$.tree_info,$1.tree_info);
	}
    |   exclusive_OR_expression   CIRCONFLEX   AND_expression
	{
		reduce("xor_expression => xor_exp & and_exp");
		$$.tree_info = create_node("xor_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    ;

AND_expression
    :   equality_expression
	{
		reduce("and_expression => equality_expression");
		$$.tree_info = create_node("and_expression");
		add_child($$.tree_info,$1.tree_info);
	}
    |   AND_expression   AMPERSAND   equality_expression
	{
		reduce("and_expression => and_exp & equality_exp");
		$$.tree_info = create_node("and_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    ;

equality_expression
    :   relational_expression
	{
		reduce("equality_expression => relational_expression");
		$$.tree_info = create_node("equality_expression");
		add_child($$.tree_info,$1.tree_info);
	}
    |   equality_expression   EQUAL_EQUAL   relational_expression
	{
		reduce("equality_expression => equality_exp == relational_exp");
		$$.tree_info = create_node("equality_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    |   equality_expression   NOT_EQUAL     relational_expression
	{
		reduce("equality_expression => equality_exp != relational_exp");
		$$.tree_info = create_node("equality_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    ;

relational_expression
    :   shift_expression
	{
		reduce("relational_expression => shift_expression");
		$$.tree_info = create_node("relational_expression");
		add_child($$.tree_info,$1.tree_info);
	}
    |   relational_expression   LESS             shift_expression
	{
		reduce("relational_expression => relation_exp < shift_exp");
		$$.tree_info = create_node("relational_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    |   relational_expression   MORE             shift_expression
	{
		reduce("relational_expression => relation_exp > shift_exp");
		$$.tree_info = create_node("relational_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    |   relational_expression   LESS_EQUAL       shift_expression
	{
		reduce("relational_expression => relation_exp <= shift_exp");
		$$.tree_info = create_node("relational_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    |   relational_expression   GREATER_EQUAL    shift_expression
	{
		reduce("relational_expression => relation_exp <= shift_exp");
		$$.tree_info = create_node("relational_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    ;

shift_expression
    :   additive_expression
	{
		reduce("shift_expression => additive_expression");
		$$.tree_info = create_node("shift_expression");
		add_child($$.tree_info,$1.tree_info);
	}
    |   shift_expression   LEFT_SHIFT         additive_expression
	{
		reduce("shift_expression => << additive_expression");
		$$.tree_info = create_node("shift_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    |   shift_expression   RIGHT_SHIFT        additive_expression
	{
		reduce("shift_expression => >> additive_expression");
		$$.tree_info = create_node("shift_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    ;

additive_expression
    :   multiplicative_expression
	{
		reduce("additive_expression => multiplicative_exp");
		$$.tree_info = create_node("additive_expression");
		add_child($$.tree_info,$1.tree_info);
	}
    |   additive_expression   PLUS   multiplicative_expression
	{
		reduce("additive_expression => add_exp + mult_exp");
		$$.tree_info = create_node("additive_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    |   additive_expression   MOINUS multiplicative_expression
	{
		reduce("additive_expression => add_exp - mult_exp");
		$$.tree_info = create_node("additive_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    ;

multiplicative_expression
    :   cast_expression
	{
		reduce("multiplicative_expression => cast_expression");
		$$.tree_info = create_node("multiplicative_expression");
		add_child($$.tree_info,$1.tree_info);
	}
    |   multiplicative_expression   ASTERISK  cast_expression
	{
		reduce("multiplicative_expression => mult_exp * cast_expression");
		$$.tree_info = create_node("multiplicative_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    |   multiplicative_expression   SLASH     cast_expression
	{
		reduce("multiplicative_expression => mult_exp / cast_expression");
		$$.tree_info = create_node("multiplicative_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    |   multiplicative_expression   PERCENT   cast_expression
	{
		reduce("multiplicative_expression => mult_exp % cast_expression");
		$$.tree_info = create_node("multiplicative_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    ;

cast_expression
    :   unary_expression
	{
		reduce("cast_expression => unary_expression");
		$$.tree_info = create_node("cast_expression");
		add_child($$.tree_info,$1.tree_info);
	}
    |   LEFT_PARENTH   type_name   RIGHT_PARENTH   cast_expression
	{
		reduce("cast_expression => ( type_name ) cast_expression");
		$$.tree_info = create_node("cast_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
		add_child($$.tree_info,$4.tree_info);
	}
    ;

unary_expression
    :   postfix_expression
	{
		reduce("unary_expression => postfix_expression");
		$$.tree_info = create_node("unary_expression");
		add_child($$.tree_info,$1.tree_info);
	}
    |   PLUS_PLUS             unary_expression
	{
		reduce("unary_expression => ++ unary_expression");
		$$.tree_info = create_node("unary_expression");
		add_child($$.tree_info,$1.tree_info);
	}
    |   MINUS_MINUS           unary_expression
	{
		reduce("unary_expression => -- unary_expression");
		$$.tree_info = create_node("unary_expression");
		add_child($$.tree_info,$1.tree_info);
	}
    |   unary_operator   cast_expression
	{
		reduce("unary_expression => unary_operator cast_expression");
		$$.tree_info = create_node("unary_expression");
		add_child($$.tree_info,$1.tree_info);
	}
    |   SIZEOF   unary_expression
	{
		reduce("unary_expression => sizeof unary_expression");
		$$.tree_info = create_node("unary_expression");
		add_child($$.tree_info,$1.tree_info);
	}
    |   SIZEOF   LEFT_PARENTH  type_name  RIGHT_PARENTH
	{
		reduce("unary_expression => sizeof ( type_name )");
		$$.tree_info = create_node("unary_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    ;

unary_operator
    :   AMPERSAND
	{
		reduce("unary_operator => AMPERSAND");
		$$.tree_info = create_node("unary_operator");
		add_child($$.tree_info,$1.tree_info);
	}
    |   ASTERISK
	{
		reduce("unary_operator => ASTERISK");
		$$.tree_info = create_node("unary_operator");
		add_child($$.tree_info,$1.tree_info);
	}
    |   PLUS
	{
		reduce("unary_operator => PLUS");
		$$.tree_info = create_node("unary_operator");
		add_child($$.tree_info,$1.tree_info);
	}
    |   MOINUS
	{
		reduce("unary_operator => MOINUS");
		$$.tree_info = create_node("unary_operator");
		add_child($$.tree_info,$1.tree_info);
	}
    |   TILDE
	{
		reduce("unary_operator => TILDE");
		$$.tree_info = create_node("unary_operator");
		add_child($$.tree_info,$1.tree_info);
	}
    |   EXCLAMATION
	{
		reduce("unary_operator => EXCLAMATION");
		$$.tree_info = create_node("unary_operator");
		add_child($$.tree_info,$1.tree_info);
	}
    ;

postfix_expression
    :   primary_expression
	{
		reduce("postfix_expression => primary_expression");
		$$.tree_info = create_node("postfix_expression");
		add_child($$.tree_info,$1.tree_info);
	}
    |   postfix_expression  LEFT_BRACKET  expression  RIGHT_BRACKET
	{
		reduce("postfix_expression => postfix_exp [ expression ]");
		$$.tree_info = create_node("postfix_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
		add_child($$.tree_info,$4.tree_info);
	}
    |   postfix_expression  LEFT_PARENTH  argument_expression_list  RIGHT_PARENTH
	{
		reduce("postfix_expression => postfix_exp ( argument_exp_list )");
		$$.tree_info = create_node("postfix_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
		add_child($$.tree_info,$4.tree_info);
	}

    |   postfix_expression  LEFT_PARENTH                            RIGHT_PARENTH
	{
		reduce("postfix_expression => postfix_exp ( )");
		$$.tree_info = create_node("postfix_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    |   postfix_expression  POINT  IDENTIFIER
	{
		reduce("postfix_expression => postfix_exp . IDENTIFIER");
		$$.tree_info = create_node("postfix_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    |   postfix_expression  ARROW IDENTIFIER
	{
		reduce("postfix_expression => postfix_exp -> IDENTIFIER");
		$$.tree_info = create_node("postfix_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    |   postfix_expression  PLUS_PLUS
	{
		reduce("postfix_expression => postfix_exp ++");
		$$.tree_info = create_node("postfix_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    |   postfix_expression  MINUS_MINUS
	{
		reduce("postfix_expression => postfix_exp --");
		$$.tree_info = create_node("postfix_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
	}
    ;

primary_expression
    :   IDENTIFIER
	{
		reduce("primary_expression => IDENTIFIER");
		$$.tree_info = create_node("primary_expression");
		add_child($$.tree_info,$1.tree_info);
	}
    |   constant
	{
		reduce("primary_expression => constant");
		$$.tree_info = create_node("primary_expression");
		add_child($$.tree_info,$1.tree_info);
	}
    |   STRING
	{
		reduce("primary_expression => STRING");
		$$.tree_info = create_node("primary_expression");
		add_child($$.tree_info,$1.tree_info);
	}
    |   LEFT_PARENTH  expression  RIGHT_PARENTH
	{
		reduce("primary_expression => ( expression )");
		$$.tree_info = create_node("primary_expression");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    ;

argument_expression_list
    :   assignment_expression
	{
		reduce("argument_expression_list => assignment_expression");
		$$.tree_info = create_node("argument_expression_list");
		add_child($$.tree_info,$1.tree_info);
	}
    |   argument_expression_list  COMMA  assignment_expression
	{
		reduce("argument_expression_list => argument_expression_list , assignment_expression");
		$$.tree_info = create_node("argument_expression_list");
		add_child($$.tree_info,$1.tree_info);
		add_child($$.tree_info,$2.tree_info);
		add_child($$.tree_info,$3.tree_info);
	}
    ;

constant
    :   INTEGER_CONSTANT
	{
		reduce("constant => INTEGER_CONSTANT");
		$$.tree_info = create_node("constant");
		add_child($$.tree_info,$1.tree_info);
	}
    |   CHARACTER_CONSTANT
	{
		reduce("constant => CHARACTER_CONSTANT");
		$$.tree_info = create_node("constant");
		add_child($$.tree_info,$1.tree_info);
	}
    |   FLOATING_CONSTANT
	{
		reduce("constant => FLOATING_CONSTANT");
		$$.tree_info = create_node("constant");
		add_child($$.tree_info,$1.tree_info);
	}
    |   ENUMERATION_CONSTANT
	{
		reduce("constant => ENUMERATION_CONSTANT");
		$$.tree_info = create_node("constant");
		add_child($$.tree_info,$1.tree_info);
	}
    ;

%%      /* start of programs */

void yyerror(s)   /* simple-minded error-handling routine */
char *s;
{
    fprintf(stderr, "%s near line %d\n", s,yylineno);
    exit(EXIT_FAILURE);
}

