Skip to content
Snippets Groups Projects
parser.mly 26.24 KiB
%{
open Lxm
open Predef
open SyntaxTree
open SyntaxTreeCore
open ParserUtils


(**********************************************************************************)
(**********************************************************************************)
(**********************************************************************************)

%}

%token TK_EOF

%token <Lxm.t> TK_ERROR

%token <Lxm.t> TK_EXTERN

%token <Lxm.t> TK_AND
%token <Lxm.t> TK_ARROW
%token <Lxm.t> TK_ASSERT
%token <Lxm.t> TK_BAR
%token <Lxm.t> TK_BOOL
%token <Lxm.t> TK_CDOTS
%token <Lxm.t> TK_CLOSE_BRACE
%token <Lxm.t> TK_CLOSE_BRACKET
%token <Lxm.t> TK_CLOSE_PAR
%token <Lxm.t> TK_CLOSE_STATIC_PAR
%token <Lxm.t> TK_COLON
%token <Lxm.t> TK_COMA
%token <Lxm.t> TK_CONST
%token <Lxm.t> TK_CURRENT
%token <Lxm.t> TK_DIESE
%token <Lxm.t> TK_DIV
%token <Lxm.t> TK_DOT
%token <Lxm.t> TK_EQ
%token <Lxm.t> TK_ELSE
%token <Lxm.t> TK_ENUM
%token <Lxm.t> TK_FALSE
%token <Lxm.t> TK_FIELD
%token <Lxm.t> TK_FUNCTION
%token <Lxm.t> TK_GT
%token <Lxm.t> TK_GTE
%token <Lxm.t> TK_HAT
%token <Lxm.t> TK_ICONST
%token <Lxm.t> TK_IDENT
%token <Lxm.t> TK_LONGIDENT
%token <Lxm.t> TK_IF
%token <Lxm.t> TK_IMPL
%token <Lxm.t> TK_INT
%token <Lxm.t> TK_LET
%token <Lxm.t> TK_LT
%token <Lxm.t> TK_LTE
%token <Lxm.t> TK_MINUS
%token <Lxm.t> TK_MOD
%token <Lxm.t> TK_NEQ
%token <Lxm.t> TK_NODE
%token <Lxm.t> TK_NOR
%token <Lxm.t> TK_NOT
%token <Lxm.t> TK_OPEN_BRACE
%token <Lxm.t> TK_OPEN_BRACKET
%token <Lxm.t> TK_OPEN_PAR
%token <Lxm.t> TK_OPEN_STATIC_PAR
%token <Lxm.t> TK_OPERATOR
%token <Lxm.t> TK_OR
%token <Lxm.t> TK_PCENT
%token <Lxm.t> TK_PLUS
%token <Lxm.t> TK_POWER
%token <Lxm.t> TK_PRE
%token <Lxm.t> TK_FBY
%token <Lxm.t> TK_RCONST
%token <Lxm.t> TK_REAL
%token <Lxm.t> TK_RETURNS
%token <Lxm.t> TK_SEMICOL
%token <Lxm.t> TK_SLASH
%token <Lxm.t> TK_STAR
%token <Lxm.t> TK_STEP
%token <Lxm.t> TK_STRUCT
%token <Lxm.t> TK_TEL
%token <Lxm.t> TK_THEN
%token <Lxm.t> TK_TRUE
%token <Lxm.t> TK_TYPE
%token <Lxm.t> TK_VAR
%token <Lxm.t> TK_WHEN
%token <Lxm.t> TK_WITH
%token <Lxm.t> TK_XOR
%token <Lxm.t> TK_MODEL
%token <Lxm.t> TK_PACKAGE
%token <Lxm.t> TK_NEEDS
%token <Lxm.t> TK_PROVIDES
%token <Lxm.t> TK_USES
%token <Lxm.t> TK_IS
%token <Lxm.t> TK_BODY
%token <Lxm.t> TK_END
%token <Lxm.t> TK_INCLUDE
%token <Lxm.t> TK_STRING 
%token <Lxm.t> TK_SLICE_START
/* %token <Lxm.t> TK_QUOTE */

/* Priorities */

%left TK_ELSE
%left TK_BAR
%left TK_ARROW
%nonassoc TK_STEP
%nonassoc TK_CDOTS
%left TK_OR TK_XOR
%left TK_AND
%nonassoc TK_LT TK_LTE TK_EQ TK_GTE TK_GT TK_NEQ TK_IMPL 
%nonassoc TK_NOT
%left TK_PLUS TK_MINUS
%left TK_STAR TK_SLASH TK_PCENT TK_MOD TK_DIV
%left TK_POWER
%left TK_WHEN
%nonassoc TK_INT TK_REAL
%nonassoc TK_UMINUS TK_PRE TK_CURRENT TK_DIESE TK_NOR
%left TK_HAT TK_FIELD TK_DOT
%right TK_OPEN_BRACKET TK_OPEN_BRACE TK_SEMICOL
%right TK_COMA
%right TK_FBY 

/* sxEntry point */
%start sxLusFile
%type <SyntaxTree.t> sxLusFile

%%

