/*****************************************************************************
  FILE           : $Source: /usr/local/bv/SNNS/SNNSv3.3/kernel/sources/RCS/kr_pat_parse_bison.y,v $
  SHORTNAME      : pat_parse
  SNNS VERSION   : 3.3

  PURPOSE        : parser for new pattern format; bison format 
  NOTES          : impossible to use with yacc

  AUTHOR         : Michael Vogt
  DATE           : 10.9.93

  CHANGED BY     : 
  IDENTIFICATION : $State: Exp $ $Locker:  $
  RCS VERSION    : $Revision: 2.2 $
  LAST CHANGE    : $Date: 1994/10/04 13:26:39 $

             Copyright (c) 1990-1993  SNNS Group, IPVR, Univ. Stuttgart, FRG

******************************************************************************/
%{
#include <stdio.h>

/* since the generated parser needs alloca we need to do some special things */
/* for some architectures: */

#ifndef alloca
#ifndef __GNUC__

#ifdef __hpux
#include <malloc.h>
#include <stdio.h>
#endif /* __hpux */

#ifdef sparc
#include <alloca.h>
#endif /* sparc */

#endif /* GNU C. not defined  */
#endif /* alloca not defined.  */

#include "kr_typ.h"
#include "glob_typ.h"
#include "kernel.h"
#include "kr_pat_scan.h"
#include "kr_newpattern.h"
#include "kr_pat_parse.ph"
%}

%union
{
	float	value;		/* allgemeine Zahl */	
	struct
	{
		int	v;
		int	r;
	}	version;	/* Versionsnummer #.# */
}

%token	L_BRACKET R_BRACKET
%token	VERSION_HEADER
%token	GENERATED_AT
%token	NO_OF_PATTERN NO_OF_INPUT NO_OF_OUTPUT
%token	NO_OF_VAR_IDIM NO_OF_VAR_ODIM
%token	MAXIMUM_IDIM MAXIMUM_ODIM
%token	ERROR PATTERNEND

%token	<value> NUMBER
%token	<version> V_NUMBER

%%

pattern_file:	header
		{	
		    current_pattern = 0;
		    next_pattern_is_input = 1;

		    if (kr_np_AllocatePatternSet(&pattern_set, no_of_pattern)
			!= KRERR_NO_ERROR)
		    { 
			yyerror("can't allocate memory"); 
			YYABORT; 
		    }
		}		
		pattern_list
		{
		    if (current_pattern < no_of_pattern ||
			!next_pattern_is_input)
		    { 
			yyerror("unexpected end of file"); 
			YYABORT; 
		    }
		}
;

header:	VERSION_HEADER V_NUMBER 
	{
		if (($2.v == CURRENT_VERSION_V && $2.r > CURRENT_VERSION_R) ||
		    $2.v > CURRENT_VERSION_V)
		{ 
		    yyerror("version of pattern file not supported"); 
		    YYABORT; 
		}
	}
	GENERATED_AT NO_OF_PATTERN NUMBER
	{
		no_of_pattern = (int) $6;
		if (no_of_pattern <= 0)
		{ 
		    yyerror("illegal number of pattern"); 
		    YYABORT; 
		}
	}
        i_head o_head vi_head vo_head
;

i_head:	NO_OF_INPUT NUMBER
	{ 
		no_of_input = (int) $2;
		if (no_of_input < 0)
		{ 
		    yyerror("illegal number of input units"); 
		    YYABORT; 
		} 
	}
;

o_head:	NO_OF_OUTPUT NUMBER
	{ 
		no_of_output = (int) $2;
		if (no_of_output < 0)
		{ 
		    yyerror("illegal number of output units"); 
		    YYABORT; 
		} 
	}
	|
	{ no_of_output = 0; }
;

vi_head: NO_OF_VAR_IDIM NUMBER MAXIMUM_IDIM actual_dim
	{
		variable_input_dim = $2; 
		if (variable_input_dim < 0 || 
		    variable_input_dim > MAX_NO_OF_VAR_I_DIM)
		{ 
		    yyerror("illegal variable input dimensions"); 
		    YYABORT; 
		}
		if (actual_dim_count != variable_input_dim)
		{ 
		    yyerror("illegal number of entries in dimension list"); 
		    YYABORT; 
		}
		for (i=0; i<variable_input_dim; i++)
			max_i_dims[i] = dims[i];
	}
	|
	{ variable_input_dim = 0; }
;

vo_head: NO_OF_VAR_ODIM NUMBER MAXIMUM_ODIM actual_dim
	{
		variable_output_dim = $2; 
		if (variable_output_dim < 0 || 
		    variable_output_dim > MAX_NO_OF_VAR_O_DIM ||
		    no_of_output == 0)
		{ 
		    yyerror("illegal variable output dimensions"); 
		    YYABORT; 
		}
		if (actual_dim_count != variable_output_dim)
		{ 
		    yyerror("illegal number of entries in dimension list"); 
		    YYABORT; 
		}
		for (i=0; i<variable_output_dim; i++)
			max_o_dims[i] = dims[i];	
	}
	|
	{ variable_output_dim = 0; }
;

actual_dim: L_BRACKET 
		{
			actual_dim_count = 0;
		}
	    actual_dim_rest R_BRACKET
        | L_BRACKET R_BRACKET                
                {
		        actual_dim_count = 0;
		}
