// \file

%{
    // -*- Mode : c++ -*-
    //
    // SUMMARY  :
    // USAGE    :
    // ORG      :
    // AUTHOR   : Frederic Hecht
    // E-MAIL   : hecht@ann.jussieu.fr
    //

    /*

     This file is part of Freefem++

     Freefem++ is free software; you can redistribute it and/or modify
     it under the terms of the GNU Lesser General Public License as published by
     the Free Software Foundation; either version 2.1 of the License, or
     (at your option) any later version.

     Freefem++  is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU Lesser General Public License for more details.

     You should have received a copy of the GNU Lesser General Public License
     along with Freefem++; if not, write to the Free Software
     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     */
/*
  bug of clang if optimisation !!!!!
*/
#ifdef   __clang__
#pragma clang optimize off
#endif

#include <config.h>
#include <iostream>
#include  <complex>
#include <string>
  // for reset cout,cin  in windows  dll
#ifdef _WIN32
#include <ext/stdio_filebuf.h>
#include <iostream>
#include <cstdio>
#endif

#include "error.hpp"
class Iden;
#include "strversionnumber.hpp"
#include "InitFunct.hpp"
#ifdef __MWERKS__
#ifdef __INTEL__
#include <malloc.h>
#else
#include <alloca.h>
#endif
#endif
#include "RNM.hpp"

#include "AFunction.hpp"
//  to reserve space to graphical pointer function
#include "rgraph.hpp"
#include "fem.hpp"
#include "FESpacen.hpp"
#include "FESpace.hpp"
#include "MeshPoint.hpp"

#include "lgfem.hpp"
#include "lex.hpp"
#include "environment.hpp"
extern long storageused();
    extern FILE *ThePlotStream;
    extern KN<String> *pkarg;

class Routine;
bool load(string s);

 template <class R,int d> class FE;
 template <class R,int d,int i> class FE_;

extern mylex *zzzfff;
// modif FH for window to have 1 dll  for mpi and none mpi ..
extern  void (*initparallele)(int &, char **&);
extern  void (*init_lgparallele)();
// extern  void (*end_parallele)();
//
#ifdef HAVE_LIBARPACK
  void init_eigenvalue();
#endif

  aType dcltype;
const int nbembtype=10;
aType rettype[nbembtype];
Block * routineinblock[nbembtype]; // Add FH july 2005 pb clean on return
int kkembtype=-1;
int inloopcount=0;

/// <<currentblock>> Block class from [[file:../fflib/AFunction.hpp::Block]]

Block *currentblock;

// Add FH july 2005
//  problem clean variable after break,continue and return.
const int sizeStackOfLoop=100;
Block * StackOfLoop[sizeStackOfLoop];
// end ADD
double CPUcompileInit =0;
//class pfes;
C_F0  fespacetype;
bool fespacecomplex;
int fespacedim;
extern int UnShowAlloc;
int ShowAlloc(const char *s,size_t &);
// <<yylex>> Connection from grammar to lexer object zzzfff [[file:../fflib/lex.hpp::zzzfff]] of class mylex
// [[file:../fflib/lex.hpp::class mylex]]. Method mylex::scan() is implemented at [[file:../fflib/lex.cpp::mylex_scan]]


inline int yylex()  {return zzzfff->scan();}
inline int lineno() {return zzzfff->lineno();}

extern bool withrgraphique;

/// <<fingraphique>>

inline void fingraphique()
 { if(withrgraphique)
   { withrgraphique=false;
    rattente(1);
    closegraphique();
  }}

void lgerror (const char* s) ;


 // mpi ptr to function ...
void (*initparallele)(int &argc, char **& argv)=0 ;
void (*init_lgparallele)()=0;
//void (*end_parallele)()=0;

// Add dec 2014
#include <vector>
typedef void (*AtEnd)();
vector<AtEnd> AtFFEnd;
void ff_finalize()
{
    for (vector<AtEnd>::const_reverse_iterator i=AtFFEnd.rbegin(); i !=AtFFEnd.rend(); ++ i)
    (**i)();
    AtFFEnd.clear();
}
void ff_atend(AtEnd f)
{
    AtFFEnd.push_back(f);
}

#include <csignal>
void signalCPUHandler( int signum ) {
    ff_finalize();
    std::cout << "Cputime limit exceeded:  (" << signum << ") received.\n";
    
    exit(24);
}

%}


/* <<YYSTYPE>> definition. <<yylval>> is renamed <<lglval>> by bison at [[file:lg.tab.cpp::lglval]]. It is allocated in
 lg.tab.o */
%union{
 double dnum;

 /* <<YYSTYPE_lnum>> */
 long   lnum;// to read long long number !!!! FH dec 2022

 /* <<YYSTYPE_str>> */
 char * str;
 char oper[8];

 /* <<YYSTYPE_cexp>> [[file:../fflib/AFunction.hpp::CC_F0]] */
 CC_F0 cexp;

 Routine   *routine;

 /* <<YYSTYPE_args>> [[file:~/ff/src/fflib/AFunction.hpp::AC_F0]] */
 AC_F0 args;

 /* <<YYSTYPE_type>> refers to [[file:~/ff/src/fflib/AnyType.hpp::aType]] */
 aType type;

 /* <<YYSTYPE_cinst>> refers to [[file:~/ff/src/fflib/AFunction.hpp::CListOfInst]] */
 CListOfInst cinst;

 Block * block;

 /* <<YYSTYPE_clist_id>> [[file:~/ff/src/fflib/AFunction.hpp::ListOfId]] */
 ListOfId *clist_id;

/* ListCatch * clist_Catchs;*/

 vectorOfInst * endb;
}

/* BISON Declarations */