/*-------------------------------------------------------
	GRAMMAR
---------------------------------------------------------
NOTES ON THE CODE:

- Nothing is "built" for the main list declarations :
each definition is directly inserted in the corresponding
hash table (i.e. each declaration makes a side effect)

- Any rule that produces a caml list builds it in THE REVERSE
ORDER (in order to save the yacc stack and to avoid
the use of the caml @ operator). This is why they are
named "sxTotoReverseList". This is why they must not be
used in other rules: onr have to use the corresponding
"sxTotoList" which finally reverse the list.
-------------------------------------------------------*/

/*
A lustre file is either an old-fashioned list of item decl,
or a list of pack/model declaration
*/

sxLusFile:
	/* WARNING ! il faut remettre la liste  l'endroit */
	sxIncludeList sxPackBody TK_EOF
	{
		SyntaxTree.PRPackBody($1, $2)
	}
|	sxIncludeList sxPackList TK_EOF
	{ 
		SyntaxTree.PRPack_or_models ($1, List.rev $2)
	}
;

sxPackList:
	sxOnePack
	{ [$1] }
|	sxPackList sxOnePack
	{ $2::$1 }
;

sxOnePack:
	sxModelDecl
		{ SyntaxTree.NSModel $1 }
|	sxPackDecl
		{ SyntaxTree.NSPack $1 }
|	sxPackEq
		{ SyntaxTree.NSPack $1 }
;

sxInclude:
	TK_INCLUDE TK_STRING
	{ (Lxm.str $2)  }
;

sxIncludeList:
	{ [] }
|	sxInclude sxIncludeList
	{ $1::$2 }
;  

/*
Pour les provides, on rend des decls, bien
que syntaxiquement, on n'autorise pas n'importe quoi ... 

*/
sxProvides:
	/* nada */
		{ None }
/* |	TK_PROVIDES sxStaticParamList TK_SEMICOL */
|	TK_PROVIDES sxProvideList TK_SEMICOL
	{ Some (List.rev $2) }
;

sxProvideList: sxOneProvide
		{ [$1]  }
	|   sxProvideList TK_SEMICOL sxOneProvide
		{ $3::$1 }
	;

sxConstDefOpt: 
	{ None}
|	TK_EQ sxExpression
	{
	  Some $2
	}


sxOneProvide:
	/* constante abstraite */
	TK_CONST sxIdent TK_COLON sxType sxConstDefOpt 
	{
		Lxm.flagit
		  (ConstInfo (ExternalConst (Lxm.id $2, $4, $5)))
		$2
	}
	/* noeud abstrait */
|	TK_NODE sxIdent sxParams TK_RETURNS sxParams 
	{
		treat_abstract_node true $2 $3 $5
	}
	/* fonction abstraite */
|	TK_FUNCTION sxIdent sxParams TK_RETURNS sxParams 
	{
		treat_abstract_node false $2 $3 $5
	}
	/* type abstrait ... */
|	TK_TYPE	sxIdent
	{
		Lxm.flagit
		(TypeInfo (ExternalType (Lxm.id $2)))
		$2
	}
	/* un alias sur type immdiat */
|	TK_TYPE sxIdent TK_EQ sxType 
	{
		Lxm.flagit
		(TypeInfo (AliasedType (Lxm.id $2, $4)))
		$2
	}
	/* type numr */
	/* WARNING ! la liste n'est pas  l'endroit */
|	TK_TYPE sxIdent TK_EQ TK_ENUM TK_OPEN_BRACE sxIdentList TK_CLOSE_BRACE
	{
		let fields = List.rev_map lexeme_to_ident_flagged $6 in
		Lxm.flagit
		(TypeInfo (EnumType (Lxm.id $2, fields)))
		$2
	}
	/* type structure  champs nomms */
	/* WARNING ! la liste est dj  l'endroit */
|	TK_TYPE sxIdent TK_EQ opt_TK_STRUCT
          TK_OPEN_BRACE sxTypedValuedIdents TK_CLOSE_BRACE
	{
		let sti = make_struct_type_info $2 $6 in
		Lxm.flagit
		(TypeInfo (StructType sti))
		$2
	}
;

sxModelDecl:
	TK_MODEL sxIdent
	sxUses
	/* TK_NEEDS sxPackParamList TK_SEMICOL */
	TK_NEEDS sxStaticParamList TK_SEMICOL
	sxProvides
	TK_BODY
		sxPackBody
	TK_END
	{
		let mdecl = {
			mo_name = (Ident.pack_name_of_string (Lxm.str $2));
			mo_uses = $3 ;
			mo_needs = (List.rev $5) ;
			mo_provides = $7 ;
			mo_body = $9;
		} in
		{it = mdecl; src = $2 }
	}
;


sxPackDecl:
	TK_PACKAGE sxIdent
	sxUses
	sxProvides
	TK_BODY
		sxPackBody
	TK_END
	{
		let pdef = PackGiven {
			pg_uses = $3 ;
			pg_provides = $4 ;
			pg_body = $6;
		} in	
		let pdecl = {
			pa_name = (Ident.pack_name_of_string (Lxm.str $2));
			pa_def = pdef;
		} in
		{it = pdecl; src = $2 }
	}
;

