             @L   }5 _$% l0$)$$Hȱ$ UhL"
`e$$%`$%`  
R@P!( L(1 	
	 Y	I`  d L  d
M
	*@ $%
C C$$)%1 Udߥ$9%:	 !0 S$% D D˙`  }J)Lr 
/*
   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(ar 
}gs, arg_idx, n_args)
char * args[];
int * arg_idx;			/* we might increment this */
int n_args;
{
  int i;
  
  i = *ar }g_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 ar }g */
}

#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_n }ame = arg_value(argv, &i, argc);
				break;
				}
#ifdef DEBUG
			case 's': case 'S':
				{
				sym_name = arg_value(ar }gv, &i, argc);
				if (!sym_name)
					sym_name = "foo.sym";
				break;
				}
#endif
#ifdef EITHER
/* this is always o }n for this version of the assembler */
			case 'r': case 'R':
				{
				rel_p = 1;
				if (verbose)
					printf("Relocat }able 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();
#endi }f
  init_gen();

  for (local_pass = 0 ; local_pass < gen_n_passes() ; local_pass++)
	{
	errcount = 0;
	pass = local_pa }ss;
	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");
/* pr }intf("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_coun !}t = 0;
			parse_line(line, &p);
			if (p.opcode)
				{
				if (opcode_p(p.opcode, &code, &class))
					{
					if (!disa "}bled)
						assemble_op(code, class, 
							&p.arg[0]);
					}
				    else
				if (!do_pseudo())
					barf("Bogus lin #}e");
				}
			    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 er %}rors");
	}
}
UG
	if (sym_name)
		dump_syms();
#endif
	if (output_p)
		gen_o_close();
	if (errcount)
		printf("%d er   CC65 ---- This is the (c) copyright notice for RA65, LINK65, LIBR65, and other Atari 8-bit programs.  Said programs a'}re Copyright 1989, by John R. Dunning.  All rights reserved, with the following exceptions: Anyone may copy or redistrib(}ute these programs, provided that: 1:  You don't charge anything for     the copy.  It is permissable     to charge a no)}minal fee for     media, etc. 2:  All source code and     documentation for the programs     is made available as part o*}f     the distribution. 3:  This copyright notice is     preserved verbatim, and     included in the distribution. You+} are allowed to modify these programs, and redistribute the modified versions, provided that the modifications are clearly,} noted. There is NO WARRANTY with this software, it comes as is, and is distributed in the hope that it may be useful.-} This copyright notice is based on the one published by the Free Software Foundation, sometimes known as the GNU project..}  The idea is the same as theirs, ie the software is free, and is intended to stay that way. Everybody has the right to c/}opy, modify, and redistribute this software. Nobody has the right to prevent anyone else from copying, modifying or redis0}tributing it.d redistribute this software. Nobody has the right to prevent anyone else from copying, modifying or redis 
/*
   This software is copyright 1989 by John Dunning.  See the file
   'COPYLEFT.JRD' for the full copyright notice.
*/2}

/* error stuff */

#include <stdio.h>
#include "global.h"

#ifdef M6502
barf()
{
  int * arg;
  
  arg = &arg;	3}	/* point at self */
  arg += arg[1] + 1;	/* add next word; arg count, plus 1 */
  fprintf(stderr, *arg, *--arg, *--arg, *-4}-arg);
  fprintf(stderr, "\n");
  exit(1);
}

#else
barf(msg, arg1, arg2, arg3)
char * msg;
int arg1, arg2, arg3;
{5}
  list_line(1);
  printf("Error: ");
  printf(msg, arg1, arg2, arg3);
  printf("\n");
  errcount++;
}
#endif

3;
{ w
/*
   This software is copyright 1989 by John Dunning.  See the file
   'COPYLEFT.JRD' for the full copyright notice.
*/7}

/* expression evaluator */

#include "eval.h"
#include "symtab.h"
#include "global.h"

char tbuf[32];

char * eva8}l_internal();		/* forward decl */

int digit(c)
char c;
{

  if ((c >= '0') && (c <= '9'))
	return(c - '0');
    else9}
  if ((c >= 'A') && (c <= 'F'))
	return(c - 'A' + 10);
    else
	return(-1);
}

char * grok_fixnum(str, base, result):}
char * str;
int base;
int * result;
{
  int d;
  char * s;
  int neg;

  s = str;
  *result = 0;
  neg = 0;

  ;}if (*s == '-')
	{
	neg = 1;
	s++;
	}
  while (((d = digit(toupper(*s))) >= 0) && (d <= base))
	{
	*result = *result * <}base + d;
	s++;
	}
  if (neg)
	{
	*result = -(*result);
	}
  return(s);
}
  
/* eval one q, return updated string p=}tr */
char * eval_q(str, val, expr_flags, sym_ref)
char * str;
int * val;
int * expr_flags;
struct sym ** sym_ref;
{
 >} char c;
  char * p;
  struct sym * sy;
  int i;

  while((c = *str) && white_p(c))
	str++;
  if (id_start_p(c))
	{
?}/* symbol */
	p = tbuf;
	*p++ = *str++;
	while(id_char_p(*str))
		*p++ = *str++;
	*p = '\0';
	if ((tbuf[0] == '.') && (@}tbuf[1] == '\0'))
		*val = pc;
	    else
		{
		sy = find_sym(tbuf, 1);
		if ((!(sy->flags & DEFINED)) && (pass == 1))
	A}		barf("undefined symbol '%s'", tbuf);
		if (!(sy->flags & DEFINED))
			*expr_flags |= E_UNDEF;
		if (!(sy->flags & ABS))B}
			*expr_flags |= E_REL;
		*sym_ref = sy;
		*val = sy->value;
		}
	}
    else
  if (c == '$')		/* hex constant */
	stC}r = grok_fixnum(str + 1, 16, val);
    else
  if (c == '0')		/* octal constant */
	str = grok_fixnum(str, 8, val);
    elD}se
  if (c == '@')		/* octal constant */
	str = grok_fixnum(str + 1, 8, val);
    else
  if (c == '%')		/* binary constanE}t */
	str = grok_fixnum(str + 1, 2, val);
    else
  if (c == '^')		/* constant with radix */
	{
	switch(str[1])
		{
	F}	case 'o': { str = grok_fixnum(str + 2, 8, val); break; };
		case 'x': { str = grok_fixnum(str + 2, 16, val); break; };
		cG}ase 'd': { str = grok_fixnum(str + 2, 10, val); break; };
		}
	}
    else
  if (((c > '0') && (c <= '9')) || (c == '-'))	H}/* decimal constant */
	str = grok_fixnum(str, 10, val);
    else
  if (c == '\'')
	{
	*val = str[1];
	str += 2;
	}
 I}   else
  if (c == '*')
	{
	*val = pc;
	str++;
	}
    else
  if (c == '<')
	str = eval_internal(str + 1, val, expr_flJ}ags, sym_ref);
    else
  barf("eval error: bogus operand '%c'", c);

  return(str);
}

char * binop(str, accum, expr_K}flags, sym_ref)
char * str;
int * accum;
int * expr_flags;
struct sym ** sym_ref;
{
  int val;
  char c;

  c = *strL}++;
  str = eval_q(str, &val, expr_flags, sym_ref);
  switch (c)
	{
	case '+': { *accum += val; break; }
	case '-': { *aM}ccum -= val; break; }
	case '*': { *accum *= val; break; }
	case '/': { *accum /= val; break; }
	case '&': { *accum &= valN}; break; }
	case '|':
	case '!': { *accum |= val; break; }
	}
  return(str);
}

char * eval_internal(str, val, expr_flO}ags, sym_ref)
char * str;
int * val;
int * expr_flags;
struct sym ** sym_ref;
{
  int accum;

  str = eval_q(str, &acP}cum, expr_flags, sym_ref);
  while (white_p(*str))
	str++;
  while (*str)				/* more expr? */
	switch(*str)
		{
		case Q}'+': case '-': case '*': case '/':
		case '&': case '|': case '!':
			{
			str = binop(str, &accum, expr_flags, sym_ref);R}
			break;
			}
		case '\\':
			{
			(*expr_flags) |= E_LO_BYTE;
			accum &= 0xFF;
			str++;
			break;
			}
		case 'S}^':
			{
			(*expr_flags) |= E_HI_BYTE;
			accum >>= 8;
			str++;
			break;
			}
		case '>':		/* end recursive eval */T}
			{
			*val = accum;
			return(++str);			
			}
		default: str++;
		};
  *val = accum;
  return(str);
}

int evalU}(str, expr_flags, sym_ref)
char * str;
int  * expr_flags;
struct sym ** sym_ref;
{
  int accum;

  *expr_flags = 0;
 V} *sym_ref = (struct sym *)0;
  eval_internal(str, &accum, expr_flags, sym_ref);

#ifdef DEBUG
  printf("eval('%s')->%X flW}ags %X sym %X\n", str, accum, *expr_flags, *sym_ref);
#endif
  return(accum);
}
#ifdef DEBUG
  printf("eval('%s')->%X fl T
/*
   This software is copyright 1989 by John Dunning.  See the file
   'COPYLEFT.JRD' for the full copyright notice.
*/Y}


/* defs for the evaluator */

/* these are bits in the 'expr_flags' byte returned from eval */

#define	E_UNDEF	1	/Z}* expr contains an undefined sym */
#define	E_REL	2	/* expr contains a relative reference */
#define E_HI_BYTE 8	/* hi part[} of some value */
#define E_LO_BYTE 16	/* lo part */
 expr contains a relative reference */
#define E_HI_BYTE 8	/* hi part 7
/*
   This software is copyright 1989 by John Dunning.  See the file
   'COPYLEFT.JRD' for the full copyright notice.
*/]}

/* entry pts for code generator */

extern genlit();
extern genbyte();
extern genword();
extern gen_label();
extern^} gen_n_passes();
or code generator */

extern genlit();
extern genbyte();
extern genword();
extern gen_label();
extern 
/*
   This software is copyright 1989 by John Dunning.  See the file
   'COPYLEFT.JRD' for the full copyright notice.
*/`}

/* global vars for a65 */

#ifdef MAIN
#define ID
#else
#define ID extern
#endif

ID char line[256];		/* line bufa}fer */
ID struct parse p;		/* parsed line */
ID int line_nbr;		/* current line number */

ID char * list_name;		/* name ob}f file we're listing to, if any */
ID int list_pc;			/* pc before read line */
ID char list_pc_p;		/* lsit pc even if no obc}ject bytes */
ID char obj[4];			/* generated code */
ID int obj_count;		/* n valid bytes */
ID char line_listed_p;		/* if d}text this line has been printed */
ID int list_v;			/* other value to show up in listing */
ID char list_v_p;		/* use that e}instead of obj bytes */

ID char page_title[64];		/* page title string */
ID char page_subttl[64];	/* subtitle */
ID int f}page_nbr;		/* page number */
ID int line_in_page;

ID int errcount;
ID char output_p;		/* flag for generating output */
g}
/* conditional stuff */

ID char disabled;		/* if we've evaluated an IF that was false */

/* global assembler state */h}

ID unsigned int pc;		/* pc for assembler */

#define SEG_ABS	0		/* we're doing absolute defs */
#define SEG_REL	1		/* i}we're doing relative defs */
ID int curr_seg;		/* current state; one of the above values */
ID unsigned int abs_pc, rel_pc;j}	/* last known pc, each seg */
ID char rel_p;			/* if relocatable output */

ID int pass;			/* what pass we're doing */
Ik}D int end_file;		/* if we saw a .end pseudo */
ID char list_p;			/* generating listing */

ID char verbose;			/* various vl}erbosities */

/* if we saw a .end pseudo */
ID char list_p;			/* generating listing */

ID char verbose;			/* various v 
/*
   This software is copyright 1989 by John Dunning.  See the file
   'COPYLEFT.JRD' for the full copyright notice.
*/n}

/* defs for library files

#ifndef _TYPES_
#include "types.h"
#endif

A library file consists of a header lump, as o}described below, some number
of module descriptors, and images of files.

magic number identifies library files */
#definp}e LIBR_HEADER 0xFCFC

struct librfile
	{
	USHORT l_header;	/* magic num, as above */
	USHORT type;		/* type of library, q}values below */
	USHORT n_modules;	/* number modules this library */
	USHORT l_flags;		/* library flags, defined below */
r}	};

/* library types */
#define LT_OLB	1			/* an object library */

/* flags for object libraries */
#define LOLB_DEF	s}0x0001		/* library contains a symbol dictionary */

/* a module of the library */
struct librmod
	{
	char m_name[12];		/t}* entry name, typically file name */
	USHORT m_nbytes;		/* n bytes in entry */
	};

uct librmod
	{
	char m_name[12];		/ X
/*
   This software is copyright 1989 by John Dunning.  See the file
   'COPYLEFT.JRD' for the full copyright notice.
*/ v}


/* object library maintainer for atari 8-bit .obj files.
   later, maybe random other kinds of files too. */

#defin w}e VERSION "1.0"

#include <stdio.h>
#include <ctype.h>
#include <file.h>

#ifdef M6502
/* lots of things in here are d x}efined to use 16-bit values */
#define USHORT int
/* other stuff might as well go here */
#define unlink delete
#define m y}alloc xmalloc

#else
#define USHORT unsigned short
#endif

#include "symtab.h"
#include "obj.h"
#include "libr.h"

 z}#ifdef M6502
/* do this part differently on 800 */
#else
#include <types.h>
#include <stat.h>		/* for _dta, for file size {} */
#endif

char * lfname;			/* name of the file we've got open */
int in_lfd;			/* fd of the file we've got open */
int |} out_lfd;			/* fd output, if writing */
int obj_lfd;			/* fd for .obj files */

struct librfile lfile;		/* header of the f }}ile we've got open */

