/*
   This program is an Assembler shell. It can run multiple Assemblers.
   Written by David Summers
   Originally written January 1986
   Modified for ANSI C June 1997

   $Log: main.c,v $
   Revision 1.4  1997/06/04 01:45:07  david
   Changed versioning information.

   Revision 1.3  1997/06/02 02:51:20  david
   Ansi-fied.

*/

#include <stdio.h>
#include "xasm.h"
#include "symbols.h"
#include "macros.h"

static char *RcsId  = "$Id: main.c,v 1.4 1997/06/04 01:45:07 david Exp $";

void usage( void );
void sferror( void );

#define COMMENT ';'

/* Common variables - declared external in "defs.h" */
int errnum; /* Number of errors this pass */
int line; /* Line # */
BYTE dp; /* 'Direct Page' register */
WORD loc; /* Current location pointer */
WORD locinc; /* Amount to increment location pointer */
BYTE pass; /* Assembler pass # */
WORD start = 0; /* Initialize to 0 */
char *objfile = NULL; /* Name of Object Code file (if any) */
char out_form; /* Format of Object Code file */
char *filename = NULL; /* Name of Assembler File */
FILE *infd; /* Pointer to source code file */

extern int yy_flex_debug;

int main( int argc, char **argv )
{
char *lptr; /* Pointer to beginning of line */
int count;

yy_flex_debug = 0;

setbuf( stderr, NULL ); /* Explicitly turn off buffering */
setbuf( stdout, NULL ); /* Turn off buffering */

if ( argc < 2 || argc > 6 )
   usage();
   
/* Parse options on command line */
for ( count = 1; count < argc; count++ )
   {
   if (	strcmp(	argv[count], "-I" ) == 0 || strcmp( argv[count], "-i" )	== 0 )
      {
      objfile = argv[++count];
      out_form = 'I'; /* Set to Intel Output format */
      continue;
      }

   if ( strcmp( argv[count], "-O" ) == 0 || strcmp( argv[count], "-o" ) == 0 )
      {
      objfile = argv[++count];
      out_form = 'O'; /* Set to relocatable Object Output format */
      continue;
      }
      
   if (	strcmp(	argv[count], "-S" ) == 0 || strcmp( argv[count], "-s" )	== 0 )
      {
      objfile = argv[++count];
      out_form = 'S'; /* Set to SYM Output format */
      continue;
      }

   if ( strcmp( argv[count], "-l" ) == 0 )
      {
      count++;
      yy_flex_debug = 1;
      }
      
   if ( filename == NULL )
      filename = argv[count];
   }
   
if ( filename == NULL )
   usage();
   
if ( objfile != NULL && filename != NULL )
   if ( strcmp( filename, objfile ) == 0 )
      sferror();
      
for ( pass = 1; pass <= 2; pass++ )
   {
   /* Reset pass variables */
   errnum = 0; /* Set # of errors to 0 */
   line = 0; /* Set line # to 0 */
   loc = 0; /* Set location to 0 */
   dp = 0; /* Set 'Direct Page' register to 0 */
#ifdef MSDOS
   infd = fopen( filename, "rb" ); /* Open file for read only */
#else
   infd = fopen( filename, "r" ); /* Open file for read only */
#endif
   if ( infd == NULL )
      {
      fprintf( stderr, "Can't open file %s\n", filename );
      exit( 1 );
      }

   /* Process lines until no more files (or include files) */
   do {
      for ( lptr = getline(); lptr != NULL; lptr = getline() )
         doline( lptr );
      } while ( deinclude() != 0 );

   if ( fclose( infd ) == EOF )
      {
      fprintf( stderr, "Error on close of file %s\n", filename );
      exit( 1 );
      }
	 
   } /* End 'pass' for loop */
   
genobj( NULL ); /* Send end of file signal */
printf( "\nTotal Errors: %5d\n", errnum );
xrefdisp(); /* Create Cross Reference file */
#ifdef ESD
esddisp(); /* Display the ESD Table */
#endif /* ESD */
return errnum; /* Exit with number of errors */
}

void doline( char *lptr )
{
char *label, *opcode, *operand;
struct table *opptr = NULL; /* Pointer to the Object code buffer */
char *objcode = NULL; /* Pointer to object code */
struct macros *macptr; /* Temporary Pointer to macro */

locinc = 0; /* Reset location increment to 0 */
if ( doparse( lptr, &label, &opcode, &operand ) != COMMENT )
   {
   /* Now begin processing */
   if ( *opcode )
      {
      if ( (macptr = findmac( opcode )) != NULL )
	 domac( label, macptr, operand, lptr );
       else /* Well, it's not a macro */
	 {
	 lower( opcode );
         if ( !psuedop( label, opcode, operand, lptr ) )
	    {
	    if ( !findop( opcode, &opptr ) )
	       xerror( "main: Invalid Opcode" );
	     else /* It's a valid opcode */
	       {
	       labproc( label );
	       objcode = proper( label, opcode, operand, opptr );
	       if ( objcode != NULL )
	          genobj( objcode ); /* Generate Object Code */
	       }
	    printl( (long) loc, objcode, 0, lptr );
	    } /* End if psuedop */
	 } /* End if findmac */
      } /* End 'if ( *opcode )' */
    else /* No opcode, do label & print line */
      {
      labproc( label );
      printl( (long) loc, NULL, 1, lptr );
      }
   } /* End of 'if ( COMMENT ) */
 else /* Nothing, print comment */
   printl( (long) -1, NULL, 1, lptr ); /* Print Comment */
/* Cleanup for next line */
loc += locinc; /* Increment Program counter by 'locinc' */
locinc = 0; /* Reset location increment to 0 */
}

int doparse( char *lptr, char **rlabel, char **ropcode, char **roperand )
{
static char label[81]; /* Current label */
static char opcode[81]; /* Current operation code */
static char operand[81]; /* Current operand */

/* Reset line variables */
*label = '\0'; *opcode = '\0'; *operand = '\0';
/* If first char. not ';' (comment) */
if ( *lptr != COMMENT )
   {
   /* First, get label, opcode, and operand */
   if ( *lptr != ' ' && *lptr != '\t' )
      if ( parse( &lptr, label, sizeof(label)-1, ' ' ) )
         xerror( "doparse: Invalid Label" );

   parse( &lptr, opcode, sizeof(opcode)-1, ' ' );

   if ( *opcode == COMMENT )
      *opcode = '\0'; /* It's a comment; not an opcode */

   if ( *opcode != '\0' )
         /* Parse operand */
      if ( parse( &lptr, operand, sizeof(operand)-1, COMMENT ) )
         xerror( "doparse: Invalid Operand" );

   if ( *operand == COMMENT )
      *operand = '\0'; /* It's a comment; not an operand */
   *rlabel = label; *ropcode = opcode; *roperand = operand;
   return( 0 );
   }
*rlabel = label; *ropcode = opcode; *roperand = operand;
return( COMMENT );
}

void usage(void)
{
fprintf( stderr, "Xasm09 Motorola MC6809 Macro Cross Assembler\n" );
fprintf( stderr, "Version 4.0 by David Summers\n" );
fprintf( stderr, "Usage: xasm09 filename [-[i|o|s] objfile]\n" );
exit( 1 );
}

void xerror( char *mesg )
{
errnum++; /* Increment Error Number */
if ( pass == 2 )
   printf( "%s(%d): Error - %s\n", filename, line, mesg );
}

/* Error - Two files have the same name */
void sferror(void)
{
fprintf(stderr,"Error: Two of the output files have the same name\n");
exit( 1 );
}
