~ndiddy/a65

d3f747299b851b46ee81aa219938f3892fdb2452 — Nathan Misner 4 months ago a501e2a
organized stuff into header files
12 files changed, 493 insertions(+), 71 deletions(-)

A .editorconfig
M a65.c
M a65.h
M a65.vcxproj
M a65.vcxproj.filters
M a65eval.c
A a65eval.h
M a65util.c
A a65util.h
M readme.txt
M test.asm
M test.lst
A .editorconfig => .editorconfig +136 -0
@@ 0,0 1,136 @@
# Visual Studio generated .editorconfig file with C++ settings.
root = true

[*.{c++,cc,cpp,cppm,cxx,h,h++,hh,hpp,hxx,inl,ipp,ixx,tlh,tli}]

# Visual C++ Code Style settings

cpp_generate_documentation_comments = doxygen_triple_slash

# Visual C++ Formatting settings

cpp_indent_braces = false
cpp_indent_multi_line_relative_to = innermost_parenthesis
cpp_indent_within_parentheses = indent
cpp_indent_preserve_within_parentheses = true
cpp_indent_case_contents = true
cpp_indent_case_labels = false
cpp_indent_case_contents_when_block = false
cpp_indent_lambda_braces_when_parameter = true
cpp_indent_goto_labels = one_left
cpp_indent_preprocessor = leftmost_column
cpp_indent_access_specifiers = false
cpp_indent_namespace_contents = true
cpp_indent_preserve_comments = false
cpp_new_line_before_open_brace_namespace = ignore
cpp_new_line_before_open_brace_type = ignore
cpp_new_line_before_open_brace_function = ignore
cpp_new_line_before_open_brace_block = ignore
cpp_new_line_before_open_brace_lambda = ignore
cpp_new_line_scope_braces_on_separate_lines = false
cpp_new_line_close_brace_same_line_empty_type = false
cpp_new_line_close_brace_same_line_empty_function = false
cpp_new_line_before_catch = true
cpp_new_line_before_else = true
cpp_new_line_before_while_in_do_while = false
cpp_space_before_function_open_parenthesis = remove
cpp_space_within_parameter_list_parentheses = false
cpp_space_between_empty_parameter_list_parentheses = false
cpp_space_after_keywords_in_control_flow_statements = true
cpp_space_within_control_flow_statement_parentheses = false
cpp_space_before_lambda_open_parenthesis = false
cpp_space_within_cast_parentheses = false
cpp_space_after_cast_close_parenthesis = false
cpp_space_within_expression_parentheses = false
cpp_space_before_block_open_brace = true
cpp_space_between_empty_braces = false
cpp_space_before_initializer_list_open_brace = false
cpp_space_within_initializer_list_braces = true
cpp_space_preserve_in_initializer_list = true
cpp_space_before_open_square_bracket = false
cpp_space_within_square_brackets = false
cpp_space_before_empty_square_brackets = false
cpp_space_between_empty_square_brackets = false
cpp_space_group_square_brackets = true
cpp_space_within_lambda_brackets = false
cpp_space_between_empty_lambda_brackets = false
cpp_space_before_comma = false
cpp_space_after_comma = true
cpp_space_remove_around_member_operators = true
cpp_space_before_inheritance_colon = true
cpp_space_before_constructor_colon = true
cpp_space_remove_before_semicolon = true
cpp_space_after_semicolon = true
cpp_space_remove_around_unary_operator = true
cpp_space_around_binary_operator = insert
cpp_space_around_assignment_operator = insert
cpp_space_pointer_reference_alignment = left
cpp_space_around_ternary_operator = insert
cpp_wrap_preserve_blocks = one_liners

[*.{c++,cc,cpp,cppm,cxx,h,h++,hh,hpp,hxx,inl,ipp,ixx,tlh,tli}]

# Visual C++ Code Style settings

cpp_generate_documentation_comments = doxygen_triple_slash