int input_fd;			/* fd of obj files we read */

#ifdef __GNUC__
int _stksize = 16384;
#endif

/ ~}* defs for keeping track of what we're doing when maintaining a library */

/* we build a linked list of these when adding/ }deleting etc.  If we
   were writing this in a real language, we'd do this with included
   defstructs, but since we must u }se C, we make the first part of
   this look just like the def of a librmod, in libr.h.  */

struct entry
	{
	char e_nam }e[12];	/* the file name of this entry */
	USHORT e_nbytes;	/* nbytes this entry */
	struct entry * e_next;	/* next entry */ }
	int new;		/* if this is a new entry */
	int skip;		/* this is an old entry being skipped */
	};

#define SKIP_REPLACE	 }1
#define SKIP_DELETE	2

char * skip_names[] =
	{
	"", "Replacing", "Deleting"
	};

struct entry * lfile_components; }



#ifdef M6502
/* debug code */

char * xmalloc(n)
int n;
{
  char * foo;
  
  foo = pmalloc(n);
/*  printf("xm }alloc(%d)->%x; sp %x\n", n, foo, &foo); */
  bzero(foo, n);
  return(foo);
}
#endif

/* util routines */

min(x, y)
 }int x,y;
{
  if (x < y) 
    return(x);
   else
    return(y);
}

#ifndef M6502
unsigned
#endif
char read8(input_f }d)
int input_fd;
{
#ifdef M6502
  unsigned 
#endif
	char foo;
  read(input_fd, &foo, 1);
  return(foo);
}

USHORT  }read16(input_fd)
int input_fd;
{
  return(read8(input_fd) | (read8(input_fd) << 8));
}

write8(ch)
char ch;
{
  writ }e(out_lfd, &ch, 1);
}

write16(sh)
USHORT sh;
{
  write8(sh & 0xFF);
  write8(sh >> 8);
}

int open_carefully(name, } mode, must_exist)
char * name;
int mode;
int must_exist;
{
  int fd;
#ifdef M6502
  char buf[64];
/* prepend a D: if } necessary */
  if (!strchr(name, ':'))
	{
	strcpy(buf, "D:");
	strcat(buf, name);
	name = buf;
	}
#endif
  printf("o }pen('%s', %x)->", name, mode);
  fd = open(name, mode);
  if ((fd < 0) && must_exist)
  	barf("Can't open '%s'\n", name); }
  printf("%d\n", fd);
  return(fd);
}

read_header(fd)
int fd;
{
  lfile.l_header = read16(fd);
  lfile.type = read1 }6(fd);
  lfile.n_modules = read16(fd);
  lfile.flags = read16(fd);
/*
#ifdef M6502
  printf("read_header: %x %x %x %x\n" }, lfile.l_header, 
	lfile.type, lfile.n_modules, lfile.flags);
#endif
*/
}

read_mdesc(fd, mod)
int fd;
struct librmo }d * mod;
{
  read(fd, mod->m_name, 12);
  mod->m_nbytes = read16(fd);
}

/* build the module list for an existing file. }  assume the next byte 
   to be read is the first one of the module structs.  assume lfile
   is valid */
build_modlist(f }d)
int fd;
{
  int i;
  struct entry * elt;
  struct entry * prev_elt;

  lfile_components = elt = 
#ifdef M6502
			 }	0;
#else
				(struct entry * )NULL;
#endif
  for (i = 0 ; i < lfile.n_modules ; i++)
	{
	prev_elt = elt;
	elt = 
#if }def M6502
		malloc(sizeof(struct entry));
#else
		(struct entry *)malloc(sizeof(struct entry));
#endif
	read(fd, elt->e_ }name, 12);
	elt->e_nbytes = read16(fd);
/*
#ifdef M6502
  printf("build_modlist: got name '%s' nbytes %d\n", 
	elt->e_na }me, elt->e_nbytes);
#endif
*/
	elt->new = 0;
	elt->skip = 0;
	if (prev_elt)
		prev_elt->e_next = elt;
	    else
		lfi }le_components = elt;
	}	
}

string_upcase(str)
char * str;
{
  for ( ; *str ; str++)
	if (islower(*str))
		*str = to }upper(*str);
}

int string_equal(str1, str2)
char * str1, * str2;
{
  for ( ; *str1 || *str2 ; str1++, str2++)
	if (*s }tr1 != *str2)
		return(0);
	return(1);
}
/* not needed?
char * string_copy(str)
char * str;
{
  char * t = (char * )m }alloc(strlen(str) + 1);
  strcpy(t, str);
  return(t);
}
*/

string_pad(target, source, nbytes)
char * target;
char * } source;
int nbytes;
{
  int i;
  
  for (i = nbytes ; (i > 0) && (*source) ; i--)
	*target++ = *source++;
  for ( ; i } > 0 ; i--)
	*target++ = ' ';
}

string_trim(target, source, nbytes)
char * target;
char * source;
int nbytes;
{
  f }or ( ; ((nbytes > 0) && (*source != ' ')) ; nbytes--)
	*target++ = *source++;
  *target = '\0';
}

/* maintaining entry  }list */

struct entry * last_entry()
{
  struct entry * elt;
  
  for (elt = lfile_components ; elt && elt->e_next ; el }t = elt->e_next)
	;
  return(elt);
}

/* delete an entry.  return 1 if found it */

int del_entry(name, why)
char * n }ame;
int why;
{
  struct entry * elt;
  char buf[80];
  int found;

  found = 0;
  string_upcase(name);
  for (elt = } lfile_components ; elt ; )
	{
	string_trim(buf, elt->e_name, 12);
	if (string_equal(name, buf))
		{
		/* set skip bit i }n this one; we always add new 
		   entries at the end */
		elt->skip = why;
		found++;
		}
	if (elt)
		elt = elt->e_ne }xt;
	}
  return(found);
}

/* return 1 if replaced old entry */
int add_entry(name, nbytes)
char * name;
int nbytes; }
{
  struct entry * elt;
  struct entry * prev_elt;
  int replaced;
  char buf[14];

  prev_elt = 
#ifdef M6502
		NUL }L;
#else
		(struct entry *)NULL;
#endif
  replaced = del_entry(name, SKIP_REPLACE);
  prev_elt = last_entry();

  /* n }ow make the new one */
  elt = 
#ifdef M6502
	malloc(sizeof(struct entry));
#else
	(struct entry *)malloc(sizeof(struct  }entry));
#endif

#ifdef M6502
/* dump drivespec if any */
  {
    char * p;
    
    if (p = strchr(name, ':'))
     }	name = p + 1;
  }
#endif

/*  elt->e_name = string_copy(name); */
  string_pad(elt->e_name, name, 12);
  elt->new = 1; }				/* get this from file, not libr */
  elt->e_nbytes = nbytes;
  if (prev_elt)
	prev_elt->e_next = elt;
    else
	lfil }e_components = elt;
  return(replaced);
}

/* on 800, this will have to read and count the whole file,
   unless we're u }sing Spartados */
int file_nbytes(name)
char * name;
{
#ifdef M6502
  char buf[64];
  int fd;
  int siz, total;
  
  } fd = open_carefully(name, O_RDONLY, 1);
  for (total = 0 ; ((siz = read(fd, buf, 64)) > 0) ; )
	total += siz;
  printf("c }lose->%x\n", close(fd));
  printf("%s is %d bytes long\n", name, total);
  return(total);
#else
  struct stat st;
  
   }if (stat(name, &st) < 0)
	return(-1);
    else
	return(st.st_size);
#endif
}

/* zzz */

#ifdef M6502
barf()
{
   }int * arg;
  
  arg = &arg;		/* point at self */
  arg += arg[1] + 1;	/* add next word; arg count, plus 1 */
  fprintf(st }derr, *arg, *--arg, *--arg, *--arg);
  fprintf(stderr, "\n");
  exit(1);
}

#else
barf(msg, arg1, arg2, arg3)
{
  fpr }intf(stderr, msg, arg1, arg2, arg3);
  fprintf(stderr, "\n");
  exit(1);
}
#endif

/* open libr and generate the initia }l components list */
read_library(must_exist)
int must_exist;
{
  int i;

  lfile_components = 
#ifdef M6502
			NULL; }
#else
			(struct entry * )NULL;
#endif
  in_lfd = open_carefully(lfname, O_RDONLY, must_exist);
/*
#ifdef M6502
  pri }ntf("read_lib: fd %x\n", fd);
#endif
*/
  if (in_lfd > 0)			/* open it ok? */
	{
	read_header(in_lfd);		/* read header * }/
	build_modlist(in_lfd);
	return;
	}
    else
	{
	if (must_exist)
		barf("Can't open %s", lfname);
	    else
		{
	 }	fprintf(stderr, "Creating library %s\n", lfname);
		in_lfd = 0;
		lfile_components = (struct entry * )NULL;
		}
	}
}
 }
/* using the components_list, write a new library */

write_library()
{
  struct entry * elt;
  int copy_lfd;
  char b }uf[64];
  int size;
      
  out_lfd = open_carefully("libr65.tmp", O_WRONLY | O_CREAT | O_TRUNC, 0);

  lfile.l_header  }= LIBR_HEADER;
  lfile.type = LT_OLB;		/* fixed, for now */
  lfile.flags = 0;
/* refresh module count */
  lfile.n_modul }es = 0;
  for (elt = lfile_components ; elt ; elt = elt->e_next)
	if (!elt->skip)			/* not skipping this one? */
	  	lfile }.n_modules++;	/* then count it */

/* write the header */
  write16(lfile.l_header);
  write16(lfile.type);
  write16(lf }ile.n_modules);
  write16(lfile.flags);

/* write the dictionary */
  for (elt = lfile_components ; elt ; elt = elt->e_ne }xt)
	if (!elt->skip)
		{
		write(out_lfd, elt->e_name, 12);
		write16(elt->e_nbytes);
		}

/* write the modules themse }lves */
  for (elt = lfile_components ; elt ; elt = elt->e_next)
	{
	string_trim(buf, elt->e_name, 12);
	if (elt->skip)
 }		{
		/* skip this entry in the original library */
		fprintf(stderr, "%s %s\n", skip_names[elt->skip], buf);
		size = elt }->e_nbytes;
		for ( ; size > 0 ; size -= 64)
			read(in_lfd, buf, min(size, 64));
		}
	    else
		{
		if (elt->new)
		 }	{
			/* new file.  open the obj file */
			fprintf(stderr, "Adding %s\n", buf);
			obj_lfd = open_carefully(buf, O_RDONLY }, 1);
			copy_lfd = obj_lfd;
			}
		    else
			{
			fprintf(stderr, "Copying %s\n", buf);
			copy_lfd = in_lfd;
			} }
		/* run the copy loop */
		for (size = elt->e_nbytes ; size > 0 ; size -= 64)
			{
			read(copy_lfd, buf, min(size, 64)) };
			write(out_lfd, buf, min(size, 64));
			}
		/* if have an obj file open, close it */
		if (obj_lfd > 0)
			{
			clo }se(obj_lfd);
			obj_lfd = 0;
			}
		}
	}
  /* copy writing.  close libr file */
  close(out_lfd);
  printf("closing in }_lfd %d\n", in_lfd);
  if (in_lfd > 0)
  	close(in_lfd);
  printf("del '%s'->%x\n", lfname, unlink(lfname));
  printf("re }n '%s','%s'->%x\n", "libr65.tmp", lfname, 
	rename("libr65.tmp", lfname));
  out_lfd = 0;
  printf("New library written\n" });
}
	
/* routines to really do things */

add_files(argc, argv)
int argc;
char ** argv;
{
  int i, nbytes, found;
 }  
  if (argc <= 3)
	barf("Add what files?");
  found = 0;
  read_library(0);		/* read the library */
  for (i = 3 ; i < } argc ; i++)
	{
	nbytes = file_nbytes(argv[i]);
	if (nbytes < 0)
		fprintf(stderr, "%s not found", argv[i]);
	    else
 }		{
		found++;
		add_entry(argv[i], nbytes);
		}
	}
  if (found = 0)
	fprintf(stderr, "No files added");
    else
	wr }ite_library();
  printf("Finished adding files\n");
}

/* delete some library members */
del_files(argc, argv)
int argc };
char ** argv;
{
  struct entry * elt;
  int i, deleted;
  
  if (argc <= 3)
	barf("Delete what files?");
  read_lib }rary(1);
  for (i = 3, deleted = 0 ; i < argc ; i++)
	if (del_entry(argv[i], SKIP_DELETE))
		deleted++;
	    else
		fpri }ntf(stderr, "Library contains no member %s\n", argv[i]);
  if (deleted)
	write_library();
    else
	fprintf(stderr, "No m }embers matched");
   close(in_lfd);
}

list_library()
{
  struct entry * elt;
  char buf[80];
  int i;
  
  read_li }brary(1);
  close(in_lfd);
  strcpy(buf, lfname);
  string_upcase(buf);
  printf("  Library %s\n", buf);
  printf("  --- }---------  -----\n");
  for (elt = lfile_components ; elt ; elt = elt->e_next)
	{
	buf[12] = '\0';
	for (i = 0 ; i < 12 ; } i++)
		{
		buf[i] = elt->e_name[i];
/*
printf("idx %d chr %c buf '%s'\n", i, elt->e_name[i], buf);
*/
		}
	printf("   }%12s  %5d\n", buf, elt->e_nbytes);
	}
}

print_version()
{
  printf("Libr65 v %s\n", VERSION);
}

/* main body */
 }
#ifdef M6502
char cmdline[80];
#endif

main(argc, argv)
int argc;
char ** argv;
{
  char op;			/* what we're doing t }o a file */

#ifdef M6502
/* might not be able to get cmd line from os, so prompt for it */
  if (argc == 0)
	argc = rea }dargs("LIBR65>", cmdline, argv + 1) + 1;
