/*******************************************************************************
 * Copyright (c) 2015-2017 ONERA and IRT AESE (IRT Saint Exupéry).
 * Ce logiciel est la propriété de l’ONERA (the French Aerospace Lab) et de
 * l'IRT AESE (IRT Saint Exupéry).
 * Tous droits réservés.
 * 
 * Ce programme et les éléments qui l'accompagnent sont mis à disposition
 * aux conditions définies par le contrat de licence logiciel CeCILL-C soumise
 * au droit français et respectant les principes de diffusion des logiciels libres. 
 * Vous pouvez utiliser, modifier et/ou redistribuer ce programme 
 * sous les conditions de la licence CeCILL-C (http://www.cecill.info).

 * This software is property of ONERA (the French Aerospace Lab) and of
 * the IRT AESE (IRT Saint Exupéry).
 * All rights reserved.
 * 
 * This program and the accompanying materials are made available under
 * the terms of the CeCILL-C license under French law and
 * abiding by the rules of distribution of free software.  
 * You can  use, modify and/ or redistribute the software under the terms of 
 * the CeCILL-C license (http://www.cecill.info).
 *
 * Contributeurs/contributors:
 *     Florent Teichteil-Königsbuch, Guillaume Infantes (ONERA - Centre de Toulouse) - initial API and implementation
 *     Alexandre Albore (IRT Saint-Exupéry) - Altarica/Fiacre translation
 *******************************************************************************/

%skeleton "lalr1.cc"
//%pure-parser
%defines
//%define api.namespace "epoch::altarica"
//%define api.parser_class_name "altarica_parser"
// DEPRECATED defines
%define namespace "epoch::altarica" 
%define parser_class_name "altarica_parser"


%code requires {
#include <string>
    class altarica_driver;
#include "grammars/altarica/domains/Domains.hh"
#include "grammars/altarica/Event.hh"
#include "grammars/altarica/EventLaw.hh"
#include "grammars/altarica/Assignment.hh"
#include "grammars/altarica/MemberAccess.hh"
#include "grammars/altarica/Synchronisation.hh"
#include "grammars/altarica/Constant.hh"
#include "grammars/altarica/Node.hh"
#include "grammars/altarica/Transition.hh"
#include "grammars/altarica/Values.hh"
#include "grammars/altarica/Variable.hh"
#include "grammars/altarica/Parameter.hh"
#include "grammars/altarica/expressions/Expressions.hh"
#include "grammars/altarica/parser_helper.hh"



    namespace epoch {
	namespace altarica {
	    typedef struct Cov {
		short type;
		Expression * fv;
	    } Cov;
	    typedef struct Bast {
		bool optional;
		MemberAccess* ma;
	    } Bast;
	    typedef struct exprPair {
		Expression *first;
		Expression *second;
	    } exprPair;
	    typedef struct VarD {
		std::string name;
		Domain * d;
	    } VarD;
	    typedef struct nodeArray {
		Node * n;
		std::vector<int> * indexes;
	    } nodeArray;
	}
    }

 }

%parse-param {altarica_driver & driver}
%parse-param {void* yyscanner}
%lex-param {altarica_driver & driver}
%lex-param {void* yyscanner}

%locations
%initial-action
{
    @$.begin.filename = @$.end.filename = &driver.m_ParsedRessource;
};

%debug
%error-verbose

%union
 {
     std::vector<std::string> * stvec;
     bool *b;
     double fl;
     std::string * st;
     nft* nf;
     int* i;
     unsigned int  ui;
     LawType lt;
     std::vector<int> *ivec;
     std::vector<nft*> *nfvec;
     ArrayDomain* ad;
     EnumDomain* ed;
     RangeDomain* rd;
     Event* ev;
     EventLaw *evl;
     VarD * vard;
     std::vector<VarD*> * vardvec;
     std::vector<Event*> *evvec;
     std::vector<EventLaw*> *evlvec;
     StructuredDomain* sd;
     Assignment* ass;
     std::vector<Assignment*> *assvec;
     MemberAccess* ma;
     std::vector<MemberAccess*> *mavec;
     Synchronisation* sync;
     std::vector<Synchronisation*>* syncvec;
     Cov * cov;
     Bast * bast;
     std::vector<Bast*> *bastvec; 
     Constant* cons;
     Node* node;
     std::vector<Node*> *nodevec;
     Transition* trans;
     std::vector<Transition*> *transvec;
     /* ContinuousDomain * cd; */
     Variable* var;
     std::vector<Variable*> *varvec;
     Assertion * assert;
     std::vector<Assertion*> * assertdvec;
     DiscreteDomain* dd;
     Parameter* param;
     std::vector<Parameter*> *paramvec;
     Domain* domain;
     PredefinedDomain* pd;
     exprPair * epair;
     nodeArray * na;
     std::vector<exprPair*> *epairvec;

     ExpressionADD* eADD;
     ExpressionFUNCTIONCALL* eFC;
     ExpressionPAREN* ePAR;
     ExpressionAND * eAND;
     Expression* expr;
     std::vector<Expression* > *exprvec;
     ExpressionQUANTIFIED* eQUANT; 
     ExpressionARITH* eARITH;
     ExpressionIfThenElse * eITE;
     ExpressionUNARY* eUNARY;
     ExpressionATOMIC* eATOMIC;
     ExpressionLOG* eLOG;
     ExpressionBOOLCONSTANT* eBC;
     ExpressionUNSIGNEDINT* eUI;
     ExpressionREAL * eR;
     ExpressionCASE* eCASE;
     ExpressionMINMAX* eMINMAX;
     ExpressionCONSTARRAY * eCA;
     ExpressionMUL* eMUL;
     ExpressionCONSTSTRUCT* eCS;
     ExpressionOR * eOR;
     ExpressionCARD * eCARD;
};

%code {
#include "altarica_driver.hh"
#include "altarica_lexer.h"
#include "grammars/details/parsingdriverbaseimpl.hh"


    void epoch::altarica::altarica_parser::error (const epoch::altarica::altarica_parser::location_type& loc, const std::string& msg) {
	driver.error<epoch::altarica::altarica_parser>(loc, msg);
    }
 }

%token ALTARICA_END   0

%token ALTARICA_COMMA
%token ALTARICA_COLON
%token ALTARICA_SEMICOLON
%token ALTARICA_EQUAL
%token ALTARICA_LEFTBRACKET
%token ALTARICA_RIGHTBRACKET
%token ALTARICA_LEFTEMBRACE
%token ALTARICA_RIGHTEMBRACE
%token <st> ALTARICA_IDENTIFIER
%token ALTARICA_CONST
%token ALTARICA_DOMAIN
%token ALTARICA_BOOL
%token ALTARICA_INTEGER
%token ALTARICA_REAL
%token ALTARICA_STRUCT
%token ALTARICA_TCURTS

%token ALTARICA_SORT
%token ALTARICA_SIG
%token ALTARICA_TO
%token ALTARICA_STAR
%token ALTARICA_IF
%token ALTARICA_ELSE
%token ALTARICA_THEN
%token ALTARICA_LAW
%token ALTARICA_EVENT

%token ALTARICA_OPAREN
%token ALTARICA_CPAREN
%token ALTARICA_IMARK
%token ALTARICA_EXCL

