/*		
 *		GRAMophone II, a grammar based algorithmic musical composition tool
 *		-------------------------------------------------------------------
 *		
 *		Yacc/Bison Grammar
 *
 *		Copyright (c) 2007, Giovanni Ferranti <giovanni@giovanniferranti.it>
 *
 * 		GRAMophone II is free software; you can redistribute it and/or modify
 * 		it under the terms of the GNU General Public License as published by
 * 		the Free Software Foundation; either version 2 of the License, or
 * 		(at your option) any later version.
 *
 * 		This program 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 Library General Public License for more details.
 *
 *		You should have received a copy of the GNU General Public License along
 *		with this program; if not, write to the Free Software Foundation, Inc.,
 *		51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *		-------------------------------------------------------------------
 */

%token	DEFINE COMPOSITION OF AUTHOR GRAMMAR
%token	TEMPO RESOLUTION ITERATIONS CNTX_PREV CNTX_SUCC
%token	TIME_SIGNATURE VELOCITY PLAYER INSTRUMENT AXIOM
%token	CHOMSKY LINDENMAYER TRANSPOSE INVERSION RETROGRADE
%token	RETROGRADE_INV OCTAVE CHANNEL REPEAT MSB
%token	DURATION RELEASE AT_COMPOSITION STEP RAND UPDATE

%token	NOTE REST DEFNOTE DEFREST IDENTIFIER NUMBER MACRO 
%token	NON_TERMINAL STRING NONDET CHORD PRINT

%token	PLUS MINUS MULT DIVIDE MODULE EQ NE LT LE GT GE AND OR NOT ASSIGN PROD COND ELSE
%token  PLUSPLUS MINMIN

%{
   #include "global.h"
   #include "lex.yy.c"

   extern unsigned int global_resolution, global_iterations, global_params[];
   extern unsigned char grammarOption, probType, 
		           glob_num, glob_den, isGlobal;
   extern char *yytext, string_buf[], idTemp[];
   extern char *title, *copyright; 
   extern unsigned int tempo;
   unsigned char isDef=0;
   int ctrl[NUM_CTRL], ctrlTemp[MAX_RECURSION];
   unsigned int ec, cc, ccCond;
   pnote_var noteVarTemp, noteVarTempBis;
   unsigned char i, j=0, w=0;
%}

%start composition

%right ASSIGN
%left OR
%left AND
%left EQ NE
%left LT LE GT GE
%left PLUS MINUS
%left MULT DIVIDE MODULE
%left UMINUS PLUSPLUS MINMIN NOT
%left '('

%%

open_parenthesis
	:'('
	|error
		{
		  sntx_err(EXPECTED, "open parenthesis ");
		}
	;

close_parenthesis
	:')'
	|error
		{
		  sntx_err(EXPECTED, "closed parenthesis ");
		}
	;

expression
	:'(' expression ')'
		{
		  $$=$2; 
		}
	|id PLUSPLUS 	
		{
		  ctrl[1]=$1;
		}
	 stepPlus
	 	{
		  $$=$4;
		}
	|id MINMIN 	
		{
		  ctrl[1]=$1;
		}
	 stepMin
	 	{
		  $$=$4;
		}
	|MINUS expression	%prec UMINUS
		{
		  $$=-$2
		}
	|expression MULT expression
		{
		  $$=$1*$3;
		}
	|expression DIVIDE expression
		{
		  $$=$1/$3;
		}
	|expression MODULE expression
		{
		  $$=$1%$3;
		}		
	|expression PLUS expression
		{
		  $$=$1+$3;
		}
	|expression MINUS expression
		{
		  $$=$1-$3;
		}	
	|RAND open_parenthesis expression close_parenthesis
		{
		  $$=rand()%$3;
		}
	|id
	|unsigned
	;

stepPlus
	:	
		{
		  $$=++ctrl[1];
		  ctrl[1]=0;
		}
	|STEP unsigned	
		{
		  $$=ctrl[1]+=$2;
		  ctrl[1]=0;
		}
	;

stepMin
	:
		{
		  $$=--ctrl[1];
		  ctrl[1]=0;
		}
	|STEP unsigned
		{
		  $$=ctrl[1]-=$2;
		  ctrl[1]=0;
		}
	;

bool_expr
	:'(' bool_expr ')'
		{
		  $$=$2;
		}
	|NOT bool_expr
		{
		  gen_exp3_code(_NOT, $2, ctrl[2]);
		  $$=2;
		}		
	|bool_expr 
		{
		  ($1<2)?(ctrlTemp[w++]=ctrl[2]):(ctrlTemp[w++]=ctrl[1]);
		}
	 AND bool_expr
		{
		  gen_exp1_code(_AND, $1, ctrlTemp[--w], $4, ctrl[2]);
		  $$=2;
		}		
	|bool_expr 
		{  
		  ($1<2)?(ctrlTemp[w++]=ctrl[2]):(ctrlTemp[w++]=ctrl[1]);
		}
	 OR bool_expr
		{
		  gen_exp1_code(_OR, $1, ctrlTemp[--w], $4, ctrl[2]);
		  $$=2;
		}
	|translate_expression 
		{
		  ($1<2)?(ctrlTemp[w++]=ctrl[2]):(ctrlTemp[w++]=ctrl[1]);
		}
	 LT translate_expression
		{
		  gen_exp1_code(_LT, $1, ctrlTemp[--w], $4, ctrl[2]);
		  $$=2;
		}
	|translate_expression 
		{
		  ($1<2)?(ctrlTemp[w++]=ctrl[2]):(ctrlTemp[w++]=ctrl[1]);
		}
	 LE translate_expression
		{
		  gen_exp1_code(_LE, $1, ctrl[--w], $4, ctrl[2]);
		  $$=2;
		}
	|translate_expression 
		{
		  ($1<2)?(ctrlTemp[w++]=ctrl[2]):(ctrlTemp[w++]=ctrl[1]);
		}
	 GT translate_expression
		{
		  gen_exp1_code(_GT, $1, ctrl[--w], $4, ctrl[2]);
		  $$=2;
		}
	|translate_expression 
		{
		  ($1<2)?(ctrlTemp[w++]=ctrl[2]):(ctrlTemp[w++]=ctrl[1]);
		}
	 GE translate_expression
		{
		  gen_exp1_code(_GE, $1, ctrlTemp[--w], $4, ctrl[2]);
		  $$=2;
		}		
	|translate_expression 
		{
		  ($1<2)?(ctrlTemp[w++]=ctrl[2]):(ctrlTemp[w++]=ctrl[1]);
		}
	 EQ translate_expression
		{
		  gen_exp1_code(_EQ, $1, ctrlTemp[--w], $4, ctrl[2]);
		  $$=2;
		}
	|translate_expression 
		{
		  ($1<2)?(ctrlTemp[w++]=ctrl[2]):(ctrlTemp[w++]=ctrl[1]);
		}
	 NE translate_expression
		{
		  gen_exp1_code(_NE, $1, ctrlTemp[--w], $4, ctrl[2]);
		  $$=2;
		}
	|error
		{
		  sntx_err(EXPECTED, "boolean expression ");
		}
	;

translate_expression
	:assign_expr
		{
		  if(!ctrl[0] && $1==2 && !ctrl[13])
		    gen_exp4_code(_ENDEXP);
		  j=0;
		  $$=$1;
		}
	|expr
		{
		  if(ctrl[16])
			sntx_err(EXPECTED, "variable assignment ");
		  if(!ctrl[0] && $1==2 && !ctrl[13]) 
		    gen_exp4_code(_ENDEXP);
		  j=0;
		  $$=$1;
		}
	;