#endif

  if (argc < 3)
	barf("Try LIBR65 <option> <file>");

  op = *argv[1]; }
  lfname = argv[2];

  switch (op)
	{
	case 'a': case 'A':
		add_files(argc, argv);
		break;
	case 'd': case 'D':
	 }	del_files(argc, argv);
		break;
	case 'l': case 'L':
		list_library();
		break;
	case 'v': case 'V':
		print_version() };
		break;
	default:
		barf("I don't understand option '%c'", op);
	}
  exit(0);
}

'v': case 'V':
		print_version()  \
/*
   This software is copyright 1989 by John Dunning.  See the file
   'COPYLEFT.JRD' for the full copyright notice.
*/$}

/* Linker for .obj files produced by ra65 */

#define VERSION "1.0"

#include <stdio.h>
#include <file.h>

#ifdef $}M6502

/* for now, use debug version */
#define malloc xmalloc

#else

/* for other-than-atari, make this a no-op */
$}#define frob_name(name) name

#endif

#include "symtab.h"
#include "obj.h"
#include "libr.h"

#define MAX_MODULES 256$}
#define MAX_LIBS 4
#define MAX_FILES 32

struct obj_module
	{
	USHORT seg_type;	/* either OBJ_HEADER or LIBR_HEADER */$}
	char * seg_name;	/* the name of this file */
	USHORT lib_nbr;		/* the library number */
	USHORT lib_idx;		/* if libr fil$}e, the module nbr in the lib */
	USHORT seg_start;	/* segment start address */
	USHORT seg_size;	/* segment size */
	struc$}t sym ** syms;	/* vector of pointers to symbols */
	};

struct obj_module * module[MAX_MODULES];
int nmodules;

struct $}libr_module
	{
	int used;		/* if this module used */
	int n_defs;		/* n symbols defined this obj module */
	char ** lsyms$};		/* vector of pointers to syms defined */
	};
	
struct libr
	{
	char * l_name;		/* filename this libr */
	int n_mods;$}		/* n modules this libr */
	struct librmod * dict;	/* module dictionary this libr */
	struct libr_module * lm; /* vector o$}f libr_module structs */
	};

struct libr * lib[MAX_LIBS];		/* the libraries we're using */
int n_libs;

char * input_f$}ile[MAX_FILES];
int n_input_files;

/* stuff for hashing syms */
#define HASHMOD 53
struct sym * symtab[HASHMOD];

/* $}stuff for the output file */
int exe_start = 0x2000;		/* executable start addr */
int exe_high_water;

char litbuf[32];
$}
char * output_name = "foo.com";
int input_fd, output_fd;

char map_p = 0;			/* write a map */
char start_p = 1;		/* wri$}te an autostart vector */
char verbose = 0;		/* print debug msgs */

struct relfile rf;
struct librfile lf;

/* flags f$}or searching libraries */
int n_undef;			/* current number undefined symbols */
int satisfied;			/* flag if anything satisf$}ied this pass */
int libs_searched;

char symbuf[32];
int symflags, symval;

#ifdef M6502
/* debug code */

char * x$}malloc(n)
int n;
{
  char * foo;
  
  foo = pmalloc(n);
/*  printf("xmalloc(%d)->%x; sp %x\n", n, foo, &foo); */
  bze$}ro(foo, n);
  return(foo);
}

/* file-name frobber */
char * frob_name(name)
char * name;
{
  char * new_name;
  
 $} if (!strchr(name, ':'))
	{
	new_name = malloc(strlen(name)+3);
	strcpy(new_name, "D:");
	strcat(new_name, name);
	retur$}n(new_name);
	}
  return(name);
}

/* should put this in lib */
int strncmp(s1, s2, n)
char * s1;
char * s2;
int n;$}
{
  for ( ; n > 0 ; --n)
	if (*s1++ != *s2++)
		return(1);
  return(0);
}
#endif

unsigned char read8()
{
  unsign$}ed char foo;
  read(input_fd, &foo, 1);
  return(foo);
}

USHORT read16()
{
  return(read8() | (read8() << 8));
}

$}readskip(nbytes)
int nbytes;
{
  char buf[32];

  while (nbytes > 0)
	{
	read(input_fd, buf, (nbytes > 32) ? 32 : nbyt$}es);
	nbytes -= 32;
	}
}

write8(ch)
unsigned char ch;
{
  write(output_fd, &ch, 1);
}

write16(sh)
USHORT sh;
{$}
  write8(sh & 0xFF);
  write8(sh >> 8);
}

int open_carefully(name, mode)
char * name;
int mode;
{
  int fd;

  n$}ame = frob_name(name);
  if (verbose)
	printf("open('%s', %x)->", name, mode);
  fd = open(name, mode);
  if (fd < 0)
  $}	barf("Can't open '%s'\n", name);
  if (verbose)
	printf("%d\n", fd);
  return(fd);
}

/* read the header of a file int$}o the appropriate data structure.
   return the header type word */
USHORT read_header()
{
  USHORT typ;

  typ = read1$}6();		/* get the header word */
/* printf("read_header: typ=%x\n", typ); */
  switch (typ)
  	{
	case OBJ_HEADER:
		rf.h$}eader = typ;
		rf.nb_sym = read16();
		rf.nb_seg = read16();
		rf.nb_segdata = read16();
		rf.n_sym = read16();
/* print$}f("  obj: nb_sym %d. nb_seg %d. n_sym %d.\n",
	rf.nb_sym, rf.nb_seg, rf.n_sym); */
		break;
	case LIBR_HEADER:
		lf.l_hea$}der = typ;
		lf.type = read16();
		lf.n_modules = read16();
		lf.l_flags = read16();
/* printf("  lib: type %d. n_mod %d.$} flg %x\n", 
	lf.type, lf.n_modules, lf.l_flags); */
		break;
	}
  return(typ);
}

int iswhite(c)
char c;
{
  retur$}n((c == ' ') || (c == '\r') || (c == '\n') || (c == '\t'));
}

int read_token(f, buf)
FILE * f;
char * buf;
{
  int c;$}

  for ( ; ((c = fgetc(f)) != EOF) && iswhite(c) ; )
	;
  if (c == EOF)
	return(0);
  *buf++ = c;
  for ( ; ((c = fge% }tc(f)) != EOF) && !iswhite(c) ; )
	*buf++ = c;
  *buf = '\0';
  return(1);
}

char * clone(s)
char * s;
{
  char * s%}s;

  ss = (char * )malloc(strlen(s) + 1);
  strcpy(ss, s);
  return(ss);
}

#ifdef M6502
char xbuf[80];
#endif

a%}dd_file(name)
char * name;
{
  char * newname;
  char * buf;
  FILE * inf;

/* printf("add_file('%s')\n", name); */
 %} if (name[0] == '@')
	{
#ifdef M6502
	buf = xbuf;
#else
	buf = (char * )alloca(80);
#endif
	if ((inf = fopen(frob_name%}(++name), "r")) == NULL)
		barf("can't open indirect file %s\n", name);
	while (read_token(inf, buf) && (strlen(buf) > 0))%}
		{
		add_file(clone(buf));
		}
	fclose(inf);
	}
    else
	{
	/* maybe caononicalize name here? */
	input_file[n_inp%}ut_files++] = name;
	}
}

struct obj_module * add_object_module(name)
char * name;
{
  module[nmodules] = (struct obj_%}module * )malloc(sizeof(struct obj_module));
  module[nmodules]->seg_name = frob_name(name);
  module[nmodules]->seg_start %}= 0;
  module[nmodules]->seg_size = 0;
  module[nmodules]->syms = (struct sym ** )0;
  nmodules++;
  return(module[nmodul%	}es - 1]);
}

/* intern a symbol */
struct sym * intern(str, flags, value)
char * str;
{
  int hash;
  char * p;
  st%
}ruct sym * sym;

/* printf("intern %s val %04x flags %04x\n", str, value, flags); */
  for (p = str, hash = 0 ; *p ; )
	h%}ash = (hash + *p++) % HASHMOD;
  for (sym = symtab[hash] ; sym ; sym = sym->next)
	if (!strcmp(str, sym->name))
		{
		if %}(flags & DEFINED)
			{
			if ((sym->flags & DEFINED) && 
			    !(sym->flags & ABS))	/* kludge */
				printf("%s multiply%} defined\n", str);
			sym->value = value;
			sym->flags = flags;
			}
		return(sym);
		}
  sym = (struct sym *)malloc((%}sizeof (struct sym) + strlen(str) + 1));
  strcpy(sym->name, str);
  sym->nbr = -1;
  sym->flags = flags;
  sym->value = %}value;
  sym->next = symtab[hash];
  symtab[hash] = sym;
  return(sym);
}

#ifdef M6502
barf()
{
  int * arg;
  
 %} arg = &arg;		/* point at self */
  arg += arg[1] + 1;	/* add next word; arg count, plus 1 */
  fprintf(stderr, *arg, *--ar%}g, *--arg, *--arg);
  fprintf(stderr, "\n");
  exit(1);
}

#else
barf(msg, arg1, arg2, arg3)
{
  fprintf(stderr, msg,%} arg1, arg2, arg3);
  fprintf(stderr, "\n");
  exit(1);
}
#endif

/* a little frob to make referencing symbols easier *%}/
USHORT reference(sym, m)
struct sym * sym;
struct obj_module * m;
{
  if (!(sym->flags & DEFINED))
	printf("Undefined%} symbol %s referenced in module %s\n",
		sym->name, m->seg_name);
  return(sym->value);
}

/* read all interesting data %}about an object file, open on input_fd */
struct obj_module * digest_object_file(name, module, base_addr)
char * name;
int%} module;		/* module index */
USHORT base_addr;
{
  struct obj_module * m;
  int j, k;
  
  m = add_object_module(name);%}
  m->syms = (struct sym ** )malloc(rf.n_sym * 
				         sizeof(struct sym *));
  for (j = 0 ; j < rf.n_sym ; j++)
	{%}
	k = read8();		/* size of symbol name */
	read(input_fd, symbuf, k);
	symbuf[k] = '\0';
	symval = read16();
	symflags =%} read16();
	m->syms[j] = intern(symbuf, symflags, symval);
	if (symflags & THIS_SEG)
		{
/* defined here.  adjust value b%}y segment base */
		m->syms[j]->nbr = module;	/* zzz should check for multiple def */
		if (!(symflags & ABS))
			m->syms[%}j]->value += base_addr;
		m->syms[j]->flags &= ~THIS_SEG;
		m->syms[j]->flags |= DEFINED;
		}
	}
  return(m);
}

/* m%}ap over all syms, applying fun to sym and arg, until fun returns t */
int map_syms(fun, funarg)
int (* fun)();
char * funa%}rg;
{
  int i, ret;
  struct sym * sym;

  for (i = 0 ; i < HASHMOD ; i++)
	{
/* printf("map_syms: bucket %d %x\n", i,%} symtab[i]); */
	for (sym = symtab[i] ; sym ; sym = sym->next)
		{
/* printf("  sym %x\n", sym); */
		if (ret = (*fun)(sy%}m, funarg))
			return(ret);
		}
	}
}

int count_undef_sym(sym, arg)
struct sym * sym;
char * arg;		/* ignored */
{
% }  if (!(sym->flags & DEFINED))
	n_undef++;
  return(0);
}

int sym_needed(sym, sym_name)
struct sym * sym;
char * sym_%!}name;		/* a textc string */
{
  return((!(sym->flags & DEFINED)) &&
	 (strlen(sym->name) == *sym_name) &&
	 (!strncmp(sym%"}->name, sym_name+1, *sym_name)));
}

#ifdef old
search_lib(lib_nbr)
int lib_nbr;
{
  char * syms;			/* buf for a modul%#}e's symbols */
  char * sym_p;			/* ptr into symbuf */
  int m;			/* module index */
  int s;			/* symbol number */
  int%$} needed;			/* module needed flag */
  int m_type;
  int flags, value;
  unsigned short * iptr;
  struct obj_module * mod;%%}

  syms = (char * )malloc(65536);	/* kludge */
  input_fd = open_carefully(lib[lib_nbr], O_RDONLY);
  read_header();		/*%&} read the libr header */
  for (m = 0 ; m < lf.n_modules ; ++m)
	read(input_fd, symbuf, 14);	/* skip the libr dictionary */%'}
  for (m = 0 ; m < lf.n_modules ; ++m)
	{
	if ((m_type = read_header()) != OBJ_HEADER)
		barf("Search: not an object mod%(}ule?!? type %04x", m_type);
	read(input_fd, syms, rf.nb_sym - 2);	/* read the whole symtab */
/*
printf("trying module %d\%)}n", m);
{ int ii;
  for (ii = 0 ; ii < 16 ; ii++)
    printf(" %02x", syms[ii]);
  printf("\n");
}
*/
	/* walk syms in%*} this module, seeing if we need any of them */
	sym_p = syms;
	needed = 0;		/* so far ... */
	for (s = 0 ; s < rf.n_sym ; %+}s++)
		{
/*		iptr = sym_p + (*sym_p) + 1;	/* point at value */
/*		value = *iptr;
/*		flags = *++iptr;		*/
		strncpy(sym%,}buf, sym_p + 1, *sym_p);
		if ((flags & THIS_SEG) &&	/* defined here? */
		    (map_syms(sym_needed, sym_p)))
			{
			nee%-}ded = 1;
			break;
			}
		}
	if (needed)
	/* add the module, and intern all these syms */
		{
		mod = add_object_modul%.}e(lib[lib_nbr]);
		mod->seg_type = LIBR_HEADER;
		mod->lib_idx = m;		/* module nbr in libr */
		mod->syms = (struct sym **%/} )malloc(rf.n_sym * 
				         sizeof(struct sym *));
		mod->seg_start = exe_high_water;
		mod->seg_size = rf.nb_seg;