%token ALTARICA_CASE
%token ALTARICA_OR
%token ALTARICA_LOR
%token ALTARICA_MIN
%token ALTARICA_MAX
%token ALTARICA_AND
%token ALTARICA_LAND
%token ALTARICA_DIF
%token ALTARICA_IMPLIES
%token ALTARICA_INF
%token ALTARICA_SUP
%token ALTARICA_INFEQ
%token ALTARICA_SUPEQ
%token ALTARICA_PLUS 
%token ALTARICA_MINUS
%token ALTARICA_DIV
%token ALTARICA_MOD 
%token ALTARICA_TILDE
%token ALTARICA_NOT
%token ALTARICA_DOT
%token ALTARICA_TRUE
%token ALTARICA_FALSE
%token ALTARICA_NO
%token ALTARICA_EDON
%token ALTARICA_INIT 
%token ALTARICA_ASSERT
%token ALTARICA_PARAM
%token ALTARICA_STATE
%token ALTARICA_TR
%token ALTARICA_AFFECT
%token ALTARICA_FLOW
%token ALTARICA_TRANS
%token ALTARICA_SYNC
%token ALTARICA_SUB
%token ALTARICA_PARAM_SET
%token ALTARICA_EXTERN
%token ALTARICA_NODE
%token ALTARICA_CARD
%token ALTARICA_CCF
%token ALTARICA_WITHCCF
%token ALTARICA_NODEPROPERTY
%token ALTARICA_STRING
%token ALTARICA_GLOBAL
%token ALTARICA_LAW_DIRAC;
%token ALTARICA_LAW_DISCRETE;
%token ALTARICA_LAW_EXP;
%token ALTARICA_LAW_TIMED;
%token ALTARICA_REMARK;
%token ALTARICA_ATTRIBUTE;


%token <ui> ALTARICA_UNSIGNED_INTEGER
%token <fl> ALTARICA_FLOAT;

%type <node> node_definition
%type <domain> domain
%type <domain> scalar_domain
%type <ed> enumeration_domain
%type <domain> predefined_domain
%type <sd> structure_domain
%type <sd> structure_fields
%type <sd> field_list
%type <ad> array_domain
%type <expr> constant_expression
%type <expr> expression 
%type <eITE> if_then_else_expr 
%type <eCASE> case_expr  case_choice_list
%type <expr> case_default boolean_expr

%type <epair> case_conditional_choice
%type <epairvec> case_conditional_choice_list
%type <expr> numerical_constant_expression 


%type <assert> assertion
%type <st> constant_name
%type <ui> variables_class
%type <st> domain_name node_name
%type <st> symbol
%type <stvec> symbol_list
%type <stvec> list_of_identifiers
%type <stvec> id_list
%type <stvec> attributes attributes_list 
%type <nfvec> node_field_list
%type <nf> node_field
%type <varvec> variables_declaration  variables_decl_list variables_decl
%type <transvec>  transitions_definition transition_list transition_target_list transition
%type <trans>  transition_target
%type <assertdvec> assertions_definitions assertion_list
%type <nodevec> subnodes_declaration subnodes_decl_list  subnodes_decl
%type <na> node_type
%type <syncvec> vectors_definition vector_list
%type <sync> vector ccf_type_sync 
%type <bastvec> broadcast_list ccf_list
%type <bast> broadcast ccf
%type <ma>  event_instance_identifier identifier_path dot_separated_identifier_list
%type <cov> constraint_on_vector
%type <i> broadcast_kind
%type <assvec> init_declaration  init_assignment_list 
%type <assvec> parameter_set_declaration assignment_list param_assignment_list
%type <ass> assignment init_assignment param_assignment
%type <paramvec> parameters_declaration parameters_decl_list parameters_decl
%type <stvec> parameters_name_list
%type <stvec>  variables_name_list subnodes_name_list 
%type <ma> ident event_name
%type <mavec> event_name_list trans_label_list 
%type <evvec> event_set event_dag event_dag_list_rec event_dag_list event_decl events_declaration  events_decl_list 
%type <ma> member_access  struct_member  array_member 
%type <ivec> position_in_array list_of_array_position
%type <eOR> disjunctive_expr
%type <eAND> conjunctive_expr
%type <eLOG> logical_comparison_expr
%type <eARITH> arithmetic_comparison_expr
%type <eADD> additive_expr
%type <eMUL> multiplicative_expr
%type <eUNARY> unary_expr
%type <eATOMIC> atomic_expr

%type <expr> parenthezed_expr
%type <eMINMAX> min_max_expr
%type <exprvec> comma_separated_expr_list function_parameters
%type <eUI> unsigned_integer
%type <eR> real
%type <eBC> boolean_constant
%type <eQUANT> quantified_expr
%type <eFC> function_call_expr
%type <eCS> constant_structure constant_field_assignment_list constant_field_assignment
%type <eCA> constant_array constant_expression_list
%type <eCARD> card_expr

%type <vardvec> quantified_variables_decl quantified_variables_decl_list quantified_variables
%type <mavec> events_name_law events_name_law_set
%type <ma> event_name_law
%type <expr> law_param
%type <lt> law_type
%type <evl> law
%type <evlvec> law_decl external_directive external_directives external_directives_declaration



%%
 /* AltaRica description */
altarica_description : 
| definition_list 
;

definition_list : definition_list ALTARICA_SEMICOLON definition
| definition_list definition
| definition
;

definition : 
constant_definition 
| domain_definition  
| sort_declaration
{
    error(yyla.location, "not yet implemented");
}
| signature_declaration
{
    error(yyla.location, "not yet implemented");
}
| node_definition  { driver.amodel->addNode($1);} // $1->finalize(driver.amodel);}
;

/* AltaRica constants */
constant_definition : 
ALTARICA_CONST constant_name ALTARICA_EQUAL constant_expression 
{
    Constant* c = driver.amodel->findConstantByName(*$2);
    if (c == NULL) {
	Constant *n = new Constant(*$2);
	n->setExpression($4);
	driver.amodel->addConstant(n);
    } else {
	c->setExpression($4);
    }
    delete $2;
}
| ALTARICA_CONST constant_name ALTARICA_COLON domain ALTARICA_EQUAL constant_expression
{
    driver.amodel->addConstant(new Constant(*$2, $4, $6));
    delete $2;
}
| ALTARICA_CONST constant_name ALTARICA_COLON domain
{
    driver.amodel->addConstant(new Constant(*$2, $4));
    delete $2;
}
;

constant_name : ALTARICA_IDENTIFIER
{
    $$ = $1;
};

constant_expression : expression; 

/* AltaRica domains */
domain_definition : ALTARICA_DOMAIN domain_name ALTARICA_EQUAL domain
{
    $4->set_name(*$2);
    if (driver.amodel->findDomainByName(*$2) == NULL)
	driver.amodel->addDomain($4);
    delete($2);
}
/* NB: 3.0 doesn't uses ALTARICA_EQUAL, while dataflow does */

	| ALTARICA_DOMAIN domain_name domain 
	{
    $3->set_name(*$2);
    if (driver.amodel->findDomainByName(*$2) == NULL)
	driver.amodel->addDomain($3);
    delete($2);
};

domain_name : ALTARICA_IDENTIFIER
{
    $$ = $1;
} ;

domain :
scalar_domain 
{$$ = $1;}
| enumeration_domain 
{$$ = $1;}
| predefined_domain 
{$$ = $1;}
| domain_name 
{
    $$ = driver.amodel->findDomainByName(*$1);
    delete $1;
}
| structure_domain 
{$$ = $1;}
| array_domain 
{$$ = $1;}
;

