%{ 
#define yyparse neuralparse
#define yylex neurallex
#define yyerror neuralerror
#define yylval neurallval
#define yychar neuralchar
#define yydebug neuraldebug
#define yynerrs neuralnerrs

#include "epos.h"
#include "neural.h"
#include "utils.h" // toString
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>

#define YYPARSE_PARAM neuralnet
//to make debug information visible, uncomment the next bison_row 
//and assign somewhere yydebug=1
//#define YYDEBUG 1

const int DECDIGIT_NULL = -1;
const int MSG_LENGTH = 1000;

CExpression *bison_input_result;

CString bison_row_buf;
const char *bison_row;
int row_num;
CNeuralNet *bison_nnet;
// chartofloat's from the "in" function
int chartofloat_in;

int yylex ();
int yyerror (char *s);

void
resolve_vars(char *line, hash *vars, text *file = NULL); //defined in block.cc

inline UNIT get_level (const char *level_name)
{
	return str2enum (level_name, scfg->unit_levels, U_DEFAULT);
}

CExpression *
add_infix_bin_func (TFunc ifunc, CExpression *par1, CExpression *par2)
{
	CExpression *result = new CExpression;
	result->owner = bison_nnet;
	result->function = ifunc;
	result->args.push_back (*par1);
	result->args.push_back (*par2);
	delete par1;
	delete par2;
	return result;
}

CExpression *
add_infix_un_func (TFunc ifunc, CExpression *par1)
{
	CExpression *result = new CExpression;
	result->owner = bison_nnet;
	result->function = ifunc;
	result->args.push_back (*par1);
	delete par1;
	return result;
}

CExpression *
add_prefix_func (TFunc ifunc, const char *chtof, 
	CExpression *par1 = NULL, CExpression *par2 = NULL, CExpression *par3 = NULL)
{
	CExpression *result = new CExpression;
	result->owner = bison_nnet;
	result->function = ifunc;
	if (chtof != NULL) {
		TChar2Floats::iterator ich2f;
		for (ich2f = bison_nnet->char2floats.begin(); ich2f != bison_nnet->char2floats.end(); ++ich2f)
			if (!strcmp(ich2f->name.c_str(), chtof))
				break;
		if (ich2f == bison_nnet->char2floats.end())
			shriek (812, fmt ("BISON:add_prefix_func:Unknown function %s", chtof));
		result->which_char2float = ich2f;
	}
	if (par1) { result->args.push_back (*par1); delete par1; }
	if (par2) { result->args.push_back (*par2); delete par2; }
	if (par3) { result->args.push_back (*par3); delete par3; }
	return result;
}

CExpression *
make_tree (TTypedValue val = TTypedValue())
{
	CExpression *result = new CExpression;
	result->owner = bison_nnet;
	result->function = fu_value;
	result->which_value = val;
	return result;
}

%}
     
/* * * * * * * * * * * * * * * * * * * * * * * * * * */
/*                    SYMBOLS                        */
/* * * * * * * * * * * * * * * * * * * * * * * * * * */

%token_table
//%raw bison nefunguje s raw! (aspon yylex ne)

%union {
	int int_val;
	double float_val;
	char string_val [MSG_LENGTH];
	unit *unit_val;
	TTypedValue *typed_val;
	CExpression *func_val;
	TFunc func_index;
}

%token EQ "=="
%token NOTEQ "!="
%token LESSEQ "<="
%token GREATEREQ ">="
%token AND "AND"
%token OR "OR"

/* Infix binary functions by precedence order: 
Each bison_row is one precedence level, items on the same bison_row have the same precedence.

e.g. 2 + 3 * 4 becomes 2 + (3*4)

The statement is defining associativity as well. Hence
	  2 * 3 / 4 becomes (2 * 3) / 4 (left associativity)
*/

%left OR
%left AND
%left EQ NOTEQ
%left '<' LESSEQ '>' GREATEREQ
%left '+' '-'
%left '*' '/'
%nonassoc NOT

%token <float_val> FLOAT_NUM
%token <int_val> INT_NUM
%token <string_val> STRING
%token <string_val> QUOTED_STRING

%token COUNT "count"
%token INDEX "index"
%token THIS "this"
%token ANCESTOR "ancestor"
%token PREV "prev"
%token NEXT "next"
%token NEURAL "neural"
%token BASAL_F "basal_f"
%token CONT "cont"

%type <func_val> input_exp
%type <func_val> float_exp
%type <func_val> int_exp
%type <func_val> unit_exp
%type <func_val> string_exp
%type <func_val> prev_next_params
%type <func_val> unit_level

%expect 1 //let bison expect one shift/reduce conflict: ( int_exp ) could be int_exp as well as ( float_exp )

%%

/* * * * * * * * * * * * * * * * * * * * * * * * * * */
/*                    INPUTS                         */
/* * * * * * * * * * * * * * * * * * * * * * * * * * */