%type <cinst>   input
%type <cinst>   instructions
%type <cexp>   instruction
%type  <cexp>  try
%type  <cexp>  catchs
/* %type  <cexp>  throw */
%type <cexp>  declaration
%type <cexp>  declaration_for
%type <cexp>  list_of_dcls
%type <cexp>  fespace_def
%type <cexp>  fespace_def_list
%type <cexp>   Expr
%type <cexp>   no_comma_expr
%type <cexp>   sub_script_expr
%type <cexp>   no_ternary_expr
%type <cexp>   no_set_expr
%type <cexp>   unary_expr
%type <cexp>   pow_expr
%type <cexp>   primaryp
%type <cexp>   primary
%type <oper>   unop
%type <args>  parameters
%type <args>  parameterstype
%type <args>  array
%type <args>  FEarray
%type <args>  parameters_list
%type  <cexp> begin
%type  <endb> end
%type  <clist_id> list_of_id_args
%type  <clist_id> list_of_id1
%type <cexp>  spaceIDs
%type <cexp>  spaceIDa
%type <cexp>  spaceIDb
%type <cexp> ID_space
%type <cexp>  ID_array_space
%type <args> bornes;
%type <args>   border_expr;
%type <type>   type_of_dcl;
%type <str> id;
%type <str> fespace123;
%type <clist_id> IDfor

/* Add precedence rules to solve dangling else s/r conflict */

%nonassoc IF
%nonassoc ELSE

%left <oper> ','
%right <oper> '=' SET
%left  <oper> LTLT GTGT
%left  <oper> OR '|'
%left  <oper> AND '&'
%left  <oper> EQ NE
%left  <oper>  '<' '>' LE GE
%left  <oper>  '+' '-'
%left  <oper> '*' '/'  '%' DOTSTAR DOTSLASH
%right <oper> UNARY PLUSPLUS MOINSMOINS '!'
%right <oper>  '^' '\''
%right <oper>  '_'
%left  <oper>  '(' '[' '.'

%token <oper> ')'  ']'

/* <<LNUM>> */
%token <lnum> LNUM
%token <dnum> DNUM
%token <dnum> CNUM

/* <<ID>> produced by [[file:../fflib/lex.cpp::mylex_scan]] */
%token <str> ID

%token <str> FESPACEID
%token <str> IDPARAM
%token <str> STRING

%token ENDOFFILE
%token INCLUDE
%token LOAD
%token BIDON

%token FOR
%token WHILE
%token IF
%token ELSE
%token BREAK
%token CONTINUE
%token RETURN
%token TRY
%token CATCH
%token THROW

/* <<TYPE>> */
%token <type> TYPE

%token <type> FUNCTION

/* <<FESPACE>> used by [[file:../fflib/lex.cpp::mylex_scan]] */
%token <str> FESPACE
%token <str> FESPACE1
%token <str> FESPACE3
%token <str> FESPACES
%token <str> FESPACEL
%token <str> VGFESPACE
%token <str> GFESPACE /* A supprimer*/

%token DOTSTAR
%token DOTSLASH
%token AND
%token OR
%token EQ
%token NE
%token LE
%token GE
%token PLUSPLUS
%token MOINSMOINS
%token SET

/* <<LTLT>> */
%token LTLT

%token PLUSEQ
%token MOINSEQ
%token MULEQ
%token DIVEQ
%token DOTMULEQ
%token DOTDIVEQ
%token GTGT
%token ARROW
%token BORDER
%token SOLVE

%%

start:   input ENDOFFILE {
                        if(  ffapi::ff_justcompile) exit(0);
    // clean FH  mach 2014
		        const char *  magicffglut="#!ffglutdata4.1\n";// for complex and vector 3d plot
			//FFCS: divert stream to FFCS
                        if(ThePlotStream) ffapi::fwriteinit(magicffglut,strlen(magicffglut),1,ThePlotStream);

                        // <<sizestack_set>>
                        size_t sizestack = currentblock->size()+1024 ; //  before close

                        // <<close_final_block>>
                       // $1+=currentblock->close(currentblock);
                       $1.setclose(Block::snewclose(currentblock));// Sep 2016 FH
                        if(verbosity>2 || ( (mpirank==0) && verbosity)) cout << " sizestack + 1024 =" << sizestack << "  ( " << sizestack-1024 <<" )\n" ;
                        size_t lg0,lg1;
                        ffapi::ifchtmpdir(); // change  to tmp after compile FH sep 2015 ...
                        int NbPtr = ShowAlloc("init execution ",lg0); // number of un delele ptr
                        debugstack= new vector<pair<const E_Routine*,int> >;
                        size_t stu0=storageused(); // get Storage usage
			UnShowAlloc =0;// add FH for parallee
                        if(verbosity>2  || ( (mpirank==0) && verbosity) ) cout << endl;
                        {

                            // <<create_global_FF_stack>> calls [[file:../fflib/ffstack.hpp::newStack]]

                            Stack stack = newStack(sizestack);

                        double CPUcompile= CPUtime();
                        try {

                          // <<evaluate_parsed_FF_script>> calls [[file:../fflib/AFunction.hpp::CListOfInst::eval]]
                          $1.eval(stack);
                        }
                        catch ( E_exception & e)  {
                          cerr << e.what() << " ,  mpirank " << mpirank << endl;
                          return 1; }
                        catch( Error & err) {
                          cerr << err.what() << endl;
			  cerr << " err code " << err.errcode() << " ,  mpirank " << mpirank << endl;
                          return err.errcode();
                        }
                         catch( ...) { cerr << "Strange catch exception ???\n";
                          cerr << " at exec line  " << TheCurrentLine << " ,  mpirank " << mpirank << endl;
                          return 1;
                         }

                        if(verbosity)  cout << "times: compile "<< CPUcompile-CPUcompileInit <<"s, execution "
			    <<  CPUtime()-CPUcompile  <<"s,  mpirank:" << mpirank << endl;


                        // <<delete_global_FF_stack>>

                        deleteStack(stack);

                        //debugstack.clear()
                        }
                        fingraphique();
			//FFCS: divert stream to FFCS
			if(ThePlotStream) {ffapi::ff_pclose(ThePlotStream); ThePlotStream=0;}
			UnShowAlloc =1;
                        if(debugstack) delete debugstack;
                        NbPtr = ShowAlloc("end execution -- ",lg1) - NbPtr;
                        long stu1 =storageused()-stu0    ;


			    if (verbosity && (NbPtr || (stu1>100000) )) { cout << " ######## unfreed pointers   " << NbPtr
			                      << " Nb pointer,   " <<  lg1-lg0 << "Bytes " << " ,  mpirank " << mpirank << ", memory leak ="<< stu1 <<  endl;}
  return 0;}
;

input:   instructions /*[[instructions:]]*/
;

instructions: /* returns a [[YYSTYPE_cinst]] */
          instruction /* [[instruction:]] returns a [[YYSTYPE_cexp]] */   {$$ = $1;}
        | instructions  instruction                                       {$$ = ($1+=$2);}
        ;