assign_expr
	:'(' assign_expr ')'
		{
		  $$=$2;
		}
	|asmId ASSIGN expr
		{
		  if($3==2) {
		    if(!ctrl[13])
		      gen_exp2_code(_MOV, $1, $3, ctrl[2]);
		    $$=2;
		  }
		  else {
			if(!ctrl[13]) {
		      if((players[playerCount]->productions[hash(idTemp, 0)]->
				 exp==NULL) &&
				 !(players[playerCount]->productions[hash(idTemp, 0)]->
		         exp=(pExp)malloc(sizeof(expression))))
		        sntx_err(MEMORY_ERR, "");			
		      gen_exp2_code(_MOV, $1, $3, ctrl[2]);			
			}  
		    $$=2;
		  }	
		}
	;	

expr
	:'(' expr ')'
		{
		  $$=$2;
		}
	|asmId PLUSPLUS stepAsm
		{
		  if(!ctrl[13]) {
		    if((players[playerCount]->productions[hash(idTemp, 0)]->
		       exp==NULL) &&
		       !(players[playerCount]->productions[hash(idTemp, 0)]->
		       exp=(pExp)malloc(sizeof(expression))))
		      sntx_err(MEMORY_ERR, "");   
		    gen_exp3_code(_INC, $1, $3);
		  } 
		  $$=2;
		}
	|asmId MINMIN stepAsm
		{
		  if(!ctrl[13]) {
		    if((players[playerCount]->productions[hash(idTemp, 0)]->
		       exp==NULL) &&
		       !(players[playerCount]->productions[hash(idTemp, 0)]->
		       exp=(pExp)malloc(sizeof(expression))))
		      sntx_err(MEMORY_ERR, ""); 
		    gen_exp3_code(_DEC, $1, $3);
		  }
		  $$=2;
		}
	|MINUS expr	%prec UMINUS
		{
		  if(!ctrl[13]) {
		    if((players[playerCount]->productions[hash(idTemp, 0)]->
		       exp==NULL) &&
		       !(players[playerCount]->productions[hash(idTemp, 0)]->
		       exp=(pExp)malloc(sizeof(expression))))
		      sntx_err(MEMORY_ERR, "");
		    gen_exp3_code(_UMIN, $2, ctrl[2]);
		  }
		  $$=2;
		}		
	|expr 
		{
		  if(!ctrl[13]) {
		    if((players[playerCount]->productions[hash(idTemp, 0)]->
		       exp==NULL) &&
		       !(players[playerCount]->productions[hash(idTemp, 0)]->
		       exp=(pExp)malloc(sizeof(expression))))
		      sntx_err(MEMORY_ERR, ""); 
			($1<2)?(ctrlTemp[j++]=ctrl[2]):(ctrlTemp[j++]=ctrl[1]);
		  }  
		}
	 MULT expr
		{
		  if(!ctrl[13])
		    gen_exp1_code(_MUL, $1, ctrlTemp[--j], $4, ctrl[2]);
		  $$=2;
		}
	|expr 
		{
		  if(!ctrl[13]) {
		    if((players[playerCount]->productions[hash(idTemp, 0)]->
		       exp==NULL) &&
		       !(players[playerCount]->productions[hash(idTemp, 0)]->
		       exp=(pExp)malloc(sizeof(expression))))
		      sntx_err(MEMORY_ERR, ""); 
			($1<2)?(ctrlTemp[j++]=ctrl[2]):(ctrlTemp[j++]=ctrl[1]);
		  }  
		}
	 DIVIDE expr
		{
		  if(!ctrl[13])
		    gen_exp1_code(_DIV, $1, ctrlTemp[--j], $4, ctrl[2]);
		  $$=2;
		}
	|expr 
		{
		  if(!ctrl[13]) {
			  if((players[playerCount]->productions[hash(idTemp, 0)]->
				  exp==NULL) &&
				 !(players[playerCount]->productions[hash(idTemp, 0)]->
				   exp=(pExp)malloc(sizeof(expression))))
				  sntx_err(MEMORY_ERR, ""); 
		  		($1<2)?(ctrlTemp[j++]=ctrl[2]):(ctrlTemp[j++]=ctrl[1]);
		  }  
		}
	MODULE expr
		{
		  if(!ctrl[13])
			  gen_exp1_code(_MOD, $1, ctrlTemp[--j], $4, ctrl[2]);
		  $$=2;
		}		
	|expr
		{ 
		  if(!ctrl[13]) {
		    if((players[playerCount]->productions[hash(idTemp, 0)]->
		       exp==NULL) &&
		       !(players[playerCount]->productions[hash(idTemp, 0)]->
		       exp=(pExp)malloc(sizeof(expression))))
		      sntx_err(MEMORY_ERR, ""); 
			($1<2)?(ctrlTemp[j++]=ctrl[2]):(ctrlTemp[j++]=ctrl[1]);
		  }    
		}
	 PLUS expr
		{
		  if(!ctrl[13])
		    gen_exp1_code(_ADD, $1, ctrlTemp[--j], $4, ctrl[2]);
		  $$=2;
		}
	|expr 
		{
		  if(!ctrl[13]) {
		    if((players[playerCount]->productions[hash(idTemp, 0)]->
		       exp==NULL) &&
		       !(players[playerCount]->productions[hash(idTemp, 0)]->
		       exp=(pExp)malloc(sizeof(expression))))
		      sntx_err(MEMORY_ERR, ""); 
			($1<2)?(ctrlTemp[j++]=ctrl[2]):(ctrlTemp[j++]=ctrl[1]);
		  }  
		}
	 MINUS expr
		{
		  if(!ctrl[13])
	 	    gen_exp1_code(_SUB, $1, ctrlTemp[--j], $4, ctrl[2]);
		  $$=2;
		}	
	|RAND open_parenthesis expr close_parenthesis
		{
		  if(!ctrl[13]) {
		    if((players[playerCount]->productions[hash(idTemp, 0)]->
		       exp==NULL) &&
		       !(players[playerCount]->productions[hash(idTemp, 0)]->
		       exp=(pExp)malloc(sizeof(expression))))
		      sntx_err(MEMORY_ERR, ""); 
		    /*if($3>1)
		      sntx_err(EXPECTED, "variable or positive integer ");*/
		    gen_exp3_code(_RND, $3, ctrl[2]);
		  }
		  $$=2;
		}
	|asmId
		{
		  ctrl[2]=$1;
		  $$=1;
		}
	|unsigned
		{
		  ctrl[2]=$1;
		  $$=0;
		}
	;

id	
	:IDENTIFIER
		{
		  switch(isGlobal) {
		    case 0:
		      if(!(noteVarTempBis=(pnote_var)dhSearch(yytext, 0)) && 
		         !(noteVarTempBis=(pnote_var)dhSearch(yytext, 1)))	 
				sntx_err(VAR_NOT_DECLARED, "");
			  break;	
		    case 1:
		      if(!(noteVarTempBis=(pnote_var)dhSearch(yytext, 1)))
		        sntx_err(VAR_NOT_DECLARED, "");
		  }  
		  if(noteVarTempBis->type!=noteVarTemp->type)
		    sntx_err(TYPE_ERR, "");
		  $$=noteVarTempBis->value;
		}
	;

stepAsm
	:
		{
		  $$=1;
		}
	|STEP unsigned
		{
		  $$=$2;
		}
	;

asmId
	:IDENTIFIER
		{
		  $$=hash(yytext, 1);
		}
	;

