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