/* List of function arguments used in [[declaration:]] */

list_of_id_args: /* returns [[YYSTYPE_clist_id]] */
                                               { $$ = new ListOfId();}
  | id                                         { $$ = new ListOfId(); $$->push_back(UnId($1));}
  | id '=' no_comma_expr                       { $$ = new ListOfId(); $$->push_back(UnId($1,$3));}
  | FESPACE id                                 { $$ = new ListOfId(); $$->push_back(UnId($2,Find($1),atype<FE<double,2> **>()));}
  | FESPACE '&' id                             { $$ = new ListOfId(); $$->push_back(UnId($3,Find($1),atype<FE<double,2> **>(),true));}
  | FESPACE3 id                                { $$ = new ListOfId(); $$->push_back(UnId($2,Find($1),atype<FE<double,3> **>()));}
  | FESPACE3 '&' id                            { $$ = new ListOfId(); $$->push_back(UnId($3,Find($1),atype<FE<double,3> **>(),true));}
  | FESPACES id                                { $$ = new ListOfId(); $$->push_back(UnId($2,Find($1),atype<FE<double,4> **>()));}
  | FESPACES '&' id                            { $$ = new ListOfId(); $$->push_back(UnId($3,Find($1),atype<FE<double,4> **>(),true));}
  | FESPACEL id                                { $$ = new ListOfId(); $$->push_back(UnId($2,Find($1),atype<FE<double,5> **>()));}
  | FESPACEL '&' id                            { $$ = new ListOfId(); $$->push_back(UnId($3,Find($1),atype<FE<double,5> **>(),true));}
  | type_of_dcl id                             { $$ = new ListOfId(); $$->push_back(UnId($2,C_F0(),$1->right()));}
  | type_of_dcl '&' id                         { $$ = new ListOfId(); $$->push_back(UnId($3,C_F0(),$1,true));}
  | '[' list_of_id_args ']'                    { $$ = new ListOfId(); $$->push_back(UnId($2));}
  | '<' '[' list_of_id_args ']' '>'            { $$ = new ListOfId(); $$->push_back(UnId($3,true,true));} /* chevron problem */
  | '<' '[' list_of_id_args ']'                { $$ = new ListOfId(); $$->push_back(UnId($3,true,false));} /* chevron problem */
  | list_of_id_args ',' id                     { $$ = $1; $$->push_back(UnId($3));}
  | list_of_id_args ',' '[' list_of_id_args ']' { $$ = $1; $$->push_back(UnId($4));}
  | list_of_id_args ',' '[' list_of_id_args ']' '>' { $$ = $1; $$->push_back(UnId($4,false,true));} /* chevron problem */
  | list_of_id_args ',' '<' '[' list_of_id_args ']' '>' { $$ = $1; $$->push_back(UnId($5,true,true));} /* chevron problem */
  | list_of_id_args ',' '<' '[' list_of_id_args ']'  { $$ = $1; $$->push_back(UnId($5,true,false));} /* chevron problem */
  | list_of_id_args ',' id '=' no_comma_expr   { $$ = $1; $$->push_back(UnId($3,$5));}
  | list_of_id_args ',' FESPACE id             { $$ = $1; $$->push_back(UnId($4,Find($3),atype<FE<double,2> **>()));}
  | list_of_id_args ',' FESPACE '&' id         { $$ = $1; $$->push_back(UnId($5,Find($3),atype<FE<double,2> **>(),true));}
  | list_of_id_args ',' FESPACE3 id            { $$ = $1; $$->push_back(UnId($4,Find($3),atype<FE<double,3> **>()));}
  | list_of_id_args ',' FESPACE3 '&' id        { $$ = $1; $$->push_back(UnId($5,Find($3),atype<FE<double,3> **>(),true));}
  | list_of_id_args ',' FESPACES id            { $$ = $1; $$->push_back(UnId($4,Find($3),atype<FE<double,4> **>()));}
  | list_of_id_args ',' FESPACES '&' id        { $$ = $1; $$->push_back(UnId($5,Find($3),atype<FE<double,4> **>(),true));}
  | list_of_id_args ',' FESPACEL id            { $$ = $1; $$->push_back(UnId($4,Find($3),atype<FE<double,5> **>()));}
  | list_of_id_args ',' FESPACEL '&' id        { $$ = $1; $$->push_back(UnId($5,Find($3),atype<FE<double,5> **>(),true));}
  | list_of_id_args ',' type_of_dcl id         { $$ = $1; $$->push_back(UnId($4,C_F0(),$3->right()));}
  | list_of_id_args ',' type_of_dcl '&' id     { $$ = $1; $$->push_back(UnId($5,C_F0(),$3,true));}
  ;

list_of_id1:  id                      { $$ = new ListOfId(); $$->push_back(UnId($1));}
            | list_of_id1 ',' id      { $$=$1  ; $$->push_back(UnId($3));}
;

/* <<id>> (anchor required because 'id:' is another type of hyperlink) */

id: ID | FESPACE|FESPACE3|FESPACES|FESPACEL|FESPACE1;

list_of_dcls:
      id                            {$$=currentblock->NewVar<LocalVariable>($1,dcltype);}
    | id '='   no_comma_expr        {$$=currentblock->NewVar<LocalVariable>($1,dcltype,$3);}
    | id  '(' parameters_list ')'   {$$=currentblock->NewVar<LocalVariable>($1,dcltype,$3);$3.destroy();}
    | list_of_dcls ',' list_of_dcls {$$=C_F0($1,$3);}
    ;

/* used by [[list_of_dcls:]] and [[fespace_def:]] */

parameters_list:
	  no_set_expr  /*[[no_set_expr:]]*/      { $$=$1;}
	| FESPACE  id                            { $$=Find($1);}
	| FESPACE1  id                           { $$=Find($1);}
	| FESPACE3  id                           { $$=Find($1);}
  | FESPACES  id                           { $$=Find($1);}
  | FESPACEL  id                           { $$=Find($1);}
  | FESPACE                                { $$=Find($1);}
  | FESPACE1                               { $$=Find($1);}
  | FESPACE3                               { $$=Find($1);}
  | FESPACES                               { $$=Find($1);}
  | FESPACEL                               { $$=Find($1);}
	| id '=' no_set_expr                     { $$=make_pair<const char *,const C_F0>((const char *) $1,(C_F0) $3);}
	| parameters_list ',' parameters_list    { $$ = ($1 += $3);}
	/* | parameters_list ',' id '=' no_set_expr { $$= ($1+= make_pair<const char *,const C_F0>((const char *) $3,(C_F0) $5));} */
    ;


