/* a first go at a pretzel formatted grammar for C++
 *
 * by Felix Gaertner
 *
 * $Id$
 *
 * taken from the file headerparse.y by Karel Zuiderveld <karel@cv.ruu.nl>
 *
 */


%token CLASS BASENAME EXPLICIT
%token TEMPLATE PUBLIC PRIVATE PROTECTED
%token CONST ENUM CSCOPE STRUCT UNION SIZEOF
%token VIRTUAL OPERATOR NO_WRAPPER NO_PARSE
%token INLINE FRIEND TYPEDEF IMPLEMENTATION DESCRIPTION DEPENDENCY
%token MUTABLE NUL COLON
%token PLUS PLUS_EQUAL PLUS_PLUS
%token MINUS MINUS_EQUAL MINUS_MINUS
%token MULT MULT_EQUAL END_OF_DATA
%token DIV DIV_EQUAL NOT NOT_EQUAL EXTERN CXXSCOPE
%token LEFT_SHIFT RIGHT_SHIFT SMALLER LARGER
%token EQUAL EQUAL_EQUAL CURLY_CLOSE STATIC

%token <markedpos> SEMICOLON CURLY_OPEN

%token <string> PREPROC_LINE PREPROC_INCLUDE PREPROC_IF PREPROC_ELSE
%token <string> PREPROC_ELIF PREPROC_ENDIF PREPROC_ASSERT PREPROC_DEFINE
%token <string> PREPROC_UNDEF PREPROC_ERROR PREPROC_IFDEF PREPROC_PRAGMA

%token <string> ID TEMPLATE_ID COMMENT CHAPTER NUMBER CHAR_CONST
%token <string> STRING TYPE PT_FUNC CONCAT_STRING TEMPLATE_SPEC

%type<string> basic_type type stars operator function_default
%type<string> varcomment dc arraydef const_expression variable_argument
%type<string> var_func_name simple_const_expression
%type<string> grouped_simple_const_expression classdef
%type<string> variablename argument initvalue simple_initvalue
%type<string> initvalue_list initvalues type_prefix type_scope type_mod
%type<string> initstatements initlist
%type<string> variable_modifier simple_type template_intro
%type<string> template_intro_id_list
%type<string> source_select constructed_type preproc_global preproc_ifelse
%type<string> nameless_arg_list nameless_arg
%type<string> nameless_type variable_init_value template_id_list


%type<variable> variable
%type<function> function_prelud tfn_prelud
%type<function> instantiate_function_prelud

%type<markedpos> func_braces inline_func_def


%%

/* A program is a sequence of definitions */

program:	/* nothing */
	| definition program
;

preproc_ifelse: PREPROC_IF
	| PREPROC_ELSE
	| PREPROC_ELIF
	| PREPROC_ENDIF
        | PREPROC_IFDEF
;

preproc_global: PREPROC_LINE
	| PREPROC_INCLUDE
	| PREPROC_ASSERT
	| PREPROC_DEFINE
	| PREPROC_UNDEF
	| PREPROC_ERROR
        | PREPROC_PRAGMA
;

preproc: preproc_global
	|  preproc_ifelse
;

   // The following is a list of everything that can be found on a global
   // level.

definition: classdecl             // A class declaration
	| globalenumdef         // An enum defintion */
	| var_def               // Global variables definitions */
	| var_func_def          // Global variables or functions def */
	| typedef               // A hack for typedefs */
	| source_change         // Change output file */
	| preproc               // preprocessor literals */
	| COMMENT		// Unbound C++ comment. Just ignore.
				// Doesn't belong here in
	| CHAPTER		// Unbound C++ comment. A warning is
				// in place. A possible CHAPTER that
				// is unbound may be caused by the
				// fact that the user inserted inline
				// functions between the classdef and
				// the documentation. Just ignore.
				// Doesn't belong here in the first
				// place :-(
	| CSCOPE CURLY_OPEN	// extern "C"
	| CURLY_CLOSE		// probably from extern "C"