%0}		exe_high_water += rf.nb_seg;

		sym_p = syms;
		for (s = 0 ; s < rf.n_sym ; ++s)
			{
			iptr = sym_p + (*sym_p) + 1;	%1}/* point at value */
			value = *iptr;
			flags = *++iptr;
			sym_p[*sym_p+1] = '\0';		/* so it's a C string */
			mod->s%2}yms[s] = intern(sym_p+1, flags, value);
			}
		}
	/* skip the segment data this obj module */
	read(input_fd, syms, rf.nb%3}_segdata);
	}
  close(input_fd);		/* close the library */
  free(syms);
}
#endif

/* for debugging */
int describe_sy%4}m(sym, str)
struct sym * sym;
char * str;
{
  printf("%s: sym %x name %s\n", str, sym, sym->name);
  return(0);
}

/*%5} search all libr structs for syms that satisfy refs from our symtab */
int search_lib(sym, ignore)
struct sym * sym;
int i%6}gnore;
{
  int libnum;
  int modnum;
  struct libr_module * mod;
  int symnum;
  char ** defname;

/* describe_sym(sy%7}m, "    search"); */
  if (!(sym->flags & DEFINED))		/* sym not defined? */
    for (libnum = 0 ; libnum < n_libs ; libnum+%8}+)
	for (modnum = 0 ; modnum < lib[libnum]->n_mods ; modnum++)
	    {
	    mod = &lib[libnum]->lm[modnum];
	    for (symn%9}um = 0, defname = mod->lsyms ;
	         symnum < mod->n_defs ;
		 defname++, symnum++)
		{
	   	if (!(strcmp(sym->name, %:}*defname)))
			{
			mod->used = 1;
			satisfied = 1;
			return(0);		/* keep scanning syms */
			}
		}
	    }
  return%;}(0);
}

char * xsyms = 0;	/* ptr to temp buffer for syms */

add_library(name)
char * name;
{
/*  char * syms;		/* sy%<}mtab buffer */
  char * sym_p;
  int s, m;		/* symbol number, module number */
  unsigned char * fp;
  USHORT flags;		/* %=}symbol flags */
  struct libr * l;
  struct libr_module * mod;
  int i;

  l = lib[n_libs] = (struct libr * )malloc(size%>}of(struct libr));
  
  l->l_name = frob_name(name);	/* record the name */
  l->n_mods = lf.n_modules;

  if (!xsyms)
#i%?}fdef M6502
  xsyms = (char * )malloc(4096);	/* kludge */
#else
  xsyms = (char * )malloc(65536);	/* kludge */
#endif

 %@} l->dict = (struct librmod *)malloc(lf.n_modules * sizeof(struct librmod));
/* printf("lib contains %d modules\n", lf.n_modu%A}les); */
  for (m = 0 ; m < lf.n_modules ; m++)
  	{
	read(input_fd, l->dict[m].m_name, 12);	/* get the module name */
	l%B}->dict[m].m_nbytes = read16();		/* get module size */
/* printf("%d: %12s %d\n", m, l->dict[m].m_name, l->dict[m].m_nbytes);%C} */
	}

  l->lm = (struct libr_module * )
  		malloc(lf.n_modules * sizeof(struct libr_module));

  for (m = 0 ; m < lf%D}.n_modules ; m++)
	{
/* printf("digest module %d\n", m); */
	if ((i = read_header()) != OBJ_HEADER)	/* read obj header */%E}
		barf("internal error, lib contains module type %04x\n", i);

	mod = &l->lm[m];
	mod->used = mod->n_defs = 0;

	if (rf%F}.nb_sym > 2)
		read(input_fd, xsyms, rf.nb_sym - 2);	/* read the whole symtab */
	sym_p = xsyms;
	for (s = 0 ; s < rf.n_sy%G}m ; s++)
		{
		/* construct the flags word */
		fp = (unsigned char * )sym_p + *sym_p + 3;
		flags = *fp | (fp[1] << 8);%H}
/* printf("    sym %d ptr %x flags %x\n", s, fp, flags); */

		if (flags & THIS_SEG)		/* defined here? */
			{
			/* cou%I}nt this one */
			mod->n_defs++;
			}
		sym_p = sym_p + *sym_p + 5;
		}
	/* make a vector to hold all the names */
/* p%J}rintf("  %d syms defined here\n", mod->n_defs); */
	if (mod->n_defs > 0)
		{
		mod->lsyms = (char ** )malloc(mod->n_defs *%K} sizeof(char **));
		sym_p = xsyms;
		for (s = 0, i = 0 ; s < rf.n_sym ; s++)
			{
			fp = (unsigned char * )sym_p + *sym%L}_p + 3;
			flags = *fp | (fp[1] << 8);

			if (flags & THIS_SEG)		/* defined here? */
				{
				sym_p[*sym_p + 1] = '\0'%M};
				mod->lsyms[i++] = clone(sym_p + 1);
				}
			sym_p = sym_p + *sym_p + 5;
			}
		}		
	readskip(rf.nb_segdata);	/* %N}skip the segment data */
	}			/* loop for module... */
/*  free(syms); */
  close(input_fd);
  n_libs++;		/* count the li%O}brary */
}

process_segdata(mod)
struct obj_module * mod;		/* struct corresponding to this data */
{
  int j, k, op;
%P}
  readskip(rf.nb_sym - 2);			/* skip symtab */

  for (j = 0 ; j < rf.nb_segdata ; )
	{
	op = read8();		/* get an opcode%Q} */
/* printf("  op %x\n", op); */
	j += 1;			/* count it */
	switch (op & OP_GEN_MASK)
	    {
	    case OP_LIT:
		{
	%R}	if (op == 0)
			op = 32;
		read(input_fd, litbuf, op);
		write(output_fd, litbuf, op);
		j += op;
		break;
		}
	    c%S}ase OP_REL:
		{
		switch(op)
		    {
		    case OP_REL:
			{
			write16(read16() + mod->seg_start);
			j += 2;
			bre%T}ak;
			}
		    case OP_REL_HI:
			{
			write8((read16() + mod->seg_start) >> 8);
			j += 2;
			break;
			}
		    case%U} OP_REL_LO:
			{
			write8((read16() + mod->seg_start) & 0xFF);
			j += 2;
			break;
			}
		    }
		break;
		}
	    %V}default:		/* must be sym */
		{
		k = op & 0x1F;
		if (op & OP_SYM_EMASK)
			{
			k = (k << 8) | read8();
			j++;
			}%W}
		switch (op & OP_SYM_MASK)
		    {
		    case OP_SYM:
			{
			int foo;

			foo = read16();
/* printf("generate word%X} %X + '%s' value %X\n", foo,
	&module[i]->syms[k]->name, module[i]->syms[k]->value); */
			write16(foo + reference(mod->sym%Y}s[k], mod));
			j += 2;
			break;
			}
		    case OP_SYM_HI:
			{
/*			write16((read16() + reference(mod->syms[k], mod)%Z})
				>> 8);		*/
			write8((read16() + reference(mod->syms[k], mod))
				>> 8);
			j += 2;
			break;
			}
		    case O%[}P_SYM_LO:
			{
/*			write16((read16() + reference(mod->syms[k], mod))
				& 0xFF);		*/
			write8((read16() + reference(mo%\}d->syms[k], mod))
				& 0xFF);
			j += 2;
			break;
			}
		    }
		break;
		}
	    }
	}
}

#ifdef M6502
char arg%]}buf[80];
#endif

main(argc, argv)
int argc;
char ** argv;
{
  int i, j, k, op;
  struct obj_module * m;

  struct s%^}ym * high_water;		/* special sym for top of executable */

#ifdef M6502
/* if no args, prompt for 'em */
  if (argc < 2)%_}
	argc = readargs("LINK65>", argbuf, argv + 1) + 1;
#endif

/* init stuff */
  for (i = 0 ; i < HASHMOD ; i++)
	symtab[i%`}] = (struct sym *)0;

  n_input_files = nmodules = n_libs = 0;

/* grok args */
  argv++;
  while (--argc)
	{
	if ((*%a}argv)[0] == '-')
		switch ((*argv)[1])
			{
			case 'v': case 'V':
				{
				++verbose;
				break;
				}
			case 'b':%b} case 'B':
				{
				char * x;
				char * hex;
				int base;
				int d;
				
				x = (*argv)+2;
				hex = "0123456789%c}ABCDEF";
				d = 0;
/* printf("base string '%s'\n", x); */
				while (d = *x++)
					{
					if (d < 'A')
						d = d - %d}'0';
					    else
						d = (d - 'A') + 10;
					base = (base * 16) + d;
					}
				exe_start = base;
				break;
				%e}}
			case 'o': case 'O':
				{
				output_name = *++argv;
				argc--;
				break;
				}
			case 'm': case 'M':
				{
%f}				map_p = 1;
				break;
				}
			case 'n': case 'N':
				{
				start_p = 0;
				break;
				}
			/* more later... */%g}
			default:
				printf("don't grok arg %s\n", *argv);
			}
	    else
	 	add_file(*argv);
	argv++;
	}

  if (verbose%q}&                                                                                                                      B"  A65     C  B & COPYLEFTDOCB 1 ERROR   C  B" 6 EVAL    C  B X EVAL    H  B \ GEN     H  B _ GLOBAL  H  B m LIBR    H  Bf u LIBR65  C  B  LINK65  C  B LIST    C  B MAKE8      B MAKEFILE   B	 OBJ     H  Bj OPCODE  C  B  9PARSE   C  B YPARSE   H  B ^PRINTOBJC   {README  TXTB }SYMTAB  C  B SYMTAB  H  B TYPES   H  B UTIL    C  B UTIL    H  $ XGEN    C                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  )
	printf("Link65 v %s\n", VERSION);

  exe_high_water = exe_start;

/* intern special symbols */
  high_water = intern%r}("__FREEMEM", DEFINED | ABS, 0);
  
/* Read each input file, classifying file type.  For obj files, read each
   object he%s}ader, recording segment size, start addr etc, intern symbols
   for this module.  For librs, digest each module as though it%t} were a
   distinct obj file, but leave the 'used' bit in the struct clear. */

  for (i = 0 ; i < n_input_files ; i++)
	%u}{
	input_fd = open_carefully(input_file[i], O_RDONLY);
	j = read_header();
	if (j == OBJ_HEADER)
		{
		m = digest_object%v}_file(input_file[i], i, exe_high_water);
		m->seg_start = exe_high_water;
		m->seg_size = rf.nb_seg;
		exe_high_water += r%w}f.nb_seg;
		}
	    else
	if (j == LIBR_HEADER)
		{
		/* just record the name */
		add_library(input_file[i]);
		}
	  %x}  else
		barf("%s is not an object file or library: header word %04x\n",
			module[i]->seg_name, j);
	close(input_fd);
	}%y}
/* if there are any undefined symbols, search libraries for them */
  satisfied = 1;		/* hot-wire loop */
  for( ; (satis%z}fied != 0) ; )
	{
	satisfied = 0;
	map_syms(search_lib, NULL);

	if (satisfied)
		/* walk all librs, digesting modules %{}that are used */
		{
		for (i = 0 ; i < n_libs ; i++)
			{
			input_fd = open_carefully(lib[i]->l_name, O_RDONLY);
			re%|}ad_header();
			/* skip dictionary */
			readskip(lf.n_modules * 14);

			for (j = 0 ; j < lf.n_modules ; j++)
				{
		%}}		struct libr_module * lmod;
/*				struct obj_module * m;	*/
				
				if ((k = read_header()) != OBJ_HEADER)
					barf ("%~}internal error, type %04x", k);
				lmod = &lib[i]->lm[j];
				if (lmod->used)
					{
					m = digest_object_file(lib[i]-%}>l_name, 0, 
						exe_high_water);
					m->seg_type = LIBR_HEADER;
					m->lib_idx = j;
					m->seg_start = exe_high_wat%}er;
					m->seg_size = rf.nb_seg;
					exe_high_water += rf.nb_seg;
					readskip(rf.nb_segdata);
					lmod->used = 0;
/%}*					free(lmod->syms);	*/
					lmod->lsyms = NULL;
					lmod->n_defs = 0;
					}
				    else
					{
					readskip(rf.%}nb_segdata + rf.nb_sym - 2);
					}
				}				
			close(input_fd);
			}
		}
	}

/* set values for special symbols */
%}  if (verbose)
	printf("setting high water to %x sym %x\n", exe_high_water, high_water);
  high_water->value = exe_high_wat%}er;

/* all modules now digested.  read each seg data, interpreting fragment types */

  output_fd = open_carefully(outpu%}t_name, O_WRONLY | O_CREAT | O_TRUNC);
/* write the atari executable header */
  write16(0xFFFF);
  write16(exe_start);
 %} write16(exe_high_water - 1);

  {
  char * curr_lib;			/* current library file open */
  int curr_idx;				/* current lib%} idx, if lib */
  
  curr_lib = NULL;
  curr_idx = -1;
  for (i = 0 ; i < nmodules ; i++)
	{
	m = module[i];
	if ((m->%}seg_type == LIBR_HEADER) &&
	    curr_lib &&
	    (!strcmp(m->seg_name, curr_lib)) &&
	    (curr_idx <= m->lib_idx))
		{%}
	/* skip modules til find the place in lib where this one starts */
		for ( ; curr_idx < m->lib_idx ; curr_idx++)
			{
		%}	readskip(lib[m->lib_nbr]->dict[curr_idx].m_nbytes);
			}
		}
	  else
	    {
	    if (curr_lib)		/* we have a library op%}en? */
		{
		close(input_fd);
		curr_lib = NULL;
		}
	/* just open the file */
	    input_fd = open_carefully(m->seg_na%}me, O_RDONLY);
	    if (module[i]->seg_type == LIBR_HEADER)
		{
		curr_lib = m->seg_name;
		read_header();
		readskip(lf%}.n_modules * sizeof(struct librmod));
		curr_idx = 0;
	/* skip modules til find the place in lib where this one starts */
%}		for ( ; curr_idx < m->lib_idx ; curr_idx++)
			{
			readskip(lib[m->lib_nbr]->dict[curr_idx].m_nbytes);
			}
		}
	    %}}
	read_header();
	process_segdata(m);
	if (curr_lib)
		curr_idx++;
	if (!curr_lib)			/* if a libr, leave it open for no%}w */
		close(input_fd);
	}
  if (start_p)				/* write autostart vec? */
	{
	write16(0x02E0);		/* autostart vec goes at #%}x2E0 */
	write16(0x02E1);
	write16(exe_start);		/* write the address */
	}
  close(output_fd);
  }

/* print map, if d%}esired */
  if (map_p)
	{
	FILE * mapf;
/*	int i, j;	*/
	char * p, * q;
	struct sym * sym;
/*	struct obj_module * m; *%}/

	for (p = output_name ; *p && (*p != '.') ; p++)
		;
	strcpy(p, ".map");
	output_name = frob_name(output_name);
	
	%}mapf = fopen(output_name, "w");
/* printf("map '%s'->%x\n", output_name, mapf); */
	fprintf(mapf, "Base address %04x\n", ex%}e_start);
	for (i = 0 ; i < nmodules ; i++)
		{
		m = module[i];
		strcpy(symbuf, m->seg_name);
		/* if library, append %}libr element name */
		if (m->seg_type == LIBR_HEADER)
			{
			p = symbuf + strlen(symbuf);
			*p++ = '(';
#ifdef M6502%}
			q = lib[m->lib_nbr]->dict[m->lib_idx].m_name;
#else
			q = (char * )&lib[m->lib_nbr]->dict[m->lib_idx].m_name;
#endif%}
			for (j = 0 ; ((j < 12) && (*q != ' ')) ; j++)
				*p++ = *q++;
			*p++ = ')';
			*p='\0';
			}
		fprintf(mapf, " %-2%}8s data from %04x to %04x: %5d. bytes\n",
			symbuf, m->seg_start, 
			m->seg_start + m->seg_size,
			m->seg_size);
		}
%}	j = 999;
	for (i = 0 ; i < HASHMOD ; i++)
		for (sym = symtab[i] ; sym ; sym = sym->next)
			{
			if (j > 3)
				{
			%}	fprintf(mapf, "\n");
				j = 0;
				}
			fprintf(mapf, "%-11s%04x %c  ", sym->name, sym->value,
				sym->flags & DEFINED%} ? 
				  (sym->flags & ABS ? 'A' : 'R') :
				  'U');
			j++;
			}
	fclose(mapf);
	}
}
ue,
				sym->flags & DEFINED$ `
/*
   This software is copyright 1989 by John Dunning.  See the file
   'COPYLEFT.JRD' for the full copyright notice.
*/)}

