/*		
 *		GRAMophone II, a grammar based algorithmic musical composition tool
 *		--------------------------------------------------------------------
 *
 *		Lex/Flex definitions
 *
 *		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.
 *		--------------------------------------------------------------------
 */

D		[0-9]
L		[a-z_]


%{
#include <string.h>
#include "GRAMophone.tab.h"
#define MAX_INCLUDE_DEPTH	64
YY_BUFFER_STATE strbuf, include_stack[MAX_INCLUDE_DEPTH];

unsigned char include_stack_ptr=1;
extern char string_buf[];
char *string_buf_ptr;
unsigned int countStr;
unsigned int row=1;
void count();
%}

%x comment comment2 string incl
%%

"/*"				BEGIN(comment);
<comment>[^*\n]*
<comment>"*"+[^/\n]*
<comment>\n			{++row;}
<comment><<EOF>>	sntx_err(EOF, "");
<comment>"*"+"/"	BEGIN(INITIAL);

"//"	BEGIN(comment2);
<comment2>[^\n]*
<comment2><<EOF>> sntx_err(EOF, "");
<comment2>\n		{
					  ++row;
					  BEGIN(INITIAL);
					}

"discography"		{BEGIN(incl);}  

<incl>[ \t\v\n\f\r]*
<incl>[^ \t\n]+		{
					  if(include_stack_ptr>=MAX_INCLUDE_DEPTH)
					    sntx_err(TOO_DEEPLY, "");
					  include_stack[include_stack_ptr++]=YY_CURRENT_BUFFER;
					  yyin=fopen(yytext, "r");
					  if(!yyin)
					    sntx_err(DISCOGRAPHY_NOT_FOUND, "");
					  yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
					  BEGIN(INITIAL);				       
					}

<<EOF>>				{
					  if(--include_stack_ptr<1)
						yyterminate();
					  else {
						yy_delete_buffer(YY_CURRENT_BUFFER);
						yy_switch_to_buffer(include_stack[include_stack_ptr]);
					  }
					}
"+"					{return(PLUS);}
"-"					{return(MINUS);}
"*"					{return(MULT);}
"/"					{return(DIVIDE);}
"mod"				{return(MODULE);}
"++"				{return(PLUSPLUS);}
"--"				{return(MINMIN);}
"=="				{return(EQ);}
"!="				{return(NE);}
"<"					{return(LT);}
"<="				{return(LE);}
">"					{return(GT);}
">="				{return(GE);}
"||"				{return(OR);}
"&&"				{return(AND);}
"|"					{return(NONDET);}
"="					{return(ASSIGN);}
"->"				{return(PROD);}
"?"					{return(COND);}
":"					{return(ELSE);}
"!"					{return(NOT);}
"{"					{return('{');}
"}"					{return('}');}
"["					{return('[');}
"]"					{return(']');}
"("					{return('(');}
")"					{return(')');}
","					{return(',');}
";"					{return(';');}
"%"					{return('%');}
"^"					{return(CHORD);}
"<<"				{return(CNTX_PREV);}
">>"				{return(CNTX_SUCC);}
"step"				{return(STEP);}
"define"			{return(DEFINE);}
"composition"		{return(COMPOSITION);}
"of"				{return(OF);}
"author"			{return(AUTHOR);}
"grammar"			{return(GRAMMAR);}
"tempo"				{return(TEMPO);}
"resolution"		{return(RESOLUTION);}
"iterations"		{return(ITERATIONS);}
"time_signature"	{return(TIME_SIGNATURE);}
"velocity"			{return(VELOCITY);}
"release"			{return(RELEASE);}
"duration"			{return(DURATION);}
"player"			{return(PLAYER);}
"instrument"		{return(INSTRUMENT);}
"axiom"				{return(AXIOM);}
"@composition"		{return(AT_COMPOSITION);}
"chomsky"			{ 
					  yylval=1;
					  return(CHOMSKY); 
					}
"lindenmayer"		{ 
					  yylval=2;
					  return(LINDENMAYER); 
					}