type_of_dcl:   TYPE
    | TYPE '[' TYPE ']'                       {$$=TypeArray($1,$3);}
    | TYPE '[' TYPE ']' '[' TYPE ']'          {$$=TypeArray(TypeArray($1,$3),$6);} // Add FH mars 2012
    | TYPE '[' TYPE ',' TYPE ']'              {$$=TypeArray($1,$3,$5);}
    | TYPE '[' TYPE ',' TYPE ']' '[' TYPE ']' {$$=TypeArray(TypeArray($1,$3,$5),$8);}
    | TYPE '<' TYPE '>'                       {$$=TypeTemplate($1,$3);}
    | TYPE '<' TYPE '>' '[' TYPE ']'          {$$=TypeArray(TypeTemplate($1,$3),$6);}
    | TYPE '<' TYPE '>' '[' TYPE ',' TYPE ']' {$$=TypeArray(TypeTemplate($1,$3),$6,$8);}
    ;

ID_space:
      id                                      { $$ =  NewFEvariable($1,currentblock,fespacetype,fespacecomplex,fespacedim); }
    | id '[' no_set_expr ']'                  { $$ =  NewFEarray($1,currentblock,fespacetype,$3,fespacecomplex,fespacedim); }
    | id '=' no_set_expr                      { $$ =  NewFEvariable($1,currentblock,fespacetype,$3,fespacecomplex,fespacedim);}
    | '[' list_of_id1 ']'                     { $$ =  NewFEvariable($2,currentblock,fespacetype,fespacecomplex,fespacedim);}
    | '[' list_of_id1 ']' '[' no_set_expr ']' { $$ =  NewFEarray($2,currentblock,fespacetype,$5,fespacecomplex,fespacedim);}
    | '[' list_of_id1 ']' '=' no_set_expr     { $$ =  NewFEvariable($2,currentblock,fespacetype,$5,fespacecomplex,fespacedim);}
    ;

ID_array_space:
 id '(' no_set_expr ')'              { $$ =  NewFEarray($1,currentblock,fespacetype,$3,fespacecomplex,fespacedim); }
  |  '[' list_of_id1 ']' '(' no_set_expr ')'  { $$ =  NewFEarray($2,currentblock,fespacetype,$5,fespacecomplex,fespacedim);}

;

fespace123:
      FESPACE { fespacedim=2;}
    | FESPACE1 { fespacedim=1;}
    | FESPACE3 { fespacedim=3;}
    | FESPACES { fespacedim=4;}
    | FESPACEL { fespacedim=5;}
    | VGFESPACE { fespacedim=6;}
    | GFESPACE { fespacedim=7;} /* A enlever */
    ;

fespace:  fespace123 {fespacecomplex=false;  fespacetype = Find($1);}
        | fespace123 '<' TYPE '>' {
             if ($3 != typevarreal && $3 != typevarcomplex) lgerror (" type of finite element <real> or <complex>");
             fespacecomplex=($3==typevarcomplex);
             fespacetype = Find($1);}
;
spaceIDa  :      ID_array_space {  $$ = $1;}
            |    spaceIDa ',' ID_array_space { $$=C_F0($1,$3);} ;

spaceIDb  :      ID_space {  $$ = $1;}
            |    spaceIDb ',' ID_space { $$=C_F0($1,$3);} ;

spaceIDs :    fespace               spaceIDb    { $$=0;  $$ = $2;}
           |  fespace '[' TYPE ']'  spaceIDa    { $$=0;  $$ = $5;}; 

fespace_def:
   id '(' parameters_list ')'  {$$=currentblock->NewVar<LocalVariableFES,KN<size_t>>($1,typeFESpace($3),$3,dimFESpaceImage($3));
     $3.destroy(); }
    ;
  | id '=' parameters_list  {$$=currentblock->NewVar<LocalVariableFES,KN<size_t>>($1,typeFESpace($3),$3,dimFESpaceImage($3));
     $3.destroy(); }
    ;

fespace_def_list:  fespace_def
                 | fespace_def_list ',' fespace_def {$$=C_F0($1,$3);} /* plusieurs fespace Uh(), Vh(), ...; */
;

declaration:   type_of_dcl {dcltype=$1;} list_of_dcls ';' {$$=$3;} /* [[type_of_dcl:]] [[list_of_dcls:]] */
             | FESPACEID  fespace_def_list    ';' {$$=$2;}
             | spaceIDs ';'{ $$=$1;}
             | FUNCTION id '=' Expr ';' {$$=currentblock->NewID($1,$2,$4);}
             | FUNCTION type_of_dcl id  '(' list_of_id_args ')'
                   {   /* use the stack to store the prev return type*/
                      assert(kkembtype+1<nbembtype);
                      rettype[++kkembtype] = $2->right();
                      routineinblock[kkembtype] = currentblock;
                      $<routine>5=new Routine($1,$2->right(),$3,$5,currentblock);
		      // routineinblock[kkembtype]->Add($3,"(",$<routine>5); //pas recursif pour l'instanat test  FH 27 dec 2008
                     // cout << " \n after new routine \n " << endl;
                      }
                    '{' instructions'}'
                     { currentblock=$<routine>5->Set($9);
                       currentblock->Add($3,"(",$<routine>5); //pas recursif pour l'instant test  FH 27 dec 2008
                       kkembtype--;
                       $$=0;

                        }
             | FUNCTION id '(' list_of_id_args ')'
                      {Block::open(currentblock); $1->SetArgs($4);}
                   '='   no_comma_expr  ';'
                      {  //$<cinst>$=currentblock->close(currentblock);
                         $<cinst>$.setclose(Block::snewclose(currentblock));// Sep 2016 FH.
                         $$=currentblock->NewID($1,$2,$8,*$4);
                         delete $4; //  FH 23032005
                         }
;

begin: '{'  {  Block::open(currentblock);};
end:   '}'  { $$=Block::snewclose(currentblock);
//  $$=currentblock->close(currentblock);
};

