/* Copyright (C) 2001 Michael Leonhard
 * Mike Leonhard
 * mike at tamale dot net
 * http://tamale.net/
 */

#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "sebae.h"

struct InstructionSet iset[] = {
	/* name       		num se parms asmproduce */
	{ "HALT",		 0, 0, 0, Sebae_Assembly_ProduceDEFNTERMINAL },
	{ "JUMP",		 1, 0, 1, Sebae_Assembly_ProduceDEFNTERMINAL },
	{ "LOADCODE",		 2, 2, 1, Sebae_Assembly_ProduceGENERIC },
	{ "VECTOR",		 3, 1, 0, Sebae_Assembly_ProduceGENERIC },

	{ "PUSH",		 4, 1,-1, Sebae_Assembly_ProduceGENERIC },
	{ "POP",		 5,-1, 0, Sebae_Assembly_ProduceGENERIC },
	{ "ASSIGN",		 6, 0, 2, Sebae_Assembly_ProduceGENERIC },
	{ "STACKSIZE",		 7, 1, 0, Sebae_Assembly_ProduceGENERIC },
	{ "STACKHEIGHT",	 8, 1, 0, Sebae_Assembly_ProduceGENERIC },

	{ "ADD",		 9, 1, 2, Sebae_Assembly_ProduceGENERIC },
	{ "FPADD",		10, 1, 2, Sebae_Assembly_ProduceGENERIC },
	{ "SUBTRACT",		11, 1, 2, Sebae_Assembly_ProduceGENERIC },
	{ "FPSUBTRACT",		12, 1, 2, Sebae_Assembly_ProduceGENERIC },
	{ "MULTIPLY",		13, 1, 2, Sebae_Assembly_ProduceGENERIC },

	{ "FPMULTIPLY",		14, 1, 2, Sebae_Assembly_ProduceGENERIC },
	{ "DIVIDE",		15, 1, 2, Sebae_Assembly_ProduceGENERIC },
	{ "FPDIVIDE",		16, 1, 2, Sebae_Assembly_ProduceGENERIC },
	{ "REMAINDER",		17, 1, 2, Sebae_Assembly_ProduceGENERIC },
	{ "FPREMAINDER",	18, 1, 2, Sebae_Assembly_ProduceGENERIC },
	{ "GREATERTHAN",	19, 1, 2, Sebae_Assembly_ProduceGENERIC },
	{ "FPGREATERTHAN",	20, 1, 2, Sebae_Assembly_ProduceGENERIC },
	
	{ "AND",		21, 1, 2, Sebae_Assembly_ProduceGENERIC },
	{ "OR",			22, 1, 2, Sebae_Assembly_ProduceGENERIC },
	{ "XOR",		23, 1, 2, Sebae_Assembly_ProduceGENERIC },
	{ "ROTATE",		24, 1, 2, Sebae_Assembly_ProduceGENERIC },
	{ "EQUAL",		25, 1, 2, Sebae_Assembly_ProduceGENERIC },
	{ "DECIDE",		26, 1, 3, Sebae_Assembly_ProduceGENERIC },
	
	{ "LOAD",		27, 0, 2, Sebae_Assembly_ProduceGENERIC },
	{ "SAVE",		28, 0, 2, Sebae_Assembly_ProduceGENERIC },
	{ "MEMSIZE",		29, 1, 0, Sebae_Assembly_ProduceGENERIC },

	/* assembly directives */
	{ "DATA", 		-1, 0,-1, Sebae_Assembly_ProduceDATA },
	{ "DEFN", 		-1, 0, 2, Sebae_Assembly_ProduceDEFN }

	};

int Sebae_Error( struct SebaeVM *vm, char *text ) {
	assert( vm );
	assert( text );
	
	/* free previous error */
	if( vm->errortext != NULL ) free( vm->errortext );
	
	/* allocate for error text */
	vm->errortext = (char *)malloc( strlen( text ) + 1 );
	assert( vm->errortext ) ;
	
	/* copy error text */
	strcpy( vm->errortext, text );
	
	return -1;
	}

int Sebae_PError( struct SebaeVM *vm, char *text ) {
	const char *syserrtext;
	
	assert( vm );
	assert( text );
	
	/* get system error description */
	syserrtext = strerror( errno );
	
	/* free previous error */
	if( vm->errortext != NULL ) free( vm->errortext );
	
	/* allocate for error text */
	vm->errortext = (char *)malloc( strlen( text ) + 2 + strlen( syserrtext ) + 1 );
	assert( vm->errortext ) ;
	
	/* copy error text */
	strcpy( vm->errortext, text );
	strcat( vm->errortext, ", " );
	strcat( vm->errortext, syserrtext );
	
	return -1;
	}

int Sebae_PrintError( struct SebaeVM *vm ) {
	char *etext, *emsg;

	assert( vm );
	
	/* no error text */
	if( vm->errortext == NULL ) etext = "unknown error";
	/* error text is available */
	else etext = vm->errortext;
	
	/* allocate for error msg */
	emsg = (char *)malloc( strlen( etext ) + 64 );
	assert( emsg );
	
	/* line number */
	if( vm->linenumber != -1 ) sprintf( emsg, "error on line %d: ", vm->linenumber );
	
	/* no line number */
	else strcpy( emsg, "error: " );
	
	/* error text */
	strcat( emsg, etext );
	
	/* end of line */
	strcat( emsg, "\n" );
	
	/* output the error */
	printf( "%s", emsg );
	
	/* clean up */
	free( emsg );

	/* 1 is the proper error code for a command line app.        */
	/* Returning 1 lets main() do return Sebae_PrintError( vm ); */
	return 1;
	}