# Visual C++ Formatting settings

cpp_indent_braces = false
cpp_indent_multi_line_relative_to = innermost_parenthesis
cpp_indent_within_parentheses = indent
cpp_indent_preserve_within_parentheses = true
cpp_indent_case_contents = true
cpp_indent_case_labels = false
cpp_indent_case_contents_when_block = false
cpp_indent_lambda_braces_when_parameter = true
cpp_indent_goto_labels = one_left
cpp_indent_preprocessor = leftmost_column
cpp_indent_access_specifiers = false
cpp_indent_namespace_contents = true
cpp_indent_preserve_comments = false
cpp_new_line_before_open_brace_namespace = ignore
cpp_new_line_before_open_brace_type = ignore
cpp_new_line_before_open_brace_function = ignore
cpp_new_line_before_open_brace_block = ignore
cpp_new_line_before_open_brace_lambda = ignore
cpp_new_line_scope_braces_on_separate_lines = false
cpp_new_line_close_brace_same_line_empty_type = false
cpp_new_line_close_brace_same_line_empty_function = false
cpp_new_line_before_catch = true
cpp_new_line_before_else = true
cpp_new_line_before_while_in_do_while = false
cpp_space_before_function_open_parenthesis = remove
cpp_space_within_parameter_list_parentheses = false
cpp_space_between_empty_parameter_list_parentheses = false
cpp_space_after_keywords_in_control_flow_statements = true
cpp_space_within_control_flow_statement_parentheses = false
cpp_space_before_lambda_open_parenthesis = false
cpp_space_within_cast_parentheses = false
cpp_space_after_cast_close_parenthesis = false
cpp_space_within_expression_parentheses = false
cpp_space_before_block_open_brace = true
cpp_space_between_empty_braces = false
cpp_space_before_initializer_list_open_brace = false
cpp_space_within_initializer_list_braces = true
cpp_space_preserve_in_initializer_list = true
cpp_space_before_open_square_bracket = false
cpp_space_within_square_brackets = false
cpp_space_before_empty_square_brackets = false
cpp_space_between_empty_square_brackets = false
cpp_space_group_square_brackets = true
cpp_space_within_lambda_brackets = false
cpp_space_between_empty_lambda_brackets = false
cpp_space_before_comma = false
cpp_space_after_comma = true
cpp_space_remove_around_member_operators = true
cpp_space_before_inheritance_colon = true
cpp_space_before_constructor_colon = true
cpp_space_remove_before_semicolon = true
cpp_space_after_semicolon = true
cpp_space_remove_around_unary_operator = true
cpp_space_around_binary_operator = insert
cpp_space_around_assignment_operator = insert
cpp_space_pointer_reference_alignment = right
cpp_space_around_ternary_operator = insert
cpp_wrap_preserve_blocks = one_liners

M a65.c => a65.c +27 -20
@@ 48,9 48,15 @@ assembly routines uses the expression analyzer and the lexical analyzer to
parse the source line and convert it into the object bytes that it represents.
*/

#include <ctype.h>
#include <stdlib.h>
#include <string.h>

/*  Get global goodies:  */

#include "a65.h"
#include "a65eval.h"
#include "a65util.h"

/*  Define global mailboxes for all modules:				*/



@@ 61,6 67,13 @@ unsigned address, argattr, bytes, errors, listleft, obj[MAXLINE], pagelen, pc;
FILE *filestk[FILES], *source;
TOKEN token;

/* Static function definitions: */
static void asm_line();
static void flush();
static void do_label();
static void normal_op();
static void pseudo_op();

/*  Mainline routine.  This routine parses the command line, sets up	*/
/*  the assembler at the beginning of each pass, feeds the source text	*/
/*  to the line assembler, feeds the result to the listing and hex file	*/


@@ 70,15 83,9 @@ static int done, ifsp, off;