all: { 
		//yydebug = 1;
	 } 
	 input_exp						{ bison_input_result = $2; }
;

//input_exp mustn't be unit		
input_exp:
			  float_exp				//{ $$ = $1; } unnecessary: bison default
			| error					{ $$ = NULL; }
;
///For the functions definition see the neural.h documentation generated by Doxygen.
unit_exp: "next" prev_next_params					{ $$ = $2; }
		  | "prev" prev_next_params					{ $$ = $2; $$->function = fu_prev; }
		  | "this"									{ $$ = add_prefix_func (fu_this,0,NULL); }
		  | "ancestor" '(' unit_level ')'			{ $$ = add_prefix_func (fu_ancestor,0,$3); }
		  | "maxfloat" '(' QUOTED_STRING ',' unit_level ',' unit_level ')' { $$ = add_prefix_func (fu_maxfloat,$3,$5,$7); }
		  | '(' unit_exp ')'						{ $$ = $2; }
;

/// Any subset of params for next and prev functions
prev_next_params: 
		'(' unit_exp ',' unit_level ',' int_exp ')' { $$ = add_prefix_func (fu_next,0,$2,$4,$6); }
	  | '(' unit_exp ',' unit_level	')'				{ $$ = add_prefix_func (fu_next,0,$2,$4, make_tree (1)); }
	  | '(' unit_level ',' int_exp ')'				{ $$ = add_prefix_func (fu_next,0,add_prefix_func (fu_this,0,NULL),$2,$4); }
	  | '(' unit_exp ',' int_exp ')'				{ $$ = add_prefix_func (fu_next,0,$2,make_tree (),$4); }
	  | '(' unit_exp ')'							{ $$ = add_prefix_func (fu_next,0,$2,make_tree (), make_tree(1)); }
	  | '(' unit_level ')'							{ $$ = add_prefix_func (fu_next,0,add_prefix_func (fu_this,0,NULL),$2, make_tree(1)); }
	  | '(' int_exp ')'								{ $$ = add_prefix_func (fu_next,0,add_prefix_func (fu_this,0,NULL),make_tree(), $2); }
	  | '(' ')'										{ $$ = add_prefix_func (fu_next,0,add_prefix_func (fu_this,0,NULL),make_tree(), make_tree(1)); }
;
/* All operators must be part of one nonterminal because of precedence ... otherwise they would loose the precedence and I had to prepare a lot of more difficult nonterminals. That's why I'm not using bool_exp - I use float_exp instead */

float_exp: STRING '(' unit_exp ')'			{ $$ = add_prefix_func (fu_chartofloat,$1,$3); }
			| '!' float_exp %prec NOT			{ $$ = add_infix_un_func (fu_not,$2);	}
			| float_exp OR float_exp			{ $$ = add_infix_bin_func (fu_or,$1,$3); }
			| float_exp AND float_exp			{ $$ = add_infix_bin_func (fu_and,$1,$3); }
			| float_exp EQ	float_exp			{ $$ = add_infix_bin_func (fu_equals,$1,$3); }
			| float_exp NOTEQ	float_exp		{ $$ = add_infix_bin_func (fu_notequals,$1,$3); }
			| float_exp '<' float_exp			{ $$ = add_infix_bin_func (fu_less,$1,$3); }
			| float_exp LESSEQ float_exp		{ $$ = add_infix_bin_func (fu_lessorequals,$1,$3); }
			| float_exp '>' float_exp			{ $$ = add_infix_bin_func (fu_greater,$1,$3); }
			| float_exp GREATEREQ float_exp		{ $$ = add_infix_bin_func (fu_greaterorequals,$1,$3); }
			| float_exp '+' float_exp			{ $$ = add_infix_bin_func (fu_add,$1,$3); }
			| float_exp '-' float_exp			{ $$ = add_infix_bin_func (fu_subtract,$1,$3); }
			| float_exp '*' float_exp			{ $$ = add_infix_bin_func (fu_multiply,$1,$3); }
			| float_exp '/' float_exp			{ $$ = add_infix_bin_func (fu_divide,$1,$3); }
		    | "neural" '(' unit_exp ',' int_exp ')'	{ $$ = add_prefix_func (fu_neural,0,$3,$5); }
			| int_exp										//{ $$ = $1; } - default
			| '(' float_exp ')'					{ $$ = $2; }
			| FLOAT_NUM					 		{ $$ = make_tree (double ($1));	}
;

int_exp: "count" '(' unit_level ',' unit_level ')'			{ $$ = add_prefix_func (fu_count,0,$3,$5); }
		 | "index" '(' unit_level ',' unit_level ')'		{ $$ = add_prefix_func (fu_index,0,$3,$5); }
		 | "basal_f" '(' unit_exp ')'						{ $$ = add_prefix_func (fu_f0,0,$3); }
		 | "cont" '(' unit_exp ')'							{ $$ = add_prefix_func (fu_cont,0,$3); }
		 | '(' int_exp ')' 									{ $$ = $2; }
		 | INT_NUM									 		{ $$ = make_tree (int ($1)); }