composition
	:define_part composition_header orchestra
	;
	
define_part
	:COMPOSITION
		{
		  back();
		}
	|DEFINE
		{
		  isDef=1;
		}
	 IDENTIFIER 
		{
		  strcpy(idTemp, yytext);
		}
	 string
		{
		  if(++macroCount>NUM_MACRO)
		    sntx_err(TOO_MANY_MACROS, "");
		  dhInsert(NULL, idTemp, 2);
		  isDef=0;
		}
	 define_part
	|error
		{
		  if(isDef)
		    sntx_err(EXPECTED, "identifier ");
		  else
		    sntx_err(EXPECTED, "keyword 'composition' ");	
		}  
	;

string
	:STRING
	|error
		{
		  sntx_err(EXPECTED, "string ");
		}
	;
	
composition_header
	:COMPOSITION composition_title composition_author
	|error
		{
		  sntx_err(EXPECTED, "keyword 'composition' ");
		}
	;

composition_title
	:STRING
		{
		  if(!(title=(char *)malloc((1+strlen(string_buf))
									*sizeof(char))))
		    sntx_err(MEMORY_ERR, "");
		  strcpy(title, string_buf);
		}
	|error
		{
		  sntx_err(EXPECTED, "string ");
		}
	;	

composition_author
	:OF author_data
	|error
		{
		  sntx_err(EXPECTED, "keyword 'of' ");
		}

author_data
	:STRING
		{
		  if(!(copyright=(char *)malloc((1+strlen(string_buf))
		  				*sizeof(char))))
		    sntx_err(MEMORY_ERR, "");
		  strcpy(copyright, string_buf);
		}
	|error
		{
		  sntx_err(EXPECTED, "string ");
		}
	;
	
orchestra
	:'{' global_param_decl_part var_decl 
	 	{
		  isGlobal=0;
		}
	 players_part 
	|error
		{
		  sntx_err(EXPECTED, "orchestra block ");
		}
	;

global_param_decl_part
	:'%'
		{
		  ctrl[0]=ctrl[1]=ctrl[2]=ctrl[3]=ctrl[4]=ctrl[5]=ctrl[6]=
		  ctrl[7]=ctrl[8]=ctrl[9]=ctrl[10]=0;		
		}
	|GRAMMAR
		{
		  if(ctrl[0]++)
		    sntx_err(ALREADY, "keyword 'grammar' ");
		}
	 grammar_type 
	 	{
		  grammarOption=$3;
		}
	 global_param_decl_part
	|TEMPO
		{
		  if(ctrl[1]++)
		    sntx_err(ALREADY, "keyword 'tempo' ");
		}
	 unsigned 
	 	{
		  if(($3<1) || ($3>300))
		    sntx_err(TEMPO_OUT, "");
		  tempo=$3;  
		}
	 global_param_decl_part
	|RESOLUTION
		{
		  if(ctrl[2]++)
		    sntx_err(ALREADY, "keyword 'resolution' ");
		}
	 unsigned 
	 	{
		  if(($3<24) || ($3>960))
		    sntx_err(RES_OUT, "");
		  global_resolution=$3;  
		}
	 global_param_decl_part
	|ITERATIONS
		{
		  if(ctrl[3]++)
		    sntx_err(ALREADY, "keyword 'iterations' ");
		}
	 unsigned 
	 	{
		  if($3<1)
		    sntx_err(IT_OUT, "");
		  global_iterations=$3;
		}
	 global_param_decl_part
	|TIME_SIGNATURE
		{
		  if(ctrl[4]++)
		    sntx_err(ALREADY, "keyword 'time_signature' ");
		}
	 fraction global_param_decl_part
	|OCTAVE
		{
		  if(ctrl[5]++)
		    sntx_err(ALREADY, "keyword 'octave' ");
		}
	 signed
	 	{
		  if(($3<-2) || ($3>8))
		    sntx_err(OCTAVE_OUT, "");
		  global_params[DEFOCT]=$3;  
		}
	 global_param_decl_part
	|VELOCITY
		{
		  if(ctrl[6]++)
		    sntx_err(ALREADY, "keyword 'velocity' ");
		}
	 unsigned 
	 	{
		  if($3>127)
		    sntx_err(OUT, "'velocity' value ");
		  global_params[DEFVEL]=$3;  
		}
	 global_param_decl_part    	
	;
	|DURATION
		{
		  if(ctrl[7]++)
		    sntx_err(ALREADY, "keyword 'duration' ");
		}
	 unsigned 
	 	{
		  global_params[DEFDUR]=$3;
		}
	 global_param_decl_part
	|RELEASE
		{
		  if(ctrl[8]++)
		    sntx_err(ALREADY, "keyword 'release' ");
		}
	 unsigned 
	 	{
		  if($3>127)
		    sntx_err(OUT, "'release' value ");
		  global_params[DEFREL]=$3;  
		}
	 global_param_decl_part
	|MSB
		{
		  if(ctrl[9]++)
		    sntx_err(ALREADY, "keyword 'msb' ");
		}
	 unsigned
	 	{
		  if($3>127)
		    sntx_err(OUT, "'msb' value ");
		  global_params[DEFMSB]=$3;  
		}
	 global_param_decl_part 
	|INSTRUMENT
		{
		  if(ctrl[10]++)
		    sntx_err(ALREADY, "keyword 'instrument' ");
		}
	 unsigned
	 	{
		  if($3>127)
		    sntx_err(OUT, "'instrument' value ");
		  global_params[DEFINSTR]=$3;  
		}
	 global_param_decl_part
	;
	
grammar_type
	:CHOMSKY
		{
		  $$=$1;
		}
	|LINDENMAYER
		{
		  $$=$1;
		}
	|error
		{
		  sntx_err(EXPECTED, "grammar type ");
		}
	;
	
unsigned
	:NUMBER
		{
		  $$=$1;
		}
	|error
		{
		  sntx_err(EXPECTED, "positive integer ");
		}
	;
	
signed
	:NUMBER
		{
		  $$=$1;
		}
	|MINUS NUMBER
		{
		  $$=-$2;
		}
	|error
		{
		  sntx_err(EXPECTED, "positive or negative integer ");
		}
	;

fraction
	:NUMBER
		{
		  if(($1<1) || ($1>64))
		    sntx_err(NUMERATOR_OUT, "");
		  if(isGlobal)
		    glob_num=$1;
		  else
		    players[playerCount]->num=$1;
		}
	 div	
	 unsigned
	 	{
		  if($4!=1 && $4!=2 && $4!=4 &&$4!=8 && $4!=16 && $4!=32 && 
		     $4!=64)
		    sntx_err(FRACTION_DEN_ERR, "");
		  if(isGlobal)
		    glob_den=$3;
		  else
		    players[playerCount]->den=$3;
		}
	|error
		{
		  sntx_err(EXPECTED, "fraction of form num/den ");
		}
	;

div
	:DIVIDE
	|error
		{
		  sntx_err(EXPECTED, "fraction symbol '/' ");
		}
	;			
	      
var_decl
	:PLAYER
		{
		  ctrl[0]=0;
		  back();
		}
	|AXIOM
		{
		  ctrl[0]=0;
		  back();
		}
	|AT_COMPOSITION
		{
		  ctrl[0]=ctrl[1]=0;
		  back();
		}
	|type
		{
		  noteVarTemp->type=ctrl[0];
		}
	 assign_list semicolon var_decl		
	|error
		{
		  if(isGlobal)
		    sntx_err(PLAYER_EXPECTED, "");
		  else
		    switch(players[playerCount]->grammar) {
		      case 0:
		        switch(grammarOption) {
		        case 1:
		          sntx_err(EXPECTED, "@composition production ");
		        case 2:		
		          sntx_err(EXPECTED, "axiom production ");
		        }
		      case 1:  
		        sntx_err(EXPECTED, "@composition production ");
		      case 2:
		        sntx_err(EXPECTED, "axiom production ");
		    }  
		}
	;