for_loop:  FOR {ffassert(inloopcount<sizeStackOfLoop);  // modif FH july 2005
                StackOfLoop[inloopcount++]=currentblock;};
while_loop:  WHILE {ffassert(inloopcount<sizeStackOfLoop);
                StackOfLoop[inloopcount++]=currentblock;}; // modif FH july 2005

declaration_for:
    type_of_dcl {dcltype=$1; Block::open(currentblock);  }
               list_of_dcls {$$=$3;};

try: TRY { Block::open(currentblock);};

IDfor:     id  { $$ = new ListOfId(); $$->push_back(UnId($1));Block::open(currentblock); }
         | id ',' id   { $$ = new ListOfId(); $$->push_back(UnId($1));$$->push_back(UnId($3));Block::open(currentblock); }
         | id ',' id ','  id   { $$ = new ListOfId(); $$->push_back(UnId($1));$$->push_back(UnId($3));$$->push_back(UnId($5));Block::open(currentblock); }
/*<<instruction>>*/
instruction:   ';' {$$=0;}
         | INCLUDE  STRING  {zzzfff->input($2);$$= 0; }
         | LOAD  STRING  {load($2);$$= 0; }
         |  try  '{' instructions '}' catchs {$$=Try($3,currentblock->close(currentblock,$5));}
         |  Expr ';' {$$=$1;} /*[[Expr:]]*/
         |  declaration  {$$=$1;} /*[[declaration:]]*/
         |  for_loop  '[' IDfor  ':' primary ']'
                {$5=ForAll(currentblock,$3,$5);}
             instruction {
                    inloopcount--;
                    $$=Block::close(currentblock,C_F0(ForAll($5,$8)));
                 }
         |  for_loop  '(' Expr ';' Expr ';' Expr ')' instruction {inloopcount--; $$=For($3,$5,$7,$9);}
         |  for_loop  '(' declaration_for ';' Expr ';' Expr ')' instruction
                {inloopcount--;
                 $$=Block::close(currentblock,C_F0(For($3,$5,$7,$9)));
                }
         |  while_loop '(' Expr ')' instruction {inloopcount--;$$=While($3,$5);}
         |  IF '(' Expr ')'   instruction  {$$=FIf($3,$5);}
         |  IF '(' Expr ')'   instruction  ELSE instruction {$$=FIf($3,$5,$7);}
         |  begin  instructions end { /* [[begin:]] [[end:]] */
             $2.setclose($3);
             $$=$2;
                    //  $$=C_F0(new E_block($2,$3),atype<void>());
         }
         |  BORDER  id   border_expr { /* <<BORDER_ID>> */
                      $$=0;currentblock->NewID(atype<const E_Border *>(),$2,C_F0(TheOperators,"[border]",$3));}
         |  BORDER  id  '['  array ']' ';' {
                      $$=0;currentblock->NewID(atype<const E_Border *>(),$2,C_F0(TheOperators,"[border]",$4));}

         |  BREAK ';' {
                    if(inloopcount)
                      $$= C_F0(new E_throw(E_exception::e_break),atype<void>());
                    else lgerror("break not in loop");}
         |  CONTINUE ';' {
                    if(inloopcount)
                        $$= C_F0(new E_throw(E_exception::e_continue),atype<void>()) ;
                    else lgerror("continue not in loop");}
         |  RETURN  Expr ';' {
                    if (kkembtype>=0)
                      $$= C_F0(new E_throw(E_exception::e_return,(rettype[kkembtype]->CastTo($2)).OnReturn()) ,atype<void>());
                     else lgerror(" return not in routine ");}
;

catchs:
  CATCH '(' '.' '.' '.'  ')' instruction {$$ =  $7; }
;

bornes: '(' id '=' Expr ',' Expr ')' {
   Block::open(currentblock);
   $$ = currentblock->NewVar<LocalVariable>($2,atype<double*>());
   $$+= $4;
   $$+= $6;
   $$+= currentblock->NewVar<LocalVariable>("IndexBorder",atype<long*>());}
;

bornes: '(' id '=' Expr ',' Expr ';' id ')' {
    Block::open(currentblock);
    $$ = currentblock->NewVar<LocalVariable>($2,atype<double*>());
    $$+= $4;
    $$+= $6;
    $$+= currentblock->NewVar<LocalVariable>($8,atype<long*>());}
;

border_expr:   bornes instruction {
    //currentblock->close(currentblock;);
   $$ = ($1 += currentblock->close(currentblock,$2));
   }
 ;

Expr:
    no_comma_expr /*[[no_comma_expr:]]*/
  | Expr ',' Expr {$$=C_F0(TheOperators,$2,$1,$3);}
  ;

unop:
    '-'
  | '+'
  | '!'
  | PLUSPLUS
  | MOINSMOINS
  ;

no_comma_expr:
    no_set_expr /*[[no_set_expr:]]*/
  | no_set_expr '=' no_comma_expr      {$$=C_F0(TheOperators,$2,$1,$3);} /* <<assignation>> */
  | no_set_expr PLUSEQ no_comma_expr   {$$=C_F0(TheOperators,"+=",$1,$3);}
  | no_set_expr MOINSEQ no_comma_expr  {$$=C_F0(TheOperators,"-=",$1,$3);}
  | no_set_expr MULEQ no_comma_expr    {$$=C_F0(TheOperators,"*=",$1,$3);}
  | no_set_expr DIVEQ no_comma_expr    {$$=C_F0(TheOperators,"/=",$1,$3);}
  | no_set_expr DOTMULEQ no_comma_expr {$$=C_F0(TheOperators,".*=",$1,$3);}
  | no_set_expr DOTDIVEQ no_comma_expr {$$=C_F0(TheOperators,"./=",$1,$3);}
  ;

/* <<no_set_expr:>> */
no_set_expr: /* returns [[YYSTYPE_cexp]] */
	no_ternary_expr /*[[no_ternary_expr:]]*/
  | no_ternary_expr '?' no_ternary_expr ':' no_ternary_expr {$$=C_F0(TheOperators,"?:",$1,$3,$5);}
  | no_ternary_expr ':' no_ternary_expr                     {$$=C_F0(TheOperators,"::",$1,$3);}
  | no_ternary_expr ':' no_ternary_expr ':' no_ternary_expr {$$=C_F0(TheOperators,"::",$1,$3,$5);}
  ;

