/* SCCSWHAT( "@(#)grammar.y	1.4 89/05/09 21:22:03	" ) */

/*****************************************************************************/
/**						Microsoft LAN Manager								**/
/**				Copyright(c) Microsoft Corp., 1987-1990						**/
/*****************************************************************************/
%{

/****************************************************************************
 ***		local defines
 ***************************************************************************/

#define pascal 
#define FARDATA
#define NEARDATA
#define FARCODE
#define NEARCODE
#define NEARSWAP

#define PASCAL pascal
#define CDECL
#define VOID void
#define CONST const
#define GLOBAL

#define YYSTYPE         lextype_t
#define YYNEAR          NEARCODE
#define YYPASCAL        PASCAL
#define YYPRINT         printf
#define YYSTATIC        static
#define YYLEX           yylex
#define YYPARSER        yyparse

#define MAXARRAY				1000
#define CASE_BUFFER_SIZE		10000

#define CASE_FN_FORMAT			("\nstatic void\ncase_fn_%.4d()")
#define DISPATCH_ENTRY_FORMAT	("\n\t,case_fn_%.4d")
#define DISPATCH_FIRST_ENTRY	("\n\t case_fn_%.4d")

/****************************************************************************
 ***		include files
 ***************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include "lex.h"

/****************************************************************************
 ***		externals 
 ***************************************************************************/

extern	int			Incase;
extern	int			ActionSensed;
extern	int			yylex();
extern	int			yyparse();

/****************************************************************************
 ***		local procs 
 ***************************************************************************/

void				Init( void );
void				EmitCaseTableArray( void );
void				EmitDefaultCase( void );
void				EmitCaseBody( int );
void				RegisterCase( int );
void				BufferIt( char * pStr, int iLen );
void				ResetBuffer();
void				FlushBuffer();

/****************************************************************************
 ***		local data 
 ***************************************************************************/

unsigned	long	SavedIDCount	= 0;
unsigned	long	IDCount			= 0;
unsigned	char	CaseTable[ MAXARRAY ] = { 0 };
int					CaseNumber		= 0;
int					MaxCaseNumber	= 0;
char		*		pBufStart;
char		*		pBufCur;
char		*		pBufEnd;

%}

%token		ID
%token		NUMBER
%token		TOKEN_CASE
%token		TOKEN_CHAR
%token		TOKEN_END
%token		TOKEN_END_CASE
%token		TOKEN_MYACT
%token		TOKEN_START

%type		<yynumber>	NUMBER
%type		<yycharval>	TOKEN_CHAR
%type		<yystring>	ID

%%

Template:
	  OptionalJunk TOKEN_START
		{
		Init();
		}
		OptionalJunk Body OptionalJunk TOKEN_END OptionalJunk
		{
		EmitDefaultCase();
		EmitCaseTableArray();
		}
	;
Body:
	  TOKEN_MYACT 
		{
		ActionSensed++;
		ResetBuffer();
		}
	  OptionalJunk CaseList 
		{
		}
	;

CaseList:
	  CaseList OneCase
		{
		}
	| OneCase
		{
		}
	;

OneCase:
	  TOKEN_CASE TOKEN_CHAR NUMBER TOKEN_CHAR
		{
		Incase = 1;

		CaseNumber		= $3;
		if($3 >= MAXARRAY)
			{
			fprintf(stderr, "Case Limit Reached : Contact Dov/Vibhas\n");
			return 1;
			}

		SavedIDCount	= IDCount;
		}
	  OptionalJunk TOKEN_END_CASE
		{
		if(SavedIDCount != IDCount)
			{
			RegisterCase( CaseNumber );
			EmitCaseBody( CaseNumber );
			}

		ResetBuffer();

		if(CaseNumber > MaxCaseNumber)
			MaxCaseNumber = CaseNumber;
		Incase = 0;
		}
	;

OptionalJunk:
	  Junk
		{
		}
	|  /* Empty */
		{
		}
	;

Junk: 
	  Junk JunkElement
		{
		}
	| JunkElement
		{
		}
	;

JunkElement:
	  TOKEN_CHAR
		{
		if(!ActionSensed)
			fprintf(stdout, "%c", $1);
		else
			BufferIt( &$1, 1);
		}
	| ID
		{
		IDCount++;
		if(!ActionSensed)
			fprintf(stdout, "%s", $1);
		else
			BufferIt( $1, strlen($1) );
		}
	| NUMBER
		{
		if(!ActionSensed)
			fprintf(stdout, "%d", $1);
		else
			{
			char	buffer[20];
			sprintf(buffer,"%d", $1 );
			BufferIt( buffer, strlen(buffer) );
			}
		}
	;
	
%%

/*****************************************************************************
 *	utility functions
 *****************************************************************************/
YYSTATIC VOID FARCODE PASCAL 
yyerror(char *szError)
	{
		extern int Line;
		extern char LocalBuffer[];

		fprintf(stderr, "%s at Line %d near %s\n", szError, Line, LocalBuffer);
	}
void
Init()
	{
	pBufStart = pBufCur = malloc( CASE_BUFFER_SIZE );
	if( !pBufStart )
		{
		fprintf(stderr,"Out Of Memory\n");
		exit(1);
		}
	pBufEnd = pBufStart + CASE_BUFFER_SIZE;
	}

void
BufferIt( 
	char	*	pStr,
	int			iLen )
	{
	if( pBufCur + iLen > pBufEnd )
		{
		printf("ALERT iLen = %d\n", iLen );
//		assert( (pBufCur + iLen) <= pBufEnd );
		exit(1);
		}
	strncpy( pBufCur , pStr, iLen );
	pBufCur += iLen;
	*pBufCur = '\0';
	}

void
ResetBuffer()
	{
	pBufCur = pBufStart;
	*pBufCur= '\0';
	}

void
FlushBuffer()
	{
	fprintf(stdout, "%s", pBufStart);
	ResetBuffer();
	}

void
EmitCaseBody( 
	int		CaseNumber )
	{
	fprintf( stdout, CASE_FN_FORMAT, CaseNumber );
	FlushBuffer();
	fprintf( stdout, "}\n" );
	}

void
EmitCaseTableArray()
	{
	int		i, iTemp;

	fprintf( stdout, "static void\t (*case_fn_array[])() = \n\t{" );
	fprintf( stdout,DISPATCH_FIRST_ENTRY, 0 );

	for( i = 1 ; i <= MaxCaseNumber ; ++i )
		{
		iTemp = CaseTable[ i ] ? i : 0;
		fprintf(stdout,DISPATCH_ENTRY_FORMAT, iTemp );
		}

	fprintf( stdout, "\n\t};\n" );
	fprintf( stdout, "\nstatic void\nyy_vc_init(){ pcase_fn_array = case_fn_array;\nyym_vc_max = %d;\n }\n" , MaxCaseNumber);
	}

void
EmitDefaultCase()
	{
	fprintf(stdout, "static void\ncase_fn_%.4d() {\n\t}\n\n", 0 );
	}
void
RegisterCase(
	int		iCase )
	{
	CaseTable[ iCase ] = 1;
	}