;

actual_dim_rest: dim_entry
	| actual_dim_rest dim_entry
;

dim_entry: NUMBER
	{
		if (actual_dim_count >= MAX_NO_OF_VAR_DIM)
		{ 
		    yyerror("to many entries in dimension list"); 
		    YYABORT; 
		}
		dims[actual_dim_count] = (int) $1;
		if (dims[actual_dim_count] <= 0)
		{ 
		    yyerror("illegal size of dimension"); 
		    YYABORT; 
		}
		actual_dim_count++;
	}
;

pattern_list: pattern
	|     pattern_list pattern
;

pattern: 
{
    if (current_pattern >= no_of_pattern)
    { 
	yyerror("to many patterns"); 
	YYABORT; 
    }
} 
pattern_start 
{
    if (kr_np_GetDescriptor(pattern_set, current_pattern, &pattern)
	!= KRERR_NO_ERROR)
    {
	yyerror("pattern parser internal error");
	YYABORT;
    }
    if (next_pattern_is_input)
    {
	pattern -> input_fixsize = no_of_input;
	pattern -> input_dim = variable_input_dim;
	pattern -> output_fixsize = no_of_output;
	pattern -> output_dim = variable_output_dim;
	if (actual_dim_count != variable_input_dim)
	{ 
	    yyerror("illegal number of entries in dimension list"); 
	    YYABORT; 
	}
	act_size = no_of_input;
	for (i=0; i<variable_input_dim; i++)
	{
	    if (dims[i] > max_i_dims[i])
	    { 
		yyerror("variable dimension overflow"); 
		YYABORT; 
	    }
	    act_size *= dims[i];
	    (pattern -> input_dim_sizes)[i] = dims[i];
	}
	if (kr_np_AllocatePattern(pattern, next_pattern_is_input)
	    != KRERR_NO_ERROR)
	{ 
	    yyerror("can't allocate memory"); 
	    YYABORT; 
	}
	pat_mem = pattern -> input_pattern;
    }
    else
    {
	if (actual_dim_count != variable_output_dim)
	{ 
	    yyerror("illegal number of entries in dimension list"); 
	    YYABORT; 
	}
	act_size = no_of_output;
	for (i=0; i<variable_output_dim; i++)
	{
	    if (dims[i] > max_o_dims[i])
	    { 
		yyerror("variable dimension overflow"); 
		YYABORT; 
	    }
	    act_size *= dims[i];
	    (pattern -> output_dim_sizes)[i] = dims[i];
	}
	if (kr_np_AllocatePattern(pattern, next_pattern_is_input)
	    != KRERR_NO_ERROR)
	{ 
	    yyerror("can't allocate memory"); 
	    YYABORT; 
	}
	pat_mem = pattern -> output_pattern;
    }
}
pattern_body 
{
    if (act_size > 0)
    { 
	yyerror("to little values in pattern"); 
	YYABORT; 
    }
    
    if (no_of_output > 0)
	next_pattern_is_input = !next_pattern_is_input;
    
    if (next_pattern_is_input)
	current_pattern++;
}
PATTERNEND
;

pattern_start: actual_dim
        | /* empty */
{
    actual_dim_count = 0;
}
;


pattern_body: pattern_entry
	|     pattern_body pattern_entry
;

pattern_entry: NUMBER
	{
		if (act_size == 0)
		{ 
		    yyerror("to many values in pattern"); 
		    YYABORT; 
		}
		*pat_mem++ = $1;
		if (--act_size == 0)
		    scanner_await_pattern_end(); 
	}
;


%%

#ifndef alloca
#ifndef __GNUC__
#ifdef __hpux
/*****************************************************************************
  FUNCTION : alloca

  PURPOSE  : must be provided for the parser.
             Uses malloc to allocate memory. This memory is not automatically
             freed as in the original alloca definition 
  RETURNS  : pointer to memory
  NOTES    : This is necessary for HP_UX only since there comes no alloca() 
             with the HP cc C-compiler.
	     It is not necessary with Gnu C

  UPDATE   : 
******************************************************************************/
void *alloca(int size)
{
    void *p;

    p = malloc(size);
    fprintf(stderr, "warning: malloc called instead of alloca\n");
    return p;
}
#endif /* __hpux */
#endif /* GNU C. not defined  */
#endif /* alloca not defined.  */

/*****************************************************************************
  FUNCTION : yyerror

  PURPOSE  : must be provided for the parser.
             reports errors in pattern file to stderr
  RETURNS  : nothing
  NOTES    :

  UPDATE   : 
******************************************************************************/
static void yyerror(char *error)
{
    fprintf(stderr, "Parse error in pattern file at line %d:\n%s\n",
	    lineno, error);
}

/*****************************************************************************
  FUNCTION : parse_pattern_file

  PURPOSE  : calls the real parser

  RETURNS  : parser error code and the handle to the loaded pattern set
  NOTES    :

  UPDATE   : 
******************************************************************************/
int parse_pattern_file(int *set)
{
    int err;

    lineno = 1;
    err = yyparse();
    *set = pattern_set;

    if (err == 0)
	lineno = 0;

    return err;
}

/*****************************************************************************
END OF FILE
******************************************************************************/