no_ternary_expr: /* returns a [[YYSTYPE_cexp]] */
    unary_expr /*[[unary_expr:]]*/
  | no_ternary_expr '*' no_ternary_expr      {$$=C_F0(TheOperators,$2,$1,$3);}
  | no_ternary_expr DOTSTAR no_ternary_expr  {$$=C_F0(TheOperators,$2,$1,$3);}
  | no_ternary_expr DOTSLASH no_ternary_expr {$$=C_F0(TheOperators,$2,$1,$3);}
  | no_ternary_expr '/' no_ternary_expr      {$$=C_F0(TheOperators,$2,$1,$3);}
  | no_ternary_expr '%' no_ternary_expr      {$$=C_F0(TheOperators,$2,$1,$3);}
  | no_ternary_expr '+' no_ternary_expr      {$$=C_F0(TheOperators,$2,$1,$3);}
  | no_ternary_expr '-' no_ternary_expr      {$$=C_F0(TheOperators,$2,$1,$3);}
  | no_ternary_expr LTLT no_ternary_expr     {$$=C_F0(TheOperators,$2,$1,$3);}
  | no_ternary_expr GTGT no_ternary_expr     {$$=C_F0(TheOperators,$2,$1,$3);}
  | no_ternary_expr '&' no_ternary_expr      {$$=C_F0(TheOperators,$2,$1,$3);}
  | no_ternary_expr AND no_ternary_expr      {$$=C_F0(TheOperators,$2,$1,$3);}
  | no_ternary_expr '|' no_ternary_expr      {$$=C_F0(TheOperators,$2,$1,$3);}
  | no_ternary_expr OR no_ternary_expr       {$$=C_F0(TheOperators,$2,$1,$3);}
  | no_ternary_expr '<' no_ternary_expr      {$$=C_F0(TheOperators,$2,$1,$3);}
  | no_ternary_expr LE no_ternary_expr       {$$=C_F0(TheOperators,$2,$1,$3);}
  | no_ternary_expr '>' no_ternary_expr      {$$=C_F0(TheOperators,$2,$1,$3);}
  | no_ternary_expr GE no_ternary_expr       {$$=C_F0(TheOperators,$2,$1,$3);}
  | no_ternary_expr EQ no_ternary_expr       {$$=C_F0(TheOperators,$2,$1,$3);}
  | no_ternary_expr NE no_ternary_expr       {$$=C_F0(TheOperators,$2,$1,$3);}
  ;

sub_script_expr:
	    no_ternary_expr /*[[no_ternary_expr:]]*/                {$$=$1;}
    |   ':'                                                     {$$=C_F0(TheOperators,":");}
    |   no_ternary_expr ':' no_ternary_expr                     {$$=C_F0(TheOperators,":",$1,$3);}
    |   no_ternary_expr ':' no_ternary_expr ':' no_ternary_expr {$$=C_F0(TheOperators,":",$1,$3,$5);}
    ;

/* only used in [[primary:]] */
parameterstype:
  sub_script_expr ',' parameters {
      $$ = $1;
      $$ += $3; }
  
parameters: /* returns [[YYSTYPE_args]] */                  {$$ = 0;} /* <<no_parameter>> */
  | FESPACE                                                 {$$ = Find($1);} /*[[file:../fflib/AFunction2.cpp::Find]]*/
  | FESPACE1                                                {$$ = Find($1);}
  | FESPACE3                                                {$$ = Find($1);}
  | FESPACES                                                {$$ = Find($1);}
  | FESPACEL                                                {$$ = Find($1);}
  | VGFESPACE                                               {$$ = Find($1);} // Add Morice
  | id /*[[id]]*/ '=' no_set_expr /*[[no_set_expr:]]*/      {$$ = make_pair<const char *,const C_F0>((const char *) $1,(C_F0) $3);}
  | sub_script_expr /*[[sub_script_expr:]]*/                {$$ = $1;}
  | parameters ',' FESPACE                                  {$$ = ($1 += Find($3));}
  | parameters ',' FESPACE1                                 {$$ = ($1 += Find($3));}
  | parameters ',' FESPACE3                                 {$$ = ($1 += Find($3));}
  | parameters ',' FESPACES                                 {$$ = ($1 += Find($3));}
  | parameters ',' FESPACEL                                 {$$ = ($1 += Find($3));}
  | parameters ',' VGFESPACE                                {$$ = ($1 += Find($3));}
  | parameters ',' sub_script_expr /*[[sub_script_expr:]]*/ {$$ = ($1 += $3);}

    /* <<named_function_parameters>> */
  | parameters ',' id '=' no_set_expr /*[[no_set_expr:]]*/  {$$ = ($1+= make_pair<const char *,const C_F0>((const char *)$3,(C_F0) $5));}
  ;

array:   no_comma_expr           {$$=$1;}
       | array ',' no_comma_expr {$$ = ($1 += $3);}
  ;

FEarray: FESPACE                   { $$=Find($1)}        
      | FESPACE1                   { $$=Find($1);}
      | FESPACE3                   { $$=Find($1);}
      | FESPACES                   { $$=Find($1);}
      | FESPACEL                   { $$=Find($1);}
      | FEarray ',' FESPACE        { $$ = ($1 += Find($3));}
      | FEarray ',' FESPACE1       { $$ = ($1 += Find($3));}
      | FEarray ',' FESPACE3       { $$ = ($1 += Find($3));}
      | FEarray ',' FESPACES       { $$ = ($1 += Find($3));}
      | FEarray ',' FESPACEL       { $$ = ($1 += Find($3));}
      | FEarray '*' FESPACE        { $$ = ($1 += Find($3));}
      | FEarray '*' FESPACE1       { $$ = ($1 += Find($3));}
      | FEarray '*' FESPACE3       { $$ = ($1 += Find($3));}
      | FEarray '*' FESPACES       { $$ = ($1 += Find($3));}
      | FEarray '*' FESPACEL       { $$ = ($1 += Find($3));}
  ;

unary_expr:                                                 /* returns a [[YYSTYPE_cexp]] */
    pow_expr                                                /*[[pow_expr:]]*/
  | unop pow_expr %prec UNARY {$$=C_F0(TheOperators,$1,$2);} /*[[unop:]]*/
  ;