semicolon
	:';'
	|error
		{
			sntx_err(EXPECTED, "semicolon ");
		}

type
	:OCTAVE
		{
	  	  ctrl[0]=OCT;
		}  
	|VELOCITY
		{
		  ctrl[0]=VEL;
		}
	|DURATION
		{
		  ctrl[0]=DUR;
		}  
	|RELEASE
		{
		  ctrl[0]=REL;
		}
	|MSB
		{
		  ctrl[0]=BYTEDATA;
		}	
	;

assign_list
	:assign
	|assign_list comma assign
	|error
		{
		  sntx_err(EXPECTED, "identifier ");
		}
	;
	
comma
	:','
	|error
		{
			sntx_err(EXPECTED, "comma ");
		}

assign
	:IDENTIFIER
		{
		  if(++varCount>NUM_VARS)
		    sntx_err(TOO_MANY_VARS, "");
		  strcpy(noteVarTemp->name, yytext);
		}
	 inizialization	
	;

inizialization
	:
		{
		  dhInsert(noteVarTemp, "", isGlobal);
		}
	|ASSIGN expression
		{
		  switch(ctrl[0]) {
		    case OCT:
			  $$=$2;
			  if($$<-2)
			    $$=-2;
			  if($$>8)
			    $$=8;	
			  break;
			case DUR:
			  if(($$=$2)<0)
			    $$=0;	
			  break;
			case BYTEDATA:
			  $$=$2;
			  if($$<-127)
			    $$=-127;
			  if($$>127)
				$$=127;
			  break;	  
			default:
			  $$=$2;
			  if($$<0)
			    $$=0;
			  if($$>127)
			    $$=127;	
		  }
		  //printf("%s %d\n", noteVarTemp->name, $$); DEBUG LINE!
		  noteVarTemp->value=$$;
		  dhInsert(noteVarTemp, "", isGlobal);
		}
	;

players_part
	:'}'
	|player_part
		{
		  playerCount++;
		}
	 players_part
	|error
		{
		  sntx_err(EXPECTED, "end of orchestra block ('}') ");
		}
	;
	
player_part
	:PLAYER
		{
		  init_local_flag();
		  if(playerCount>NUM_PLAYERS)
		    sntx_err(TOO_MANY_PLAYERS, "");
		  init_player();  
		  varCount=0;  
		}
	 IDENTIFIER
		{
		  if(!(players[playerCount]->identifier=(char *)
		  				       malloc((1+strlen(yytext))
						       *sizeof(char))))
		    sntx_err(MEMORY_ERR, "");
		  strcpy(players[playerCount]->identifier, yytext);
		}
	 player_block
	|error
		{
		  sntx_err(EXPECTED, "identifier ");
		}
	;

player_block
	:'{' local_param_decl_part var_decl player_productions
	|error
		{
		  sntx_err(EXPECTED, "player block ");
		}
	;

local_param_decl_part
	:'%'
		{
		  if(!loc_par_flag[0] && !grammarOption)
		    sntx_err(GRAMMAR_EXPECTED, "");	
		}
	|GRAMMAR
		{
		  if(loc_par_flag[0]++)
		    sntx_err(ALREADY, "keyword 'grammar' ");
		}
	 grammar_type 
	 	{
		  players[playerCount]->grammar=$3;
		}
	 local_param_decl_part
	|ITERATIONS
		{
		  if(loc_par_flag[1]++)
		    sntx_err(ALREADY, "keyword 'iterations' ");
		}
	 unsigned 
	 	{
		  if($3<1)
		    sntx_err(IT_OUT, "");
		  players[playerCount]->iterations=$3;  
		}
	 local_param_decl_part
	|TIME_SIGNATURE
		{
		  if(loc_par_flag[2]++)
		    sntx_err(ALREADY, "keyword 'time_signature' ");
		}
	 fraction local_param_decl_part
	|OCTAVE
		{
		  if(loc_par_flag[3]++)
		    sntx_err(ALREADY, "keyword 'octave' ");
		}
	 signed
	 	{
		  if(($3<-2) || ($3>8))
		    sntx_err(OCTAVE_OUT, "");
		  players[playerCount]->local_params[DEFOCT]=$3;  
		}
	 local_param_decl_part
	|VELOCITY
		{
		  if(loc_par_flag[4]++)
		    sntx_err(ALREADY, "keyword 'velocity' ");
		}
	 unsigned 
	 	{
		  if($3>127)
		    sntx_err(OUT, "'velocity' value ");
		  players[playerCount]->local_params[DEFVEL]=$3;  
		}
	 local_param_decl_part 
	|DURATION
		{
		  if(loc_par_flag[5]++)
		    sntx_err(ALREADY, "keyword 'duration' ");
		}
	 unsigned 
	 	{
		  players[playerCount]->local_params[DEFDUR]=$3;
		}
	 local_param_decl_part
	|RELEASE
		{
		  if(loc_par_flag[6]++)
		    sntx_err(ALREADY, "keyword 'release' ");
		}
	 unsigned 
	 	{
		  if($3>127)
		    sntx_err(OUT, "'release' value ");
		  players[playerCount]->local_params[DEFREL]=$3;  
		}
	 local_param_decl_part
	|MSB
		{
		  if(loc_par_flag[7]++)
		    sntx_err(ALREADY, "keyword 'msb' ");
		}
	 unsigned
	 	{
		  if($3>127)
		    sntx_err(OUT, "'msb' value ");
		  players[playerCount]->local_params[DEFMSB]=$3;  
		}
	 local_param_decl_part  
	|INSTRUMENT
		{
		  if(loc_par_flag[8]++)
		    sntx_err(ALREADY, "keyword 'instrument' ");
		}
	 unsigned
	 	{
		  if($3>127)
		    sntx_err(OUT, "'instrument' value ");
		  players[playerCount]->local_params[DEFINSTR]=$3;  
		}
	 local_param_decl_part	
	|CHANNEL
		{
		  if(loc_par_flag[9]++)
		    sntx_err(ALREADY, "keyword 'channel' ");
		}
	 unsigned
	 	{
		  if($3>15)
		    sntx_err(CHN_OUT, "");
		  players[playerCount]->local_params[CHN]=$3;  
		}
	 local_param_decl_part
	|error
		{
		  if(!loc_par_flag[0] && !grammarOption)
		    sntx_err(GRAMMAR_EXPECTED, "");
		  else
		    sntx_err(EXPECTED, "'%' ");
		}
	;

player_productions
	:chomsky_composition_prod
	|lindenmayer_axiom_prod
	;
	
chomsky_composition_prod
	:AT_COMPOSITION
		{
		  switch(players[playerCount]->grammar) {
		    case 0:
		      if(grammarOption==2)
		        sntx_err(EXPECTED, "axiom production ");
		      break;	
		    case 2:
		      sntx_err(EXPECTED, "axiom production ");
		  }
		  strcpy(idTemp, yytext);
		  dhInsert(NULL, idTemp, 3, 0);
		}
	 condition chomsky_prod_assign alternative_chomsky chomsky_productions
	;