/* listing code */

#include "parse.h"
#include "global.h"
#include <stdio.h>

/* defs for field positions in outpu)}t line */

#define	PC_POS	7
#define VAL_POS	10
#define OBJ_POS	12
#define	N_OBJ	4
#define	LAB_POS	26
#define	OP_POS	34)}
#define	ARG_POS	40
#define COM_POS	50

char listbuf[132];
int listidx;
int page_line;

FILE * listf;

char hexchar)}[] = "0123456789ABCDEF";

/* output one listing char */
outlchar(ch)
char ch;
{
  listbuf[listidx++] = ch;
}

outlst)}r(str)
char * str;
{
  for ( ; *str ; )
	outlchar(*str++);
}

/* output spaces until column, at least one */
out2col()}col)
int col;
{
  outlchar(' ');
  while(listidx < col)
	outlchar(' ');
}

outnum(num, base, nplaces, fill)
int num;)}
int base;
int nplaces;
char fill;
{
  int i;
  char digit[10];

  for (i = 0 ; i < nplaces ; i++)
	if (num == 0)
	)}	digit[i] = fill;
	    else
		{
		digit[i] = hexchar[num % base];
		num = num / base;
		}
  while (i > 0)
	outlchar(di)}git[--i]);
		
}

new_page()
{
  listidx = 0;
  outlchar('\f');
  outlstr(page_title);
  out2col(64);
  outlstr("Pag)}e ");
  outnum(page_nbr, 10, 4, ' ');
  outlchar('\n');
  outlchar('\0');
  fputs(listbuf, listf);
  if (strlen(page_sub)}ttl) > 0)
	{
	listidx = 0;
	outlstr(page_subttl);
	outlchar('\n');
	outlchar('\0');
	fputs(listbuf, listf);
	}
  fput)}s("\n\n", listf);
  page_nbr++;
  line_in_page = 0;
}


list_line(override)
int override;
{
  int i;

  if (!(over)}ride || (list_p && (pass > 0))))
	{
	obj_count = 0;
	return;
	}
	
  if (line_in_page > 55) 
	new_page();

  listidx )}= 0;
  if (!line_listed_p)
	outnum(line_nbr, 10, 5, ' ');

  if (list_v_p)
	{
	out2col(VAL_POS);		/* get set to out ran)}dom value */
	outnum(list_v, 16, 4, '0');
	}
    else
	{
	if ((obj_count > 0) || (list_pc_p))
		{
		out2col(PC_POS);
)}		outnum(list_pc, 16, 4, '0');
		}
	if (obj_count > 0)
		{
		out2col(OBJ_POS);
		for (i = 0 ; i < obj_count ; i++)
			{)}
			outnum(obj[i] & 0xFF, 16, 2, '0');
			outlchar(' ');
			}
		}
	}

  if(!line_listed_p)
	{
	if (p.label)
		{
		)}out2col(LAB_POS);
		outlstr(p.label);
		if (p.label_suffix)
			outlstr(p.label_suffix);
		}

	if (p.opcode)
		{
		out)}2col(OP_POS);
		outlstr(p.opcode);
		}

	if (p.arg[0])
		{
		out2col(ARG_POS);
		outlstr(p.arg[0]);
		for (i = 1 ; p.)}arg[i] ; i++)
			{
			outlchar(',');
			outlstr(p.arg[i]);
			}
		}

	if (p.comment)
		{
		if (p.comment_column > 0))}
			out2col(COM_POS);
		    else
			out2col(LAB_POS);
		outlstr(p.comment);
		}
	}
  outlchar('\n');
  outlchar('\0'))};
  fputs(listbuf, listf);
  obj_count = 0;
  line_listed_p = 1;
  list_v_p = 0;
  list_pc_p = 0;
  line_in_page++;
})}

init_list()
{
  page_title[0] = '\0';
  page_subttl[0] = '\0';
  page_nbr = 1;
  if (list_name)
	listf = fopen(list_)}name, "w");
    else
	listf = stdout;
  line_in_page = 999;
}
;
  page_nbr = 1;
  if (list_name)
	listf = fopen(list_( C.SUFFIXES: .com .ttp .o .obj .m65 .c

.c.obj:
	cc65 -a -c -O $<
	ra65 $*.m65

all: libr65.com link65.com ra65.com

li-}br65.com : libr65.obj
	link65 -m -o libr65.com ..\cc65\runtime.obj libr65.obj ..\cc65\c.olb

#libr65.obj : libr65.c symtab-}.h obj.h libr.h
#	cc65 -a -c -O libr65.c
#	ra65 libr65.m65

link65.com : link65.obj
	link65 -b2000 -m -o link65.com ..\c-}c65\runtime.obj link65.obj ..\cc65\c.olb

#link65.obj : link65.c symtab.h obj.h
#	cc65 -a -c -O link65.c
#	ra65 link65.m6-}5

ra65.com : a65.obj symtab.obj parse.obj opcode.obj util.obj \
		xpseudo.obj error.obj eval.obj xxgen.obj
	link65 -b200-}0 -m -o ra65.com ..\cc65\runtime.obj a65.obj symtab.obj \
		parse.obj opcode.obj util.obj xpseudo.obj \
		error.obj eval.ob-}j xxgen.obj ..\cc65\c.olb

printobj.com : printobj.obj
	link65 -b2000 -m -o printobj.com ..\cc65\runtime.obj printobj.obj -}\
		..\cc65\c.olb
c.olb

printobj.com : printobj.obj
	link65 -b2000 -m -o printobj.com ..\cc65\runtime.obj printobj.obj , 
CFLAGS = -O

a65.ttp : a65.o symtab.o parse.o opcode.o util.o list.o pseudo.o	\
		error.o eval.o gen.o 
	cc -o $@ $(CFL1}AGS) @a65.lnk 

a65.sym : a65.ttp
	xld -r -o a65.sym @a65.lnk h:\gnu\lib\gnugdb.olb

xra65.ttp : a65.o symtab.o parse.o 1}opcode.o util.o list.o xpseudo.o	\
		error.o eval.o xgen.o
	cc $(CFLAGS) -o $@ @ra65.lnk

ra65.sym : ra65.ttp
	xld -r -o1} ra65.sym f:\gnu\lib\gcrt0.o @ra65.lnk f:\gnu\lib\gnugdb.olb

printobj.ttp : printobj.c
	cc -O -s -o printobj.ttp printobj1}.c

link65.ttp : link65.c obj.h
	cc -O -s -o $@ link65.c

xlink65.ttp : xlink65.c obj.h
	cc -O -s -o $@ xlink65.c

li1}br65.ttp : libr65.c libr.h obj.h
	cc -O -s -o libr65.ttp libr65.c

ra65-etc.arc : a65.c symtab.c parse.c opcode.c util.c l1}ist.c xpseudo.c	\
		error.c eval.c xgen.c libr65.c link65.c 
	arc a ra65-etc a65.c symtab.c parse.c opcode.c util.c list.c 1}xpseudo.c	\
		error.c eval.c xgen.c libr65.c link65.c k65.c 
	arc a ra65-etc a65.c symtab.c parse.c opcode.c util.c list.c 0 7
/*
   This software is copyright 1989 by John Dunning.  See the file
   'COPYLEFT.JRD' for the full copyright notice.
*/5}

/* defs for relocatable object files */

#ifndef _TYPES_
#include "types.h"
#endif

#define OBJ_HEADER	0xFDFD

st5}ruct relfile
	{
	USHORT header;		/* the above header value */
	USHORT nb_sym;		/* n bytes of symbol table this file */
	U5}SHORT nb_seg;		/* nbytes this segment occupies */
	USHORT nb_segdata;	/* n bytes of segment data this file */
	USHORT n_sym5};		/* n symbols */
	};

/* mask for looking at op bytes */
#define OP_GEN_MASK	0xE0
/* values for op flds */

#define 5}OP_LIT		0x00	/* literal bytes follow */
#define OP_REL		0x20	/* rel word follows */
#define OP_REL_HI	0x21	/* rel byte hi f5}ollows */
#define OP_REL_LO	0x22	/* rel byte lo follows */

#define OP_SYM_MASK	0xC0
#define OP_SYM_EMASK	0x20	/* if sym 5}num is extended in next byte */
#define OP_SYM		0x40	/* next word is relative to sym num */
#define OP_SYM_HI	0x80	/* gen h5}i byte of resultant value */
#define OP_SYM_LO	0xC0	/* .. lo byte */
elative to sym num */
#define OP_SYM_HI	0x80	/* gen h4 G
/*
   This software is copyright 1989 by John Dunning.  See the file
   'COPYLEFT.JRD' for the full copyright notice.
*/9}

/* opcode decoder */

#include "util.h"
#include "parse.h"
#include "gen.h"
#include "eval.h"
#include "global.h"
9}
/* opcode classes */

/* opcode is the compete instr */
#define	CLIMM	0
/* register inst */
#define CLREG	1
/* genera9}l addressing */
#define CLEA	2
/* subset addressing */
#define	CLSA	3
/* subset + accum */
#define CLRSA	4
/* branch */9}
#define CLBR	5

#define CLJSR	6
#define CLJMP	7

/* defs for operand types */

#define OPIMM	0x0001		/* immediate */9}
#define	OPABS	0x0002		/* absolute, long */
#define OPABSS	0x0004		/* absolute, short */
#define OPABSX	0x0008		/* long,x 9}*/
#define OPABSSX	0x0010		/* short,x */
#define OPABSY	0x0020		/* long,y */
#define OPABSSY	0x0040		/* short,y */
#defin9}e OPINDX	0x0080		/* (foo,x) */
#define OPINDY	0x0100		/* (foo),y */
#define OPACCUM	0x0200		/* A */
#define OPINDL	0x0400	9}	/* (addr) */
#define OPBR	0x0800		/* like abs, but different so we can
				   tell what to generate */
/* the opcode tabl9}e */

#ifndef old

struct op_elt 
	{
	char * name;		/* opcode name */
	char basecode;		/* basic opcode */
	int valid;9}		/* a bit mask of valid operand types */
	};