pow_expr:        /* returns a [[YYSTYPE_cexp]] */
         primaryp /*[[primary:]]*/
  |      primaryp '^'  unary_expr   {$$=C_F0(TheOperators,$2,$1,$3);}
  |      primaryp '_'  unary_expr   {$$=C_F0(TheOperators,$2,$1,$3);}
;

primaryp:  /*  change prioryty of ' operator    */
         primary /*[[primary:]]*/
  |      primary '\''              {$$=C_F0(TheOperators,$2,$1);}
  ;

primary: /* returns a [[YYSTYPE_cexp]] */

            /* <<primary_ID>> calls [[file:../fflib/AFunction2.cpp::Find]]
               returns [[file:../fflib/AFunction.hpp::C_F0]] */

           ID           {$$=Find($1);}

           /* <<primary_constant>> uses [[file:~/ff/src/fflib/AFunction.hpp::CConstant]] */

  |        LNUM         {$$= CConstant($1);}
  |        DNUM         {$$= CConstant($1);}
  |        CNUM         {$$= CConstant(complex<double>(0,$1));}
  |        STRING {$$= CConstant<const char *>($1);} /* <<primary_STRING>> */

           /* <<primary_brackets_parameters>> refers to [[parameters:]] and creates an object of class
              [[file:../fflib/AFunction.hpp::C_F0]] */

  |        primary '('  parameters /*[[parameters:]]*/ ')'  {$$=C_F0($1,$2,$3);}

  |        primary '[' sub_script_expr ']'    {$$=C_F0($1,$2,$3);}
  |        primary '[' sub_script_expr ',' sub_script_expr ']'  {$$=C_F0($1,$2,$3,$5);}
  |        primary '['  ']'        {$$=C_F0($1,"[]");}
  |        primary '.'  id       { $$=C_F0($1,$3) ;}
  |        FESPACE '.'  id       { $$=C_F0(Find($1),$3) ;}
  |        FESPACE '(' parameters ')'     { $$=C_F0(Find($1),$2,$3) ;}
  |        FESPACE1 '.'  id       { $$=C_F0(Find($1),$3) ;}
  |        FESPACE1 '(' parameters ')'     { $$=C_F0(Find($1),$2,$3) ;}
  |        FESPACE3 '.'  id       { $$=C_F0(Find($1),$3) ;}
  |        FESPACE3 '(' parameters ')'     { $$=C_F0(Find($1),$2,$3) ;}
  |        FESPACES '.'  id       { $$=C_F0(Find($1),$3) ;}
  |        FESPACES '(' parameters ')'     { $$=C_F0(Find($1),$2,$3) ;}
  |        FESPACEL '.'  id       { $$=C_F0(Find($1),$3) ;}
  |        FESPACEL '(' parameters ')'     { $$=C_F0(Find($1),$2,$3) ;}
  |        primary PLUSPLUS      {$$=C_F0(TheRightOperators,$2,$1);}
  |        primary MOINSMOINS    {$$=C_F0(TheRightOperators,$2,$1);}
  |        TYPE '('  sub_script_expr ')' {
             if ($1->right()->CastingFrom($3.left()) )
                $$=$1->right()->CastTo($3)  ;
             else { $$=$1->right()->Find("<--",basicAC_F0_wa($3));
             if (!$$.left()) { cerr << " no wait to change " << $3.left()->right()->name() << " in " <<
                                        $1->right()->name() << endl;
                                CompileError(" Error in type(exp) "); }
             }
            }
  |        TYPE '('  parameterstype ')' {
           { $$=$1->right()->Find("<--",basicAC_F0_wa($3));
           if (!$$.left()) { cerr << " no wait to change (args) in " <<
                                      $1->right()->name() << endl;
                              CompileError(" Error in type(exp) "); }
           }
          }

  |        '(' Expr ')' {$$=$2;}
  |        '[' array  ']' { $$=C_F0(TheOperators,"[]",$2);}
  |        '<' FEarray '>' { $$=C_F0(TheOperators,"<>",$2);} /* chevron definition FE space */
  |        FEarray { $$=C_F0(TheOperators,"<>",$1);} /*  Xh=Uh*Vh  */
;


%%


#include <fstream>
using namespace std;
void ForDebug();
void ForDebug()
{
  int i=0;
  i++;
}
//extern void ShowAlloc(const char *s, size_t lg);
//extern void ShowNbAlloc(const char *s);
void init_lgfem() ;
void init_lgmesh() ;
void init_lgmesh3() ;
void init_algo();
void msh3_Load_Init( ); //

bool withrgraphique = false;

/// <<Compile>> Called by mainff(). Activates the bison parser by calling yyparse()
int Compile()
{

  // see [[YYSTYPE]] [[yylval]] [[lglval]]
  extern   YYSTYPE *plglval;  // modif FH

  /// plglval is allocated at [[file:../fflib/global.cpp::plglval]]
  plglval = &lglval;

  int retvalue=0;

  // <<initialize_currentblock>>

  currentblock=0;
  Block::open(currentblock);
  try {
    UnShowAlloc =0;

    retvalue=yyparse(); // grammar analysis starting from [[start_symbol]]

    if(retvalue==0){
      if(currentblock)
        {retvalue=1; if(!mpirank) cerr <<  "Error:a block is not close" << endl; }
      else {
        if( verbosity  ) {
	      UnShowAlloc =1;
	      cerr << " CodeAlloc : nb ptr  "<< CodeAlloc::nb << ",  size :"  <<  CodeAlloc::lg
              << " mpirank: " <<mpirank <<  endl    ;
              extern   long npichon2d, npichon3d;
              extern   long npichon2d1, npichon3d1;
              if( npichon2d || npichon3d ) cout << " WARNING NUMBER bad SearchMethod cas in 2d: "
                 <<npichon2d << " int 3d "<< npichon3d << "(essai d2: " <<npichon2d1  <<" 3d: " << npichon3d1 <<" )"<< endl;
	      if(!mpirank) cerr <<  "Ok: Normal End" << endl;
	    }
      }
    }
  }

  catch (Error & e)
    {
      retvalue=e.errcode();
      if(mpirank ==0)
	cerr << "error " << e.what()
	     << "\n code = "<<  retvalue << " mpirank: " <<mpirank  << endl;
    }
  catch(std::ios_base::failure & e)
    {
      cerr << "std  catch io failure \n what : " << e.what() << endl;;
      cerr << " at exec line  " << TheCurrentLine << " mpirank: " <<mpirank  << endl;
    }
  catch(std::exception & e)
    {
      cerr << "std  catch exception \n what : " << e.what() << endl;;
      cerr << " at exec line  " << TheCurrentLine << " mpirank: " <<mpirank  << endl;

    }
  catch(...)
    {
      cerr << "Strange catch exception ???\n";
      cerr << " at exec line  " << TheCurrentLine << " mpirank: " <<mpirank << endl;
    }
  return retvalue;
}
static void SetcppIo()
{

#ifdef _WIN32XXXX
  freopen("conin$", "r", stdin);
  freopen("conout$", "w", stdout);
  using namespace __gnu_cxx;
  //  stdio_filebuf<char> * ccout = new stdio_filebuf<char>(stdout, std::ios_base::out);
  static  stdio_filebuf<char> ccout(stdout, std::ios_base::out);
  static  stdio_filebuf<char> ccin(stdin, std::ios_base::in);
   //stdio_filebuf<char> *ccin= new stdio_filebuf<char>(stdin, std::ios_base::in);

   cout.rdbuf(&ccout);
   cin.rdbuf(&ccin);
   cerr.rdbuf(&ccout);
   cout << " -- SetcppIo --" << endl;
#endif
   ios::sync_with_stdio();
}