;

source_select: STRING
	| BASENAME STRING
	| DEPENDENCY
	| IMPLEMENTATION
	| DESCRIPTION
	| END_OF_DATA
;

source_options: /* empty */
	| ',' NO_WRAPPER source_options
	| ',' NO_PARSE source_options
;

source_change: '[' '[' source_select source_options ']' ']'
;

typedef: TYPEDEF SEMICOLON varcomment
;

member_typedef: TYPEDEF SEMICOLON varcomment
;

enumarg: ID EQUAL NUMBER  varcomment
	| ID EQUAL '(' NUMBER ')' varcomment
	| ID EQUAL MINUS NUMBER  varcomment
	| ID EQUAL '(' MINUS NUMBER ')' varcomment
	| ID EQUAL NUL varcomment
	| ID varcomment
;

enumlist: enumarg
	| enumarg ',' varcomment enumlist
	| preproc_ifelse
	| preproc_ifelse enumlist
;

globalenumdef: ENUM ID varcomment CURLY_OPEN enumlist CURLY_CLOSE SEMICOLON varcomment
	| ENUM varcomment CURLY_OPEN enumlist CURLY_CLOSE SEMICOLON varcomment
;

memberenumdef: ENUM ID varcomment CURLY_OPEN enumlist CURLY_CLOSE SEMICOLON varcomment
	| ENUM varcomment CURLY_OPEN enumlist CURLY_CLOSE SEMICOLON varcomment
;

func_braces: varcomment CURLY_OPEN CURLY_CLOSE
;

inline_func_def: func_braces
	| func_braces SEMICOLON
;

chapters: CHAPTER varcomment chapters
	| varcomment
;

simplemember: membervariable
	| memberfunction
	| simple_union_struct_def
	| preproc_ifelse
;

class_save:
;

simplemembers: simplemember
	| simplemember simplemembers
;

simple_union_struct_def: simple_id simplemembers CURLY_CLOSE ID SEMICOLON varcomment class_save
	| simple_id simplemembers CURLY_CLOSE SEMICOLON varcomment class_save
;

simple_id: STRUCT CURLY_OPEN
	| STRUCT ID CURLY_OPEN
	| UNION CURLY_OPEN
	| UNION ID CURLY_OPEN
;

classdef: CLASS ID
	| STRUCT ID
	| UNION ID
	| UNION
;

friend_defs: FRIEND ID SEMICOLON varcomment
	| FRIEND CLASS ID SEMICOLON varcomment
	| FRIEND CLASS ID template_id_list SEMICOLON varcomment
;

classdecl: classdef inheretance classdescription CURLY_OPEN classdefinition CURLY_CLOSE SEMICOLON chapters class_save
	| classdef SEMICOLON varcomment		// forward declraration
	| template_intro classdef inheretance classdescription CURLY_OPEN classdefinition CURLY_CLOSE SEMICOLON chapters class_save
	| template_intro classdef SEMICOLON
;

simple_const_expression: NUMBER
	| MINUS NUMBER
	| PLUS NUMBER
	| NUL
	| ID
	| ID '(' initvalue_list ')'
	| '&' ID
	| MINUS ID
	| PLUS ID
	| SIZEOF '(' simple_type ')'
;

grouped_simple_const_expression: simple_const_expression
	| '(' simple_const_expression ')'
;

const_expression: grouped_simple_const_expression
	| grouped_simple_const_expression PLUS grouped_simple_const_expression
	| grouped_simple_const_expression MINUS grouped_simple_const_expression
	| grouped_simple_const_expression MULT grouped_simple_const_expression
	| grouped_simple_const_expression LEFT_SHIFT NUMBER
	| grouped_simple_const_expression RIGHT_SHIFT NUMBER
;