void main(int argc, char **argv) {
    SCRATCH unsigned *o;
    int newline();
    void asm_line();
    void lclose(), lopen(), lputs();
    void hclose(), hopen(), hputc();
    void error(), fatal_error(), warning();

    printf("6502 Cross-Assembler (Portable) Ver 0.2n\n");
    printf("Copyright (c) 1986 William C. Colley, III\n");
	printf("Modifications (c) 2023 Nathan Misner\n\n");
    printf("Copyright (c) 1986 William C. Colley, III\n\n");

    while (--argc > 0) {
		if (**++argv == '-') {


@@ 147,12 154,8 @@ static int ifstack[IFDEPTH] = { ON };

static OPCODE *opcod;

void asm_line() {
static void asm_line() {
    SCRATCH int i;
    int isalph(), popc();
    OPCODE *find_code(), *find_operator();
    void do_label(), flush(), normal_op(), pseudo_op();
    void error(), pops(), pushc(), trash();

    address = pc;  bytes = 0;  eject = forwd = listhex = FALSE;
    for (i = 0; i < BIGINST; obj[i++] = NOP);


@@ 199,12 202,22 @@ static void flush() {

static void do_label() {
    SCRATCH SYMBOL *l;
    SYMBOL *find_symbol(), *new_symbol();
    void error();
	char *ch;

    if (label[0]) {
		listhex = TRUE;

		// strip off the trailing colon if it exists
		ch = label;
		while (*ch) {
			if ((ch[0] == ':') && (ch[1] == '\0')) {
				ch[0] = '\0';
			}
			ch++;
		}

		if (pass == 1) {
			// add the label to the symbol tree
			if (!((l = new_symbol(label)) -> attr)) {
				l -> attr = FORWD + VAL;
				l -> valu = pc;


@@ 222,8 235,6 @@ static void do_label() {

static void normal_op() {
    SCRATCH unsigned opcode, operand;
    unsigned do_args();
    void do_label(), error();

    opcode = opcod -> valu;  bytes = BIGINST;
    do_label();  operand = do_args();


@@ 318,10 329,6 @@ static void pseudo_op() {
    SCRATCH char *s;
    SCRATCH unsigned *o, u;
    SCRATCH SYMBOL *l;
    unsigned expr();
    SYMBOL *find_symbol(), *new_symbol();
    TOKEN *lex();
    void do_label(), error(), fatal_error(), hseek(), unlex();

    o = obj;
    switch (opcod -> valu) {

M a65.h => a65.h +5 -0
@@ 1,3 1,6 @@
#ifndef A65_H
#define A65_H

/*
	HEADER:		CUG219;
	TITLE:		6502 Cross-Assembler (Portable);


@@ 239,3 242,5 @@ typedef struct {
/*  Utility package (A65UTIL.C) hex file output routines:		*/

#define	HEXSIZE		32

#endif

M a65.vcxproj => a65.vcxproj +2 -0
@@ 133,6 133,8 @@
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="a65.h" />
    <ClInclude Include="a65eval.h" />
    <ClInclude Include="a65util.h" />
  </ItemGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
  <ImportGroup Label="ExtensionTargets">

M a65.vcxproj.filters => a65.vcxproj.filters +6 -0
@@ 29,5 29,11 @@
    <ClInclude Include="a65.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="a65eval.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="a65util.h">
      <Filter>Header Files</Filter>
    </ClInclude>
  </ItemGroup>
</Project>
\ No newline at end of file

M a65eval.c => a65eval.c +10 -16
@@ 50,6 50,8 @@ arithmetic expressions.
/*  Get global goodies:  */

#include "a65.h"
#include "a65eval.h"
#include "a65util.h"

/*  Get access to global mailboxes defined in A65.C:			*/



@@ 59,6 61,14 @@ extern unsigned argattr, pc;
extern FILE *filestk[], *source;
extern TOKEN token;

/* Static function definitions: */
static unsigned eval(unsigned pre);
static void exp_error(char c);
static void make_number(unsigned base);
static int isnum(char c);
static int ishex(char c);
static int isalnum(char c);

/*  Machine opcode argument field parsing routine.  The token stream	*/
/*  from the lexical analyzer is processed to extract addressing mode	*/
/*  information and (possibly) an actual address that can be reduced to */


@@ 74,10 84,6 @@ static int bad;
unsigned do_args() {
    SCRATCH int c;
    SCRATCH unsigned u;
    TOKEN *lex();
    int popc();
    unsigned eval(), expr();
    void exp_error(), pushc(), trash(), unlex();

    argattr = ARGNUM;  u = 0;  bad = FALSE;
    switch (lex() -> attr & TYPE) {


@@ 153,7 159,6 @@ have_number:

unsigned expr() {
    SCRATCH unsigned u;
    unsigned eval();

    bad = FALSE;
    u = eval(START);


@@ 162,8 167,6 @@ unsigned expr() {

static unsigned eval(unsigned pre) {
   register unsigned op, u, v;
   TOKEN *lex();
   void exp_error(), unlex();

	for (;;) {
		u = op = lex()->valu;


@@ 268,9 271,6 @@ TOKEN *lex() {
	SCRATCH unsigned b;
	SCRATCH OPCODE *o;
	SCRATCH SYMBOL *s;
	OPCODE *find_operator();
	SYMBOL *find_symbol();
	void exp_error(), make_number(), pops(), pushc(), trash();

	if (oldt) { oldt = FALSE;  return &token; }
	trash();


@@ 377,7 377,6 @@ opr2:		    token.attr = BINARY + RELAT + OPR;
static void make_number(unsigned base) {
    SCRATCH char *p;
    SCRATCH unsigned d;
    void exp_error();

    token.attr = VAL;
    token.valu = 0;


@@ 419,8 418,6 @@ void unlex() {
/*  current token.  Leading blank space is trashed.			*/

void pops(char *s) {
    void pushc(), trash();

    trash();
    for (; isalnum(*s = popc()); ++s);
    pushc(*s);  *s = '\0';


@@ 431,7 428,6 @@ void pops(char *s) {

void trash() {
    SCRATCH char c;
    void pushc();

    while ((c = popc()) == ' ');
    pushc(c);


@@ 476,8 472,6 @@ void pushc(char c) {
/*  EOF	has been reached on the main source file, zero otherwise.	*/

int newline() {
    void fatal_error();

    oldc = '\0';  lptr = line;
    oldt = eol = FALSE;
    while (feof(source)) {

A a65eval.h => a65eval.h +123 -0
@@ 0,0 1,123 @@
#ifndef A65EVAL_H
#define A65EVAL_H

/*
	HEADER:		CUG219;
	TITLE:		6502 Cross-Assembler (Portable);
	FILENAME:	a65eval.h;
	VERSION:	0.1;
	DATE:		08/27/1988;

	DESCRIPTION:	"This program lets you use your computer to assemble
			code for the MOS Technology 6502 microprocessors.  The
			program is written in portable C rather than BDS C.
			All assembler features are supported except relocation
			linkage, and macros.";

	KEYWORDS:	Software Development, Assemblers, Cross-Assemblers,
			MOS Technology, 6502;

	SYSTEM:		CP/M-80, CP/M-86, HP-UX, MSDOS, PCDOS, QNIX;
	COMPILERS:	Aztec C86, Aztec CII, CI-C86, Eco-C, Eco-C88, HP-UX,
			Lattice C, Microsoft C,	QNIX C;

	WARNINGS:	"This program is written in as portable C as possible.
			A port to BDS C would be extremely difficult, but see
			volume CUG113.  A port to Toolworks C is untried."

	AUTHORS:	William C. Colley III;
*/

/*
			  6502 Cross-Assembler in Portable C

		   Copyright (c) 1986 William C. Colley, III

Revision History:

Ver	Date		Description

0.0	NOV 1986	Derived from my 6800/6801 cross-assembler.  WCC3.

0.1	AUG 1988	Fixed a bug in the command line parser that puts it
			into a VERY long loop if the user types a command line
			like "A65 FILE.ASM -L".  WCC3 per Alex Cameron.

This header file contains the function definitions for the assembler's
expression evaluator and lexical analyzer.
*/

#include "a65.h"

/*  Machine opcode argument field parsing routine.  The token stream	*/
/*  from the lexical analyzer is processed to extract addressing mode	*/
/*  information and (possibly) an actual address that can be reduced to */
/*  an unsigned value.  If an error occurs during the evaluation, the	*/
/*  global flag forwd is set to indicate to the line assembler that it	*/
/*  should not base certain decisions on the result of the evaluation.	*/
/*  The address is passed back as the return value of the function.		*/
/*  The addressing mode information is passed back through the global	*/
/*  mailbox argattr.													*/

unsigned do_args();


/*  Expression analysis routine.  The token stream from the lexical		*/
/*  analyzer is processed as an arithmetic expression and reduced to an	*/
/*  unsigned value.  If an error occurs during the evaluation, the		*/
/*  global flag	forwd is set to indicate to the line assembler that it	*/
/*  should not base certain decisions on the result of the evaluation.	*/

unsigned expr();


/*  Lexical analyzer.  The source input character stream is chopped up	*/
/*  into its component parts and the pieces are evaluated.  Symbols are	*/
/*  looked up, operators are looked up, etc.  Everything gets reduced	*/
/*  to an attribute word, a numeric value, and (possibly) a string		*/
/*  value.																*/

TOKEN* lex();


int isalph(char c);


/*  Push back the current token into the input stream.  One level of	*/
/*  pushback is supported.												*/

void unlex();


/*  Get an alphanumeric string into the string value part of the		*/
/*  current token.  Leading blank space is trashed.						*/

void pops(char *s);


/*  Trash blank space and push back the character following it.			*/

void trash();


/*  Get character from input stream.  This routine does a number of		*/
/*  other things while it's passing back characters.  All control		*/
/*  characters except \t and \n are ignored.  \t is mapped into ' '.	*/
/*  Semicolon is mapped to \n.  In addition, a copy of all input is set	*/
/*  up in a line buffer for the benefit of the listing.					*/

int popc();


/*  Push character back onto input stream.  Only one level of push-back	*/
/*  supported.  \0 cannot be pushed back, but nobody would want to.		*/

void pushc(char c);


/*  Begin new line of source input.  This routine returns non-zero if	*/
/*  EOF	has been reached on the main source file, zero otherwise.		*/

int newline();

#endif

M a65util.c => a65util.c +19 -31
@@ 53,15 53,15 @@ This module contains the following utility packages:
	5)  error flagging
*/

#include <ctype.h>
#include <stdlib.h>
#include <string.h>

/*  Get global goodies:  */

#include "a65.h"

/*  Make sure that MSDOS compilers using the large memory model know	*/
/*  that calloc() returns pointer to char as an MSDOS far pointer is	*/
/*  NOT compatible with the int type as is usually the case.		*/

char *calloc();
#include "a65eval.h"
#include "a65util.h"

/*  Get access to global mailboxes defined in A65.C:			*/



@@ 75,6 75,14 @@ extern unsigned address, bytes, errors, listleft, obj[], pagelen;

static SYMBOL *sroot = NULL;

/* Static function declarations: */
static OPCODE *bsearchtbl(OPCODE *lo, OPCODE *hi, char *nam);
static int ustrcmp(char *s, char *t);
static void list_sym(SYMBOL *sp);
static void check_page();
static void record(unsigned typ);
static void putb(unsigned b);

/*  Add new symbol to symbol table.  Returns pointer to symbol even if	*/
/*  the symbol already exists.  If there's not enough memory to store	*/
/*  the new symbol, a fatal error occurs.				*/


@@ 85,7 93,7 @@ SYMBOL *new_symbol(char *nam) {
    void fatal_error();

    for (p = &sroot; (q = *p) && (i = strcmp(nam,q -> sname)); )
	p = i < 0 ? &(q -> left) : &(q -> right);
		p = i < 0 ? &(q -> left) : &(q -> right);
    if (!q) {
		if (!(*p = q = (SYMBOL *)calloc(1,sizeof(SYMBOL) + strlen(nam))))
			fatal_error(SYMBOLS);


@@ 102,7 110,7 @@ SYMBOL *find_symbol(char *nam) {
    SCRATCH SYMBOL *p;

    for (p = sroot; p && (i = strcmp(nam,p -> sname));
	p = i < 0 ? p -> left : p -> right);
		p = i < 0 ? p -> left : p -> right);
    return p;
}



@@ 111,8 119,6 @@ SYMBOL *find_symbol(char *nam) {
/*  NULL if the opcode doesn't exist.					*/

OPCODE *find_code(char *nam) {
    OPCODE *bsearch();

    static OPCODE opctbl[] = {
		{ TWOOP,			0x61,	"ADC"	},
		{ TWOOP,			0x21,	"AND"	},


@@ 190,7 196,7 @@ OPCODE *find_code(char *nam) {
		{ INHOP,			0x98,	"TYA"	}
    };

    return bsearch(opctbl,opctbl + (sizeof(opctbl) / sizeof(OPCODE)),nam);
    return bsearchtbl(opctbl,opctbl + (sizeof(opctbl) / sizeof(OPCODE)),nam);
}

/*  Operator table search routine.  This routine pats down the		*/


@@ 198,8 204,6 @@ OPCODE *find_code(char *nam) {
/*  to it or NULL if the opcode doesn't exist.				*/

OPCODE *find_operator(char *nam) {
    OPCODE *bsearch();

    static OPCODE oprtbl[] = {
		{ REG,						'A',		"A"		},
		{ BINARY + LOG1  + OPR,		AND,		"AND"	},


@@ 221,10 225,10 @@ OPCODE *find_operator(char *nam) {
		{ REG,						'Y',		"Y"		},
    };

    return bsearch(oprtbl,oprtbl + (sizeof(oprtbl) / sizeof(OPCODE)),nam);
    return bsearchtbl(oprtbl,oprtbl + (sizeof(oprtbl) / sizeof(OPCODE)),nam);
}

static OPCODE *bsearch(OPCODE *lo, OPCODE *hi, char *nam) {
static OPCODE *bsearchtbl(OPCODE *lo, OPCODE *hi, char *nam) {
    SCRATCH int i;
    SCRATCH OPCODE *chk;



@@ 256,9 260,6 @@ static FILE *list = NULL;
/*  lputs() and lclose() have no effect.				*/

void lopen(char *nam) {
    FILE *fopen();
    void fatal_error(), warning();

    if (list) warning(TWOLST);
    else if (!(list = fopen(nam,"w"))) fatal_error(LSTOPEN);
    return;


@@ 272,7 273,6 @@ void lopen(char *nam) {
void lputs() {
    SCRATCH int i, j;
    SCRATCH unsigned *o;
    void check_page(), fatal_error();

    if (list) {
		i = bytes;  o = obj;


@@ 301,8 301,6 @@ void lputs() {
static int col = 0;

void lclose() {
    void fatal_error(), list_sym();

    if (list) {
		if (sroot) {
			list_sym(sroot);


@@ 315,8 313,6 @@ void lclose() {
}

static void list_sym(SYMBOL *sp) {
    void check_page();

    if (sp) {
		list_sym(sp -> left);
		fprintf(list,"%04x  %-10s",sp -> valu,sp -> sname);


@@ 368,8 364,6 @@ void hopen(char *nam) {
/*  disk fills up, a fatal error occurs.				*/

void hputc(unsigned c) {
    void record();

    if (hex) {
		buf[cnt++] = c;
		if (cnt == HEXSIZE) record(0);


@@ 383,8 377,6 @@ void hputc(unsigned c) {
/*  occurs.								*/

void hseek(unsigned a) {
    void record();

    if (hex) {
		if (cnt) record(0);
		addr = a;


@@ 397,8 389,6 @@ void hseek(unsigned a) {
/*  fatal error occurs.							*/

void hclose() {
    void fatal_error(), record();

    if (hex) {
		if (cnt) record(0);
		record(1);


@@ 409,8 399,6 @@ void hclose() {

static void record(unsigned typ) {
    SCRATCH unsigned i;
    void fatal_error(), putb();

    putc(':',hex);  putb(cnt);  putb(high(addr));
    putb(low(addr));  putb(typ);
    for (i = 0; i < cnt; ++i) putb(buf[i]);

A a65util.h => a65util.h +160 -0
@@ 0,0 1,160 @@
#ifndef A65_UTIL_H
#define A65_UTIL_H

/*
	HEADER:		CUG219;
	TITLE:		6502 Cross-Assembler (Portable);
	FILENAME:	a65util.h;
	VERSION:	0.1;
	DATE:		08/27/1988;

	DESCRIPTION:	"This program lets you use your computer to assemble
			code for the MOS Technology 6502 microprocessors.  The
			program is written in portable C rather than BDS C.
			All assembler features are supported except relocation
			linkage, and macros.";

	KEYWORDS:	Software Development, Assemblers, Cross-Assemblers,
			MOS Technology, 6502;

	SYSTEM:		CP/M-80, CP/M-86, HP-UX, MSDOS, PCDOS, QNIX;
	COMPILERS:	Aztec C86, Aztec CII, CI-C86, Eco-C, Eco-C88, HP-UX,
			Lattice C, Microsoft C,	QNIX C;

	WARNINGS:	"This program is written in as portable C as possible.
			A port to BDS C would be extremely difficult, but see
			volume CUG113.  A port to Toolworks C is untried."

	AUTHORS:	William C. Colley III;
*/

/*
			  6502 Cross-Assembler in Portable C

		   Copyright (c) 1986 William C. Colley, III

Revision History:

Ver	Date		Description

0.0	NOV 1986	Derived from my 6800/6801 cross-assembler.  WCC3.

0.1	AUG 1988	Fixed a bug in the command line parser that puts it
			into a VERY long loop if the user types a command line
			like "A65 FILE.ASM -L".  WCC3 per Alex Cameron.

This header file contains the function definitions for the following 
utility packages:

	1)  symbol table building and searching

	2)  opcode and operator table searching

	3)  listing file output

	4)  hex file output

	5)  error flagging
*/

#include "a65.h"

/*  Add new symbol to symbol table.  Returns pointer to symbol even if	*/
/*  the symbol already exists.  If there's not enough memory to store	*/
/*  the new symbol, a fatal error occurs.								*/

SYMBOL *new_symbol(char *nam);


/*  Look up symbol in symbol table.  Returns pointer to symbol or NULL	*/
/*  if symbol not found.												*/

SYMBOL *find_symbol(char *nam);


/*  Opcode table search routine.  This routine pats down the opcode		*/
/*  table for a given opcode and returns either a pointer to it or		*/
/*  NULL if the opcode doesn't exist.									*/

OPCODE *find_code(char *nam);


/*  Operator table search routine.  This routine pats down the			*/
/*  operator table for a given operator and returns either a pointer	*/
/*  to it or NULL if the opcode doesn't exist.							*/

OPCODE *find_operator(char *nam);


/*  Listing file open routine.  If a listing file is already open, a	*/
/*  warning occurs.  If the listing file doesn't open correctly, a		*/
/*  fatal error occurs.  If no listing file is open, all calls to		*/
/*  lputs() and lclose() have no effect.								*/

void lopen(char *nam);


/*  Listing file line output routine.  This routine processes the		*/
/*  source line saved by popc() and the output of the line assembler in	*/
/*  buffer obj into a line of the listing.  If the disk fills up, a		*/
/*  fatal error occurs.													*/

void lputs();


/*  Listing file close routine.  The symbol table is appended to the	*/
/*  listing in alphabetic order by symbol name, and the listing file is	*/
/*  closed.  If the disk fills up, a fatal error occurs.				*/

void lclose();


/*  Hex file open routine.  If a hex file is already open, a warning	*/
/*  occurs.  If the hex file doesn't open correctly, a fatal error		*/
/*  occurs.  If no hex file is open, all calls to hputc(), hseek(), and	*/
/*  hclose() have no effect.											*/

void hopen(char *nam);


/*  Hex file write routine.  The data byte is appended to the current	*/
/*  record.  If the record fills up, it gets written to disk.  If the	*/
/*  disk fills up, a fatal error occurs.								*/

void hputc(unsigned c);


/*  Hex file address set routine.  The specified address becomes the	*/
/*  load address of the next record.  If a record is currently open,	*/
/*  it gets written to disk.  If the disk fills up, a fatal error		*/
/*  occurs.																*/

void hseek(unsigned a);


/*  Hex file close routine.  Any open record is written to disk, the	*/
/*  EOF record is added, and file is closed.  If the disk fills up, a	*/
/*  fatal error occurs.													*/

void hclose();


/*  Error handler routine.  If the current error code is non-blank,		*/
/*  the error code is filled in and the	number of lines with errors		*/
/*  is adjusted.														*/

void error(char code);


/*  Fatal error handler routine.  A message gets printed on the stderr	*/
/*  device, and the program bombs.										*/

void fatal_error(char *msg);


/*  Non-fatal error handler routine.  A message gets printed on the		*/
/*  stderr device, and the routine returns.								*/

void warning(char *msg);

#endif

M readme.txt => readme.txt +3 -2
@@ 8,7 8,8 @@ your workflow.
=====Why not to use this assembler=====
- The code has that "old UNIX program" stank to it, where you have a lot of
  buffers with hard-coded sizes and if you exceed them the program will
  (hopefully) crash without telling you why.
  (hopefully) crash without telling you why. See a65.h if you want to fiddle
  with the buffer sizes.
- It's fairly opinionated regarding syntax. It doesn't support a ton of 6502
  "dialects" like all the popular assemblers do
- It's an absolute assembler, so no linking


@@ 27,6 28,7 @@ your workflow.
- Reformat code for ANSI style function declarations - done
- Change "FCB", "FCC", "FDB" to "DB", "DS", "DW" - done
- Change the syntax so "DB" accepts string(s) as arguments - done
- Change the syntax so labels can have colons after them - done
- Give each .c file its own header file
- Change the assembler to output binary files instead of Intel HEX
- Allow for forcing loads/stores to not be optimized for zero page


@@ 41,7 43,6 @@ your workflow.
=====License=====

Copyright (c) 1986 William C. Colley, III
Changes (c) 2023 Nathan Misner

This package may be used for any commercial or non-commercial purpose.  It may
be copied and distributed freely provided that any fee charged by the

M test.asm => test.asm +1 -1
@@ 4,7 4,7 @@ foo	equ	$5
bar	equ	$6
	
	org	$8000
string
string:
	db	"hello",0,1,2,3,-1,-2,-3
	db	"goodbye"
	dw	1,2,3,4,-1,-2,-3,-4

M test.lst => test.lst +1 -1
@@ 4,7 4,7 @@
   0006                 bar	equ	$6
                        	
   8000                 	org	$8000
   8000                 string
   8000                 string:
   8000   68 65 6c 6c   	db	"hello",0,1,2,3,-1,-2,-3
   8004   6f 00 01 02   
   8008   03 ff fe fd