/* pack params are identical to node static Packparams (?) */
/*
sxPackParamList:
	sxStaticParamList
		{ $1 }
;
*/


sxUses:
		/* nada */
	{ [] }
|	TK_USES sxIdentList TK_SEMICOL
	{
		List.rev_map lexeme_to_pack_name_flagged $2
	}
;

/* */
sxEq_or_Is:
|	TK_EQ
 	{}
|	TK_IS
 	{}
/* I don't like by-pos notation, but keep it
	for backward compatibility
*/
sxPackEq:
	TK_PACKAGE sxIdent sxEq_or_Is sxIdent TK_OPEN_PAR
		sxStaticArgList
	TK_CLOSE_PAR TK_SEMICOL
	{
		let pdef = PackInstance {
			pi_model =  (Lxm.id $4);
			pi_args = (List.rev $6);
		} in
		let pa = {
			pa_name = (Ident.pack_name_of_string (Lxm.str $2));
			pa_def = pdef;
		} in
		{it = pa; src = $2 }
	}
;

/* sxPackBody :
	les informations collectes dans les tables
	sont figes, et on remet les tables  0 ...
 */

sxPackBody:
	sxDeclList
	{
		let res = SyntaxTree.make_packbody
			const_table type_table node_table (List.rev !def_list) in
		(* clean all ... *)
		Hashtbl.clear const_table ;
		Hashtbl.clear type_table ;
		Hashtbl.clear node_table ;
		def_list := [] ;
		res
	}
;

/* sxDeclarations */

sxDeclList:   sxOneDecl
			{ }
	|   sxDeclList sxOneDecl
			{ }
	;

sxOneDecl:
		sxConstDecl 
			{ }
	|	sxTypeDecl
			{ }
	|	sxExtNodeDecl
			{ } 
	|	sxNodeDecl
			{ }
	;

/* sxIdentifiers and lists */
sxIdentRef :
	/* simple or long ... */
	TK_IDENT
	{ idref_of_lxm $1 }
|	TK_LONGIDENT
	{ idref_of_lxm $1 }
;

/* sxIdentifiers and lists */
sxIdent: TK_IDENT sxPragma
	{ $1 }
	;


sxIdentList:   sxIdent
			{ [$1] }
	|   sxIdentList TK_COMA sxIdent
			{ $3::$1 }
	; 

sxTypedIdentsList: sxTypedIdents
			{ [ $1 ] }
	|   sxTypedIdentsList TK_SEMICOL sxTypedIdents
			{ $3::$1 }
	;

sxTypedIdents:   sxIdentList TK_COLON sxType
	/* WARNING ! il faut remettre la liste  l'endroit */
			{ ((List.rev $1), $3 ) }
	;

sxTypedValuedIdents: sxTypedValuedIdent
			{ $1 }
	|   sxTypedValuedIdents TK_SEMICOL sxTypedValuedIdent
			{ List.append $1 $3 }
	;

sxTypedValuedIdent :
	/* Les listes d'idents en partie gauche sont 
	   acceptes pour les idents SANS valeur
	 */
		sxIdent TK_COLON sxType 
			{ (id_valopt_list_of_id_list [$1] $3 ) }
	|	sxIdent TK_COMA sxIdentList TK_COLON sxType 
			{ (id_valopt_list_of_id_list ($1::(List.rev $3)) $5) }
	/* Mais pas pour les constantes dfinies :
	*/
	|  sxIdent TK_COLON sxType TK_EQ sxExpression
			{ [id_valopt_of_id_val $1 $3 $5]  }
;


/* constantes */

sxConstDecl: TK_CONST sxConstDeclList {} ;

sxConstDeclList: 
 | sxOneConstDecl TK_SEMICOL {}
 | sxConstDeclList sxOneConstDecl TK_SEMICOL {} ;

sxOneConstDecl: 
/* Les listes d'idents en partie gauche sont 
   acceptes pour les constantes externes : */
 | sxIdent TK_COLON sxType { (treat_external_const_list [$1] $3 ) }
 | sxIdent TK_COMA sxIdentList TK_COLON sxType 
{ (treat_external_const_list ($1::(List.rev $3)) $5) }
/* Mais pas pour les constantes dfinies : */
|  sxIdent TK_COLON sxType TK_EQ sxExpression
{ (treat_defined_const $1 (Some $3) $5)  }
|  sxIdent TK_EQ sxExpression
			{ (treat_defined_const $1 (None) $3 ) }
	; 


/* types */

sxTypeDecl:   TK_TYPE sxTypeDeclList
			{} 
	;

sxTypeDeclList:   sxOneTypeDecl TK_SEMICOL
			{}
	|   sxTypeDeclList sxOneTypeDecl TK_SEMICOL
			{}
	;

sxOneTypeDecl:
	/* liste de types abstraits (externes) */
		sxIdentList
		{ treat_external_type_list (List.rev $1) }
	/* un alias sur type immdiat */
	|	sxIdent TK_EQ sxType 
		{ treat_aliased_type $1 $3 }
	/* type numr */
	/* WARNING ! il faut remettre la liste  l'endroit */
	|	sxIdent TK_EQ TK_ENUM TK_OPEN_BRACE sxIdentList TK_CLOSE_BRACE
		{
				treat_enum_type $1 (List.rev $5)
		}
	/* type structure  champs nomms */
	/* WARNING ! la liste est dj  l'endroit */
	|	sxIdent TK_EQ opt_TK_STRUCT TK_OPEN_BRACE sxTypedValuedIdents TK_CLOSE_BRACE
		{ treat_struct_type $1 $5 }
	;