arraydef: /* NOTHING */
	| '[' ']' arraydef
	| '[' const_expression ']' arraydef
;

variablename: ID
	| ID COLON NUMBER
	| '(' stars ID ')' '(' optional_function_args ')'
;

optional_function_args: function_args
	| /* nothing */
;

variable: type variablename arraydef
;

membervariable: variable SEMICOLON varcomment
;

dc: COMMENT
	| COMMENT dc
;

varcomment: /* NOTHING */
	| dc
;

var_func_open: regular_func
	| template_func_def
	| template_specialisation
;

regular_var_func_prelud: type function_prelud
	| function_prelud
;

template_var_func_prelud: type tfn_prelud
	| tfn_prelud
	| type OPERATOR operator '('		// This is a global
						// operator, not part
						// of a class
	| type ID '('				// This is a global
						// function (non
						// class) prelud
;

template_instantiate_prelud: type instantiate_function_prelud
	| instantiate_function_prelud
;

regular_func: regular_var_func_prelud
   // Suppress possible warnings about missing arguments in case of
   // the function definition. Missing arguments in that case are no
   // problem. In some case this is even needed to suppress warnings
   // from the C++ compiler
	| INLINE regular_var_func_prelud
   // Suppress possible warnings about missing arguments in case of
   // the function definition. Missing arguments in that case are no
   // problem. In some case this is even needed to suppress warnings
   // from the C++ compiler
;

template_func_def: template_intro template_var_func_prelud
	| template_intro INLINE template_var_func_prelud
;

template_specialisation: template_instantiate_prelud
	| INLINE template_instantiate_prelud
;

var_func_def: var_func_open function_tail varcomment func_braces
    // If the function found has a parent, we must locate the function
    // in parent. We then add the definition to the already existing
    // definition and remove the build function so far. There is one
    // exception. If the just found function is a specialization, we
    // must add it as a new function to the class

    // or t'is standalone function. This function must be registered,
    // so that the data can eventually can be removed

	| var_func_open function_args function_tail varcomment func_braces

    // If the function found has a parent, we must locate the function
    // in parent. We then add the definition to the already existing
    // definition and remove the build function so far. There is one
    // exception. If the just found function is a specialization, we
    // must add it as a new function to the class. Possible function
    // comment is ignored

    // or t'is standalone function. This function must be registered,
    // so that the data can eventually can be removed

	| var_func_open ')' SEMICOLON varcomment
	| var_func_open function_args ')' SEMICOLON varcomment

   // In the var_func_prelud part of the parser, we assumed we found a
   // function. Since a variable with arguments is so close to a
   // function definition we "abuse" the FunctionStore type to store
   // this variable in.

| var_func_open initvalue_list ')' SEMICOLON varcomment

   // In the var_func_prelud part of the parser, we assumed we found a
   // function. Ignore this function def and create a variable. Store
   // the variable in the output file
;

template_intro_id_list: CLASS ID
	| CLASS ID ',' template_intro_id_list
;

template_intro: TEMPLATE SMALLER template_intro_id_list LARGER
;

instantiate_function_prelud: ID template_id_list CXXSCOPE ID '('
    // Specialization of template. Example:
    //   RGBColor Interpolation<RFB8>::akima(...){}
;

template_id_list: SMALLER ID TEMPLATE_SPEC LARGER
	| TEMPLATE_SPEC
;

tfn_prelud: ID  template_id_list CXXSCOPE ID '('
    // Example:
    //     RGBColor Interpolation<T>::akima(...){}
    //              ~~~~~~~~~~~~~~~~~~~~~~~~

	| ID template_id_list CXXSCOPE ID CXXSCOPE ID '('
   // Nested class definition
   // Example:
   //   type Interpolation<T>::netstedclass::name() {}

	| ID template_id_list CXXSCOPE ID CXXSCOPE OPERATOR operator '('

   // Nested class definition

	| ID template_id_list CXXSCOPE OPERATOR operator '('
	| ID template_id_list CXXSCOPE OPERATOR type '('
