
/*
   This software is copyright 1989 by John Dunning.  See the file
   'COPYLEFT.JRD' for the full copyright notice.
*/

/*
   A65:  a macro assembler for 6502's.
 
   a65 [-o foo.obj] [-l foo.l] f1.m65 f2.m65...
*/

#define VERSION "1.0"

#include <stdio.h>
#include "symtab.h"
#include "parse.h"
#include "util.h"

#define MAIN 1
#include "global.h"

/* #define LIST ... turn this on for listing code */
/* #define EITHER .. turn this if ever get around to making the 
			assembler produce either rel or abs files */

FILE * inf;
FILE * outf;
char * in_name[16];
int n_files;
char * out_name;

#ifdef DEBUG
char * sym_name;
#endif

extern int _start;

/* util fun for grokking arglist */
char * arg_value(args, arg_idx, n_args)
char * args[];
int * arg_idx;			/* we might increment this */
int n_args;
{
  int i;
  
  i = *arg_idx;
  if (args[i][2])		/* was there something after the '-x'? */
	return(args[i] + 2);	/* yes, just return that */

  i++;				/* try the next arg */
  if (i >= n_args)		/* no next arg? */
	return(NULL);

  if (*args[i] == '-')		/* next arg not a value? */
	return(NULL);

  *arg_idx = i;			/* put updated value back */
  return(args[i]);		/* and return this arg */
}

#ifdef M6502
char argbuf[80];
#endif

main(argc, argv)
int argc;
char ** argv;
{
  int i, local_pass, fidx, code, class;
/*
  printf("base = %X\n", &_start);
*/

  n_files = 0;		/* no files yet */
#ifdef LIST
  list_p = 0;		/* no listing */
#endif
#ifdef DEBUG
  sym_name = 0;		/* no sym file name yet */
#endif
#ifdef EITHER
  rel_p = 0;		/* no relocatable output */
#endif
  verbose = 0;

#ifdef M6502
/* if no args, prompt for 'em */
  if (argc < 2)
	argc = readargs("RA65>", argbuf, argv + 1) + 1;
#endif

  for (i = 1 ; i < argc ; i++)
	{
/*	printf("considering arg %d '%s'\n", i, argv[i]);	*/
	if (argv[i][0] == '-')
		{
		switch (argv[i][1])
			{
#ifdef LIST
			case 'l': case 'L':
				{
				list_p = 1;
				list_name = arg_value(argv, &i, argc);
				break;
				}
#endif
			case 'o': case 'O':
				{
				out_name = arg_value(argv, &i, argc);
				break;
				}
#ifdef DEBUG
			case 's': case 'S':
				{
				sym_name = arg_value(argv, &i, argc);
				if (!sym_name)
					sym_name = "foo.sym";
				break;
				}
#endif
#ifdef EITHER
/* this is always on for this version of the assembler */
			case 'r': case 'R':
				{
				rel_p = 1;
				if (verbose)
					printf("Relocatable output\n");
				break;
				}
#endif
			case 'v': case 'V':
				{
				verbose++;
				break;
				}
			}
		}
	    else
		{
		in_name[n_files] = frob_name(argv[i]);
		n_files++;
		if (verbose)
			printf("Input file %d %s\n", n_files, argv[i]);
		}
	}

  if (verbose)
	printf("RA65 v %s\n", VERSION);

  if (n_files < 1)
	{
	printf("Try A65 <file>...\n");
	exit(1);
	}

  if (verbose)
	printf("RA65 v %s\n", VERSION);

  init_sym();
#ifdef LIST
  init_list();
#endif
  init_gen();

  for (local_pass = 0 ; local_pass < gen_n_passes() ; local_pass++)
	{
	errcount = 0;
	pass = local_pass;
	pc = 0;
	disabled = 0;
	output_p = (pass == (gen_n_passes() - 1));
	if (output_p != 0)
		{
		gen_o_open(out_name, in_name[0]);
		}
	for (fidx = 0 ; fidx < n_files ; fidx++)
		{
		end_file = 0;
		inf = fopen(in_name[fidx], "r");
/* printf("open('%s')->%X\n", in_name[fidx], inf); */
		line_nbr = 0;
		while (!end_file && read_line(inf, line))
			{
			if (verbose)
				printf("%4d: '%s'\n", line_nbr, line);
			line_nbr++;
#ifdef LIST
			line_listed_p = 0;
#endif
			obj_count = 0;
			parse_line(line, &p);
			if (p.opcode)
				{
				if (opcode_p(p.opcode, &code, &class))
					{
					if (!disabled)
						assemble_op(code, class, 
							&p.arg[0]);
					}
				    else
				if (!do_pseudo())
					barf("Bogus line");
				}
			    else
				if (!disabled)
					gen_label();
#ifdef LIST
			list_line(0);
#endif
			}
		fclose(inf);
		}
#ifdef DEBUG
	if (sym_name)
		dump_syms();
#endif
	if (output_p)
		gen_o_close();
	if (errcount)
		printf("%d errors");
	}
}