condition
	:PROD
		{
		  back();
		}
	|COND
		{
		  ctrl[17]++;
		  if((players[playerCount]->productions[hash(idTemp, 0)]->
		     exp==NULL) &&
		     !(players[playerCount]->productions[hash(idTemp, 0)]->
		     exp=(pExp)malloc(sizeof(expression))))
		    sntx_err(MEMORY_ERR, "");
		  ec=players[playerCount]->productions[hash(idTemp, 0)]->ec;
		  //gen_code(_EXP, );
		  ctrl[0]++;  
		}
	 bool_expr
	 	{
		  w=0;
		  gen_exp4_code(_ENDEXP);
		  //gen_code2(_CHK, ec);
		  gen_code(_CHK, ec);
		  ccCond=(players[playerCount]->productions[hash(idTemp, 0)]->cc)-1;
		  ctrl[0]=ctrl[1]=ctrl[2]=ctrl[3]=0;
		}
	|error
		{
		  sntx_err(EXPECTED, "condition or operator '->' ");
		}
	;

alternative_chomsky
	:
	|ELSE
		{
		  (!ctrl[17])?(sntx_err(ELSE_WITHOUT_CONDITION, "")):(ctrl[17]++);
		  gen_code2(_ELSE);
		  gen_code(_PRD_ALT, players[playerCount]
		  	  	   ->productions[hash(idTemp, 0)]->numOrAlt);
		  cc=(players[playerCount]->productions[hash(idTemp, 0)]->cc)-1;
		  code_update(cc, ccCond);
		}
	 chomsky_prod_body
	;

alternative_lindenmayer
	:
	|ELSE
		{
		  (!ctrl[17])?(sntx_err(ELSE_WITHOUT_CONDITION, "")):(ctrl[17]++);
		  gen_code2(_ELSE);
		  gen_code(_PRD_ALT, players[playerCount]
		  	  	   ->productions[hash(idTemp, 0)]->numOrAlt);					 
		  cc=(players[playerCount]->productions[hash(idTemp, 0)]->cc)-1;
		  code_update(cc, ccCond);		  
		}
	 lindenmayer_prod_body
	;
	
chomsky_prod_assign
	:PROD
		{
		  if(players[playerCount]->productions[hash(idTemp, 0)]->numOr==1)
		    gen_code(_PRD, players[playerCount]
		  	  	     ->productions[hash(idTemp, 0)]->numOr);			 
		}
	 chomsky_prod_body
	|error
		{
		  sntx_err(EXPECTED, "operator '->' ");
		}
	;

chomsky_prod_body
	:';'
		{
			if(ctrl[17]==2)
				ctrl[17]=0;
		}		
	|chomsky_seq chomsky_prod_body
	|error
		{
		  sntx_err(EXPECTED, "semicolon ");
		}
	;

chomsky_seq
	:note
		{
		  (ctrl[4]<0)?(gen_note_code(_EMPTY, ctrl[4], ctrl[5], ctrl[6], ctrl[7], ctrl[8], ctrl[9], ctrl[10], ctrl[11], ctrl[12])):(gen_note_code(_NOTEON, ctrl[4], ctrl[5], ctrl[6], ctrl[7], ctrl[8], ctrl[9], ctrl[10], ctrl[11], ctrl[12]));		  
		  ctrl[4]=ctrl[5]=ctrl[6]=ctrl[7]=ctrl[8]=ctrl[9]=ctrl[10]=ctrl[11]=ctrl[12]=0;
		}
	|CHORD
		{
		  gen_code2(_CHORD);		  
		}
	 note_seq
	|DEFNOTE
		{
		   ctrl[4]=$1;
		   if(loc_par_flag[4])
		     ctrl[5]=players[playerCount]->local_params[DEFOCT];
		   else
		     ctrl[5]=global_params[DEFOCT];
		   if(loc_par_flag[5])
		     ctrl[6]=players[playerCount]->local_params[DEFVEL];
		   else
		     ctrl[6]=global_params[DEFVEL];
		   if(loc_par_flag[6])
		     ctrl[7]=players[playerCount]->local_params[DEFDUR];
		   else
		     ctrl[7]=global_params[DEFDUR];
		   if(loc_par_flag[7])
		     ctrl[8]=players[playerCount]->local_params[DEFREL];
		   else
		     ctrl[8]=global_params[DEFREL];
		  (ctrl[4]<0)?(gen_note_code(_EMPTY, ctrl[4], 0, ctrl[5], 0, ctrl[6], 0, ctrl[7], 0, ctrl[8])):(gen_note_code(_NOTEON, ctrl[4], 0, ctrl[5], 0, ctrl[6], 0, ctrl[7], 0, ctrl[8]));		  
		  ctrl[4]=ctrl[5]=ctrl[6]=ctrl[7]=ctrl[8]=0;
		}
	|REST begin duration 
		{
		  gen_code3(_REST, ctrl[9], ctrl[10]);		  
		  ctrl[1]=ctrl[2]=ctrl[3]=ctrl[9]=ctrl[10]=0;
		}
	 end
	|AT_COMPOSITION
		{
		  gen_code(_GOTO, hash(yytext, 0));		  
		}
	|NON_TERMINAL
		{
		  if(!players[playerCount]->productions[hash(yytext, 0)])
		    dhInsert(NULL, yytext, 3, 1);
		  gen_code(_GOTO, hash(yytext, 0));		  
		}
	|TRANSPOSE
	 open_parenthesis msb
		{
		  gen_code3(_TRN, ctrl[4], ctrl[5]);		  
		}
	 comma melodic_op_chomsky_seq 
	 	{
		  ctrl[1]=ctrl[2]=ctrl[3]=ctrl[4]=ctrl[5]=0;
		}
	|INVERSION 
		{
		  gen_code2(_INV);		  
		}
	 open_parenthesis melodic_op_chomsky_seq
	|RETROGRADE 
		{
		  gen_code2(_RTRGD);		  
		}
	 open_parenthesis melodic_op_chomsky_seq
	|RETROGRADE_INV
		{
		  gen_code2(_RTGINV);		  
		}
	 open_parenthesis melodic_op_chomsky_seq
	|REPEAT open_parenthesis msb 
		{
		  gen_code3(_REP, ctrl[4], ctrl[5]);		  
		  ctrl[15]++;
		}
	 comma chomsky_rep_seq
	|UPDATE begin
		{
		  ctrl[16]++;
		}
	 exp_init translate_expression
		{
		  gen_code3(_UPDATE, ec, ctrl[3]);		  
		}
	 end
		{
		  ctrl[1]=ctrl[2]=ctrl[3]=ctrl[16]=0;
		}
	|NONDET
		{
		  if(ctrl[15])
		    sntx_err(REPEAT_ERR, "");	
		  (ctrl[17]==2)?(gen_code(_PRD_ALT, ++players[playerCount]->productions[hash(idTemp, 0)]->numOrAlt)):(gen_code(_PRD, ++players[playerCount]->productions[hash(idTemp, 0)]->numOr)); 
		}
	|PRINT open_parenthesis exp_init print_seq close_parenthesis		  
	;