;

function_prelud: ID CXXSCOPE ID '('
	| ID CXXSCOPE OPERATOR operator '('
	| ID CXXSCOPE OPERATOR type '('
	| ID '('
   // This is either a global function prelud or a variable prelud.
   // For the moment we just assume it is a function and later on, we
   // may ignore the function later on if it is a variable after all.

	| OPERATOR operator '('
   // This is a global operator, not part of a class
;

variable_init_value:
;

	// -------------------------------------------------------
	// var_def: Variable definitions

var_def: type var_func_name arraydef SEMICOLON varcomment
	| type var_func_name EQUAL variable_init_value SEMICOLON varcomment
	| type var_func_name '[' ']' EQUAL variable_init_value SEMICOLON varcomment
	| type '(' stars var_func_name ')' '(' ')' EQUAL variable_init_value SEMICOLON varcomment
	| type '(' stars var_func_name ')' '(' function_args ')' EQUAL variable_init_value SEMICOLON varcomment
;

var_func_name: ID
	| ID CXXSCOPE ID
	| OPERATOR operator
;

classdef_member: classmember
	| classmember classdef_member
;

classdefinition: classdef_member
	| /* nothing */
;

classmember: classdecl
	| member_typedef
	| membervariable
	| simple_union_struct_def
	| friend_defs
	| memberfunction
	| memberenumdef
	| PRIVATE COLON
	| PUBLIC  COLON
	| PROTECTED COLON
	| SEMICOLON
	| preproc_ifelse
;

operator: EQUAL
	| NOT
	| PLUS
	| MINUS
	| MULT
	| '~'
	| DIV
	| SMALLER
	| LARGER
	| '^'
	| '|'
	| '&'
	| '[' ']'
	| LEFT_SHIFT		// <<
	| RIGHT_SHIFT		// >>
	| EQUAL_EQUAL		// ==
	| NOT_EQUAL		// !=
	| PLUS_EQUAL		// +=
	| MULT_EQUAL		// *=
	| DIV_EQUAL		// /=
	| MINUS_EQUAL		// -=
	| PLUS_PLUS		// ++
	| MINUS_MINUS		// --
	| '(' ')'		// ()
;

variable_modifier: stars
	| '&'
	| /* empty */
;

variable_argument: variable_modifier ID
	| variable_modifier ID '.' variable_argument
	| variable_modifier ID CXXSCOPE ID
	| variable_modifier ID '(' ')'
	| variable_modifier ID '(' initvalue_list ')'
	| variable_modifier ID CXXSCOPE ID '(' ')'
	| variable_modifier ID CXXSCOPE ID '(' initvalue_list ')'
	| variable_modifier ID '[' const_expression ']'
;

simple_initvalue: variable_argument
	| NUMBER
	| MINUS NUMBER
	| NUL
	| STRING
	| CONCAT_STRING
;

initvalue: simple_initvalue
	| '(' type ')' simple_initvalue
;

initvalues: initvalue
	| initvalue PLUS initvalues
	| initvalue MINUS initvalues
	| initvalue DIV initvalues
	| initvalue MULT initvalues
;

initvalue_list: initvalues
	| initvalues ',' initvalue_list
;

initstatements:
;

initlist: COLON initstatements
;

function_tail: ')' initlist
	| ')'
	| ')' initlist CONST
	| ')' CONST
	| ')' CONST EQUAL NUL
	| ')' EQUAL NUL
;

memberfunction_open: memberfunction_prelud
	| FRIEND memberfunction_prelud
	| INLINE memberfunction_prelud
	| VIRTUAL memberfunction_prelud
;

memberfunction_prelud: type ID '('
	| EXPLICIT ID '('
	| ID '('
	| type PT_FUNC '('
	| type OPERATOR operator '('

    // The operators '++' and '--' are odd kind of operators that may
    // require an optional argument without variable name. Suppress
    // possible warnings in the case that the operator is '++' or
    // '--'.
	| OPERATOR type '('
