/*
 *  YACC Grammar file for Config File Parser
 */

%{
//#define HOST_DEBUG

#include <stdlib.h>
#include <stdio.h>

#include "G168_UART_Interface.h"
#include "COMET_Support.h"

#define YY_ACCEPT return(0)
#define YY_ABORT  return(1)

int param1;
int param2;

/* prototype for lexer function */
int yylex(void);

/* prototypes for error handling functions */
int  yyerror         (char * pErrorMsg);

int size; char str[YY_BUF_SIZE];

%}

/////* Type definition for terminal symbols (symbols received from lexer) */
////%union {
////  int   intVal;
////}

/* Definition of terminal TOKENS to be provided by lexer */
%token G168_CONFIG
%token G168_STATUS
%token LAST_ERROR
%token VERSION
%token DOUBLE_TALK_DETECTED
%token CONVERGED
%token READ_COEFFS
%token INTEGER
%token STRING
%token FREEZE
%token NLP_SUPP_THRESH
%token NLP_GAIN
%token LEAK_RATE_THRESH
%token NLP_ENABLE
%token ENABLE
%token RIN_BUFF_LEN
%token RIN_BUFF_BASE
%token SIN_BUFF_LEN
%token SIN_BUFF_BASE
%token SOUT_BUFF_LEN
%token SOUT_BUFF_BASE
%token SET_COEFFS
%token TEST;
%token COMET_READ_REG
%token COMET_WRITE_REG
%token ALL
%token NOTHING
%token DASH
%token RANGE
%token READ_MEM_8
%token READ_MEM_16
%token READ_MEM_32
%token WRITE_MEM_8
%token WRITE_MEM_16
%token WRITE_MEM_32