print_seq
	:		
	|translate_expression
		{
			ctrl[5]=_EXP;
			if(!ctrl[13])
				ctrl[6]=ec;
			switch($1) {
				case 0:
				  ctrl[5]=0;	
				  ctrl[6]=ctrl[2];
				  break;
				case 1:
				  ctrl[5]=1;
				  ctrl[6]=ctrl[2];
			}
			gen_code4(_PRNT, ctrl[5], ctrl[6], ctrl[3]);
			ctrl[1]=ctrl[2]=ctrl[3]=ctrl[4]=ctrl[5]=ctrl[6]=0;
		}
	 print_seq exp_init
	|STRING
		{
			if(stringCount>MAX_STR)
				sntx_err(TOO_MANY_STRINGS, "");		
			if(!(strings[stringCount]=(char *)malloc((1+strlen(string_buf))
							*sizeof(char))))
				sntx_err(MEMORY_ERR, "");
			strcpy(strings[stringCount], string_buf);
			gen_code3(_PRNT, _STR, stringCount++);
		}
	 print_seq	
	;
	
chomsky_rep_seq
	:close_parenthesis
		{
		  gen_code2(_ENDREP);
		  ctrl[15]=0;
		}  
	|chomsky_seq chomsky_rep_seq
	;

endchord
	:CHORD
	|error
		{
		  sntx_err(EXPECTED, "end of chord '^' ");
		}
	;

note_seq
	:endchord
		{
		  gen_code2(_ENDCHORD);
		}
	|note
		{
		  (ctrl[4]<0)?(gen_note_code(_EMPTY, ctrl[4], ctrl[5], ctrl[6], ctrl[7], ctrl[8], ctrl[9], ctrl[10], ctrl[11], ctrl[12])):(gen_note_code(_NOTEON, ctrl[4], ctrl[5], ctrl[6], ctrl[7], ctrl[8], ctrl[9], ctrl[10], ctrl[11], ctrl[12]));
		  ctrl[4]=ctrl[5]=ctrl[6]=ctrl[7]=ctrl[8]=ctrl[9]=ctrl[10]=
		  ctrl[11]=ctrl[12]=0;
		}
	 note_seq
	|AT_COMPOSITION
		{
		  gen_code(_GOTO, hash(yytext, 0));
		}
	 note_seq 
	|NON_TERMINAL
		{
		  if(!players[playerCount]->productions[hash(yytext, 0)])
		    dhInsert(NULL, yytext, 3, 1);		
		  gen_code(_GOTO, hash(yytext, 0));
		}
	 note_seq
	|REST begin duration
		{
		  gen_code3(_REST, ctrl[9], ctrl[10]);
		  ctrl[1]=ctrl[2]=ctrl[3]=ctrl[9]=ctrl[10]=0;		
		}
	 end note_seq	 	
	;

note_seq_bis
	:endchord
		{
		  gen_code2(_ENDCHORD);
		}  
	|note	
		{
		  (ctrl[4]<0)?(gen_note_code(_EMPTY, ctrl[4], ctrl[5], ctrl[6], ctrl[7], ctrl[8], ctrl[9], ctrl[10], ctrl[11], ctrl[12])):(gen_note_code(_NOTEON, ctrl[4], ctrl[5], ctrl[6], ctrl[7], ctrl[8], ctrl[9], ctrl[10], ctrl[11], ctrl[12]));
		  ctrl[4]=ctrl[5]=ctrl[6]=ctrl[7]=ctrl[8]=ctrl[9]=ctrl[10]=
		  ctrl[11]=ctrl[12]=0;
		}
	 note_seq_bis
	|REST begin duration
		{
		  gen_code3(_REST, ctrl[9], ctrl[10]);
		  ctrl[1]=ctrl[2]=ctrl[3]=ctrl[9]=ctrl[10]=0;		
		}
	 end note_seq_bis
	;

note_seq_tre
	:endchord
		{
		  //strcat(idTemp, yytext);
		}
	|note
		{
		  if(ctrl[4]<0)
			sntx_err(SILENT_ERR, "");
		  if(ctrl[5]|ctrl[7]|ctrl[9]|ctrl[11])
		    sntx_err(EXPECTED, "constant chord ");
		  sprintf(string_buf, "%d%d%d%d%d", ctrl[4], ctrl[6], ctrl[8], ctrl[10], ctrl[12]);
		  strcat(idTemp, string_buf);
		  strcpy(string_buf, "");
		  ctrl[4]=ctrl[5]=ctrl[6]=ctrl[7]=ctrl[8]=ctrl[9]=ctrl[10]=
		  ctrl[11]=ctrl[12]=0;
		}
	 note_seq_tre	
	|REST begin duration
		{
		  if(ctrl[9])
		    sntx_err(EXPECTED, "constant chord ");
		  sprintf(string_buf, "%d", ctrl[10]);
		  strcat(idTemp, string_buf);
		  strcpy(string_buf, "");
		  ctrl[4]=ctrl[9]=ctrl[10]=0;
		}
	 end note_seq_tre	
	;

melodic_op_chomsky_seq
	:close_parenthesis
		{
		  gen_code2(_ENDMELOP);
		}
	|note 
		{ 
		  (ctrl[4]<0)?(gen_note_code(_EMPTY, ctrl[4], ctrl[5], ctrl[6], ctrl[7], ctrl[8], ctrl[9], ctrl[10], ctrl[11], ctrl[12])):(gen_note_code(_NOTEON, ctrl[4], ctrl[5], ctrl[6], ctrl[7], ctrl[8], ctrl[9], ctrl[10], ctrl[11], ctrl[12]));
		  ctrl[4]=ctrl[5]=ctrl[6]=ctrl[7]=ctrl[8]=ctrl[9]=ctrl[10]=
		  ctrl[11]=ctrl[12]=0;
		}
	 melodic_op_chomsky_seq
	|REST begin duration
		{
		  gen_code3(_REST, ctrl[9], ctrl[10]);
		  ctrl[1]=ctrl[2]=ctrl[3]=ctrl[9]=ctrl[10]=0;		
		}
	 end melodic_op_chomsky_seq	 
	|CHORD
		{
		  gen_code2(_CHORD);
		}
	 note_seq melodic_op_chomsky_seq	 
	|NON_TERMINAL
		{
		  if(!players[playerCount]->productions[hash(yytext, 0)])
		    dhInsert(NULL, yytext, 3, 1);		
		  gen_code(_GOTO, hash(yytext, 0));
		}
	 melodic_op_chomsky_seq
	|AT_COMPOSITION 
		{ 
		  gen_code(_GOTO, hash(yytext, 0));
		}
	 melodic_op_chomsky_seq
	|TRANSPOSE open_parenthesis exp_init msb
		{
		  gen_code3(_TRN, ctrl[4], ctrl[5]);
		}
	 comma melodic_op_chomsky_seq melodic_op_chomsky_seq
	 	{
		  ctrl[1]=ctrl[2]=ctrl[3]=ctrl[4]=ctrl[5]=0;
		}
	|INVERSION
		{
		  gen_code2(_INV);
		}
	 open_parenthesis melodic_op_chomsky_seq melodic_op_chomsky_seq
	|RETROGRADE
		{
		  gen_code2(_RTRGD);
		}
	 open_parenthesis melodic_op_chomsky_seq melodic_op_chomsky_seq
	|RETROGRADE_INV
		{
		  gen_code2(_RTGINV);
		}
	 open_parenthesis melodic_op_chomsky_seq melodic_op_chomsky_seq 
	;

exp_init
	:
		{
			if(!ctrl[13])
			  ec=players[playerCount]->productions[hash(idTemp, 0)]->ec;  
		}
	;

note
	:NOTE
		{
		  ctrl[4]=$1;
		}
	 begin exp_init octave comma
	 	{
		  ctrl[1]=ctrl[2]=ctrl[3]=0;
		}
	 exp_init velocity comma
	 	{
		  ctrl[1]=ctrl[2]=ctrl[3]=0;
		}
	 exp_init duration comma
	 	{
		  ctrl[1]=ctrl[2]=ctrl[3]=0;
		}
	 exp_init release 
	 	{
		  ctrl[1]=ctrl[2]=ctrl[3]=0;
		}
	 end
	;
	