;

memberfunction: memberfunction_open function_tail SEMICOLON varcomment
	| memberfunction_open function_args function_tail SEMICOLON varcomment
	| memberfunction_open function_args function_tail inline_func_def varcomment
	| memberfunction_open function_tail inline_func_def varcomment
;

function_default: NUL
	| STRING
	| '\"' '\"'
	| '(' NUL ')'
	| NUMBER
	| '(' NUMBER ')'
	| CHAR_CONST
	| '(' CHAR_CONST ')'
	| ID
	| MINUS ID
	| MINUS NUMBER
	| '(' ID ')'
	| ID CXXSCOPE ID
	| '(' ID CXXSCOPE ID ')'
	| '&' ID
	| '(' '&' ID ')'
;

argument: type
	| type CXXSCOPE type
	| type CXXSCOPE type variablename arraydef
	| type variablename arraydef
	| type PT_FUNC '(' ')'
	| type PT_FUNC '(' nameless_arg_list ')'
;

function_arg: argument
	| argument EQUAL function_default
	| '.' '.' '.'
;

nameless_type: type
	| type variablename arraydef
	| type PT_FUNC '(' ')'
	| type PT_FUNC '(' nameless_arg_list ')'
;

nameless_arg: nameless_type
	| nameless_type EQUAL function_default
	| '.' '.' '.'
;

function_args: function_arg
   | function_arg ',' function_args
;

nameless_arg_list: nameless_arg
	| nameless_arg ',' nameless_arg_list
;

stars: MULT
	| MULT stars
;

simple_type: TYPE
	| TEMPLATE TYPE
	| ID
	| ID CXXSCOPE ID
	| ID '[' const_expression ']'
;

type_scope: STATIC
	| EXTERN
	| CSCOPE
;

type_mod: CONST
	| MUTABLE
;

type_prefix: type_scope type_mod
	| type_mod
	| type_scope
;

basic_type: TYPE
	| ID
	| TEMPLATE_ID
	| ENUM ID
	| STRUCT ID
	| ID CXXSCOPE ID
	| TEMPLATE TYPE
	| ID template_id_list
	| ID SMALLER ID LARGER CXXSCOPE ID

   // Really a hack for nested definitions. Need some something
   // dynamic one day

	| ID SMALLER ID LARGER CXXSCOPE TYPE

   // Really a hack for nested definitions. Need some something
   // dynamic one day

	| ID SMALLER basic_type stars LARGER
	| ID SMALLER basic_type LARGER
	| ID SMALLER basic_type '&' LARGER
	| ID SMALLER basic_type ',' basic_type LARGER
	| ID SMALLER basic_type ',' basic_type stars LARGER
	| ID SMALLER basic_type ',' basic_type '&' LARGER
	| ID SMALLER basic_type stars ',' basic_type LARGER
	| ID SMALLER basic_type stars ',' basic_type stars LARGER
	| ID SMALLER basic_type stars ',' basic_type '&' LARGER
;

constructed_type: basic_type
	| basic_type stars
	| basic_type stars '&'
	| basic_type stars CONST
	| basic_type '&'
;

type: constructed_type
	| type_prefix  constructed_type
;

classdescription: varcomment
;

inheretance: /* empty string */
	| COLON inheretancelist
;

inheretancemember: PUBLIC ID
	| PRIVATE ID
	| PROTECTED ID
	| PUBLIC ID template_id_list
	| PRIVATE ID template_id_list
	| PROTECTED ID template_id_list
	| PUBLIC ID SMALLER type LARGER
	| PRIVATE ID SMALLER type LARGER
	| PROTECTED ID SMALLER type LARGER
;

inheretancelist: inheretancemember
	| inheretancemember ',' inheretancelist
;


%%