"transpose"			{return(TRANSPOSE);}
"inversion"			{return(INVERSION);}
"retrograde"		{return(RETROGRADE);}
"retrograde_inv"	{return(RETROGRADE_INV);}
"repeat"			{return(REPEAT);}
"octave"			{return(OCTAVE);}
"channel"			{return(CHANNEL);}
"rand"				{return(RAND);}
"update_var"		{return(UPDATE);}
"msb"				{return(MSB);}
"print"				{return(PRINT);}

"A"					{
					  yylval=9;
					  return(NOTE); 
					}
"A#"				{
					  yylval=10;
					  return(NOTE);
					}
"Ab"				{
					  yylval=8;
					  return(NOTE);
					}
"B"					{
					  yylval=11;
					  return(NOTE);
					}
"B#"				{
					  yylval=0;
					  return(NOTE);
					}
"Bb"				{
					  yylval=10;
					  return(NOTE);
					}
"C"					{
					  yylval=0;
					  return(NOTE);
					}
"C#"				{
					  yylval=1;
					  return(NOTE);
					}
"Cb"				{
					  yylval=11;
					  return(NOTE);
					}
"D"					{
					  yylval=2;
					  return(NOTE);
					}
"D#"				{
					  yylval=3;
					  return(NOTE);
					}
"Db"				{
					  yylval=1;
					  return(NOTE);
					}
"E"					{
					  yylval=4;
					  return(NOTE);
					}
"E#"				{
					  yylval=5;
					  return(NOTE);
					}
"Eb"				{
					  yylval=3;
					  return(NOTE);
					}
"F"					{
					  yylval=5;
					  return(NOTE);
					}
"F#"				{
					  yylval=6;
					  return(NOTE);
					}
"Fb"				{
					  yylval=4;
					  return(NOTE);
					}		
"G"					{
					  yylval=7;
					  return(NOTE);
					}
"G#"				{
					  yylval=8;
					  return(NOTE);
					}
"Gb"				{
					  yylval=6;
					  return(NOTE);
					}
"R"					{
					  return(REST);
					}
"N"					{
					  yylval=-1;
					  return(NOTE);
					}

{L}({L}|{D}|_)*		{
					  if(strlen(yytext)>VAR_LENGTH)
					    sntx_err(TOO_LONG, "variable identifier ");
					  if(check_id()==MACRO) {
						strbuf=YY_CURRENT_BUFFER;
						yy_switch_to_buffer(
											yy_scan_buffer((char *)
											dhSearch2(yytext), YY_BUF_SIZE));							
					  }
					  else
						return(IDENTIFIER);
					  }

[\0]				{
					  yy_delete_buffer(YY_CURRENT_BUFFER);
					  yy_switch_to_buffer(strbuf);
					}

{D}+				{
					  yylval=atoi(yytext);
					  return(NUMBER); 
					}

"@"{L}({L}|{D}|_)*	{return(NON_TERMINAL);}

\"					{
					  string_buf_ptr=string_buf;
					  countStr=0;
					  BEGIN(string); 
					}
<string>\"			{ 
					  BEGIN(INITIAL); 
					  *string_buf_ptr='\0';
					  if(countStr>MAX_STR)
					    sntx_err(TOO_LONG, "string ");
					  return(STRING); 
					}
<string>\n			sntx_err(UNTERMINATED_STR, "");
<string>\\n			{
					  ++countStr;
					  *string_buf_ptr++='\n';
					}
<string>\\t			{
					  ++countStr;
					  *string_buf_ptr++='\t';
					}  
<string>\\r			{
					  ++countStr;
					  *string_buf_ptr++='\r';
					}
<string>\\b			{
					  ++countStr;
					  *string_buf_ptr++='\b';
					}
<string>\\f			{
					  ++countStr;
					  *string_buf_ptr++='\f';
					}
<string>\\(.|\n)	{
					  ++countStr;
					  *string_buf_ptr++=yytext[1];
					}
<string>[^\\\n\"]+	{
					  char *yptr=yytext;
					  while(*yptr) {
					    ++countStr;
					    *string_buf_ptr++=*yptr++;
					  }
					}
"\n"				{++row;}
[ \t\v\f\n]		
.					{ /* ignore bad characters */ }

%%

#ifndef yywrap
yywrap() {
  return(1);
}
#endif

int check_id() {
  if(dhSearch2(yytext)!='\0')
    return MACRO;  
  else
    return IDENTIFIER;
}