%%  /*  Grammar rules and actions follow  */
command:
  G168_CONFIG INTEGER FREEZE INTEGER
  {
    size = sprintf(str, "G168_CONFIG %d FREEZE %d;\n\r", $2, $4);
    YY_OUTPUT(str, size);
  }
  |
  G168_CONFIG INTEGER NLP_SUPP_THRESH INTEGER
  {
  	size = sprintf(str, "G168_CONFIG %d NLP_SUPP_THRESH %d;\n\r", $2, $4);
    YY_OUTPUT(str, size);
  }
  |
  G168_CONFIG INTEGER NLP_GAIN INTEGER
  {
    size = sprintf(str, "G168_CONFIG %d NLP_GAIN %d;\n\r", $2, $4);
    YY_OUTPUT(str, size);
  }
  |
  G168_CONFIG INTEGER LEAK_RATE_THRESH INTEGER
  {
    size = sprintf(str, "G168_CONFIG %d LEAK_RATE_THRESH %d;\n\r", $2, $4);
    YY_OUTPUT(str, size);
  }
  |
  G168_CONFIG INTEGER NLP_ENABLE INTEGER
  {
    size = sprintf(str, "G168_CONFIG %d NLP_ENABLE %d;\n\r", $2, $4);
    YY_OUTPUT(str, size);
  }
  |
  G168_CONFIG INTEGER ENABLE INTEGER
  {
    size = sprintf(str, "G168_CONFIG %d ENABLE %d;\n\r", $2, $4);
    YY_OUTPUT(str, size);
  }
  |
  G168_CONFIG INTEGER RIN_BUFF_LEN INTEGER
  {
    size = sprintf(str, "G168_CONFIG %d RIN_BUFF_LEN %d;\n\r", $2, $4);
    YY_OUTPUT(str, size);
  }
  |
  G168_CONFIG INTEGER RIN_BUFF_BASE INTEGER
  {
    size = sprintf(str, "G168_CONFIG %d RIN_BUFF_BASE %d;\n\r", $2, $4);
    YY_OUTPUT(str, size);
  }
  |
  G168_CONFIG INTEGER SIN_BUFF_LEN INTEGER
  {
    size = sprintf(str, "G168_CONFIG %d SIN_BUFF_LEN %d;\n\r", $2, $4);
    YY_OUTPUT(str, size);
  }
  |
  G168_CONFIG INTEGER SIN_BUFF_BASE INTEGER
  {
    size = sprintf(str, "G168_CONFIG %d SIN_BUFF_BASE %d;\n\r", $2, $4);
    YY_OUTPUT(str, size);
  }
  |
  G168_CONFIG INTEGER SOUT_BUFF_LEN INTEGER
  {
    size = sprintf(str, "G168_CONFIG %d SOUT_BUFF_LEN %d;\n\r", $2, $4);
    YY_OUTPUT(str, size);
  }
  |
  G168_CONFIG INTEGER SOUT_BUFF_BASE INTEGER
  {
    size = sprintf(str, "G168_CONFIG %d SOUT_BUFF_BASE %d;\n\r", $2, $4);
    YY_OUTPUT(str, size);
  }
  |
  G168_CONFIG INTEGER SET_COEFFS INTEGER
  {
    size = sprintf(str, "G168_CONFIG %d SET_COEFFS %d;\n\r", $2, $4);
    YY_OUTPUT(str, size);
  }
  |
  G168_STATUS INTEGER LAST_ERROR
  {
    size = sprintf(str, "G168_STATUS %d LAST_ERROR;\n\r", $2);
    YY_OUTPUT(str, size);
  }
  |
  G168_STATUS INTEGER VERSION
  {
    size = sprintf(str, "G168_STATUS %d VERSION;\n\r", $2);
    YY_OUTPUT(str, size);
  }
  |
  G168_STATUS INTEGER DOUBLE_TALK_DETECTED
  {
    size = sprintf(str, "G168_STATUS %d DOUBLE_TALK_DETECTED;\n\r", $2);
    YY_OUTPUT(str, size);
  }
  |
  G168_STATUS INTEGER CONVERGED
  {
    size = sprintf(str, "G168_STATUS %d CONVERGED;\n\r", $2);
    YY_OUTPUT(str, size);
  }
  |
  G168_STATUS INTEGER READ_COEFFS
  {
    size = sprintf(str, "G168_STATUS %d READ_COEFFS;\n\r", $2);
    YY_OUTPUT(str, size);
  }
  |
  COMET_READ_REG INTEGER INTEGER
  {
  	unsigned char temp;
    size = sprintf(str, "COMET_READ_REG 0x%x 0x%x;\n\r", $2, $3);
    YY_OUTPUT(str, size);
  	temp = COMET_readReg($2, $3);
    size = sprintf(str, "COMET_READ_REG (0x%x, 0x%x) -> 0x%x;\n\r", $2, $3, temp);
    YY_OUTPUT(str, size);
  }
  |
  COMET_READ_REG INTEGER RANGE INTEGER INTEGER
  {
  	unsigned char temp;
 	int i;
    size = sprintf(str, "COMET_READ_REG 0x%x 0x%x-0x%x;\n\r", $2, $4, $5);
    YY_OUTPUT(str, size);
    for (i = $4; i < $5; i++) {
	  	temp = COMET_readReg($2, i);
	    size = sprintf(str, "COMET_READ_REG (0x%x, 0x%x) -> 0x%x;\n\r", $2, i, temp);
	    YY_OUTPUT(str, size);
    }
  }
  |
  COMET_READ_REG INTEGER ALL
  {
  	unsigned char temp;
  	int i;
    size = sprintf(str, "COMET_READ_REG 0x%x ALL;\n\r", $2, $3);
    YY_OUTPUT(str, size);
    for (i = 0; i < 128; i++) {
	  	temp = COMET_readReg($2, i);
	    size = sprintf(str, "COMET_READ_REG (0x%x, 0x%x) -> 0x%x;\n\r", $2, i, temp);
	    YY_OUTPUT(str, size);
    }
  }  
  |
  COMET_WRITE_REG INTEGER INTEGER INTEGER
  {
    size = sprintf(str, "COMET_WRITE_REG 0x%x 0x%x 0x%x;\n\r", $2, $3, $4);
    YY_OUTPUT(str, size);
  	COMET_writeReg($2, $3, $4);	
    size = sprintf(str, "COMET_WRITE_REG (0x%x, 0x%x, 0x%x);\n\r", $2, $3, $4);
    YY_OUTPUT(str, size);
  }
  |
  READ_MEM_8 INTEGER
  {
  	char temp;
    size = sprintf(str, "READ_MEM_8 0x%x;\n\r", $2);
    YY_OUTPUT(str, size);
  	temp = *((volatile char*)($2));
    size = sprintf(str, "READ_MEM_8 (0x%x) -> 0x%x;\n\r", $2, temp);
    YY_OUTPUT(str, size);
  }  
  |
  READ_MEM_16 INTEGER
  {
  	short temp;
    size = sprintf(str, "READ_MEM_16 0x%x;\n\r", $2);
    YY_OUTPUT(str, size);
    if (($2%2) != 0) {
    	size = sprintf(str, "The address is not on a 16-bit boundary!\n\r");
    	YY_OUTPUT(str, size);    	
    }
    else {
	  	temp = *((volatile short*)($2));
	    size = sprintf(str, "READ_MEM_16 (0x%x) -> 0x%x;\n\r", $2, temp);
	    YY_OUTPUT(str, size);
	}
  }
  |    
  READ_MEM_32 INTEGER
  {
  	char temp;
    size = sprintf(str, "READ_MEM_32 0x%x;\n\r", $2);
    YY_OUTPUT(str, size);
    if (($2%4) != 0) {
    	size = sprintf(str, "The address is not on a 32-bit boundary!\n\r");
    	YY_OUTPUT(str, size);    	
    }    
    else {
	  	temp = *((volatile int*)($2));
	    size = sprintf(str, "READ_MEM_32 (0x%x) -> 0x%x;\n\r", $2, temp);
	    YY_OUTPUT(str, size);
	}
  }
  |  
  WRITE_MEM_8 INTEGER INTEGER
  {
  	char temp;
    size = sprintf(str, "WRITE_MEM_8 0x%x 0x%x;\n\r", $2, $3);
    YY_OUTPUT(str, size);
  	*((volatile char*)($2)) = $3;
    size = sprintf(str, "WRITE_MEM_8 (0x%x) -> 0x%x;\n\r", $2, $3);
    YY_OUTPUT(str, size);
  }      
  |
  WRITE_MEM_16 INTEGER INTEGER
  {
  	char temp;
    size = sprintf(str, "WRITE_MEM_16 0x%x 0x%x;\n\r", $2, $3);
    YY_OUTPUT(str, size);
    if (($2%2) != 0) {
    	size = sprintf(str, "The address is not on a 16-bit boundary!\n\r");
    	YY_OUTPUT(str, size);    	
    }
    else {    
	  	*((volatile short*)($2)) = $3;
	    size = sprintf(str, "WRITE_MEM_16 (0x%x) -> 0x%x;\n\r", $2, $3);
	    YY_OUTPUT(str, size);
	}
  }      
  |
  WRITE_MEM_32 INTEGER INTEGER
  {
  	char temp;
    size = sprintf(str, "WRITE_MEM_32 0x%x 0x%x;\n\r", $2, $3);
    YY_OUTPUT(str, size);
    if (($2%4) != 0) {
    	size = sprintf(str, "The address is not on a 32-bit boundary!\n\r");
    	YY_OUTPUT(str, size);    	
    }    
	else {    
	  	*((volatile int*)($2)) = $3;
	    size = sprintf(str, "WRITE_MEM_32 (0x%x) -> 0x%x;\n\r", $2, $3);
	    YY_OUTPUT(str, size);
    }
  }      
  |
  TEST
  {
    size = sprintf(str, "TEST;\n\r");
    YY_OUTPUT(str, size);
  } 
  ;

%%

int yyerror(char * pErrorMsg)
{
  size = sprintf(str, "Invalid Command!  Try Again.\n\r");
  YY_OUTPUT(str, size);
  yyrestart();
  YY_ABORT; /* Recovery not attempted */
}

/*
int main(void) {
  yyparse();
  return 0;
}
*/