/* COMPATIBILITY : "struct" keyword is optional */
opt_TK_STRUCT:
	/* nothing */ {}
|	TK_STRUCT     {}
;
	

/* Notation de type "immdiat" */
sxType:
		/* prdfini */
	    TK_BOOL  { {src=$1; it=Bool_type_exp } }
	|   TK_INT   { {src=$1; it=Int_type_exp } }
	|   TK_REAL  { {src=$1; it=Real_type_exp } }
		/* ref  un type nomm */
	|	sxIdentRef  { {src=$1.src; it= Named_type_exp $1.it } }
		/* ou tableau immdiat */
	|	sxType TK_HAT sxExpression
			{ {src=$2; it=Array_type_exp ($1 , $3) } }
	;


/* extern nodes */

sxExtNodeDecl:
  TK_EXTERN TK_FUNCTION sxIdent sxParams TK_RETURNS sxParams sxOptSemicol
          { treat_external_node false $3 $4 $6 }
| TK_EXTERN TK_NODE     sxIdent sxParams TK_RETURNS sxParams sxOptSemicol
	  { treat_external_node true $3 $4 $6 } 
;

/* noeuds */

sxNodeDecl: sxLocalNode {};

sxLocalNode:
| TK_NODE sxIdent sxStaticParams sxParams TK_RETURNS sxParams sxPragma sxOptSemicol
		sxLocals sxBody sxOptEndNode
	{ treat_node_decl true $2 $3 $4 $6 $9 $7 (fst $10) (snd $10) }
| TK_FUNCTION sxIdent sxStaticParams sxParams TK_RETURNS sxParams sxPragma sxOptSemicol
		 sxLocals sxBody sxOptEndNode
	{ treat_node_decl false $2 $3 $4 $6 $9 $7 (fst $10) (snd $10) }
| TK_NODE sxIdent sxStaticParams sxNodeProfileOpt TK_EQ sxEffectiveNode sxOptSemicol 
	{ treat_node_alias true $2 $3 $4 $6 } ;
| TK_FUNCTION sxIdent sxStaticParams sxNodeProfileOpt TK_EQ sxEffectiveNode sxOptSemicol 
	{ treat_node_alias false $2 $3 $4 $6 } ;

sxNodeProfileOpt :
	/* nada */
	{ None }
|	sxParams TK_RETURNS sxParams
	{
		let invars = clocked_ids_to_var_infos VarInput $1 in
		let outvars = clocked_ids_to_var_infos VarOutput $3 in
		Some (invars, outvars)
	}
;

sxStaticParams: /*rien*/
		{ [] }
	|	TK_OPEN_STATIC_PAR sxStaticParamList TK_CLOSE_STATIC_PAR
		{ (List.rev $2) }
;
sxStaticParamList:
		sxStaticParam
			{ [$1] }
	|	sxStaticParamList TK_SEMICOL sxStaticParam
			{ $3::$1 }
	;
sxStaticParam:
		TK_TYPE sxIdent
			{ {it=(StaticParamType (Lxm.id $2)); src=$2} }
	|	TK_CONST sxIdent TK_COLON sxType
			{ {it=(StaticParamConst (Lxm.id $2 , $4)); src=$2} }
	|	TK_NODE sxIdent sxParams TK_RETURNS sxParams 
	{
		let invars = clocked_ids_to_var_infos VarInput $3 in
		let outvars = clocked_ids_to_var_infos VarOutput $5 in
		let xn = StaticParamNode (
			Lxm.id $2,
			invars,
			outvars,
		        true
		) in
		Lxm.flagit xn $2
	}
	|	TK_FUNCTION sxIdent sxParams TK_RETURNS sxParams 
	{
		let invars = clocked_ids_to_var_infos VarInput $3 in
		let outvars = clocked_ids_to_var_infos VarOutput $5 in
		let xn = StaticParamNode (
			Lxm.id $2,
			invars,
			outvars,
		        false
		) in
		Lxm.flagit xn $2
	}
;
/* Le "."  la fin des noeuds est une fioriture historique,
	On accepte donc '.' ';' ou rien du tout !
*/
sxOptEndNode:
		TK_DOT
			{}
	|	sxOptSemicol
			{}
	;

/* Aucune difference entre params d'entre et les autres */
/* params de sortie */

sxParams:
		/* rien */
		TK_OPEN_PAR TK_CLOSE_PAR
			{ [] }
	|
		TK_OPEN_PAR sxVarDeclList sxOptSemicol TK_CLOSE_PAR
		  /* WARNING ! il faut remettre la liste  l'endroit */
			{ (List.rev $2) }
	;

/* variables locales */
sxLocals:	/* empty */
			{ [] }
	|    TK_VAR sxVarDeclList TK_SEMICOL
		  /* WARNING ! il faut remettre la liste  l'endroit */
			{ (List.rev $2) }
	;