begin
	:'['
	|error
		{
		  sntx_err(EXPECTED, "'[' ");
		}
	;

end
	:']'
	|error
		{
		  sntx_err(EXPECTED, "']' ");
		}
	;

octave
	:
		{
		   ctrl[5]=0;
		   if(loc_par_flag[3])
		     ctrl[6]=players[playerCount]->local_params[DEFOCT];
		   else
		     ctrl[6]=global_params[DEFOCT];
		}
	|translate_expression
		{
		  if(ctrl[3] && ctrl[3]!=OCT)
		    sntx_err(EXPECTED, "variable of type octave ");
		  ctrl[5]=_EXP;  
		  if(!ctrl[13])
		    ctrl[6]=ec;
		  switch($1) {
		    case 0:
		      ctrl[5]=0;
		      if(ctrl[2]>8)
		        ctrl[2]=8;
			  if(ctrl[2]<-2)
			    ctrl[2]=-2;	
		      ctrl[6]=ctrl[2];
		      break;
		    case 1:
		      ctrl[5]=1;
		      ctrl[6]=ctrl[2];
		  }
		}
	;

velocity
	:
		{
		  ctrl[7]=0;
		  if(loc_par_flag[4])
		    ctrl[8]=players[playerCount]->local_params[DEFVEL];
		  else
		    ctrl[8]=global_params[DEFVEL];
		}
	|translate_expression
		{ 
		  if(ctrl[3] && ctrl[3]!=VEL)
		    sntx_err(EXPECTED, "variable of type velocity ");
		  ctrl[7]=_EXP;  
		  if(!ctrl[13])  
		    ctrl[8]=ec;
		  switch($1) {
		    case 0:
		      ctrl[7]=0;
		      if(ctrl[2]>127)
		        ctrl[2]=127;
			  if(ctrl[2]<0)
			    ctrl[2]=0;	
		      ctrl[8]=ctrl[2];
		      break;
		    case 1:
		      ctrl[7]=1;
		      ctrl[8]=ctrl[2];
		  }
		}	
	;

duration
	:
		{
		  ctrl[9]=0;
		  if(loc_par_flag[5])
		    ctrl[10]=players[playerCount]->local_params[DEFDUR];
		  else
		    ctrl[10]=global_params[DEFDUR];
		}
	|translate_expression
		{
		  if(ctrl[3] && ctrl[3]!=DUR)
		    sntx_err(EXPECTED, "variable of type duration ");
		  ctrl[9]=_EXP;  
		  if(!ctrl[13]) 
		    ctrl[10]=ec;
		  switch($1) {
		    case 0:
		      ctrl[9]=0;
			  if(ctrl[2]<0)
			    ctrl[2]=0;
		      ctrl[10]=ctrl[2];
		      break;
		    case 1:
		      ctrl[9]=1;
		      ctrl[10]=ctrl[2];
		  }
		}		
	;

release
	:
		{
		  ctrl[11]=0;
		  if(loc_par_flag[6])
		    ctrl[12]=players[playerCount]->local_params[DEFREL];
		  else
		    ctrl[12]=global_params[DEFREL];
		}
	|translate_expression
		{
		  if(ctrl[3] && ctrl[3]!=REL)
		    sntx_err(EXPECTED, "variable of type release ");
		  ctrl[11]=_EXP;  
		  if(!ctrl[13]) 
		    ctrl[12]=ec;
		  switch($1) {
		    case 0:
		      ctrl[11]=0;
		      if(ctrl[2]>127)
		        ctrl[2]=127;
			  if(ctrl[2]<0)
			    ctrl[2]=0;	
		      ctrl[12]=ctrl[2];
		      break;
		    case 1:
		      ctrl[11]=1;
		      ctrl[12]=ctrl[2];
		  }
		}		
	;
	
msb
	:
		{
		  ctrl[4]=0;
		  if(loc_par_flag[7])
		    ctrl[5]=players[playerCount]->local_params[DEFMSB];
		  else
		    ctrl[5]=global_params[DEFMSB];
		}
	|translate_expression
		{
		  if(ctrl[3] && ctrl[3]!=BYTEDATA)
		    sntx_err(EXPECTED, "variable of type msb ");
		  ctrl[4]=_EXP;  
		  if(!ctrl[13])  
		    ctrl[5]=ec;
		  switch($1) {
		    case 0:
		      ctrl[4]=0;
		      if(ctrl[2]>127)
		        ctrl[2]=127;
			  if(ctrl[2]<-127)
			    ctrl[2]=-127;	
		      ctrl[5]=ctrl[2];
		      break;
		    case 1:
		      ctrl[4]=1;
		      ctrl[5]=ctrl[2];
		  }
		}
	;	

chomsky_productions
	:'}'
	|NON_TERMINAL
		{
		  strcpy(idTemp, yytext);
		  dhInsert(NULL, idTemp, 3, 0);
		}

	 condition chomsky_prod_assign alternative_chomsky chomsky_productions	
	|error
		{
		  sntx_err(EXPECTED, "end of player block ('}') ");
		}
	;
	
lindenmayer_axiom_prod
	:AXIOM
		{
		  switch(players[playerCount]->grammar) {
		    case 0:
		      if(grammarOption==1)
		        sntx_err(EXPECTED, "@composition production ");
		      break;	
		    case 1:
		      sntx_err(EXPECTED, "@composition production ");
		  } 
		  strcpy(idTemp, yytext);
		  dhInsert(NULL, idTemp, 3, 0);
		}
	 condition lindenmayer_prod_assign
	 	{
		  ctrl[13]++;
		}
	 alternative_lindenmayer lindenmayer_productions
	;

lindenmayer_prod_assign
	:PROD
		{
		  gen_code(_PRD, players[playerCount]
		  		   ->productions[hash(idTemp, 0)]->numOr);
		}
	 lindenmayer_prod_body
	|error
		{
		  sntx_err(EXPECTED, "operator '->' ");
		}
	;

lindenmayer_prod_body
	:';'
		{
			if(ctrl[17]==2)
				ctrl[17]=0;
		}	
	|lindenmayer_seq lindenmayer_prod_body
	|error
		{
		  sntx_err(EXPECTED, "semicolon ");
		}
	;