/*			Integer ranges */
scalar_domain : 
ALTARICA_LEFTBRACKET numerical_constant_expression ALTARICA_COMMA numerical_constant_expression ALTARICA_RIGHTBRACKET 
{
    Value * fv1  = $2->evaluate(driver.amodel, NULL,NULL);
    Value * fv2  = $4->evaluate(driver.amodel, NULL,NULL);
    if (fv1->isInt() && fv2->isInt()) 
	$$ = new RangeDomain(fv1->toInt(), fv2->toInt());
    else 
	$$ = new RealDomain(fv1->toDouble(), fv2->toDouble());
    driver.amodel->addDomain($$);

    Value::deleteIfPossible(fv1);
    Value::deleteIfPossible(fv2);
    delete($2);
    delete($4);
}
|
ALTARICA_RIGHTBRACKET numerical_constant_expression ALTARICA_COMMA numerical_constant_expression ALTARICA_RIGHTBRACKET 
{
    Value * fv1  = $2->evaluate(driver.amodel, NULL,NULL);
    Value * fv2  = $4->evaluate(driver.amodel, NULL,NULL);
    
    if (fv1->isInt() && fv2->isInt())
	$$ = new RangeDomain(fv1->toInt()+1, fv2->toInt());
    else
	$$ = new RealDomain(fv1->toDouble(), fv2->toDouble(),true,false);
    driver.amodel->addDomain($$);

    Value::deleteIfPossible(fv1);
    Value::deleteIfPossible(fv2);
    delete($2);
    delete($4);
}
|
ALTARICA_LEFTBRACKET numerical_constant_expression ALTARICA_COMMA numerical_constant_expression ALTARICA_LEFTBRACKET 
{
    Value * fv1  = $2->evaluate(driver.amodel, NULL,NULL);
    Value * fv2  = $4->evaluate(driver.amodel, NULL,NULL);
    
    if (fv1->isInt() && fv2->isInt())
	$$ = new RangeDomain(fv1->toInt(), fv2->toInt()-1);
    else
	$$ = new RealDomain(fv1->toDouble(), fv2->toDouble()-1,false,true);
    driver.amodel->addDomain($$);

    Value::deleteIfPossible(fv1);
    Value::deleteIfPossible(fv2);
    delete($2);
    delete($4);
}
|
ALTARICA_RIGHTBRACKET numerical_constant_expression ALTARICA_COMMA numerical_constant_expression ALTARICA_LEFTBRACKET 
{
    Value * fv1  = $2->evaluate(driver.amodel, NULL,NULL);
    Value * fv2  = $4->evaluate(driver.amodel, NULL,NULL);
    
    if (fv1->isInt() && fv2->isInt())
	$$ = new RangeDomain(fv1->toInt()+1, fv2->toInt()-1);
    else
	$$ = new RealDomain(fv1->toDouble(), fv2->toDouble()-1,true,true);	
    driver.amodel->addDomain($$);

    Value::deleteIfPossible(fv1);
    Value::deleteIfPossible(fv2);
    delete($2);
    delete($4);
}
;

//interval : numerical_constant_expression ALTARICA_COMMA numerical_constant_expression
//{
//$$ = 
//};


numerical_constant_expression : constant_expression 
{
    $$ = $1;
};

/*			List of symbolic values (enumerations) */
enumeration_domain : ALTARICA_LEFTEMBRACE symbol_list ALTARICA_RIGHTEMBRACE 
{
    $$ = new EnumDomain($2->size());
    driver.amodel->addDomain($$);
    $$->addSymbols($2);
    delete $2;
};

symbol_list : 
symbol_list ALTARICA_COMMA symbol
{
    $1->push_back(*$3);
    $$ = $1;
    delete $3;
}
| symbol
{
    $$ = new std::vector<std::string>();
    $$->push_back(*$1);
    delete $1;
}
;

symbol : ALTARICA_IDENTIFIER 
{
    $$  = $1;
};


/*			Predefined domains */
predefined_domain : 
ALTARICA_BOOL 
{
    $$ = new PredefinedDomain(true);
    driver.amodel->addDomain($$);

}
| ALTARICA_INTEGER
{
    $$ = new PredefinedDomain(false);
    driver.amodel->addDomain($$);
}
| ALTARICA_REAL
{
    $$ = new RealDomain();
    driver.amodel->addDomain($$);
}
;

/*			Structured domains */
structure_domain : ALTARICA_STRUCT structure_fields ALTARICA_TCURTS
{
    $$ = $2;
    driver.amodel->addDomain($$);

}
| ALTARICA_STRUCT structure_fields ALTARICA_SEMICOLON ALTARICA_TCURTS
{
    $$ = $2;
    driver.amodel->addDomain($$);
}
;

structure_fields : structure_fields ALTARICA_SEMICOLON field_list
{
    $3->addMyDomainsTo($1);
    delete($3);
    $$ = $1;
}
| field_list
{
    $$ = $1;
}
;

field_list : id_list ALTARICA_COLON domain 
{
    $$ = new StructuredDomain();
    $$->addDomains($1, $3);
    delete $1;
}
;

id_list : list_of_identifiers 
{
    $$ = $1;
};

list_of_identifiers :
list_of_identifiers ALTARICA_COMMA ALTARICA_IDENTIFIER
{
    
    $1->push_back(*$3);
    $$ = $1;
    delete $3;
}
| ALTARICA_IDENTIFIER
{
    $$ = new std::vector<std::string>();
    $$->push_back(*$1);
    delete $1;
}
;

/*			Array domains */
array_domain : domain ALTARICA_LEFTBRACKET numerical_constant_expression ALTARICA_RIGHTBRACKET
{
    Value * fv = $3->evaluate(NULL, NULL,NULL);
    $$ = new ArrayDomain(fv->toInt(),$1);
    driver.amodel->addDomain($$);
    delete fv;
    delete $3;
} ;

/* AltaRica nodes */
node_definition : ALTARICA_NODE node_name attributes node_field_list ALTARICA_EDON
{
    $$ = new Node();
    $$->setMA(*$2);   
    $$->setTypeName($$->getMA()->clone());
    delete $2;
    if ($3 != NULL) {
	$$->addAttributes($3);
	delete $3;
    }
    for (std::vector<nft*>::iterator nfit = $4->begin();  nfit != $4->end(); ++nfit) {
	if ((*nfit)->pd != NULL) {
	    $$->addParams((*nfit)->pd);
	    delete (*nfit)->pd;
	} else if ((*nfit)->vd != NULL) {
	    $$->addVariables((*nfit)->vd);
	    delete (*nfit)->vd;
	} else if ((*nfit)->ed != NULL) {
	    $$->addEvents((*nfit)->ed);
	    delete (*nfit)->ed;
	} else if ((*nfit)->td != NULL) {
	    $$->addTransitions((*nfit)->td);
	    delete (*nfit)->td;
	} else if ((*nfit)->ad != NULL) {
	    $$->addAssertions((*nfit)->ad);
	    delete (*nfit)->ad;
	} else if ((*nfit)->snd != NULL) {
	    $$->addSubNodes((*nfit)->snd);
	    delete (*nfit)->snd;
	} else if ((*nfit)->sd != NULL) {
	    $$->addSyncs((*nfit)->sd);
	    delete (*nfit)->sd;
	} else if ((*nfit)->assd != NULL) {
	    $$->addInits((*nfit)->assd);
	    delete (*nfit)->assd;
	} else if ((*nfit)->psd != NULL) {
	    $$->addParamsSets((*nfit)->psd);
	    delete (*nfit)->psd;
	} else if ((*nfit)->eld != NULL) {
	    $$->addEventLaws((*nfit)->eld);
	    delete (*nfit)->eld;
	}
	delete *nfit;

    }
    delete $4;
    
} ;