struct op_elt optab[] =
	{
	{"LDA", 0xAD, 
		OPIMM | OPABS | OPABSS | OP9}ABSX | OPABSSX |
		OPABSY | OPINDX | OPINDY},
	{"STA", 0x8D,
		OPABS | OPABSS | OPABSX | OPABSSX |
		OPABSY | OPINDX | OP9}INDY},
	{"JMP", 0x4C, OPABS | OPINDL},
	{"JSR", 0x20, OPABS},
	{"RTS", 0x60, 0},
	{"LDX", 0xAE, 
		OPIMM | OPABS | OPABS9}S | OPABSY | OPABSSY},
	{"STX", 0x8E, 
		OPABS | OPABSS | OPABSY | OPABSSY},
	{"LDY", 0xAC, 
		OPIMM | OPABS | OPABSS | O9}PABSY | OPABSSY},
	{"STY", 0x8C, 
		OPABS | OPABSS | OPABSSX},
	{"AND", 0x2D, 
		OPIMM | OPABS | OPABSS | OPABSX | OPABSS9}X |
		OPABSY | OPINDX | OPINDY},
	{"BIT", 0x2C, OPABS | OPABSS},
	{"CMP", 0xCD, 
		OPIMM | OPABS | OPABSS | OPABSX | OPAB9}SSX |
		OPABSY | OPINDX | OPINDY},
	{"CPX", 0xEC, OPIMM | OPABS | OPABSS},
	{"CPY", 0xCC, OPIMM | OPABS | OPABSS},
	{"ADC9}", 0x6D, 
		OPIMM | OPABS | OPABSS | OPABSX | OPABSSX |
		OPABSY | OPINDX | OPINDY},
	{"SBC", 0xED, 
		OPIMM | OPABS | OP9}ABSS | OPABSX | OPABSSX |
		OPABSY | OPINDX | OPINDY},
	{"ORA", 0x0D, 
		OPIMM | OPABS | OPABSS | OPABSX | OPABSSX |
		OP9}ABSY | OPINDX | OPINDY},
	{"EOR", 0x4D, 
		OPIMM | OPABS | OPABSS | OPABSX | OPABSSX |
		OPABSY | OPINDX | OPINDY},
	{"IN9}C", 0xEE, OPABS | OPABSS | OPABSX | OPABSSX},
	{"DEC", 0xCE, OPABS | OPABSS | OPABSX | OPABSSX},
	{"INX", 0xE8, 0},
	{"DEX9}", 0xCA, 0},
	{"INY", 0xC8, 0},
	{"DEY", 0x88, 0},
	{"ASL", 0x0E, 
		OPABS | OPABSS | OPABSX | OPABSSX | 
		OPACCUM},
	9}{"ROL", 0x2E, 
		OPABS | OPABSS | OPABSX | OPABSSX |
		OPACCUM},
	{"LSR", 0x4E, 
		OPABS | OPABSS | OPABSX | OPABSSX |
	9}	OPACCUM},
	{"ROR", 0x6E, 
		OPABS | OPABSS | OPABSX | OPABSSX |
		OPACCUM},
	{"TAX", 0xAA, 0},
	{"TXA", 0x8A, 0},
	{"T9}AY", 0xA8, 0},
	{"TYA", 0x98, 0},
	{"TSX", 0xBA, 0},
	{"TXS", 0x9A, 0},
	{"CLV", 0xB8, 0},
	{"CLD", 0xD8, 0},
	{"SED", 9}0xF8, 0},
	{"CLI", 0x58, 0},
	{"SEI", 0x78, 0},
	{"CLC", 0x18, 0},
	{"SEC", 0x38, 0},
	{"BPL", 0x10, OPBR},
	{"BMI", 0x9}30, OPBR},
	{"BVC", 0x50, OPBR},
	{"BVS", 0x70, OPBR},
	{"BCC", 0x90, OPBR},
	{"BCS", 0xB0, OPBR},
	{"BNE", 0xD0, OPBR},9}
	{"BEQ", 0xF0, OPBR},
	{"BRK", 0x00, 0},
	{"RTI", 0x40, 0},
	{"PHP", 0x08, 0},
	{"PLP", 0x28, 0},
	{"PHA", 0x48, 0},
9}	{"PLA", 0x68, 0},
	{"NOP", 0xEA, 0},
	{0, 0, 0}
	};

#else
/* old way */

struct op_elt 
	{
	char name[4];		/* opc9}ode name */
	char basecode;		/* basic opcode */
	int valid;		/* a bit mask of valid operand types */
	};

struct op_elt 9}optab[] =
	{
	{'L', 'D', 'A', '\0', 0xAD, 
		OPIMM | OPABS | OPABSS | OPABSX | OPABSSX |
		OPABSY | OPINDX | OPINDY},
	{9}'S', 'T', 'A', '\0', 0x8D,
		OPABS | OPABSS | OPABSX | OPABSSX |
		OPABSY | OPINDX | OPINDY},
	{'L', 'D', 'X', '\0', 0xAE,9} 
		OPIMM | OPABS | OPABSS | OPABSY | OPABSSY},
	{'S', 'T', 'X', '\0', 0x8E, 
		OPABS | OPABSS | OPABSY | OPABSSY},
	{'L'9}, 'D', 'Y', '\0', 0xAC, 
		OPIMM | OPABS | OPABSS | OPABSY | OPABSSY},
	{'S', 'T', 'Y', '\0', 0x8C, 
		OPABS | OPABSS | OP9}ABSSX},
	{'A', 'N', 'D', '\0', 0x2D, 
		OPIMM | OPABS | OPABSS | OPABSX | OPABSSX |
		OPABSY | OPINDX | OPINDY},
	{'B', '9}I', 'T', '\0', 0x2C, OPABS | OPABSS},
	{'C', 'M', 'P', '\0', 0xCD, 
		OPIMM | OPABS | OPABSS | OPABSX | OPABSSX |
		OPABSY9} | OPINDX | OPINDY},
	{'C', 'P', 'X', '\0', 0xEC, OPIMM | OPABS | OPABSS},
	{'C', 'P', 'Y', '\0', 0xCC, OPIMM | OPABS | OPA9}BSS},
	{'A', 'D', 'C', '\0', 0x6D, 
		OPIMM | OPABS | OPABSS | OPABSX | OPABSSX |
		OPABSY | OPINDX | OPINDY},
	{'S', 'B'9}, 'C', '\0', 0xED, 
		OPIMM | OPABS | OPABSS | OPABSX | OPABSSX |
		OPABSY | OPINDX | OPINDY},
	{'O', 'R', 'A', '\0', 0x0D9}, 
		OPIMM | OPABS | OPABSS | OPABSX | OPABSSX |
		OPABSY | OPINDX | OPINDY},
	{'E', 'O', 'R', '\0', 0x4D, 
		OPIMM | OPA9}BS | OPABSS | OPABSX | OPABSSX |
		OPABSY | OPINDX | OPINDY},
	{'I', 'N', 'C', '\0', 0xEE, OPABS | OPABSS | OPABSX | OPABSS9}X},
	{'D', 'E', 'C', '\0', 0xCE, OPABS | OPABSS | OPABSX | OPABSSX},
	{'I', 'N', 'X', '\0', 0xE8, 0},
	{'D', 'E', 'X', '\09}', 0xCA, 0},
	{'I', 'N', 'Y', '\0', 0xC8, 0},
	{'D', 'E', 'Y', '\0', 0x88, 0},
	{'A', 'S', 'L', '\0', 0x0E, 
		OPABS | OP9}ABSS | OPABSX | OPABSSX | 
		OPACCUM},
	{'R', 'O', 'L', '\0', 0x2E, 
		OPABS | OPABSS | OPABSX | OPABSSX |
		OPACCUM},
	9}{'L', 'S', 'R', '\0', 0x4E, 
		OPABS | OPABSS | OPABSX | OPABSSX |
		OPACCUM},
	{'R', 'O', 'R', '\0', 0x6E, 
		OPABS | OP9}ABSS | OPABSX | OPABSSX |
		OPACCUM},
	{'T', 'A', 'X', '\0', 0xAA, 0},
	{'T', 'X', 'A', '\0', 0x8A, 0},
	{'T', 'A', 'Y', 9}'\0', 0xA8, 0},
	{'T', 'Y', 'A', '\0', 0x98, 0},
	{'T', 'S', 'X', '\0', 0xBA, 0},
	{'T', 'X', 'S', '\0', 0x9A, 0},
	{'C',9} 'L', 'V', '\0', 0xB8, 0},
	{'C', 'L', 'D', '\0', 0xD8, 0},
	{'S', 'E', 'D', '\0', 0xF8, 0},
	{'C', 'L', 'I', '\0', 0x58, 9}0},
	{'S', 'E', 'I', '\0', 0x78, 0},
	{'C', 'L', 'C', '\0', 0x18, 0},
	{'S', 'E', 'C', '\0', 0x38, 0},
	{'B', 'P', 'L', ': }\0', 0x10, OPBR},
	{'B', 'M', 'I', '\0', 0x30, OPBR},
	{'B', 'V', 'C', '\0', 0x50, OPBR},
	{'B', 'V', 'S', '\0', 0x70, OPB:}R},
	{'B', 'C', 'C', '\0', 0x90, OPBR},
	{'B', 'C', 'S', '\0', 0xB0, OPBR},
	{'B', 'N', 'E', '\0', 0xD0, OPBR},
	{'B', 'E:}', 'Q', '\0', 0xF0, OPBR},
	{'J', 'M', 'P', '\0', 0x4C, OPABS | OPINDL},
	{'J', 'S', 'R', '\0', 0x20, OPABS},
	{'R', 'T', :}'S', '\0', 0x60, 0},
	{'B', 'R', 'K', '\0', 0x00, 0},
	{'R', 'T', 'I', '\0', 0x40, 0},
	{'P', 'H', 'P', '\0', 0x08, 0},
	:}{'P', 'L', 'P', '\0', 0x28, 0},
	{'P', 'H', 'A', '\0', 0x48, 0},
	{'P', 'L', 'A', '\0', 0x68, 0},
	{'N', 'O', 'P', '\0', 0:}xEA, 0},
	0
	};
#endif

/* valid addressing modes, per opclass */
int mvalid[] = 
	{
	0,					/* climm, no args */
	0:},					/* clreg, not used? */
	OPIMM | OPABS | OPABSS | OPABSX | 
		OPABSSX | OPABSY | OPABSSY |
		OPINDX | OPINDY,		/* gen:}eral addressing */
	OPIMM | OPABS | OPABSS | OPABSX | OPABSSX,	/* subset */
	OPIMM | OPABS | OPABSS | OPABSX | OPABSSX | OP:}ACCUM,  /* sub + a */
	OPABS,					/* branch, abs */
	OPABS,					/* jsr, abs */
	OPABS | OPINDL				/* jmp, abs or ind */
	:	}};


/* given a name, return T if it's an opcode, and if so, return
   its code and flags */
int opcode_p(name, code, va:
}lid)
char * name;
int * code;
int * valid;
{
  int i;

  if (strlen(name) != 3)
	return(0);		/* don't bother */

  :}for (i = 0 ; ; i++)
	{
	if (optab[i].name[0] == '\0')
		return(0);

	if (string_equal(optab[i].name, name))
		{
		*cod:}e = optab[i].basecode;
		*valid = optab[i].valid;
		return(1);
		}
	}
}


/* handed an opcode and opflags, finish gen:}erating this instruction */

void assemble_op(basecode, valid, args)
int basecode;
int valid;
{
  int operand, optype, :}expr_flags;
  struct sym * rel_to_sym;

/* later, leave a slot for relocatable stuff, ptr to sym this
   word is relative:} to, or something */

/*  set_label();  */
  gen_label();
  operand = optype = 0;
  if (valid)
	optype = decode_operand:}(valid, &operand, &expr_flags, &rel_to_sym,
				 args);

/* now have operand etc */
  switch (optype)
	{
	case 0:			/* :}no operand */
		{
		genlit(basecode);
		break;
		}
	case OPIMM:
		{
		/* bit of a kludge here... gen code ^ 0x04, but :}if bit 0 is
		    clear, clear bit 3 as well */
		if (basecode & 0x01)
			genlit(basecode ^ 0x04);
		    else
			genlit(:}(basecode ^ 0x04) & 0xF7);
		genbyte(operand, expr_flags, rel_to_sym);
		break;
		}
	case OPABS:
		{
		genlit(basecode):};
		genword(operand, expr_flags, rel_to_sym);
		break;
		}
	case OPBR:
		{
		genlit(basecode);
/*		genlit(operand - pc:} - 1);	/* should range check this... */
		genbranch(rel_to_sym, operand);
		break;
		}
	case OPABSS:
		{
		genlit(basec:}ode ^ 0x08);
		/* rel is an error here... */
		genbyte(operand, expr_flags, rel_to_sym);
		break;
		}
	case OPABSX:			/*:} xxxx,x */
		{
		genlit(basecode ^ 0x10);
		genword(operand, expr_flags, rel_to_sym);
		break;
		}
	case OPABSSX:
		{:}
		genlit(basecode ^ 0x18);
		/* rel is an error... */
		genbyte(operand, expr_flags, rel_to_sym);
		break;
		}
	case OP:}ABSY:			/* xxxx,y */
		{
		genlit(basecode ^ 0x14);
		genword(operand, expr_flags, rel_to_sym);
		break;
		}
	case OPAB:}SSY:
		{
		genlit(basecode ^ 0x18);
		genbyte(operand, expr_flags, rel_to_sym);
		break;
		}
	case OPINDX:			/* (xx,x) :}*/
		{
		genlit(basecode ^ 0x0C);
		genbyte(operand, expr_flags, rel_to_sym);
		break;
		}
	case OPINDY:				/* (xx),y *:}/
		{
		genlit(basecode ^ 0x1C);
		genbyte(operand, expr_flags, rel_to_sym);
		break;
		}
	case OPACCUM:		/* A */
		{:}
		genlit(basecode ^ 0x04);
		break;
		}
	case OPINDL:
		{
		genlit(basecode ^ 0x20);
		genword(operand, expr_flags, re:}l_to_sym);
		break;
		}
	}

}