lindenmayer_seq
	:note
		{
		  (ctrl[4]<0)?(gen_note_code(_EMPTY, ctrl[4], ctrl[5], ctrl[6], ctrl[7], ctrl[8], ctrl[9], ctrl[10], ctrl[11], ctrl[12])):(gen_note_code(_NOTEON, ctrl[4], ctrl[5], ctrl[6], ctrl[7], ctrl[8], ctrl[9], ctrl[10], ctrl[11], ctrl[12]));		  
		  ctrl[4]=ctrl[5]=ctrl[6]=ctrl[7]=ctrl[8]=ctrl[9]=ctrl[10]=
		  ctrl[11]=ctrl[12]=0;
		}
	|CHORD
		{
		  gen_code2(_CHORD);		  
		}
	 note_seq_bis
	|DEFNOTE
		{
		   ctrl[4]=$1;
		   if(loc_par_flag[4])
		     ctrl[5]=players[playerCount]->local_params[DEFOCT];
		   else
		     ctrl[5]=global_params[DEFOCT];
		   if(loc_par_flag[5])
		     ctrl[6]=players[playerCount]->local_params[DEFVEL];
		   else
		     ctrl[6]=global_params[DEFVEL];
		   if(loc_par_flag[6])
		     ctrl[7]=players[playerCount]->local_params[DEFDUR];
		   else
		     ctrl[7]=global_params[DEFDUR];
		   if(loc_par_flag[7])
		     ctrl[8]=players[playerCount]->local_params[DEFREL];
		   else
		     ctrl[8]=global_params[DEFREL];
		  (ctrl[4]<0)?(gen_note_code(_EMPTY, ctrl[4], 0, ctrl[5], 0, ctrl[6], 0, ctrl[7], 0, ctrl[8])):(gen_note_code(_NOTEON, ctrl[4], 0, ctrl[5], 0, ctrl[6], 0, ctrl[7], 0, ctrl[8]));		  
		  ctrl[4]=ctrl[5]=ctrl[6]=ctrl[7]=ctrl[8]=0;
		}
	|REST begin duration 
		{
		  gen_code3(_REST, ctrl[9], ctrl[10]);		  
		  ctrl[1]=ctrl[2]=ctrl[3]=ctrl[9]=ctrl[10]=0;
		}
	 end
	|TRANSPOSE open_parenthesis msb
		{
		  gen_code3(_TRN, ctrl[4], ctrl[5]);
		  if(ctrl[17]==2) {
			cc=(players[playerCount]->productions[hash(idTemp, 0)]->cc)-1;
			code_update(cc, ccCond);
			ctrl[17]=0;
		  }		  
		}
	 comma melodic_op_lindenmayer_seq
	 	{
		  ctrl[1]=ctrl[2]=ctrl[3]=ctrl[4]=ctrl[5]=0;
		}
	|INVERSION 
		{
		  gen_code2(_INV);		  
		}
	 open_parenthesis melodic_op_lindenmayer_seq
	|RETROGRADE 
		{
		  gen_code2(_RTRGD);		  
		}
	 open_parenthesis melodic_op_lindenmayer_seq
	|RETROGRADE_INV
		{
		  gen_code2(_RTGINV);		  
		}
	 open_parenthesis melodic_op_lindenmayer_seq
	|REPEAT open_parenthesis msb 
		{
		  gen_code3(_REP, ctrl[4], ctrl[5]);		  
		}
	 comma lindenmayer_rep_seq
	|UPDATE begin
		{
		  ctrl[16]++;
		}
	 exp_init translate_expression
		{
		  gen_code3(_UPDATE, ec, ctrl[3]);		  
		}
	 end
		{
		 ctrl[1]=ctrl[2]=ctrl[3]=ctrl[16]=0;
		}
	|NONDET
		{
		  (ctrl[17]==2)?(gen_code(_PRD_ALT, ++players[playerCount]->productions[hash(idTemp, 0)]->numOrAlt)):(gen_code(_PRD, ++players[playerCount]->productions[hash(idTemp, 0)]->numOr));						   
		}
	|PRINT open_parenthesis print_seq close_parenthesis		  
	;

melodic_op_lindenmayer_seq
	:close_parenthesis
		{
		  gen_code2(_ENDMELOP);
		}
	|note 
		{ 
		  (ctrl[4]<0)?(gen_note_code(_EMPTY, ctrl[4], ctrl[5], ctrl[6], ctrl[7], ctrl[8], ctrl[9], ctrl[10], ctrl[11], ctrl[12])):(gen_note_code(_NOTEON, ctrl[4], ctrl[5], ctrl[6], ctrl[7], ctrl[8], ctrl[9], ctrl[10], ctrl[11], ctrl[12]));
		  ctrl[4]=ctrl[5]=ctrl[6]=ctrl[7]=ctrl[8]=ctrl[9]=ctrl[10]=
		  ctrl[11]=ctrl[12]=0;
		}
	 melodic_op_chomsky_seq
	|CHORD
		{
		  gen_code2(_CHORD);
		}
	 note_seq_bis melodic_op_lindenmayer_seq	 
	|REST begin duration
		{
		  gen_code3(_REST, ctrl[9], ctrl[10]);
		  ctrl[1]=ctrl[2]=ctrl[3]=ctrl[9]=ctrl[10]=0;		
		}
	 end melodic_op_chomsky_seq	 
	|TRANSPOSE open_parenthesis msb
		{
		  gen_code3(_TRN, ctrl[4], ctrl[5]);
		}
	 comma melodic_op_lindenmayer_seq melodic_op_lindenmayer_seq
	 	{
		  ctrl[1]=ctrl[2]=ctrl[3]=ctrl[4]=ctrl[5]=0;
		}
	|INVERSION
		{
		  gen_code2(_INV);
		}
	 open_parenthesis melodic_op_lindenmayer_seq 
	 melodic_op_lindenmayer_seq
	|RETROGRADE
		{
		  gen_code2(_RTRGD);
		}
	 open_parenthesis melodic_op_lindenmayer_seq 
	 melodic_op_lindenmayer_seq
	|RETROGRADE_INV
		{
		  gen_code2(_RTGINV);
		}
	 open_parenthesis melodic_op_lindenmayer_seq 
	 melodic_op_lindenmayer_seq 
	;

lindenmayer_rep_seq
	:close_parenthesis
		{
		  gen_code2(_ENDREP);
		}  
	|lindenmayer_seq lindenmayer_rep_seq
	;

lindenmayer_productions
	:'}'
	|note
		{
		  if(ctrl[4]<0)
			sntx_err(SILENT_ERR, "");
		  if(ctrl[5]|ctrl[7]|ctrl[9]|ctrl[11])
		    sntx_err(EXPECTED, "constant note ");
		  strcpy(idTemp, "");
		  sprintf(string_buf, "%d%d%d%d%d", ctrl[4], ctrl[6], ctrl[8], ctrl[10], ctrl[12]);
		  strcat(idTemp, string_buf);
		  strcpy(string_buf, "");
		  dhInsert(NULL, idTemp, 3, 0);
		  ctrl[4]=ctrl[5]=ctrl[6]=ctrl[7]=ctrl[8]=ctrl[9]=ctrl[10]=
		  ctrl[11]=ctrl[12]=ctrl[13]=0;
		}
	 condition lindenmayer_prod_assign 
	 	{
		  ctrl[13]++;
		}
	 alternative_lindenmayer lindenmayer_productions
	|CHORD
		{
		  strcpy(idTemp, "");
		  //strcat(idTemp, yytext);
		}
	 note_seq_tre
	 	{
		  dhInsert(NULL, idTemp, 3, 0);  
		  ctrl[13]=0;
		}
	 condition lindenmayer_prod_assign 
	 	{
		  ctrl[13]++;
		}
	 alternative_lindenmayer lindenmayer_productions
	|REST begin duration
		{
		  if(ctrl[9])
		    sntx_err(EXPECTED, "constant note ");
		  strcpy(idTemp, "");
		  sprintf(string_buf, "%d", ctrl[10]);
		  strcat(idTemp, string_buf);
		  strcpy(string_buf, "");
		  dhInsert(NULL, idTemp, 3, 0);
		  ctrl[4]=ctrl[9]=ctrl[10]=ctrl[13]=0;		  	
		}
	 end condition lindenmayer_prod_assign
		{
			ctrl[13]++;
		}
	 alternative_lindenmayer lindenmayer_productions	
	|error
		{
		  sntx_err(EXPECTED, "end of player block ('}') ");
		}
	;

%%

int yyerror() {
}

int back() {
  yyless(0);
}