node_name : ALTARICA_IDENTIFIER
{
    $$ = $1;
} ; 

attributes : ALTARICA_COLON attributes_list
{
    $$ = $2;
}
| /* empty */
{
    $$ = NULL;
}
;

attributes_list : id_list 
{
    $$ = $1;
};

node_field_list :
node_field_list node_field 
{
    $1->push_back($2);
    $$ = $1;
}
|
 {
     $$ = new std::vector<nft*>();
 }
;
     
node_field : 	 
parameters_declaration
{
    $$ = new nft();
    $$->pd = $1;
}
| variables_declaration
{
    $$ = new nft();
    $$->vd = $1;
}
| events_declaration
{
    $$ = new nft();
    $$->ed = $1;	       
}
| transitions_definition
{
    $$ = new nft();
    $$->td = $1;
}
| assertions_definitions
{
    $$ = new nft();
    $$->ad = $1;
}
| subnodes_declaration
{
    $$ = new nft();
    $$->snd = $1;
}
| vectors_definition
{
    $$ = new nft();
    $$->sd = $1;
}
| init_declaration
{
    $$ = new nft();
    $$->assd = $1;
}
| parameter_set_declaration
{
    $$ = new nft();
    $$->psd = $1;
}
| external_directives_declaration
{
    $$ = new nft();
    $$->eld = $1;
}
;

/*			Declaration of parameters */
parameters_declaration : 
ALTARICA_PARAM parameters_decl_list
{
    $$ = $2;
}
| ALTARICA_PARAM parameters_decl_list ALTARICA_SEMICOLON
{
    $$ = $2;
}
;

parameters_decl_list : 
parameters_decl_list ALTARICA_SEMICOLON parameters_decl
{
    $1->insert($1->end(),$3->begin(),$3->end());
    delete $3;
    $$ = $1;
}
| parameters_decl
{
    $$ = $1;
}
;

parameters_decl : parameters_name_list ALTARICA_COLON domain
{
    $$ = new std::vector<Parameter*>();
    for (std::vector<std::string>::iterator nit = $1->begin();
	 nit != $1->end(); ++nit)
	$$->push_back(new Parameter(*nit,$3));
    delete $1;
}
;

parameters_name_list : id_list 
{
    $$ = $1;
};

variables_declaration : variables_class variables_decl_list
{
    if ($1 == 0)
	for (std::vector<Variable*>::iterator vit = $2->begin();
	     vit != $2->end(); ++vit)
	    (*vit)->setFlow();
    else
	for (std::vector<Variable*>::iterator vit = $2->begin();
	     vit != $2->end(); ++vit)
	    (*vit)->setState();	     
    $$ = $2;
}
| variables_class variables_decl_list ALTARICA_SEMICOLON
{
    if ($1 ==  0)
	for (std::vector<Variable*>::iterator vit = $2->begin();
	     vit != $2->end(); ++vit)
	    (*vit)->setFlow();
    else
	for (std::vector<Variable*>::iterator vit = $2->begin();
	     vit != $2->end(); ++vit)
	    (*vit)->setState();
    $$ = $2;
}
;

/*			Declaration of flows and states */
variables_class :
ALTARICA_FLOW
{
    $$ = 0;
}
| ALTARICA_STATE
{
    $$ = 1;
}
;

variables_decl_list : 
variables_decl_list ALTARICA_SEMICOLON variables_decl
{
    $1->insert($1->end(),$3->begin(), $3->end());
    $$ = $1;
    delete $3;
}
| variables_decl
{
    $$ = $1;
}
;

variables_decl : variables_name_list ALTARICA_COLON domain attributes
{
    $$ = new std::vector<Variable*>();
    for (std::vector<std::string>::iterator vit = $1->begin();
	 vit != $1->end(); ++vit) {
	    if ($3 == NULL)
		    std::cerr << "BIG FAT WARNING: unable to set domain for variable " << *vit <<
			    "   you will have problems at some point" << std::endl;           
	Variable *nv = new Variable(*vit,$3);
	if ($4 != NULL)
	    nv->addAttributes($4);
	$$->push_back(nv);	     
    }	     
    delete $1;
    delete $4;
} ;

variables_name_list : id_list 
{
    $$ = $1;
}
;


/*			Declaration of events */
events_declaration : ALTARICA_EVENT events_decl_list
{
    $$ = $2;
}
| ALTARICA_EVENT events_decl_list ALTARICA_SEMICOLON
{
    $$ = $2;
}
;

events_decl_list :
events_decl_list ALTARICA_SEMICOLON event_decl
{
    std::vector<Event*>::iterator it;
    $$ = $1;
    for (it = $3->begin(); it != $3->end(); ++it) 
	$$->push_back(*it);   
    delete($3);
}
| event_decl
{
    $$ = $1;
}
;

event_decl : event_dag_list attributes 
{
    $$ = $1;
    if ($2!= NULL)
	for (std::vector<Event*>::iterator it = $$->begin(); it != $$->end(); ++it) 
	    (*it)->addAttributes($2);              
}
;

event_dag_list : event_dag_list_rec 
{
    $$ = $1;
};

event_dag_list_rec : event_dag_list_rec ALTARICA_COMMA event_dag
{
    std::vector<Event*>::iterator it;
    $$ = $1;
    for (it = $3->begin(); it != $3->end(); ++it) 
	$$->push_back(*it); 
    delete($3);
}
| event_dag
{
    $$ = $1;
}
;

event_dag : 
event_dag ALTARICA_INF event_set
{
    $$ = $1;
    std::vector<Event*>::iterator it1;
    std::vector<Event*>::iterator it2;
    
    for (it1 = $$->begin(); it1 != $$->end(); ++it1) 
	for (it2 = $3->begin(); it2 != $3->end(); ++it2) {
	    (*it2)->addLower(*it1);
	    (*it1)->addUpper(*it2);	    
	}

    for (it2 = $3->begin(); it2 != $3->end(); ++it2) 
	$$->push_back(*it2);   
    delete $3;
}
| event_set ALTARICA_SUP event_set
{
    $$ = $1;
    std::vector<Event*>::iterator it1;
    std::vector<Event*>::iterator it2;
    
    for (it1 = $$->begin(); it1 != $$->end(); ++it1) 
	for (it2 = $3->begin(); it2 != $3->end(); ++it2) {
	    (*it1)->addLower(*it2);
	    (*it2)->addUpper(*it1);	    
	}

    for (it2 = $3->begin(); it2 != $3->end(); ++it2) 
	$$->push_back(*it2); 
    delete $3;
}
| event_set
{
    $$ = $1;
}
;

event_set : 
ALTARICA_LEFTEMBRACE event_dag_list ALTARICA_RIGHTEMBRACE
{
    $$ = $2;
}
| event_name
{
    $$ =  new std::vector<Event*>();
    std::vector<MemberAccess*> * mav = $1->buildCombinations();
    for (std::vector<MemberAccess*>::iterator i = mav->begin(); i!= mav->end(); ++i) {    
	$$->push_back(new Event(*i));
    }
    delete mav;
    delete $1;
}
;

event_name : ident
{
    $$ = $1;
};

/*			Declaration of subnodes */
subnodes_declaration : ALTARICA_SUB subnodes_decl_list 
{
    $$ = $2;
}
| ALTARICA_SUB subnodes_decl_list ALTARICA_SEMICOLON
{
    $$  =$2;
}
;

