/*
 * genstubs.c: generates assembler code for the PDC version of Amiga.lib
 *            from Commodore-supplied .fd files on the extras disk.
 *
 * Copyright 1988 by J.A.Lydiatt.  Permission is given to freely distribute
 * this code for non-commercial use.
 * Maintenance Notes:
 *   18Jun88 - V1.0 Created by Jal.
 */

#include "genstubs.h"

#define SAME		0
#define END		20
#define PRIVATE		21
#define PUBLIC		22


/*
 * External variables:
 */

char base[MAXSTR] = "";			/* ##base _SysBase for example	*/
int  bias = 0;				/* ##bias 30			*/
char Section[MAXSTR];			/* Name for SECTION "<Section>".*/
FUNCINFO function;			/* The current function.	*/
char Version[] = "V1.1 (12Jun89)"; 
char FreeMsg[] = "Freely Redistributable for non-commercial use.";
FILE *fi;

/*
 * Internal variables:
 */

static int  genstate = 0;		/* ##private, ##public, ##end	*/
static TOKEN token;


/*
 * getdirective: get a directive from the current line.
 */

static void getdirective()
{
	register TOKEN *t = &token; 
	extern int strcmp();
	extern char *strcpy();


	if ( strcmp( t->id, "base" ) == SAME ){
		if ( gettok( t ) == ID )
			(void) strcpy( base, t->id );
		else {
			warn( "Expected base variable not found" );
			(void) strcpy( base, "<MISSING>");
		}
	}
	else if ( strcmp( t->id, "bias" ) == SAME ){
		if  ( gettok( t ) == NUMBER )
			bias = t->value;
		else {
			warn( "Expected bias value not found" );
			bias = 30;
		}
	}
	else if ( strcmp( t->id, "end" ) == SAME )
		genstate = END;
	else if ( strcmp( t->id, "private" ) == SAME )
		genstate = PRIVATE;
	else if ( strcmp( t->id, "public" ) == SAME )
		genstate = PUBLIC;
	else
	     warn("Unrecognized directive");
	nextline();
}
		
/*
 * getparms: get the parameter definitions; return # expected.
 */
static int getparms( t )
register TOKEN *t;
{
	int n, class;

	n = 0;
	if ( gettok( t ) != LPAREN )
		warn( "Missing '('" );
	while ( (class = gettok( t )) != RPAREN
	     && (class != EOL && class != EOF)){
		switch( class ){
		case ID:
			(void)strcpy( function.formal[ n++ ], t->id );
			break;
		case COMMA:
			break;
		default:
			warn("Unexpected token:");
		}
	}
	function.nformal = n;
	return n;
}

/*
 * getregisters: parse and store the register definitions.
 */
static void getregisters( t )
register TOKEN *t;
{
	int class, j;
	int regno, regtype;
	register FUNCINFO *f = &function;
	extern char *strcat();

	j = 0;
	f->regmask = 0;
	while ( ( class = gettok()) != RPAREN ) {
		switch( class ) {
			case ID:
				regtype = toupper(t->id[0]) == 'D' ?
					0 : 8;
				regno = t->id[1] - '0';
				f->regmask |= 1 << regtype + regno;
				strcat( f->reglist[j], t->id);
				++(f->nregs[ j ]);
				break;
			case SLASH:
				strcat( f->reglist[j], "/" );
				break;
			case COMMA:
				++j;
				/* Note the fall through */
			case LPAREN:
				f->reglist[j][0] = '\0';
				f->nregs[j] = 0;
				break;
			default:
				goto e1;
		}
	}

e1:
	if ( class != RPAREN )
		warn("Unexpected end for register list.");

	f->nlists  = f->nregs[0] > 0 ? ++j : 0;
}

/*
 * getfunc: get a function definition from the current line.
 */
static void getfunc()
{
	register TOKEN	*t = &token;
	register FUNCINFO *f = &function;
	int nparms, class;
	extern char *strcpy(), *strcat();

	(void)strcpy( f->name, "_" );
	(void)strcat( f->name, t->id );
	getcurline( f->givenline );
	nparms = getparms( t );
	if ( nparms > 0 )
		getregisters( t ); 
	else {
		f->regmask = 0;
		f->nlists = 0;
	}
	nextline();
}

static void msg( txt, p1 )
char *txt;
long p1;
{
	fprintf( stderr, txt, p1 );
	fputc( '\n', stderr );
} 

main(argc,argv)
int argc;
char *argv[];
{
	int class;
	register char *s, *p;
	extern char *strncpy();

	if ( argc != 2 ) {
		msg("Useage: %s infile.fd", argv[0] );
		exit(4);
	}

	if ( (fi = fopen(argv[1], "r")) == NULL ) {
		msg("Can't open %s for input\n", argv[1]);
		exit(4);
	}

	fprintf(stderr,	"Genstubs %s by J.A. Lydiatt.\n", Version );
	fprintf(stderr, "%s\n", FreeMsg );

	/*
	 * Make a Section name from arv[1] up to "_lib.fd"
	 */

	for ( s=Section,p=argv[1]; *p; s++,p++){
		if ( *p == '_' || *p == '.' )
			break;
		*s = *p;
	}
	*s = '\0';

	/*
	 * Capitalize the first letter.
	 */

	s = Section;
	if ( 'a' <= *s && *s <= 'z' )
		*s += 'A' - 'a';

	
	nextline();

	while (	(class = gettok( &token )) != EOF) {
		switch (class){
			case ID:
				getfunc();
				if ( genstate == PUBLIC )
					genfunc();
				bias += 6;
				break;
			case DIRECTIVE:
				getdirective();
				break;
			case COMMENT:
				nextline();
				break;
			case EOF:
				break;
			default:
				warn("Unrecognized line!\n");
				nextline();
		}

	}

	fclose(fi);

}