/* passed a bit mask of legal optypes, try to make sense out of the arg
   vector, and:} return a 16-bit operand value, and the type that it is.
   the value and relative flag are returned by reference; the type : }is
   returned as the function value;
*/
int decode_operand(valid, operand, expr_flags, rel_to_sym, args)
int valid;			/*:!} mask of valid types */
int * operand;
int * expr_flags;
struct sym ** rel_to_sym;
char * args[];
{
  int val;
  int e:"}_flags;			/* flags from eval */
  char indexed_p;		/* if operand is indexed */
  char indirect_p;		/* if operand is indirec:#}t */
  int type;			/* optype we figure out */
  char * arg0;
  char * arg1;
  int short_p;

  arg0 = args[0];
  arg1 =:$} args[1];

/* make sure there's an operand */
  if (!arg0)
	{
	barf("operand required");
	return(0);
	};

/* special:%} case check for accum */
  if (string_equal(arg0, "A"))
	{
	return(OPACCUM);
	}

/* first check for come kind of indire:&}ct operand */
  if (arg0[0] == '(')
	{
	if (arg1)
		{
		indirect_p = toupper(arg1[0]);

		/* later, be smarter.  this :'}should work for now... */
		if (indirect_p == 'Y')
			type = OPINDY;
		    else
			type = OPINDX;
		val = eval(arg0 + 1,:(} &e_flags, rel_to_sym);
		*operand = val;
		*expr_flags = e_flags;
		}
	    else		/* must be (addr) */
		{
		type = OPI:)}NDL;
		val = eval(arg0 + 1, &e_flags, rel_to_sym);
		*operand = val;
		*expr_flags = e_flags;
		}
	return(type);
	}
  :*}  else		/* first arg doesn't start with a paren */
	{
	if ((arg0[0] == '#') || (arg0[0] == '='))	/* immediate? */
		{
		v:+}al = eval(arg0 + 1, &e_flags, rel_to_sym);	/* get expr value */
		/* make sure it's 8 bits... later */

		*operand = val &:,} 0xFF;
		*expr_flags = e_flags;
		return(OPIMM);
		}
	    else		/* not immediate */
		{
		val = eval(arg0, &e_flags, re:-}l_to_sym);		/* get expr val */
		/* see if indexed by anything */
		if (arg1)
			{
			if (string_equal(arg1, "Y") || stri:.}ng_equal(arg1, "X"))
				{
				indirect_p = toupper(arg1[0]);
				/* later, figure out whether to use short
				   addres:/}sing; for now just do it the easy 
				   way */

				short_p = (((val & 0xFF00) == 0) &
					   (!(e_flags & E_UNDEF)));:0}
				if (indirect_p == 'X')
					{
					if (short_p && (valid & OPABSSX))
						type = OPABSSX;
					    else
						typ:1}e = OPABSX;
					}
				    else
					{
					if (short_p && (valid & OPABSSY))
						type = OPABSSY;
					    else
				:2}		type = OPABSY;
					}
				*operand = val;
				*expr_flags = e_flags;
				return(type);
				}
			    else
				{
				:3}/* arg1 there but not x or y?  bogus */
				barf("too many operands");
				return(0);
				}
			}		/* env of 'arg1' */
		:4}    else
			{		/* no arg1, must be absolute */
			/* later, check for page 0. */
			*operand = val;
			*expr_flags = e_fl:5}ags;
			if (valid & OPBR)
				return(OPBR);
			    else
				if ((valid & OPABSS) && 
				    ((val & 0xFF00) == 0) &&
	:6}			    (!(e_flags & E_REL)) && 
				    (!(e_flags & E_UNDEF)))
					{
/*	printf("line %d %X would have been short\n", lin:7}e_nbr, val); */
					return(OPABSS);
					}
				    else
					return(OPABS);
			}
		}			/* end of 'not immed' */
	}			:8}	/* end of 'not indirect' */		
}
);
					}
				    else
					return(OPABS);
			}
		}			/* end of 'not immed' */
	}			8 #
/*
   This software is copyright 1989 by John Dunning.  See the file
   'COPYLEFT.JRD' for the full copyright notice.
*/>:}

/* the input line parser */

#include "parse.h"

char label_buf[32];		/* buf for labels */
char suffix_buf[8];		/* b>;}uf for suffixes */
char op_buf[32];		/* char for ops and pseudos */

int id_char_p(c)
char c;
{
  return(((c >= 'a') &&><} (c <= 'z')) ||
	 ((c >= 'A') && (c <= 'Z')) ||
	 ((c >= '0') && (c <= '9')) ||
	 (c == '_') || (c == '.')
	 );
}

int>=} id_start_p(c)
char c;
{
  return(((c >= 'a') && (c <= 'z')) ||
	 ((c >= 'A') && (c <= 'Z')) ||
	 (c == '_') || (c == '.>>}')
	 );
}

int special_p(c)
{
  return((c == '=') || (c == '*'));
}


int white_p(c)
{
  return((c == ' ') || (c >?}== '\t'));
}

int find_string_end(s, i, c)
char * s;
int i;
char c;
{
  char cc;

  if (s[i] == c)
	i++;
  for ( >@}; ((cc = s[i]) && cc != c) ; i++)
	;
  return(i);
}

int find_char(s, i, c)
char * s;
int i;
char c;
{
  char cc;
>A}
  for ( ; ((cc = s[i]) && (cc != c)) ; i++)
	;
  return(c);
}

void parse_line(line, p)
char * line;
struct parse * >B}p;
{
  int i, j, k, len;
  char c;
  char * ptr;

/* first clear the whole thing */
  p->label = p->label_suffix = p->>C}opcode = p->comment = p->comment_column = 0;
  for (i = 0 ; i < 32 ; i++)
	p->arg[i] = 0;

  len = strlen(line);
  i = 0>D};

  if (i >= len)
	return;

  if (line[0] == ';')		/* comment only? */
	{
	p->comment = line;
	p->comment_column = 0>E};
	return;
	}

  if ((!white_p(line[0])) &&		/* kludge */
		(line[0] != '.'))
	{
/* parse a label */
	if (id_start_p(>F}line[0]))
		{
		p->label = ptr = label_buf;
		while ((id_char_p(line[i])) && (i < len))
			*ptr++ = line[i++];
		*ptr = >G}'\0';
/* collect the label suffix if any */
		if ((i < len) && (!white_p(line[i])))
			{
			p->label_suffix = ptr = suffi>H}x_buf;
			while ((!white_p(c = line[i])) && 
				(!id_char_p(c)) &&
				(!special_p(c)) &&
				(i < len))
				*ptr++ = l>I}ine[i++];
			*ptr = '\0';
			}
		}
	    else
		barf("illegal label char");
	};

/* done with label if any, find op */>J}
  while ((i < len) && white_p(line[i]))
	i++;
  if (i >= len)
	return;
  if (line[i] == ';')
	{
	p->comment = line + >K}i;
	p->comment_column = i;
	return;
	}
  p->opcode = ptr = op_buf;

/* "*="? */
  if ((line[i] == '*') && (line[i+1] =>L}= '='))
	{
	*ptr++ = line[i++];
	*ptr++ = line[i++];
	*ptr = '\0';
	}
    else

/* "="? */
  if (line[i] == '=')
	{>M}
	*ptr++ = line[i++];
	*ptr = '\0';
	}
    else
  if (id_start_p(line[i]))
	{
	*ptr++ = line[i++];
	while (id_char_p(>N}line[i]))
		*ptr++ = line[i++];
	*ptr = '\0';		/* terminate the op string */
	}

/* look for args */
  while ((i < len)>O} && (white_p(c = line[i])))
	i++;
  if (i >= len)
	return;

  if (c == ';')
	{
	p->comment = line + i;
	p->comment_co>P}lumn = i;
	return;
	}
    else
	{
	for (j = 0 ; j < 32 ; j++)
		{
		p->arg[j] = line + i;
		c = line[i];
		switch (c>Q})
			{
			case '"':
				{
				i = 1 + find_string_end(line, i, c);
				break;
				}
			case '\'':
				{
				i += 2;	>R}	/* skip the quote and char */
				if (line[i] == '\'')
					i++;
				break;
				}
			default:
				{
				while ((c = l>S}ine[i]) && (c != ';') &&
					(c != ',') && (!white_p(c)))
					i++;
				}
			}
		c = line[i];		/* get char that term'ed>T} us */
		line[i] = '\0';		/* end this str */
		i++;			/* next char */
		if (c == ',')		/* another fld? */
			for ( ; ((c >U}= line[i]) && white_p(c)) ; i++)
				;
		if ((i >= len) || (c == ';') || white_p(c))	/* done? */
			break;
		}			/* loop >V}collecting flds... */
	}				/* found all flds... */	

/* now if anything left, it's a comment */
  if (i >= len)
	return>W};
  for ( ; ((c = line[i]) && (white_p(c))) ; i++)
	;
  if (i >= len)
	return;
  if (c)
	{
	p->comment = line + i;
	p>X}->comment_column = i;
	}

  return;
}
	
 i++)
	;
  if (i >= len)
	return;
  if (c)
	{
	p->comment = line + i;
	p< .
/*
   This software is copyright 1989 by John Dunning.  See the file
   'COPYLEFT.JRD' for the full copyright notice.
*/BZ}

/* stuff for parser */

#ifndef _TYPES_
#include "types.h"
#endif

struct parse
	{
	char * label;		/* line label B[}*/
	char * label_suffix;	/* stray non-white chars after label */
	char * opcode;		/* op str */
	char * arg[32];		/* up to B\}32 arg strings */
	char * comment;		/* comment str */
	int comment_column;	/* where the comment started */
	};

extern vB]}oid parse_line();		/* parse a line into a parse struct */

comment_column;	/* where the comment started */
	};

extern v@ =
/*
   This software is copyright 1989 by John Dunning.  See the file
   'COPYLEFT.JRD' for the full copyright notice.
*/F_}

/* obj file dumper */

#include <stdio.h>
#include <file.h>
#include "symtab.h"
#include "obj.h"

#ifdef M6502
#dF`}efine malloc pmalloc
#endif

int obj_fd;
struct relfile rf;
struct sym ** syms;
int eof = 0;
int nbytes_read;

char Fa}litbuf[32];

USHORT read8()
{
  char foo;
  if (read(obj_fd, &foo, 1) != 1)
	eof = 1;
    else
	nbytes_read++;
  retFb}urn(foo);
}

USHORT read16()
{
  return(read8() | (read8() << 8));
}

struct sym * readsym()
{
  char len;
  strucFc}t sym * sym;

  read(obj_fd, &len, 1);
  sym = malloc(sizeof (struct sym) + len);
  read(obj_fd, sym->name, len);
  sym-Fd}>name[len] = '\0';
  sym->value = read16();
  sym->flags = read16();
  return(sym);
}


main(argc, argv)
int argc;
cFe}har ** argv;
{
  int i, j, pc;
  char op;
  
  if (argc < 2)
	{
	printf("printobj what?\n");
	exit(1);
	}
  obj_fd Ff}= open(argv[1], O_RDONLY);
  if (obj_fd < 0)
  	{
	printf("can't open %s\n", argv[1]);
	exit(1);
	}
  rf.header = read1Fg}6();
  rf.nb_sym = read16();
  rf.nb_seg = read16();
  rf.nb_segdata = read16();
  rf.n_sym = read16();
  printf("headerFh} %X\n", rf.header);
  if (rf.header != OBJ_HEADER)
  	{
	printf("%s is not an object file\n", argv[1]);
	close(obj_fd);
Fi}	exit(1);
	}
  printf("Object file %s:\n", argv[1]);
  printf("  %d symbols in %d bytes\n", rf.n_sym, rf.nb_sym);
  printFj}f("  #x%04x bytes segment data in %d bytes\n", rf.nb_seg, rf.nb_segdata);
/* allocate symbol vector */
  syms = (struct symFk} ** )malloc(rf.n_sym * sizeof (struct sym *));
/* read them in */
  for (i = 0 ; i < rf.n_sym ; i++)
	syms[i] = readsym();Fl}

/* now dump data */
  i = 0;			/* our index in seg data */
  pc = nbytes_read = 0;
  while (pc < rf.nb_seg)
	{
	prinFm}tf("%04x: ", pc);
	read(obj_fd, &op, 1);
	switch (op & OP_GEN_MASK)
		{
		case OP_LIT:
			{
			if (op == 0)
				op = 3Fn}2;
			printf("Literal: %2d bytes\n\t", op);
			read(obj_fd, litbuf, op);
			nbytes_read += op;
			for (j = 0 ; j < op ; jFo}++)
				printf(" %02x", litbuf[j] & 0xFF);
			printf("\n");
			pc += op;
			break;
			}
		case OP_REL:
			{
			switchFp}(op)
				{
				case OP_REL:
					{
					printf("Word:    %04x + segment base\n", read16());
					pc += 2;
					break;
Fq}					}
				case OP_REL_HI:
					{
					printf("Hi byte: %04x + segment base\n", read16());
					pc += 1;
					break;
		Fr}			}
				case OP_REL_LO:
					{
					printf("Lo byte: %04x + segment base\n", read16());
					pc += 1;
					break;
				Fs}	}
				}
			break;
			}
		default:		/* must be a sym */
			{
			j = op & 0x1F;
			if (op & OP_SYM_EMASK)
				j = (j <Ft}< 8) | read8();
			switch (op & OP_SYM_MASK)
				{
				case OP_SYM:
					{
					printf("Word:    %04x + %s\n", read16(),Fu}
						syms[j]->name);
					pc += 2;
					break;
					}
				case OP_SYM_HI:
					{
					printf("Hi byte: %04x + %s\n",Fv} read16(),
						syms[j]->name);
					pc += 1;
					break;
					}
				case OP_SYM_LO:
					{
					printf("Lo byte: %04Fw}x + %s\n", read16(),
						syms[j]->name);
					pc += 1;
					break;
					}
				}
			break;
			}
		}
	}
  i = read8Fx}();
  if (!eof)
	{
	printf("Extra bytes at eof!");
	printf("  %02x\n", i);
	for ( ; !eof ; )
		{
		i = read8();
		if Fy}(!eof)
			printf("  %02x\n", i);
		}
	}
  if (nbytes_read != rf.nb_segdata)
  	printf("Byte count mismatch: header says Fz}%d bytes, read %d\n",
		rf.nb_segdata, nbytes_read);
  close(obj_fd);
}



  	printf("Byte count mismatch: header says D P-*- Mode: Text -*-

    This is the readme file for RA65-ETC.ARC.
    
    This arc contains source for RA65, LINK65, andJ|} LIBR65.