;
string_exp: '(' string_exp ')'	{ $$ = $2;}
			 |	QUOTED_STRING	{ $$ = make_tree ($1); }
;
unit_level: string_exp 
			{ 
				$$ = $1;
				if (get_level($1->v()) == U_DEFAULT) shriek (812, fmt("Unknown level: %s", static_cast<const char *>($1->v()))); 
				$1->v() = static_cast<char>(get_level ($1->v()));
			}
;

%%
     

#include <ctype.h>


/* * * * * * * * * * * * * * * * * * * * * * * * * * */
/*                     YYERROR                       */
/* * * * * * * * * * * * * * * * * * * * * * * * * * */

int yyerror (char *s)
{
	shriek (812, fmt ("BISON:yyerror:bison_nnet parser: bison_row %i (not counting empty rows) '%s' is erroneous. %s\n", row_num, bison_row_buf, s));
	return -1;
}
 

/* * * * * * * * * * * * * * * * * * * * * * * * * * */
/*                      YYLEX                        */
/* * * * * * * * * * * * * * * * * * * * * * * * * * */

int yylex ()
{
	char lex [MSG_LENGTH];

	D_PRINT(0, "yylex source: %s\n", bison_row);

	if (*bison_row == '#') 
		return 0; // comment line - EOF

	char *cross = const_cast<char *>(bison_row);
	while (cross = strchr (cross, '#')) {
		cross --;
		if (strchr (" \t", *cross))
			*cross = '\x0';
		else cross += 2;
	}

	//jump over whitespace
	while (*bison_row && strchr (" \t\n",*bison_row)) ++bison_row;

	//simple symbol
	if (strchr ("[]{}(),;+-*/$",*bison_row)) {
		return *bison_row++;
	}

	const char *end;

	//quoted string - return without quotas
	if (*bison_row == '\"') {
	   end = strchr (bison_row+1,'\"');
	   if (!*end) shriek (812, fmt ("BISON:yylex:Unterminated quotas! %s\n", bison_row));
		strcpy (yylval.string_val, bison_row+1);
		yylval.string_val [end-bison_row-1]=0;
		bison_row = end + 1;
		return QUOTED_STRING;
   }

	//two-chars-symbols (like ==,<= etc.) and function names
	
	if (strchr ("!=<>&", *bison_row)) { //these chars may form operators like != or <=
		for (end = bison_row; strchr ("!=<>&", *end); ++end);
	  	if (end-bison_row == 1) 
	  	 	return *bison_row++;
	}
	else {
	  end = strpbrk (bison_row, "![]={}(),& \t\n;+-*/><$");
	  if (!end) end = bison_row + strlen (bison_row);
	}


	if (end-bison_row > MSG_LENGTH) shriek (812,"BISON:yylex:Buffer overflow");
	strncpy (lex, bison_row, end-bison_row);
	lex [end-bison_row] = 0;
	bison_row = end;

	//try to find the grammar symbol 

	if (!strcmp(lex, "==")) return EQ;
	if (!strcmp(lex, "!=")) return NOTEQ;
	if (!strcmp(lex, "<=")) return LESSEQ;
	if (!strcmp(lex, ">=")) return GREATEREQ;
	if (!strcmp(lex, "AND"))return AND;
	if (!strcmp(lex, "OR")) return OR;
	if (!strcmp(lex, "count")) return COUNT;
	if (!strcmp(lex, "index")) return INDEX;
	if (!strcmp(lex, "this")) return THIS;
	if (!strcmp(lex, "ancestor")) return ANCESTOR;
	if (!strcmp(lex, "neural")) return NEURAL;
	if (!strcmp(lex, "prev")) return PREV;
	if (!strcmp(lex, "next")) return NEXT;
	if (!strcmp(lex, "basal_f")) return BASAL_F;
	if (!strcmp(lex, "cont")) return CONT;

#if 0
	for (int i = 0; i < YYNTOKENS; i++) {
		if (yytname[i] != 0
		    && yytname[i][0] == '"'
			 && !strncmp (yytname[i] + 1, lex,
							 strlen (lex))
			 && yytname[i][strlen (lex) + 1] == '"'
			 && yytname[i][strlen (lex) + 2] == 0
			&& printf("%s\n", lex))
		  return yytoknum[i];	// in case of errors try return i;
	}
#endif

	//not a grammar symbol - a number or chartofloat name or error
	yylval.int_val = strtol (lex, const_cast<char **>(&end), 10);
	if (*end == 0 && errno != ERANGE) 
		return INT_NUM;
	
	yylval.float_val = strtod (lex, const_cast<char **>(&end));
	if (*end == 0 && errno != ERANGE)
		return FLOAT_NUM;

	strcpy (yylval.string_val, lex);
	return STRING;
}
	
 