subnodes_decl_list : subnodes_decl_list ALTARICA_SEMICOLON subnodes_decl
{
    $$ = $1;
    for (std::vector<Node*>::iterator it = $3->begin(); it != $3->end(); ++it)	
	$$->push_back(*it);
    delete($3);
}
| subnodes_decl
{
    $$ = $1;
}
;

subnodes_decl : subnodes_name_list ALTARICA_COLON node_type
{

    std::vector<Node*> *nnodes;

    for (std::vector<std::string>::iterator it = $1->begin(); it!=$1->end(); ++it) {
	if ($3->n == NULL)
	    error(yyla.location, "undeclared node");
	else {
	    nnodes = new std::vector<Node*> ();
	    if ($3->indexes->size() == 0) {
		Node * n = $3->n->clone();
		n->setMA(*it);
		nnodes->push_back(n);
	    } else {	
		std::vector<Node*> * nnodes = new std::vector<Node*>();
		MemberAccess * ma = new MemberAccess(*it, $3->indexes);
		std::vector<MemberAccess*> * mma = ma->buildCombinations();
		for (std::vector<MemberAccess*>::iterator i = mma->begin(); i!= mma->end(); ++i) {
		    Node * n = $3->n->clone();
		    n->setMA(*i); 
		    nnodes->push_back(n);
		}
		delete(ma);
		delete(mma);
	    }
	}
    }

    $$ = nnodes;
    delete($3->indexes);
    delete($1);
    //    ParserHelper::deleteStringVec($1);
    delete($3);
}
;

subnodes_name_list : id_list 
{
    $$ = $1;
}
;

node_type : node_type ALTARICA_LEFTBRACKET numerical_constant_expression ALTARICA_RIGHTBRACKET
{
    Value *fv = $3->evaluate(NULL, NULL,NULL);
    $1->indexes->push_back(fv->toInt());
    Value::deleteIfPossible(fv);
    delete $3;
    $$ = $1;    
}
| node_name
{
    $$ = new nodeArray();
    $$->n = driver.amodel->findNodeByName(*$1);
    $$->indexes = new std::vector<int>();
    if ($$->n == NULL)
	error(yyla.location, *$1); 
    delete $1;
}
;

/*			Definition of assertions */
assertions_definitions : ALTARICA_ASSERT assertion_list 
{
    $$ = $2;
}
| ALTARICA_ASSERT assertion_list  ALTARICA_SEMICOLON
{
    $$ = $2;
}
;

assertion_list : assertion_list ALTARICA_SEMICOLON assertion
{
    $$ = $1;
    $$->push_back($3);
}
|assertion_list ALTARICA_COMMA assertion
{
    $$ = $1;
    $$->push_back($3);
}
| assertion
{
    $$ = new std::vector<Assertion*>();
    $$->push_back($1);
}
;

assertion : boolean_expr
{
    $$ = new Assertion($1);
}
;

/*			Definition of transitions */
transitions_definition : ALTARICA_TRANS transition_list 
{
    $$ = $2;
}
| ALTARICA_TRANS transition_list ALTARICA_SEMICOLON
{
    $$ = $2;
}
;

transition_list : transition_list ALTARICA_SEMICOLON transition
{
    $$ = $1;
    for (std::vector<Transition*>::iterator i= $3->begin(); i!= $3->end(); ++i)
	$$->push_back(*i);
    delete $3;
    
}
| transition
{
    $$ = $1;
}
;

transition : boolean_expr transition_target_list 
{
    $$ = $2;
    for (std::vector<Transition*>::iterator i = $$->begin();
	 i != $$->end(); ++i) {
	(*i)->setPrecond($1);
    }
}
;

transition_target_list : transition_target_list transition_target
{
    $$ = $1;
    $$->push_back($2);
}
| transition_target
{ 
    $$ = new std::vector<Transition*>();
    $$->push_back($1);
}
;

transition_target : ALTARICA_TR trans_label_list ALTARICA_TO assignment_list
{
    $$ = new Transition();
    $$->addEventNames($2);
    $$->addAssignments($4);
    delete $2;
    delete $4;
}
| ALTARICA_TR trans_label_list ALTARICA_TO 
{
    $$ = new Transition();
    $$->addEventNames($2); 
    delete $2;
}
;

trans_label_list : event_name_list
{
    $$  = $1;
} ;

event_name_list : event_name_list ALTARICA_COMMA event_name
{
    $$ = $1;
    $$->push_back($3);
}
| event_name
{
    $$ = new std::vector<MemberAccess*>();
    $$->push_back($1);
}
;

assignment_list : assignment_list ALTARICA_COMMA assignment
{
    $$ = $1;
    $$->push_back($3);
}
| assignment
{
    $$ = new std::vector<Assignment*>();
    $$->push_back($1);
}
;

assignment : member_access ALTARICA_AFFECT expression
{
    $$ = new Assignment($1, $3);
}
;

/*			Broadcast synchronisation vectors */
vectors_definition : ALTARICA_SYNC vector_list 
{
    $$ = $2;
}
| ALTARICA_SYNC vector_list  ALTARICA_SEMICOLON
{
    $$ = $2;
}
;

vector_list : vector_list vector_sep vector
{
    $$ = $1;
    if (($3) != NULL)
	$$->push_back($3);
}
| vector
{    
    $$ = new std::vector<Synchronisation*>();
    if ($1 != NULL)
	$$->push_back($1);
}
;

vector_sep : ALTARICA_SEMICOLON
| ALTARICA_COMMA // COMMA IS USED BUT MAKES GRAMMAR AMBIGUOUS DUE TO CCF COMMA SEPARATOR.....
;

vector :  ALTARICA_INF broadcast_list ALTARICA_SUP constraint_on_vector broadcast_kind 
{
    if ($2->size() > 1) {
	$$ = new Synchronisation();
	
	for (std::vector<Bast*>::iterator i = $2->begin(); i!= $2->end(); ++i) {
	    $$->addEvent((*i)->ma, (*i)->optional);
	    delete *i;
	}
	if ($4 != NULL) {
	    $$->setConstraintType($4->type);
	    Value *fv = $4->fv->evaluate(NULL, NULL,NULL);
	    $$->setNumConstant(fv->toInt());
	    Value::deleteIfPossible(fv);
	    delete $4;
	}
	if (*$5 == -1)
	    $$->setMin();
	else if (*$5 == 1)
		$$->setMax();	
    } else
	$$ = NULL;
    delete $5;
    if ($2->size() == 1) {
	delete (*$2)[0]->ma;
	delete (*$2)[0];
    }
    delete $2;
}
| ccf_type_sync 
{
    $$ = $1;
}

;




ccf_type_sync :  ALTARICA_INF ALTARICA_IDENTIFIER ALTARICA_COLON ccf_list ALTARICA_SUP
{
    MemberAccess * syncName = new MemberAccess(*$2);
    delete $2;
    $$ = new Synchronisation(syncName);
    
    for (std::vector<Bast*>::iterator i = $4->begin(); i!= $4->end(); ++i) {
	$$->addEvent((*i)->ma, (*i)->optional);
	delete *i;
    }
    delete $4;
    $$->addEvent(syncName->clone(), false);
    $$->setNumConstant(2); // for ccf, consider only mandatory event plus one of the optional
    $$->setConstraintType(1);
    $$->setMax();
}
;


/* ccf_real_list : ccf_real_list ALTARICA_COMMA ccf_term */
/* | ccf_term */
/* ; */

/* ccf_term : ALTARICA_INF identifier_path ALTARICA_SUP */
/* ; */