/* liste de dclarations de vars types et clockes */
sxVarDeclList: sxVarDecl
			{ [$1] }
	|    sxVarDeclList TK_SEMICOL sxVarDecl
			{ $3::$1 }
	;

/* dclaration de vars ventuellement clockes */
sxVarDecl:
	/*
		Pas de clock : sous-entendu sur la base
		exemple: x, ..., z : type
	*/
		sxTypedIdents
		{
			([$1], Base)
		}
	|
	/*
		Clock explicite sur UNE seule liste d'idents typs
		exemple: x, ..., z : type when clock
	*/
		sxTypedIdents TK_WHEN sxIdent
		{
			([$1], (NamedClock {it=Lxm.id $3; src = $3} ))
		}
	|
	/*
		Clock explicite sur PLUSIEURS listes d'idents typs
		exemple: (x,..,z : t1 ; a,...,b : t2) when clock
	*/
		TK_OPEN_PAR sxTypedIdentsList TK_CLOSE_PAR TK_WHEN sxIdent
		/* WARNING ! il faut remettre la liste  l'endroit */
		{
			( (List.rev $2), (NamedClock {it=Lxm.id $5; src=$5} ) )
		}
	;

/* Corps d'un noeud */
/*
Retourne un couple (assertions list, equations list)
*/
sxBody:
      TK_LET TK_TEL
		{ ([], []) }
	|   TK_LET sxEquationList TK_TEL
	/* WARNING ! il faut remettre les listes  l'endroit */
		{ (List.rev (fst $2) , List.rev (snd $2)) }
	;

/* Equations */

sxEquationList:   sxEquation
	{ $1 }
	|   sxPragma sxEquation
	    { $2 }
	|   sxEquationList sxEquation
	{
		( (fst $2) @ (fst $1) , (snd $2) @ (snd $1) )
	}
	;
sxEquation:   TK_ASSERT sxExpression TK_SEMICOL
	{
		( [ {src = $1; it = $2} ] , [] )
	}
	|   sxLeft TK_EQ sxExpression TK_SEMICOL
	{
		( [] , [ {src = $2; it = ($1, $3) } ] )
	}
	;


/* partie gauche d'equation */

sxLeft:   sxLeftItemList
	/* WARNING ! il faut remettre la liste  l'endroit */
	{ (List.rev $1) }
	|   TK_OPEN_PAR sxLeftItemList TK_CLOSE_PAR
	/* WARNING ! il faut remettre la liste  l'endroit */
	{ (List.rev $2) }
	;

sxLeftItemList:   sxLeftItem
	{ [$1] }
	|   sxLeftItemList TK_COMA sxLeftItem 
	{ $3::$1 }
	;

sxLeftItem: sxIdent
	{ LeftVar ( {src = $1; it = Lxm.id $1} ) }
	|   sxFieldLeftItem 
	{ $1 }
	|   sxTableLeftItem
	{ $1 }
	;


sxFieldLeftItem: sxLeftItem TK_DOT sxIdent
	{ LeftField ($1 , {src = $3; it = Lxm.id $3} ) }
	;

sxTableLeftItem:
	    sxLeftItem TK_OPEN_BRACKET sxExpression TK_CLOSE_BRACKET
	{ LeftArray ($1 , {src = $2; it = $3})  }
	|   sxLeftItem TK_OPEN_BRACKET sxSelect TK_CLOSE_BRACKET
	{ LeftSlice ($1, $3 ) }
	;