// pour l'environement.
extern const char *  prognamearg;
extern  bool echo_edp;

/// <<mainff>> Called by [[file:mymain.cpp::mymain]] and calls [[Compile]] to run the FF language parser

int mainff (int  argc, char **argv)
{
#ifndef _WIN32
  	signal(SIGXCPU, signalCPUHandler);
#endif	
  if(argc)
    prognamearg=argv[0];

 //   int vvold=verbosity;
  if(mpirank !=0) verbosity=0;

  // ALH - 14/10/8 - This breaks FFCS output redirection
#ifndef ENABLE_FFCS
  SetcppIo();
#endif

  GetEnvironment(); // [[file:~/ff/src/fflib/environment.cpp::GetEnvironment]]
//    vvold=verbosity;
  if(mpirank !=0) verbosity=0;
  //  size_t lg000;
 // ShowAlloc("begin main ",lg000);
  int retvalue=0;
   ff_atend(fingraphique);
   if (initparallele)initparallele(argc,argv);

  CPUcompileInit= CPUtime();
  withrgraphique = false;
   atexit(ForDebug);
//  AllFunctions::maptype  xlocal;
//  local=&xlocal;
  lexdebug = false;
  lgdebug = false;

  char *  cc= new char [1024];
  //  istream * ccin=0;
  if ( ! (getprog(cc,argc,argv) >0)  ) // [[file:~/ff/src/Graphics/getprog-unix.hpp::getprog]]
    {
      cout << "-- FreeFem++ v" << StrVersionNumber() << " (error parameter!)\n"  ;
      if(ThePlotStream) {ffapi::ff_pclose(ThePlotStream); ThePlotStream=0;}
      return 1;
    }

  if(verbosity && (mpirank==0)) {
      cout << "-- FreeFem++ v" << StrVersionNumber() << endl;
      cout << "   file : " << cc ;
      if(verbosity>1) cout << " " << " verbosity= " << verbosity ;
      if( typeofscript ) cout << " " << " Markdown = " << typeofscript;
      cout  << endl;
  }

    KN<String> karg(argc);
    for(int i=0;i< argc;++i)
	karg[i]=argv[i];
    pkarg= &karg;

    /// <<zzzfff>>
    zzzfff = Newlex(cout,echo_edp,pkarg);


/*
  ccin= new ifstream(cc);
  if (argc >1 && (ccin!=0) )
     ccin= new ifstream(argv[1]),throwassert(ccin);
  if (ccin!=0)
    zzzfff = new  mylex(*ccin,cout) ;
  else
    zzzfff = new  mylex(cin,cout) ;
*/
//  les motsclefs
   zzzfff->Add("include",INCLUDE);
   zzzfff->Add("load",LOAD);
   zzzfff->Add("while",WHILE);
   zzzfff->Add("for",FOR);
 //  zzzfff->Add("forall",FORALL);
   zzzfff->Add("if",IF);
   zzzfff->Add("else",ELSE);
   zzzfff->Add("end",ENDOFFILE);
   zzzfff->Add("break",BREAK);
   zzzfff->Add("continue",CONTINUE);
   zzzfff->Add("return",RETURN);
   zzzfff->Add("border",BORDER);
   zzzfff->Add("fespace",FESPACEID);
   zzzfff->Add("try",TRY);
   zzzfff->Add("catch",CATCH);
   zzzfff->Add("throw",THROW);
//   Init_map_type();
   if(verbosity>2 || ( (mpirank==0) && verbosity ) ) cout << " Load: ";
   callInitsFunct() ; //  init for dynamique libs ...
  // init_lgfem() ;
   init_lgmesh() ;
   init_lgmesh3() ;
   init_algo();

#ifdef HAVE_LIBARPACK
   init_eigenvalue();
#endif

   if(init_lgparallele)  init_lgparallele();
   msh3_Load_Init(); // Add msh3 lib !!! 
     //  callInitsFunct() ; //  init for dynamique libs ...

   if(verbosity>2 || ((mpirank==0)&& verbosity)  )  cout << endl;
  zzzfff->input(cc,typeofscript); // [[file:../fflib/lex.cpp::mylex_input_filename]]
  EnvironmentLoad(); // just before compile [[file:~/ff/src/fflib/environment.cpp::EnvironmentLoad]]

  retvalue= Compile(); // [[Compile]]
   // cout << " xxxxx " <<  retvalue << " " << ThePlotStream << endl;

  //if(end_parallele) end_parallele();
  ff_finalize();
  //  currentblock->close(currentblock).eval(thestack);
 // fingraphique();
  // FFCS: divert stream to FFCS
  if(ThePlotStream){
    ffapi::ff_pclose(ThePlotStream);
    ThePlotStream=0;
  }
  Destroylex( zzzfff);
  delete [] cc;
   // ClearMem();
  return retvalue;
}

/* FFCS: emacs configuration for this file */

/*!
 * Local Variables:
 * mode:antlr
 * ispell-local-dictionary:"british"
 * coding:utf-8
 * End:
 */