ccf_list : ccf_list ALTARICA_OR ccf
{
    $$ = $1;
    $$->push_back($3);
}
| ccf
{
    $$ = new std::vector<Bast*>();
    $$->push_back($1);    
}
;

ccf : event_instance_identifier 
{
    $$ = new Bast();
    $$->ma = $1;
    $$->optional = true;    
}
;


broadcast_list : broadcast_list ALTARICA_COMMA broadcast
{
    $$ = $1;
    $$->push_back($3);
}
| broadcast
{
    $$ = new std::vector<Bast*>();
    $$->push_back($1);
}
;

broadcast : event_instance_identifier ALTARICA_IMARK
{
    $$ = new Bast();
    $$->ma = $1;
    $$->optional = true;
}
| ALTARICA_IMARK event_instance_identifier
{
    $$ = new Bast();
    $$->ma = $2;
    $$->optional = true;
}
| event_instance_identifier
{
    $$ = new Bast();
    $$->ma = $1;
    $$->optional = false;
}
;

event_instance_identifier : identifier_path 
{
    $$ = $1;
};

constraint_on_vector : ALTARICA_INF numerical_constant_expression
{
    $$ = new Cov();
    $$->type = -2;
    $$->fv = $2;
}
| ALTARICA_INFEQ numerical_constant_expression
{
    $$ = new Cov();
    $$->type = -1;
    $$->fv = $2;
}
| ALTARICA_SUP numerical_constant_expression
{
    $$ = new Cov();
    $$->type = 2;
    $$->fv = $2;
}
| ALTARICA_SUPEQ numerical_constant_expression
{
    $$ = new Cov();
    $$->type = 1;
    $$->fv = $2;
}
| ALTARICA_EQUAL numerical_constant_expression
{
    $$ = new Cov();
    $$->type = 0;
    $$->fv = $2;
}
|
{
    $$ = NULL;
}
;

broadcast_kind : ALTARICA_MIN
{
	$$ = new int(-1);
}
| ALTARICA_MAX
{
	$$ = new int(1);
}
| /* empty */
{
	$$ = new int(0);
}
;

identifier_path : dot_separated_identifier_list 
{
    $$ = $1;
};

dot_separated_identifier_list : dot_separated_identifier_list ALTARICA_DOT ident
{
    $$ = $1;
    $$->addMemberAccessBack($3);
    delete $3;
}
| ident
{
    $$ = $1;
}
;

ident : ALTARICA_IDENTIFIER
{
    $$ = new MemberAccess(*$1);
    delete $1;
}
| ALTARICA_IDENTIFIER position_in_array
{
    $$ = new MemberAccess();
    $$->addIdBack(*$1);
    delete $1;
    $$->addIndexesBack($2);
}
;

position_in_array : list_of_array_position 
{
    $$ = $1;
}
;

list_of_array_position : list_of_array_position ALTARICA_LEFTBRACKET numerical_constant_expression ALTARICA_RIGHTBRACKET
{
    $$ = $1;
    Value *fv = $3->evaluate(NULL, NULL,NULL);
    $$->insert($$->end()-1,fv->toInt());
    Value::deleteIfPossible(fv);
    delete $3;
}
| ALTARICA_LEFTBRACKET numerical_constant_expression ALTARICA_RIGHTBRACKET
{
    $$=new std::vector<int>();
    Value *fv = $2->evaluate(NULL,NULL,NULL);
    $$->push_back(fv->toInt());
    Value::deleteIfPossible(fv);
    delete $2;
}
;






/*			Initialization of state variables */
init_declaration : ALTARICA_INIT init_assignment_list
{
    $$ = $2;
}
| ALTARICA_INIT init_assignment_list ALTARICA_SEMICOLON
{
    $$ = $2;
}
;

init_assignment_list : init_assignment_list ALTARICA_COMMA init_assignment
{
    $$ = $1;
    $$->push_back($3);
}
| init_assignment
{
    $$ = new std::vector<Assignment*>();
    $$->push_back($1);    
}
;

init_assignment : assignment 
{
    $$ = $1;
};



/*			Parameter settings */
parameter_set_declaration : ALTARICA_PARAM_SET param_assignment_list
{
    $$ = $2;
}
| ALTARICA_PARAM_SET param_assignment_list ALTARICA_SEMICOLON
{
    $$ = $2;
}
;

param_assignment_list : param_assignment_list ALTARICA_COMMA param_assignment
{
    $$ = $1;
    $$->push_back($3);
}
| param_assignment
{
    $$ = new std::vector<Assignment*>();
    $$->push_back($1);
}
;

param_assignment : assignment 
{
    $$  = $1;
};

/*			External directives */
external_directives_declaration : ALTARICA_EXTERN external_directives 
{
    $$ = $2;
}
;

external_directives : external_directives external_directive
{
    if ($1 == NULL) {
	$$ = $2;
    }
    else {
	$$ = $1;
	if ($2 != NULL) {
	    for (std::vector<EventLaw*>::iterator i = $2->begin(); i != $2->end(); ++i)
		$$->push_back(*i);
	    delete($2);
	}
    }
}
| external_directive
{
    $$ = $1;
}
;

external_directive : law_decl ALTARICA_SEMICOLON
{
    $$ = $1;
}
|
extern_ccf ALTARICA_SEMICOLON
{
    $$ = NULL;
}
|
extern_with_ccf ALTARICA_SEMICOLON
{
    $$ = NULL;
}
|
extern_nodeproperty ALTARICA_SEMICOLON
{
    $$ = NULL;
}
|extern_remark 
{
    $$ = NULL;
}
|extern_attribute  
{
    $$ = NULL;
}
;

extern_remark : ALTARICA_REMARK ALTARICA_INF ALTARICA_EVENT ALTARICA_IDENTIFIER ALTARICA_SUP ALTARICA_EQUAL ALTARICA_STRING ALTARICA_SEMICOLON 
{
    delete $4;
};

extern_attribute : ALTARICA_ATTRIBUTE ALTARICA_IDENTIFIER ALTARICA_OPAREN ALTARICA_INF ALTARICA_EVENT ALTARICA_IDENTIFIER ALTARICA_SUP ALTARICA_CPAREN ALTARICA_EQUAL ALTARICA_STRING ALTARICA_SEMICOLON
{
    delete $2;
    delete $6;
};

extern_nodeproperty : ALTARICA_NODEPROPERTY ALTARICA_INF extern_property ALTARICA_SUP ALTARICA_EQUAL  ALTARICA_STRING ;

extern_property : ALTARICA_GLOBAL ALTARICA_IDENTIFIER
{
    delete $2;
};

extern_ccf : ALTARICA_CCF events_name_law ALTARICA_EQUAL boolean_constant
{
    for (std::vector<MemberAccess*>::iterator i = $2->begin(); i!= $2->end(); ++i)
	delete *i;
    delete $2;
    delete $4;
}
;

extern_with_ccf : ALTARICA_WITHCCF events_name_law  ALTARICA_EQUAL ALTARICA_LEFTEMBRACE events_name_law ALTARICA_RIGHTEMBRACE{
    for (std::vector<MemberAccess*>::iterator i = $2->begin(); i!= $2->end(); ++i)
	delete *i;
    delete $2;
    for (std::vector<MemberAccess*>::iterator i = $5->begin(); i!= $5->end(); ++i)
	delete *i;
    delete $5;
}
;