/* partie droite d'equation (expression) */
sxExpression: 
	/* zroaires */
	    sxConstant { $1 }
	|   sxIdentRef    { leafexp $1.src (IDENT_n $1.it) }
	/* unaires */
	|   TK_NOT sxExpression      { unexp_predef $1 NOT_n $2 }
	|   TK_MINUS sxExpression %prec TK_UMINUS
	                             { unexp_predef $1 UMINUS_n $2 }
	|   TK_PRE sxExpression      { unexp $1 PRE_n $2 }
	|   TK_CURRENT sxExpression  { unexp $1 CURRENT_n $2 }
	|   TK_INT sxExpression      { unexp_predef $1 REAL2INT_n $2 }
	|   TK_REAL sxExpression     { unexp_predef $1 INT2REAL_n $2 }
	 /* binaires */
	|  sxExpression TK_FBY  sxExpression { binexp $2 FBY_n $1 $3 }
	|  sxExpression TK_ARROW sxExpression { binexp $2 ARROW_n $1 $3 }
	|  sxExpression TK_WHEN  sxExpression { binexp $2 WHEN_n $1 $3 }
	|  sxExpression TK_AND   sxExpression { binexp_predef $2 AND_n  $1 $3 }
	|  sxExpression TK_OR    sxExpression { binexp_predef $2 OR_n  $1 $3 }
	|  sxExpression TK_XOR   sxExpression { binexp_predef $2 XOR_n  $1 $3 }
	|  sxExpression TK_IMPL  sxExpression { binexp_predef $2 IMPL_n  $1 $3 }
	|  sxExpression TK_EQ    sxExpression { binexp_predef $2 EQ_n  $1 $3 }
	|  sxExpression TK_NEQ   sxExpression { binexp_predef $2 NEQ_n  $1 $3 }
	|  sxExpression TK_LT    sxExpression { binexp_predef $2 LT_n  $1 $3 }
	|  sxExpression TK_LTE   sxExpression { binexp_predef $2 LTE_n  $1 $3 }
	|  sxExpression TK_GT    sxExpression { binexp_predef $2 GT_n  $1 $3 }
	|  sxExpression TK_GTE   sxExpression { binexp_predef $2 GTE_n  $1 $3 }
	|  sxExpression TK_DIV   sxExpression { binexp_predef $2 DIV_n  $1 $3 }
	|  sxExpression TK_MOD   sxExpression { binexp_predef $2 MOD_n  $1 $3 }
	|  sxExpression TK_MINUS sxExpression { binexp_predef $2 MINUS_n  $1 $3 }
	|  sxExpression TK_PLUS  sxExpression { binexp_predef $2 PLUS_n  $1 $3 }
	|  sxExpression TK_SLASH sxExpression { binexp_predef $2 SLASH_n  $1 $3 }
	|  sxExpression TK_STAR  sxExpression { binexp_predef $2 TIMES_n  $1 $3 }
	/* ternaires */
	|  TK_IF sxExpression TK_THEN sxExpression TK_ELSE sxExpression
			{ ternexp_predef $1 IF_n $2 $4 $6 }
	|  TK_WITH sxExpression TK_THEN sxExpression TK_ELSE sxExpression
            { CallByPos( {src = $1 ; it = WITH_n($2, $4, $6) }, Oper [] ) }
	/* n-aires */
	/* WARNING ! il faut remettre la liste  l'endroit */
	|  TK_DIESE TK_OPEN_PAR sxExpressionList TK_CLOSE_PAR
			{ naryexp_predef $1 DIESE_n (List.rev $3) }
	|  TK_NOR TK_OPEN_PAR sxExpressionList TK_CLOSE_PAR
			{ naryexp_predef $1 NOR_n (List.rev $3) }
	| sxCallByPosExpression 
			{ $1 }
	|  TK_OPEN_PAR sxExpList2 TK_CLOSE_PAR
			{ naryexp $1 TUPLE_n (List.rev $2) }
	/* Oprations sur les tableaux */
	/* -> cration  partir d'une liste */
	|  TK_OPEN_BRACKET sxExpressionList TK_CLOSE_BRACKET
			{ naryexp $1 ARRAY_n (List.rev $2) }
	/* -> cration par exponentiation */
	|  sxExpression TK_HAT sxExpression { binexp $2 HAT_n $1 $3 }
	/* -> concatnation */
	|  sxExpression TK_BAR sxExpression { binexp $2 CONCAT_n $1 $3 }
	/* -> accs  un lment */
	|  sxExpression TK_OPEN_BRACKET sxExpression TK_CLOSE_BRACKET 
			{ unexp $2 (ARRAY_ACCES_n $3) $1 }
	/* -> accs  une tranche */
	|  sxExpression TK_OPEN_BRACKET sxSelect TK_CLOSE_BRACKET 
			{ unexp $3.src (ARRAY_SLICE_n $3.it) $1 }
	/* Acces aux structures */
	|  sxExpression TK_DOT sxIdent
			{ unexp $2 (STRUCT_ACCESS_n (Lxm.id $3)) $1 } 
	/* Appels par noms */
	|	sxCallByNameExpression 
			{ $1 }
	/* Parenthses */
	|  TK_OPEN_PAR sxExpression TK_CLOSE_PAR
			{ $2 }
	;

sxPredefOp:
	|   TK_NOT    { {src=$1; it=Predef(NOT_n,[])} }
	|   TK_FBY    { {src=$1; it=FBY_n} }
	|   TK_PRE    { {src=$1; it=PRE_n} }
	|   TK_CURRENT{ {src=$1; it=CURRENT_n} } 
	|   TK_ARROW  { {src=$1; it=ARROW_n} }
	|   TK_WHEN   { {src=$1; it=WHEN_n} }
	|   TK_AND    { {src=$1; it=Predef(AND_n,[]) } }
	|   TK_OR     { {src=$1; it=Predef(OR_n,[]) } }
	|   TK_XOR    { {src=$1; it=Predef(XOR_n,[]) } }
	|   TK_IMPL   { {src=$1; it=Predef(IMPL_n,[]) } }
	|   TK_EQ     { {src=$1; it=Predef(EQ_n,[]) } }
	|   TK_NEQ    { {src=$1; it=Predef(NEQ_n,[]) } }
	|   TK_LT     { {src=$1; it=Predef(LT_n,[]) } }
	|   TK_LTE    { {src=$1; it=Predef(LTE_n,[]) } }
	|   TK_GT     { {src=$1; it=Predef(GT_n,[]) } }
	|   TK_GTE    { {src=$1; it=Predef(GTE_n,[]) } }
	|   TK_DIV    { {src=$1; it=Predef(DIV_n,[]) } }
	|   TK_MOD    { {src=$1; it=Predef(MOD_n,[]) } }
	|   TK_MINUS  { {src=$1; it=Predef(MINUS_n,[]) } }
	|   TK_PLUS   { {src=$1; it=Predef(PLUS_n,[]) } }
	|   TK_SLASH  { {src=$1; it=Predef(SLASH_n,[]) } }
	|   TK_STAR   { {src=$1; it=Predef(TIMES_n,[]) } }
	|   TK_IF     { {src=$1; it=Predef(IF_n,[]) } }
