%{

/*	Copyright (c) 1984 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/

#ident "$Header: parse.y 1.1 89/10/09 $@(#)nls:parse.y	1.2 88/01/06 AT&T UEL"

/* Preprocessor Statements */
#define PARSER
#include "colltbl.h"
#include "y.tab.h"

/* External Variables */
extern int	yydebug;
extern char	codeset[];
extern int	regexp_flag;

BOOLEAN	ellipses = FALSE;
BOOLEAN secondary = FALSE;
static  char	name_low[10];
static  char	name_high[10];
static	char	*cp;
static	char	regexp_len;
char	**array;
unsigned int	group;
int	i,n;
static  int	max_sec_weight;

/* Global Variables */
struct {
	SYMNODE		*first_sym;
	SYMNODE		*first_repl;
	unsigned short	value;
	unsigned short 	width;
} setup = { (SYMNODE *) NULL, (SYMNODE *) NULL, 2, 1 };
SYMNODE		*np, *Last_sym, *Last_repl;

/* Redefined Error Message Handler */
yyerror(text)
char *text;
{
}

/* Function to Insert Symbols */
BOOLEAN
insert_symbol(name, primary, secondary)
char	*name;
unsigned short	primary;
unsigned short	secondary;
{
	/*  Create a symbol table entry for symbol  */
	if((np = insert(name, SYMBOL, 0)) == (SYMNODE *) NULL)  {
		error(DUPLICATE, "symbol", (char *) name);
		return(FALSE);
	}
	else {
		np->uval.symval.primary = primary;
		np->uval.symval.secondary = secondary;
		np->thread = (SYMNODE *) NULL;
		if(setup.first_sym == (SYMNODE *) NULL)
			setup.first_sym = np;
		else if(Last_sym != (SYMNODE *) NULL)
			Last_sym->thread = np;
		Last_sym = np;
		return(TRUE);
	}
}

assign_pr()
{
	unsigned	short	primary;
	np = setup.first_sym;
	if (!max_sec_weight)
		max_sec_weight++;
	setup.value = max_sec_weight + 1;
	while (np != (SYMNODE *) NULL) {
		if (np->uval.symval.primary == 0) {
			np->uval.symval.primary = setup.value++;
			np = np->thread;
		}
		else   {

			primary = np->uval.symval.primary;	
			np->uval.symval.primary = setup.value;
			while (((np = np->thread) != (SYMNODE *) NULL) && np->uval.symval.primary == primary)
				np->uval.symval.primary = setup.value;
			setup.value++;
		}
	}
}
%}

/* Token Types */
%token	ELLIPSES
%token	ID
%token	IS
%token	CODESET
%token	ORDER
%token  REGEXP
%token	REPLACE
%token	SEPARATOR
%token	STRING
%token	SYMBOL
%token	WITH
%%
collation_table:
	statements
	{
		/* assign primary weights */
		assign_pr();

		/* Sort symbol link list */ 
		setup.first_sym = sortlist(setup.first_sym, Last_sym->thread);

		/* Open output file */
		if (freopen(codeset, "w", stdout) == NULL) {
			error(BAD_OPEN, codeset);
			exit(-1);
		}

		/*  Generate code for strxfrm  */
		codegen(&setup);
	}

statements:
	/* empty */
	|
	statement statements
	{
	}

statement:
	codeset_stmt
	{
	} |
	order_stmt
	{
	} |
	replace_stmts
	{
	} |
	error = error(EXPECTED,"codeset, order or replace statement");

codeset_stmt:
	CODESET ID
	{
		codeset[0] = '\0'; 
		strcpy(codeset, (char *) $2);
	}

order_stmt:
	ORDER IS order_list
	{
		if(setup.value > 255)
			setup.width = 2;
	}

replace_stmts:
	/* empty */
	{
	} |
	replace_stmt replace_stmts
	
replace_stmt:
	REPLACE REGEXP WITH STRING
	{
		/*  Create a symbol table entry for replacement  */
		regexp_len = 0;
		cp = (char *) $2;
		if (regexp_flag) {
			while (*cp++ != 026) 
				regexp_len++;
			regexp_len++;
		}
		else
			regexp_len = strlen(cp);
		if((np = insert((char *) $2, REPLACE, regexp_len)) == (SYMNODE *) NULL)
			error(DUPLICATE, "regular expression", (char *) $2);
		else {
			np->uval.replval.repl_string = (char *) $4;
			np->thread = (SYMNODE *) NULL;
			if(setup.first_repl == (SYMNODE *) NULL)
				setup.first_repl = np;
			else if(Last_repl != (SYMNODE *) NULL)
				Last_repl->thread = np;
			Last_repl = np;
		}
	}

order_list:
	order_element
	{
	} |
	order_element SEPARATOR order_list
	{
	}

order_element:
	symbol
	{
	} |
	"(" { TURNON(secondary); ++group;} sub_list ")"
	{
		max_sec_weight = setup.value - 1;
		setup.value = 2;
		TURNOFF(secondary);
	} |
	"{"  { secondary = 2; group++;} sub_list "}"
	{
		TURNOFF(secondary);
	} |
	error = error(INVALID, "order element", (char *) $1);

sub_list:
	sub_element
	{
	} |
	sub_element SEPARATOR sub_list
	{
	} |
	error = error(INVALID, "list",
		(secondary ? "secondary weighting" : "inter-filed"));

sub_element:
	symbol
	{
	} |
	error = error(INVALID, "list element",
		(secondary ? "secondary weighting" : "inter-filed"));

symbol:
	SYMBOL
	{
		switch (ellipses)  {
		case 0:
			*name_low = '\0';
			strcpy(name_low, (char *) $1);
			switch (secondary) {
			case	FALSE:
				if(!insert_symbol((char *) $1, 0, 0))
					setup.value--; 
				break;
			case	TRUE:
				if (!insert_symbol((char *) $1, group, setup.value++))  
					setup.value--;
				break;
			default:
				insert_symbol((char *) $1, group, 0);
				break;
			}
			break;
		case 1:
			*name_high = '\0';
			strcpy(name_high, (char *) $1);
			if (*name_high <= *name_low)
				error(INVALID, "List range");
			else  { 
					n = (int) *name_high - (int) *name_low;
					array = (char **)malloc(sizeof(char *) * n);
					for(i=0; i<n; i++) {
					array[i] = (char *)malloc(2);
					*name_low = (char) ((int) *name_low + 1);
					array[i][0] = *name_low;
					array[i][1] = '\0';	
					switch (secondary) {
					case	FALSE:
						if(!insert_symbol(array[i], 0, 0))
							setup.value--; 
						break;
					case	TRUE:
						if (!insert_symbol(array[i], group, setup.value++))  
							setup.value--;
						break;
					default:
						insert_symbol(array[i], group, 0);
						break;
					}
					}
			}
			free(array);
			TURNOFF(ellipses);
			break;
		default:
			error(INVALID, "List range");
			break;
		}
	} | 
	ELLIPSES
	{
		TURNON(ellipses);
	} 