law_decl : ALTARICA_LAW events_name_law ALTARICA_EQUAL law
{
    $$ = new std::vector<EventLaw*>();
    for (std::vector<MemberAccess*>::iterator i = $2->begin(); i!= $2->end(); ++i) {
	EventLaw *nel = $4->clone();
	nel->setMA(*i);
	$$->push_back(nel);
    }
    delete $2;
    delete $4;
}
;

events_name_law : ALTARICA_INF ALTARICA_EVENT event_name_law ALTARICA_SUP
{
    $$ = new std::vector<MemberAccess*>();
    $$->push_back($3);
}
|
ALTARICA_LEFTEMBRACE events_name_law_set ALTARICA_RIGHTEMBRACE
{
    $$ = $2;
}
;

events_name_law_set : events_name_law_set ALTARICA_COMMA events_name_law
{
    for (std::vector<MemberAccess*>::iterator i = $3->begin();
	 i!= $3->end(); ++i)
	$1->push_back(*i);
    $$ = $1;
    delete $3;
}
|
events_name_law
{
    $$ = $1;
}
;

event_name_law: identifier_path
{
    $$ = $1;
};

law : law_type ALTARICA_OPAREN law_param ALTARICA_CPAREN
{
    $$ = new EventLaw($1,$3);
}
/* |
law_type ALTARICA_OPAREN scalar_domain ALTARICA_CPAREN
{
    $$ = new EventLaw($1,ValueReal((RealDomain*)$3));
} */
|
law_type ALTARICA_OPAREN law_param ALTARICA_COMMA law_param ALTARICA_CPAREN
{
    $$ = new EventLaw($1,$3,$5);
}
;

/* law_param_list : law_param_list ALTARICA_COMMA law_param */
/* | */
/* law_param */
/* ; */

/* law_param : ALTARICA_FLOAT */
/* { */
/*     $$ = $1; */
/* } */
/* | ALTARICA_UNSIGNED_INTEGER */
/* { */
/*     $$ = (double) $1; */
/* } */
/* ; */

law_param : expression
{
    $$ = $1;
};
//| scalar_domain // This is for timed guards
//{
//    $$ = $1;
//};

law_type : ALTARICA_LAW_DIRAC
{
    $$ = ALTARICA_DIRAC_0;
}
|
ALTARICA_LAW_EXP
{
    $$ = ALTARICA_EXP;
}
|
ALTARICA_LAW_DISCRETE
{
    $$ = ALTARICA_DISCRETE;
}
|
ALTARICA_LAW_TIMED
{
    $$ = ALTARICA_TIMED;
};

/* AltaRica expressions */
expression : if_then_else_expr
{
    $$ =$1;
}
| case_expr
{
    $$ = $1;
}
| disjunctive_expr
{
    $$ = $1;
}
;



if_then_else_expr : 
ALTARICA_IF expression ALTARICA_THEN expression ALTARICA_ELSE expression
{
    $$ = new ExpressionIfThenElse($2,$4,$6);
}
| ALTARICA_OPAREN expression ALTARICA_IMARK expression ALTARICA_COLON expression ALTARICA_CPAREN
{
    $$ = new ExpressionIfThenElse($2,$4,$6);    
}
;


case_expr : ALTARICA_CASE ALTARICA_LEFTEMBRACE case_choice_list ALTARICA_RIGHTEMBRACE 
{
    $$ = $3;
};


case_choice_list : case_conditional_choice_list ALTARICA_COMMA case_default
{
    $$ = new ExpressionCASE();
    for (std::vector<exprPair*>::iterator i = $1->begin(); i != $1->end(); ++i) {
	$$->addCase((*i)->first, (*i)->second);
	delete *i;
    }
    delete $1;
    $$->addElse($3);
}
| case_default
{
    $$ =  new ExpressionCASE();
    $$->addElse($1);
}
;



case_conditional_choice_list : case_conditional_choice_list ALTARICA_COMMA case_conditional_choice
{
    $$ = $1;
    $$->push_back($3);
}
| case_conditional_choice
{
    $$ = new std::vector<exprPair*>();
    $$->push_back($1);
}
;


case_default : ALTARICA_ELSE expression 
{
    $$ = $2;
}
;


case_conditional_choice : boolean_expr ALTARICA_COLON expression 
{
    $$ = new exprPair();
    $$->first = $1;
    $$->second = $3;
}
;


boolean_expr : expression 
{
    $$ = $1;
}
;


disjunctive_expr : disjunctive_expr ALTARICA_OR conjunctive_expr
{
    $$ = new ExpressionOR($1,$3);
}
| disjunctive_expr ALTARICA_LOR conjunctive_expr
{
    $$ = new ExpressionOR($1,$3);
}
| conjunctive_expr
{
    $$  = $1;
}
;


conjunctive_expr : conjunctive_expr ALTARICA_AND logical_comparison_expr
{
    $$ = new ExpressionAND($1,$3);
}
| conjunctive_expr ALTARICA_LAND logical_comparison_expr
{
    $$ = new ExpressionAND($1,$3);
}
| logical_comparison_expr
{
    $$ = $1;
}
;



logical_comparison_expr : logical_comparison_expr ALTARICA_EQUAL arithmetic_comparison_expr
{
    $$ = new ExpressionLOG($1,$3);
    $$->setEquals();
}
|
logical_comparison_expr ALTARICA_EQUAL case_expr
{
    $$ = new ExpressionLOG($1,new ExpressionPAREN($3));
    $$->setEquals();
}
| logical_comparison_expr ALTARICA_DIF arithmetic_comparison_expr
{
    $$ = new ExpressionLOG($1,$3);
    $$->setNotEquals();
}
| logical_comparison_expr ALTARICA_CARD arithmetic_comparison_expr
{
    $$ = new ExpressionLOG($1,$3);
    $$->setNotEquals();
}
| logical_comparison_expr ALTARICA_IMPLIES arithmetic_comparison_expr
{
    $$ = new ExpressionLOG($1,$3);
    $$->setImplies();
}
| arithmetic_comparison_expr
{
    $$ = $1;
}
;



arithmetic_comparison_expr : 
arithmetic_comparison_expr ALTARICA_INF additive_expr
{
    $$ = new ExpressionARITH($1,$3);
    $$->setInf();
}
| arithmetic_comparison_expr ALTARICA_SUP additive_expr
{
    $$ = new ExpressionARITH($1,$3);
    $$->setSup();
}
| arithmetic_comparison_expr ALTARICA_INFEQ additive_expr
{
    $$ = new ExpressionARITH($1,$3);
    $$->setInfEq();
}
| arithmetic_comparison_expr ALTARICA_SUPEQ additive_expr
{
    $$ = new ExpressionARITH($1,$3);
    $$->setSupEq();
}
| additive_expr
{
    $$ = $1;
}
;




additive_expr : additive_expr ALTARICA_PLUS multiplicative_expr
{
    $$ = new ExpressionADD($1,$3);
    $$->setPlus();
}
| additive_expr ALTARICA_MINUS multiplicative_expr
{
    $$ = new ExpressionADD($1,$3);
    $$->setMinus();
}
| multiplicative_expr
{
    $$  = $1;
}
;


multiplicative_expr : multiplicative_expr ALTARICA_STAR unary_expr
{
    $$ = new ExpressionMUL($1,$3);
    $$->setTimes();
}
| multiplicative_expr ALTARICA_DIV unary_expr
{
    $$ = new ExpressionMUL($1,$3);
    $$->setDiv();
}
| multiplicative_expr ALTARICA_MOD unary_expr
{
    $$= new ExpressionMUL($1,$3);
    $$->setMod();
}		    
| unary_expr
{
    $$ = $1;
}
;