;
/* Appel fonctionnel par position (classique) */
/* NB
	On a 2 rgles  cause des appels chantillonn
*/
sxCallByPosExpression:
		sxEffectiveNode TK_OPEN_PAR sxExpression TK_CLOSE_PAR
		{ naryexp $1.src (CALL_n $1) [$3] }
	/* WARNING ! il faut remettre la liste  l'endroit */
	|	sxEffectiveNode TK_OPEN_PAR sxExpList2 TK_CLOSE_PAR
		{ naryexp $1.src (CALL_n $1) (List.rev $3) }
	;

/* Effective node : une constrcution qui designe un noeud */

sxEffectiveNode:
	/* Juste un nom */
		sxIdentRef
			{ {src=$1.src; it=(($1.it, [])) } }
	/* Un nom + des params statiques */
	|	sxIdentRef TK_OPEN_STATIC_PAR sxStaticArgList TK_CLOSE_STATIC_PAR
			{ {src=$1.src; it=(($1.it, List.rev $3)) }	}
	/* Un operateur prdfini 
	|	TK_OPERATOR sxPredefOp,[]
			{ {src=$; it=($2.it, []) } }
	;
XXX pour l'instant, j'enleve la possibilit d'avoir
(operator +(1,2)). On verra ca plus tard
*/

sxStaticArgList: 
		sxStaticArg
		{ [$1] }
	|	sxStaticArgList TK_COMA sxStaticArg
		{ $3::$1 }
	/* let's be permissive... */
	|	sxStaticArgList TK_SEMICOL sxStaticArg
		{ $3::$1 }
	;

/* Faut se tordre l'esprit ici !
- la nature est explicite,
	  - la nature est immediate (type, const ou node predefini)
	  - la nature est sans ambiguite const (expressions simples)
	  - la nature est compile-time (juste un ident, a rsoudre)
	  */

sxStaticArg:
	  /* nature explicite */
	| TK_TYPE sxType 
	    { {src=$1 ; it=StaticArgType $2 } }
	| TK_CONST sxExpression
	    { {src=$1 ; it=StaticArgConst $2 } }
	| TK_NODE sxEffectiveNode
	    { {src=$1 ; it=StaticArgNode (CALL_n $2) } }
	| TK_FUNCTION sxEffectiveNode
	    { {src=$1 ; it=StaticArgNode (CALL_n $2) } }
	| sxPredefOp
			{ {src=$1.src; it=StaticArgNode $1.it } }
	  /* un ident OU une expression simple ( rsoudre) */
	  /* c'est au retour qu'on choisit */
	| sxSimpleExp
	    {
	      match $1 with 
		| CallByPos (op, x) -> (
		    match op.it with
		      | IDENT_n idref -> {src=op.src ; it = StaticArgIdent idref }
		      | _ -> {src=op.src ; it= StaticArgConst $1}
		  ) 
		| CallByName _ -> 
		    print_string "*** unexpected static argument\n";
		    assert false
	    }
		/* un type sans ambiguite */
	|	sxSurelyType
			{ {src=$1.src; it=StaticArgType $1} }
		/* un node sans ambiguite */
	|	sxSurelyNode
			{ {src=$1.src; it=StaticArgNode (CALL_n $1)} }
;

sxSurelyNode:
	|	sxIdentRef TK_OPEN_STATIC_PAR sxStaticArgList TK_CLOSE_STATIC_PAR
			{ {src=$1.src; it=($1.it, List.rev $3) }	}
;

sxSurelyType:
		/* prdfini */
	    TK_BOOL  { {src=$1; it=Bool_type_exp} }
	|   TK_INT   { {src=$1; it=Int_type_exp} }
	|   TK_REAL  { {src=$1; it=Real_type_exp} }
		/* ou tableau immdiat */
	|	sxSurelyType TK_HAT sxExpression
			{ {src=$1.src; it = Array_type_exp ($1 , $3) } }
	;