(fill in more comments later... )
le for RA65-ETC.ARC.
    
    This arc contains source for RA65, LINK65, andH /
/*
   This software is copyright 1989 by John Dunning.  See the file
   'COPYLEFT.JRD' for the full copyright notice.
*/N~}

/* symbol table code */

#include "util.h"
#include "symtab.h"
#include "parse.h"
#include "global.h"
#include <stdN}io.h>

#define	HASHMOD	53

#define CASE_INSENSITIVE 1

struct sym * symtab[HASHMOD];

void string_upcase(str)
char *N} str;
{
#ifdef CASE_INSENSITIVE
  char c;

  for( ; c = *str ; str++)
	if ((c >= 'a') && (c <= 'z'))
		*str = c - 0x20N};
#endif
}
  
int hash(str)
char * str;
{
  int accum;
  char c;

  for (accum = 0 ; c = *str++ ; )
	{
#ifdef CASN}E_INSENSITIVE
	c = toupper(c);
#endif
	accum = ((accum << 1) & 0x3FFF) ^ c;
	}
  return(accum % HASHMOD);
}

struct sN}ym * find_sym(name, new_ok)
char * name;
int new_ok;
{
  struct sym * sym_p;
  int idx;

  idx = hash(name);
  for (sN}ym_p = symtab[idx] ; sym_p ; sym_p = sym_p->next)
	if (string_equal(sym_p->name, name))
		return(sym_p);

  if (!new_ok)N}
	return(0);

  sym_p = (struct sym * )malloc((sizeof (struct sym )) + strlen(name) + 1);
  sym_p->value = 0;
  sym_p->flN}ags = 0;
  sym_p->nbr = -1;
  strcpy(sym_p->name, name);
  string_upcase(sym_p->name);
  sym_p->next = symtab[idx];
  syN}mtab[idx] = sym_p;
  return(sym_p);
}

struct sym * assign_sym(name, value, no_redef)
char * name;
int value;
int no_rN}edef;
{
  struct sym * sym_p;

  sym_p = find_sym(name, 1);
  if (no_redef && (sym_p->flags & DEFINED))
	if (sym_p->valN}ue != value)
		barf("'%s' redefined: %X vs %X\n", name, sym_p->value, value);
  sym_p->value = value;
  sym_p->flags |= DEN}FINED;
  return(sym_p);
}

set_label()
{
  if (p.label)
	{
	assign_sym(p.label, pc, 1);
	if (!p.opcode)
		{
		listN}_v = pc;
		list_v_p = 1;
		}
	    else
		{
		list_pc = pc;
		}
	}
}

init_sym()
{
  int i;

  for (i = 0 ; i < N}HASHMOD ; i++)
	symtab[i] = 0;
}

describe_symtab()
{
  int i, j;
  struct sym * sym_p;

  for (i = 0 ; i < HASHMOD N}; i++ )
	{
	for (j = 0, sym_p = symtab[i] ; sym_p ; j++)
		sym_p = sym_p->next;
	printf("Bucket %d contains %d syms\n", iN}, j);
	}
}

map_syms(fun)
void (* fun)();
{
  struct sym * sym_p;
  int i;

  for (i = 0 ; i < HASHMOD ; i++ )
	{N}
	for (sym_p = symtab[i] ; sym_p ; )
		{
		(*fun)(sym_p);
		sym_p = sym_p->next;
		}
	}
}

#ifdef DEBUG
dump_syms()N}
{
  char * name[32];
  int i, j;
  struct sym * sym_p;
  FILE * f;

  sprintf(name, "pass%d.sym", pass);
  f = fopen(N}name, "w");
  for (i = 0 ; i < HASHMOD ; i++ )
	{
	for (j = 0, sym_p = symtab[i] ; sym_p ; j++)
		{
		fprintf(f, "%s:\t\N}t%X\n", sym_p->name, sym_p->value);
		sym_p = sym_p->next;
		}
	}
  fclose(f);
}
#endif

)
		{
		fprintf(f, "%s:\t\L a
/*
   This software is copyright 1989 by John Dunning.  See the file
   'COPYLEFT.JRD' for the full copyright notice.
*/R}

/* stuff for symbol table */

#ifndef _TYPES_
#include "types.h"
#endif

struct sym
	{
	struct sym * next;		/* neR}xt elt */
	short nbr;			/* for reloc files, sym nbr
					   when linking, module nbr of
					     module that defined it *R}/
	USHORT value;			/* sym's value */
	USHORT flags;			/* sym flags */
	char name[1];			/* name this sym; really longer */R}
	};

/* sym flags */

#define	DEFINED	1			/* has some value */
#define THIS_SEG 2			/* defined in this seg */
#define R}GLOBAL	4			/* globally visible */
#define	ABS	8			/* value is absolute */

#ifdef M6502
/* why doesn't this work? */
#elR}se
extern struct sym * find_sym();
extern struct sym * assign_sym();
#endif
fdef M6502
/* why doesn't this work? */
#elP P
/*
   This software is copyright 1989 by John Dunning.  See the file
   'COPYLEFT.JRD' for the full copyright notice.
*/V}

/* types used in various of these tools */

#ifdef M6502
#define USHORT int
#define void int
#else
#define USHORT uV}nsigned short
#endif

/* say we've been here */
#define _TYPES_

 USHORT int
#define void int
#else
#define USHORT uT G
/*
   This software is copyright 1989 by John Dunning.  See the file
   'COPYLEFT.JRD' for the full copyright notice.
*/Z}

/* misc utils for assembler */

#include <stdio.h>

/*
char char_upcase(c)
char c;
{
  if ((c >= 'a') && (c <= 'zZ}'))
	c -= 0x20;
  return(c);
}
*/

int string_equal(s1, s2)
char * s1, * s2;
{
  if (strlen(s1) != strlen(s2))
	retZ}urn(0);
  for ( ; *s1 && *s2 ; ++s1, ++s2)
	if (toupper(*s1) != toupper(*s2))
		return(0);
  return(1);
}

int read_liZ}ne(f, l)
FILE * f;
char * l;
{
  int c;
  int ok;

  ok = 0;
  for ( ; ((c = fgetc(f)) != EOF) ; )
	{
/* printf("reZ}ad-char '%c' %X ptr %X\n", c, c, l); */
	ok = 1;
	if (c == '\n')
		break;
	if (!(
#ifndef M6502
/* protect against mushZ}-dos format files */
(c == '\r') ||
#endif
		 (c == '\f')))	/* ^L */
		*l++ = c;
	}
  *l = '\0';
  return(ok);
}

#Z}ifdef M6502

extern char * _himem;		/* mem mgr's lo-free-mem marker */

char * malloc(n)
int n;
{
  char * p;

/* chZ}eck for being close to out of memory */
  if ((_himem + n) > (&p - 128))
	barf("Out of memory!\n");
  p = pmalloc(n);
/* Z}printf("malloc(%d)->%X\n", n, p); */
  bzero(p, n);
  return(p);
}

/* file-name frobber */
char * frob_name(name)
chaZ}r * name;
{
  char * new_name;
  
  if (!strchr(name, ':'))
	{
	new_name = malloc(strlen(name)+3);
	strcpy(new_name, "Z}D:");
	strcat(new_name, name);
	return(new_name);
	}
  return(name);
}
#else

char * frob_name(name)
{
  return(namZ}e);
}
#endif

_name, name);
	return(new_name);
	}
  return(name);
}
#else

char * frob_name(name)
{
  return(namX 
/*
   This software is copyright 1989 by John Dunning.  See the file
   'COPYLEFT.JRD' for the full copyright notice.
*/^}


/* utils */

extern char char_upcase();
extern int string_equal();
extern int read_line();
l copyright notice.
*/\ f
/*
   This software is copyright 1989 by John Dunning.  See the file
   'COPYLEFT.JRD' for the full copyright notice.
*/b}


/* code generator */

#include "parse.h"
#include "global.h"
#include "symtab.h"
#include "eval.h"
#include "obj.b}h"

#include <file.h>
#include <stdio.h>

/* fragment types */
#define FRAG_LITERAL	0
#define FRAG_SYMDEF	1
#define Fb}RAG_WORD	2
#define FRAG_BYTE_HI	3
#define FRAG_BYTE_LO	4
#define FRAG_BR_OFFSET	5
#define FRAG_LONG_BR	6

/* zzz */

b}/* when assembling, we collect a bunch of the following structs */
struct frag_literal
	{
	int nbytes;
	char bytes[32];
b}	};
	
struct frag
	{
	struct frag * f_next;		/* next frag */
#ifdef DEBUG
	int seg_pc;			/* debug only */
#endif
	chab}r type;			/* type this frag */
/* not used?	int f_pc;				/* pc this frag */
	int f_value;			/* value.  if literal, points tb}o 
					   a frag_literal.  */
	struct sym * f_sym;		/* sym defined, or sym rel to */
	};

char outname_buf[32];
int oub}tput_fd;

struct frag * all_frags;
struct frag * last_frag;

struct relfile rf;

/* data accumulated for header */
inb}t seg_max_pc;			/* nbytes this seg takes when linked */
int seg_nbytes;			/* nbytes data this seg in obj file */
int seg_nsb}yms;			/* number of (external) syms this seg */
int seg_nsbytes;		/* number of bytes of symtab this file */

/* */

charb} two_bytes[2];

char lit_buf[32];		/* buffer for literals */
int litidx;			/* nbytes segment */
int sym_num;

out16(i)b}
int i;
{
  two_bytes[0] = i & 0xFF;
  two_bytes[1] = i >> 8;
  write(output_fd, two_bytes, 2);
}

out8(i)
char i;
{b}
  two_bytes[0] = i & 0xFF;
  write(output_fd, two_bytes, 1);
}

outsym(sym)
struct sym * sym;
{
  int i;
  
  out8b}(strlen(sym->name));		/* output length */
  for (i = 0 ; i < strlen(sym->name) ; i++)
	out8(sym->name[i]);
  out16(sym->vab}lue);
  out16(sym->flags);
}

/*
 * the next section of code is dealing with frags
 */

struct frag * add_frag(type, b}value, sym)
int type;
int value;
struct sym * sym;
{
  struct frag * this_frag;
  
  this_frag = malloc(sizeof(struct b}frag));
  if (!all_frags)
	all_frags = this_frag;
    else
	last_frag->f_next = this_frag;
  last_frag = this_frag;
  tb}his_frag->f_next = NULL;
  this_frag->type = type;
  this_frag->f_sym = sym;
  if (type == FRAG_LITERAL)
	{
	struct fragb}_literal * lit;
	lit = malloc(sizeof(struct frag_literal));
  	this_frag->f_value = lit;
	lit->nbytes = 0;
	}
    else
b}	this_frag->f_value = value;
  return(this_frag);
}

/* push a literal byte, maybe add new frag first */
litbyte(b)
{
b}  struct frag_literal * litbuf;
  
  if (last_frag && (last_frag->type == FRAG_LITERAL))
  	litbuf = last_frag->f_value;
b}    else
	litbuf = 0;
  if (!litbuf || litbuf->nbytes >= 32)
	{
	add_frag(FRAG_LITERAL, 0, NULL);
	litbuf = last_frag->fb}_value;
	}
  litbuf->bytes[litbuf->nbytes++] = b;
}
 
/* write a literal buffer */
writelit(l)
struct frag_literal * lb};
{
  if ((l->nbytes <= 0) || (l->nbytes > 32))
  	barf ("internal error: bogus literal segment size");
  out8(OP_LIT | (b}l->nbytes & 0x1F));
  write(output_fd, l->bytes, l->nbytes);
  litidx = 0;
}

/*
 * The three entry points used by the b}rest of the assembler 
 */

/* generate a literal byte */
genlit(byte)
char byte;
{
  litbyte(byte);
}

/* generateb} a byte value */
genbyte(byte, flags, sym)
int byte;
int flags;
struct sym * sym;
{
  int type;

  if (!(flags & E_REb}L))		/* relative? */
	{
	genlit(byte);
	}
    else
	{
	if (flags & E_HI_BYTE)
		type = FRAG_BYTE_HI;
	    else
	if (b}flags & E_LO_BYTE)
		type = FRAG_BYTE_LO;
	    else
	barf ("internal error, byte not hi or low?");
	add_frag(type, byte, b}sym);
	}
}

/* generate a word value */
genword(word, flags, sym)
int word, flags;
struct sym * sym;
{
  if (!(flagsb} & E_REL))		/* not relative? */
	{
	genlit(word & 0xFF);
	genlit(word >> 8);
	}
    else
    	{			/* it is relative */b}
	add_frag(FRAG_WORD, word, sym);
	}
}

genbranch(sym, offset)
struct sym * sym;
int offset;
{
#ifdef DEBUG
  if (syb}m)
	printf("  genbranch %s+%X\n", sym->name, offset);
    else
	printf("  genbranch *+%X\n", offset);
#endif
  if (!sym)b}		/* no sym means pc, ie "beq *+3" */
	genlit(offset - 2);
    else
	add_frag(FRAG_BR_OFFSET, offset, sym);
}

gen_lbr(b}basecode, sym)
int basecode;		/* base opcode */
struct sym * sym;
{
#ifdef DEBUG
  printf("  gen long branch %X %s\n", b` }                                                                                                                                