unary_expr : ALTARICA_MINUS unary_expr
{
    $$ = new ExpressionUNARY($2);
    $$->setMinus();
}
| ALTARICA_TILDE unary_expr
{
    $$ = new ExpressionUNARY($2);
    $$->setCompl();
}
| ALTARICA_NOT unary_expr
{
    $$ = new ExpressionUNARY($2);
    $$->setNot();
}
| atomic_expr
{
    $$ = $1;
}
;


atomic_expr : 
parenthezed_expr
{
    $$ =  new ExpressionPAREN($1);    
}
| member_access
{
    $$ = new ExpressionMEMBER($1);
}
| min_max_expr
{
    $$ = $1;
}
| card_expr
{
    $$ = $1;
}
| unsigned_integer
{
    $$ = $1;
}
| real
{
    $$ = $1;  
}
| boolean_constant
{
    $$ = $1;
}
| quantified_expr
{
    $$ = $1;
}
| function_call_expr
{
    $$ = $1;
}
| constant_structure
{
    $$ = $1;
}
| constant_array
{
    $$ = $1;
}
;



parenthezed_expr : ALTARICA_OPAREN expression ALTARICA_CPAREN 
{
    $$ = new ExpressionPAREN($2);
};


member_access : struct_member
{
    $$ = $1;
}
| array_member
{
    $$ = $1;
}
| ALTARICA_IDENTIFIER
{
    $$ = new MemberAccess(*$1);
    delete $1;
}
;



struct_member : member_access ALTARICA_DOT ALTARICA_IDENTIFIER
{
    $$ = $1;
    $1->addIdBack(*$3);
    delete $3;
}
;


array_member : member_access ALTARICA_LEFTBRACKET numerical_constant_expression ALTARICA_RIGHTBRACKET 
{
    $$ = $1;
    Value *fv = $3->evaluate(NULL,NULL,NULL);
    $$->addIndexBack(fv->toInt());
    Value::deleteIfPossible(fv);
    delete $3;
};


min_max_expr : ALTARICA_MIN ALTARICA_OPAREN comma_separated_expr_list ALTARICA_CPAREN
{
    $$ = new ExpressionMINMAX(false);
    for (std::vector<Expression* > ::iterator i = $3->begin();
	 i != $3->end(); ++i)
	$$->addExpr(*i);
    delete($3);
}
| ALTARICA_MAX ALTARICA_OPAREN comma_separated_expr_list ALTARICA_CPAREN
{
    $$ = new ExpressionMINMAX(true);
    for (std::vector<Expression* > ::iterator i = $3->begin();
	 i != $3->end(); ++i)
	$$->addExpr(*i);    
    delete $3;
}
;


card_expr : ALTARICA_CARD ALTARICA_OPAREN comma_separated_expr_list ALTARICA_CPAREN
{
    $$ = new ExpressionCARD();
    for (std::vector<Expression* > ::iterator i = $3->begin();
	 i != $3->end(); ++i)
	$$->addExpr(*i);    
    delete($3);
}
;


comma_separated_expr_list : comma_separated_expr_list ALTARICA_COMMA expression
{
    $$ = $1;    
    $$->push_back($3);
}
| expression
{
    $$ = new std::vector<Expression*>();
    $$->push_back($1);
}
;


boolean_constant : ALTARICA_TRUE
{
    $$ = new ExpressionBOOLCONSTANT(true);
}
| ALTARICA_FALSE
{
    $$ = new ExpressionBOOLCONSTANT(false);
}
;


unsigned_integer : ALTARICA_UNSIGNED_INTEGER 
{
    $$ = new ExpressionUNSIGNEDINT($1);
}
;

real : ALTARICA_FLOAT
{
    $$ = new ExpressionREAL($1);
}
;


quantified_expr : ALTARICA_INF quantified_variables_decl ALTARICA_SUP unary_expr
{
    $$ = new ExpressionQUANTIFIED(false);
    $$->setExpr($4);
    for (std::vector<VarD*>::iterator i = $2->begin();
	 i != $2->end(); ++i)	
	$$->addVar((*i)->name, (*i)->d);
}
| ALTARICA_LEFTBRACKET quantified_variables_decl ALTARICA_RIGHTBRACKET unary_expr
{
    $$ = new ExpressionQUANTIFIED(true);
    $$->setExpr($4);
    for (std::vector<VarD*>::iterator i = $2->begin();
	 i != $2->end(); ++i)	
	$$->addVar((*i)->name, (*i)->d);    
}
;


quantified_variables_decl : quantified_variables_decl_list 
{
    $$ = $1;
}
| quantified_variables_decl_list ALTARICA_SEMICOLON
{
    $$ = $1;
}
;

quantified_variables_decl_list : quantified_variables_decl_list ALTARICA_SEMICOLON quantified_variables
{
    $$ = $1;
    for (std::vector<VarD*>::iterator i = $3->begin();
	 i!= $3->end(); ++i)
	$$->push_back(*i);
    
}
| quantified_variables
{
    $$  =$1;
}
;

quantified_variables : id_list ALTARICA_COLON domain 
{
    $$ = new std::vector<VarD*>();
    for (std::vector<std::string>::iterator i = $1->begin(); i!= $1->end(); ++i) {
	VarD * nv = new VarD();
	nv->name = *i;
	nv->d = $3;
	$$->push_back(nv);	      
    }
    delete $1;
};

function_call_expr : ALTARICA_IDENTIFIER ALTARICA_OPAREN function_parameters ALTARICA_CPAREN
{
    $$ = new ExpressionFUNCTIONCALL(*$1);
    delete $1;
    for (std::vector<Expression*>::iterator i= $3->begin(); i!= $3->end(); ++i)
	$$->addArg(*i);
}
| ALTARICA_IDENTIFIER ALTARICA_OPAREN ALTARICA_CPAREN
{
    $$ = new ExpressionFUNCTIONCALL(*$1);
    delete $1;
}
;


function_parameters : comma_separated_expr_list 
{
    $$ = $1;
};

constant_structure : ALTARICA_LEFTEMBRACE constant_field_assignment_list ALTARICA_RIGHTEMBRACE 
{
    $$ = $2;
};


constant_field_assignment_list : constant_field_assignment_list ALTARICA_COMMA constant_field_assignment
{
    $$ = $1;
    $$->mergeAssigns($3);
    delete($3);
}
| constant_field_assignment
{
    $$ = $1;
}
;


constant_field_assignment : ALTARICA_DOT ALTARICA_IDENTIFIER ALTARICA_EQUAL constant_expression 
{
    $$ = new ExpressionCONSTSTRUCT();
    $$->addAssign(*$2, $4);
    delete $2;
};


constant_array : ALTARICA_LEFTEMBRACE constant_expression_list ALTARICA_RIGHTEMBRACE 
{
    $$ = $2;
};


constant_expression_list : constant_expression_list ALTARICA_COMMA constant_expression
{
    $$ = $1;
    $$->addConst($3);
}
| constant_expression
{
    $$ = new ExpressionCONSTARRAY();
    $$->addConst($1);
}
;


/* Abstract type definitions */
sort_declaration : ALTARICA_SORT id_list
{
    delete $2;
}
;

signature_declaration : ALTARICA_SIG operator_name ALTARICA_COLON cartesian_product ALTARICA_TO domain ;

operator_name : ALTARICA_IDENTIFIER 
{
    delete $1;
};

cartesian_product : cartesian_product_list
| /* empty */
;

cartesian_product_list : cartesian_product_list ALTARICA_STAR domain
| domain
;
%%