/* sxSimpleExp = statically evaluable exp */
sxSimpleExp:
		sxConstant { $1 }
	|  sxIdentRef    { leafexp $1.src (IDENT_n $1.it) }
	|  TK_OPEN_PAR sxSimpleExp TK_CLOSE_PAR { $2 }
	|  TK_NOT sxSimpleExp      { unexp_predef $1 NOT_n $2 }
	|  TK_MINUS sxSimpleExp %prec TK_UMINUS { unexp_predef $1 UMINUS_n $2 }
	|  sxSimpleExp TK_AND   sxSimpleExp { binexp_predef $2 AND_n  $1 $3 }
	|  sxSimpleExp TK_OR    sxSimpleExp { binexp_predef $2 OR_n  $1 $3 }
	|  sxSimpleExp TK_XOR   sxSimpleExp { binexp_predef $2 XOR_n  $1 $3 }
	|  sxSimpleExp TK_IMPL  sxSimpleExp { binexp_predef $2 IMPL_n  $1 $3 }
	|  sxSimpleExp TK_EQ    sxSimpleExp { binexp_predef $2 EQ_n  $1 $3 }
	|  sxSimpleExp TK_NEQ   sxSimpleExp { binexp_predef $2 NEQ_n  $1 $3 }
	|  sxSimpleExp TK_LT    sxSimpleExp { binexp_predef $2 LT_n  $1 $3 }
	|  sxSimpleExp TK_LTE   sxSimpleExp { binexp_predef $2 LTE_n  $1 $3 }
	|  sxSimpleExp TK_GT    sxSimpleExp { binexp_predef $2 GT_n  $1 $3 }
	|  sxSimpleExp TK_GTE   sxSimpleExp { binexp_predef $2 GTE_n  $1 $3 }
	|  sxSimpleExp TK_DIV   sxSimpleExp { binexp_predef $2 DIV_n  $1 $3 }
	|  sxSimpleExp TK_MOD   sxSimpleExp { binexp_predef $2 MOD_n  $1 $3 }
	|  sxSimpleExp TK_MINUS sxSimpleExp { binexp_predef $2 MINUS_n  $1 $3 }
	|  sxSimpleExp TK_PLUS  sxSimpleExp { binexp_predef $2 PLUS_n  $1 $3 }
	|  sxSimpleExp TK_SLASH sxSimpleExp { binexp_predef $2 SLASH_n  $1 $3 }
	|  sxSimpleExp TK_STAR  sxSimpleExp { binexp_predef $2 TIMES_n  $1 $3 }
	/* ternaires */
	|  TK_IF sxSimpleExp TK_THEN sxSimpleExp TK_ELSE sxSimpleExp
			{ ternexp_predef $1 IF_n $2 $4 $6 }
	;

/* Appel fonctionnel par nom */
/* NB
Actuellement, uniquement pour les structures,
donc pas de soucis d'chantillonnage
*/
sxCallByNameExpression:
	/* WARNING ! il faut remettre la liste  l'endroit */
	sxIdentRef TK_OPEN_BRACE sxCallByNameParamList sxOptSemicol TK_CLOSE_BRACE
		{ bynameexp $1.src (STRUCT_n $1.it) (List.rev $3) }
	/* on peut avoir une liste vide */
	| sxIdentRef TK_OPEN_BRACE TK_CLOSE_BRACE
		{ bynameexp $1.src (STRUCT_n $1.it) ([]) }
	/* COMPATIBILITY : immediate "struct" without the type name
	| TK_OPEN_BRACE sxCallByNameParamList sxOptSemicol TK_CLOSE_BRACE
		{ bynameexp $1 STRUCT_anonymous_n (List.rev $2) } */
	;

sxCallByNameParamList:
		sxCallByNameParam
			{ [$1] }
	|
		sxCallByNameParamList sepVariant sxCallByNameParam	
			{ $3::$1 }
	;

/* COMPATIBILITY : ',' or ';'  */
sepVariant:
	TK_SEMICOL
		{}
|	TK_COMA
		{ Errors.warning $1 "separator mismatch, ';' expected"}
;
	

sxCallByNameParam:
		sxIdent TK_EQ sxExpression
			{ ({it=Lxm.id $1;src=$1} , $3) }
	;

/* WARNING ! : les listes sont cres  l'envers */
sxExpressionList:   sxExpression
			{ [$1] }
	|   sxExpList2 
			{ $1 }
	;

sxConstant:   TK_TRUE
			{ (leafexp $1 (Predef(TRUE_n,[]))) }
	|   TK_FALSE
			{ (leafexp $1 (Predef(FALSE_n,[]))) }
	|   TK_ICONST 
			{ (leafexp $1 (Predef((ICONST_n (Lxm.id $1)),[]))) }
	|   TK_RCONST
			{ (leafexp $1 (Predef((RCONST_n (Lxm.id $1)),[]))) }
	;

/* WARNING ! : les listes sont cres  l'envers */
sxExpList2: sxExpressionList TK_COMA sxExpression 
			{ $3::$1 }
	;

sxSelect:
	   sxExpression TK_CDOTS sxExpression sxStep
		{ {it={si_first = $1; si_last = $3 ; si_step = $4 }; src = $2} }
| 	TK_SLICE_START sxExpression sxStep
		    { threat_slice_start $1 $2 $3 }
	;

sxStep: /* empty */
			{ None }
	|   TK_STEP sxExpression
			{ Some $2 }
	;
/* NB
SyntaxTree laxiste des listes :
quand il n'y a pas d'ambiguit,
les ";" sont vus indifferemment commme 
des sparateurs ou des terminateurs
*/
sxOptSemicol :
		/* empty */
		{}
	|   TK_SEMICOL 
		{}
	;

sxPragma: /* e.g., %ASSUME:toto% */
	{ [] } /* produces 3 shift reduce conflicts! */
|	TK_PCENT TK_IDENT TK_COLON TK_IDENT TK_PCENT sxPragma
		{ (Pragma(Lxm.str $2, Lxm.str $4))::$6 }