aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/z80asm/ChangeLog124
-rw-r--r--tools/z80asm/Makefile20
-rw-r--r--tools/z80asm/TODO1
-rw-r--r--tools/z80asm/jr.diff81
-rw-r--r--tools/z80asm/z80asm.c2197
5 files changed, 1640 insertions, 783 deletions
diff --git a/tools/z80asm/ChangeLog b/tools/z80asm/ChangeLog
index ceaf821..04ea7c1 100644
--- a/tools/z80asm/ChangeLog
+++ b/tools/z80asm/ChangeLog
@@ -1,3 +1,127 @@
+2005-11-30 Jan Wilmans <jw@dds.nl>
+
+ * z80asm.c: Added unoffical syntax of ADD A,r as ADD r
+ * z80asm.c: Added unoffical syntax of SUB r as SUB A,r
+
+2005-11-30 Jan Wilmans <jw@dds.nl>
+
+ * z80asm.c: Added new seek command
+
+2005-11-29 Jan Wilmans <jw@dds.nl>
+
+ * z80asm.c: Added two extra verbosity levels.
+
+2005-11-13 Bas Wijnen <shevek@fmf.nl>
+
+ * z80asm.c: Run indent.
+
+2005-10-14 Bas Wijnen <shevek@fmf.nl>
+
+ * z80asm.c (struct reference, compute_ref, new_reference): Removed
+ copy of stack frame from struct reference.
+
+2005-09-14 Bas Wijnen <shevek@fmf.nl>
+
+ * z80asm.c (open_include_file, assemble): Open incbin'd files as
+ binary.
+
+2005-06-16 Bas Wijnen <shevek@fmf.nl>
+
+ * Makefile: Fix incorrect version.
+ * z80asm.c (enum mnemonic, mnemonics, assemble), examples/hello.asm:
+ Rename bininclude to incbin.
+ * z80asm.c (readcommand, assemble), examples/macro.asm: Allow labels
+ before endm and endif.
+
+2005-05-19 Bas Wijnen <shevek@fmf.nl>
+
+ * z80asm.c (struct reference, printerr, compute_ref, new_reference,
+ assemble): Added stack frame to reference.
+ * z80asm.c (labelfilename, parse_commandline): Remove output files
+ when compilation fails.
+ * z80asm.c (use_force, parse_commandline, assemble, main): Implement
+ --force.
+ * z80asm.c (parse_commandline): Make a.bin the default target.
+ * z80asm.c (check_label, rd_label, rd_value, rd_expr,
+ get_include_name, assemble): Give errors about junk at end of
+ line or expression.
+ * z80asm.c (rd_value): Support double quotes for character constants.
+ * z80asm.c (rd_expr_equal): Support = for equality.
+ * z80asm.1: Updated manpage.
+
+2005-05-18 Bas Wijnen <shevek@fmf.nl>
+
+ * z80asm.c (enum mnemonic, enum reftype, struct reference, struct
+ label, struct stack, struct macro_arg, struct macro_line, struct
+ macro, mnemonics, firstmacro, define_macro, sp, stack, readlabel,
+ rd_expr, compute_ref, check_label, rd_label, rd_value, rd_factor,
+ rd_term, rd_expr_shift, rd_expr_unequal, rd_expr_equal, rd_expr_and,
+ rd_expr_xor, rd_expr_or, new_reference, wrt_ref, read_line,
+ get_macro_args, assemble): Added macro support.
+ * z80asm.c (rd_value): Added several radix notations.
+ * examples/macro.asm: New file.
+
+2005-05-17 Bas Wijnen <shevek@fmf.nl>
+
+ * Makefile (clean): Clean examples and headers.
+ * Makefile (dist): Make versioned tarballs.
+ * z80asm.c (buffer, try_use_real_file, flush_to_real_file,
+ parse_commandline, assemble): Generalise writing to non-seekable
+ files.
+ * z80asm.c (reallistfile, parse_commandline, assemble): Use it for
+ list file.
+ * z80asm.c (read_line, assemble): Remove arbitrary line length limit.
+
+2005-05-13 Bas Wijnen <shevek@fmf.nl>
+
+ * examples/Makefile, examples/hello.asm, headers/msx-bios.asm,
+ headers/msx2-bios.asm, headers/msx2+-bios.asm,
+ headers/msxturbor-bios.asm: New files.
+ * z80asm.c (struct includedir, firstincludedir, open_include_file,
+ add_include, parse_commandline, assemble, main): Use include path.
+ * z80asm (parse_commandline): Make stderr default for list and label
+ files.
+ * z80asm.c (enum mnemonic, mnemonics, get_include_name, assemble): Add
+ bininclude directive.
+ * z80asm.c (printerr, assemble): Make error output parsable.
+ * z80asm.1: Updated.
+
+2005-05-11 Bas Wijnen <shevek@fmf.nl>
+
+ * Makefile (top level, dist): Use versions instead of dates.
+ * VERSION: New file.
+ * BUGS, NEWS, README: Removed.
+
+2005-05-10 Bas Wijnen <shevek@fmf.nl>
+
+ * z80asm.1: New file.
+ * z80asm.c (enum mnemonic, mnemonic, assemble): Support END directive.
+ * z80asm.c (compare, indx, readlabel): Use strncasecmp instead of
+ compare.
+ * z80asm.c (assemble): Fix bug with strings in DEFB.
+ * z80asm.c (assemble): Allow backslash-escapes in DEFB strings.
+ * z80asm.c (rd_character): Allow octal escapes in strings.
+
+2005-03-11 Bas Wijnen <shevek@fmf.nl>
+
+ * z80asm.c (rd_r): Fixed index prefix.
+ * z80asm.c (assemble): Fixed register count errors.
+
+2004-10-01 Bas Wijnen <b.wijnen@phys.rug.nl>
+
+ * z80asm (rd_comma): Fixed possible buffer overflow.
+ * z80asm (parse_commandline): Improved --help output.
+ * z80asm (new_reference): Removed useless ++.
+ * z80asm (wrt_ref, assemble): Improved list output for ds.
+
+2004-10-01 H. Peter Anvin <hpa@users.sourceforge.net>
+
+ * z80asm.c (enum mnemonic, mnemonics, assemble): Added dm/defm as an
+ alias for db/defb.
+ * README: Updated documentation accordingly.
+ * z80asm.c (write_one_byte, wrtb, new_reference, wrt_ref, assemble):
+ Fixed bug regarding addr increments.
+
2004-09-29 Bas Wijnen <b.wijnen@phys.rug.nl>
* z80asm.c: added global variable labelprefix.
diff --git a/tools/z80asm/Makefile b/tools/z80asm/Makefile
index 75c8011..a0a976d 100644
--- a/tools/z80asm/Makefile
+++ b/tools/z80asm/Makefile
@@ -1,5 +1,5 @@
# Makefile for the Z80 assembler by shevek
-# Copyright (C) 2002,2004 Bas Wijnen
+# Copyright (C) 2002-2005 Bas Wijnen
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
@@ -16,25 +16,29 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
CC = gcc
-LDFLAGS = -g -O2 -Wall
-CFLAGS = -g -O2 -Wall -Wwrite-strings -Wcast-qual -Wcast-align -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -pedantic -ansi -Wshadow -g -W -Ignulib
+LDFLAGS = -O2 -Wall
+CFLAGS = -O2 -Wall -Wwrite-strings -Wcast-qual -Wcast-align -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -Wshadow -g -W -Ignulib
+SHELL = /bin/bash
+VERSION ?= $(shell echo -n `cat VERSION | cut -d. -f1`. ; echo $$[`cat VERSION | cut -d. -f2` + 1])
all:z80asm
z80asm:z80asm.c Makefile gnulib/getopt.o gnulib/getopt1.o
- $(CC) $(CFLAGS) $(LDFLAGS) $< gnulib/getopt.o gnulib/getopt1.o -o $@
+ $(CC) $(CFLAGS) $(LDFLAGS) -DVERSION=\"$(shell cat VERSION)\" $< gnulib/getopt.o gnulib/getopt1.o -o $@
gnulib/%.o:gnulib/%.c gnulib/getopt.h Makefile
$(CC) $(CFLAGS) -c $< -o $@
clean:
- for i in . gnulib ; do \
- rm -f $$i/a.bin $$i/a.out $$i/core $$i/*~ $$i/\#* $$i/*.o ; \
+ for i in . gnulib examples headers ; do \
+ rm -f $$i/core $$i/*~ $$i/\#* $$i/*.o $$i/*.rom ; \
done
rm -f z80asm z80asm.exe
dist: clean
- rm -rf /tmp/z80asm
+ echo $(VERSION) > VERSION
+ rm -rf /tmp/z80asm-$(VERSION) /tmp/z80asm
tar cf - -C .. z80asm | tar xf - -C /tmp
find /tmp/z80asm -name CVS | xargs rm -rf
- tar cvzf ../z80asm-`date +%Y%m%d`00.tar.gz -C /tmp z80asm
+ mv /tmp/z80asm /tmp/z80asm-$(VERSION)
+ tar cvzf ../z80asm-$(VERSION).tar.gz -C /tmp z80asm-$(VERSION)
diff --git a/tools/z80asm/TODO b/tools/z80asm/TODO
index 557fb43..0f2ea4d 100644
--- a/tools/z80asm/TODO
+++ b/tools/z80asm/TODO
@@ -1,5 +1,4 @@
TODO for shevek's Z80 assembler:
-- fix the bugs from BUGS :-)
- make header files containing MSX system constants
- a flag for warnings about unofficial instructions would be nice
- an "export" assembler directive to specify the labels to be exported with -L
diff --git a/tools/z80asm/jr.diff b/tools/z80asm/jr.diff
deleted file mode 100644
index f3c25b5..0000000
--- a/tools/z80asm/jr.diff
+++ /dev/null
@@ -1,81 +0,0 @@
-? z80asm
-Index: z80asm.c
-===================================================================
-RCS file: /cvsroot/z80asm/z80asm/z80asm.c,v
-retrieving revision 1.10
-diff -u -r1.10 z80asm.c
---- z80asm.c 29 Sep 2004 13:09:48 -0000 1.10
-+++ z80asm.c 1 Oct 2004 06:36:41 -0000
-@@ -525,6 +525,7 @@
- fprintf (listfile, " %02x", b);
- listdepth += 3;
- }
-+ addr++;
- }
-
- /* write byte to outfile and possibly some index things as well */
-@@ -541,7 +542,6 @@
- indexed);
- write_one_byte (indexed, 1);
- indexed = 0;
-- addr++;
- }
- if (writebyte)
- {
-@@ -560,7 +560,6 @@
- else
- {
- write_one_byte (b, 1);
-- addr++;
- }
- if (indexjmp)
- {
-@@ -1200,6 +1199,8 @@
- firstreference->prev = tmp;
- tmp->prev = NULL;
- firstreference = tmp;
-+ /* Dummy value which should not give warnings */
-+ value = (type == TYPE_RELB) ? ds_count : 0;
- }
- wrt_ref (value, type, ds_count);
- }
-@@ -1783,23 +1784,19 @@
- return;
- }
- write_one_byte (val + 0xC7, 1);
-- addr++;
- return;
- case TYPE_ABSW:
- write_one_byte (val & 0xff, 1);
- write_one_byte ( (val >> 8) & 0xff, 1);
-- addr++;
- return;
- case TYPE_ABSB:
- write_one_byte (val & 0xff, 1);
-- addr++;
- return;
- case TYPE_DS:
- if (havelist) fprintf (listfile, " %02x...", val & 0xff);
- while (count--)
- {
- write_one_byte (val & 0xff, 0);
-- addr++;
- }
- return;
- case TYPE_BSR:
-@@ -1818,7 +1815,6 @@
- printerr ("Warning: relative jump out of range (%d).\n", val);
- }
- write_one_byte (val & 0xff, 1);
-- addr++;
- }
- }
-
-@@ -2558,7 +2554,6 @@
- for (i = 0; i < r; i++)
- {
- write_one_byte (0, 0);
-- ++addr;
- }
- break;
- case ORG:
diff --git a/tools/z80asm/z80asm.c b/tools/z80asm/z80asm.c
index a1fa4c4..f1cf86b 100644
--- a/tools/z80asm/z80asm.c
+++ b/tools/z80asm/z80asm.c
@@ -1,6 +1,7 @@
/* Z80 assembler by shevek
- Copyright (C) 2002-2004 Bas Wijnen <b.wijnen@phys.rug.nl>
+ Copyright (C) 2002-2005 Bas Wijnen <shevek@fmf.nl>
+ Copyright (C) 2005 Jan Wilmans <jw@dds.nl>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@@ -17,45 +18,48 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#define VERSION "0.2"
#include <stdio.h>
#include <string.h>
+#include <strings.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <stdarg.h>
#include <getopt.h>
+#include <unistd.h>
/* defines which are not function-specific */
#ifndef BUFLEN
-#define BUFLEN 300 /* size of readbuffer for file i/o */
+#define BUFLEN 300 /* size of readbuffer for file i/o */
#endif
#ifndef MAX_INCLUDE
-#define MAX_INCLUDE 20 /* stack size for include command */
+#define MAX_INCLUDE 200 /* stack size for include command and macros */
#endif
/* types */
/* mnemonics. THESE MUST BE IN THE SAME ORDER AS const char *mnemonic[]! */
-enum mnemonic {
- CALL,CPDR,CPIR,DJNZ,HALT,INDR,INIR,LDDR,LDIR,OTDR,OTIR,OUTD,OUTI,PUSH,
- RETI,RETN,RLCA,RRCA,DEFB,DEFW,DEFS,
- ADC,ADD,AND,BIT,CCF,CPD,CPI,CPL,DAA,DEC,EQU,EXX,INC,IND,INI,LDD,LDI,NEG,NOP,
- OUT,POP,RES,RET,RLA,RLC,RLD,RRA,RRC,RRD,RST,SBC,SCF,SET,SLA,SLL,SLI,SRA,SRL,
- SUB,XOR,ORG,
- CP,DI,EI,EX,IM,IN,JP,JR,LD,OR,RL,RR,DB,DW,DS,
- INCLUDE,IF,ELSE,ENDIF
+enum mnemonic
+{
+ CALL, CPDR, CPIR, DJNZ, HALT, INDR, INIR, LDDR, LDIR, OTDR, OTIR, OUTD,
+ OUTI, PUSH, RETI, RETN, RLCA, RRCA, DEFB, DEFW, DEFS, DEFM,
+ ADC, ADD, AND, BIT, CCF, CPD, CPI, CPL, DAA, DEC, EQU, EXX, INC, IND, INI,
+ LDD, LDI, NEG, NOP, OUT, POP, RES, RET, RLA, RLC, RLD, RRA, RRC, RRD, RST,
+ SBC, SCF, SET, SLA, SLL, SLI, SRA, SRL, SUB, XOR, ORG,
+ CP, DI, EI, EX, IM, IN, JP, JR, LD, OR, RL, RR, DB, DW, DS, DM,
+ INCLUDE, INCBIN, IF, ELSE, ENDIF, END, MACRO, ENDM, SEEK
};
/* types of reference */
enum reftype
{
- TYPE_BSR, /* bit value (0-7) for bit, set and res mnemonics */
- TYPE_DS, /* ds reference (byte count and value) */
- TYPE_RST, /* rst reference: 0-0x38, with val & 0x38 == val */
- TYPE_ABSW, /* absolute word (2 bytes) */
- TYPE_ABSB, /* absolute byte */
- TYPE_RELB /* relative byte */
+ TYPE_BSR, /* bit value (0-7) for bit, set and res */
+ TYPE_DS, /* ds reference (byte count and value) */
+ TYPE_RST, /* rst reference: val & 0x38 == val */
+ TYPE_ABSW, /* absolute word (2 bytes) */
+ TYPE_ABSB, /* absolute byte */
+ TYPE_RELB, /* relative byte */
+ TYPE_LABEL /* equ expression */
};
/* filetypes that can appear on the input. object files are on the todo list */
@@ -64,29 +68,14 @@ enum filetype
FILETYPE_ASM
};
-/* these structs will be malloced for each reference */
-struct reference
-{
- struct reference *next, *prev;
- enum reftype type; /* type of reference */
- long oseekpos; /* position in outfile for data */
- long lseekpos; /* position in listfile for data */
- char delimiter; /* delimiter for parser */
- int addr, line; /* address and line of reference */
- int comma; /* comma when reference was set */
- int count; /* only for ds: number of items */
- int infile; /* index in infile[], current infile */
- char input[1]; /* variable size buffer containing formula */
-};
-
/* labels (will be malloced) */
struct label
{
- struct label *next, *prev; /* linked list */
+ struct label *next, *prev; /* linked list */
int value; /* value */
- int valid; /* if it is valid, or not yet computed */
- int busy; /* if it is currently being computed */
- char *addr; /* mallocced memory to value for computation */
+ int valid; /* if it is valid, or not yet computed */
+ int busy; /* if it is currently being computed */
+ struct reference *ref; /* mallocced memory to value for computation */
char name[1]; /* space with name in it */
};
@@ -97,14 +86,6 @@ struct infile
enum filetype type;
};
-/* elements on the file stack */
-struct stack
-{
- const char *name; /* filename (for errors). may be malloced */
- FILE *file; /* the handle */
- int line; /* the current line number (for errors) */
-};
-
/* filenames must be remembered for references */
struct name
{
@@ -112,25 +93,97 @@ struct name
char name[1];
};
+/* the include path */
+struct includedir
+{
+ struct includedir *next;
+ char name[1];
+};
+
+/* macro stuff */
+struct macro_arg
+{
+ struct macro_arg *next;
+ unsigned pos;
+ unsigned which;
+};
+
+struct macro_line
+{
+ struct macro_line *next;
+ char *line;
+ struct macro_arg *args;
+};
+
+struct macro
+{
+ struct macro *next;
+ char *name;
+ unsigned numargs;
+ char **args;
+ struct macro_line *lines;
+};
+
+/* elements on the context stack */
+struct stack
+{
+ const char *name; /* filename (for errors). may be malloced */
+ struct includedir *dir; /* directory where it comes from, if any */
+ FILE *file; /* the handle */
+ int line; /* the current line number (for errors) */
+ int shouldclose; /* if this file should be closed when done */
+ struct label *labels; /* local labels for this stack level */
+ /* if file is NULL, this is a macro entry */
+ struct macro *macro;
+ struct macro_line *macro_line;
+ char **macro_args; /* arguments given to the macro */
+};
+
+/* these structs will be malloced for each reference */
+struct reference
+{
+ struct reference *next, *prev;
+ enum reftype type; /* type of reference */
+ long oseekpos; /* position in outfile for data */
+ long lseekpos; /* position in listfile for data */
+ char delimiter; /* delimiter for parser */
+ int addr, line; /* address and line of reference */
+ int comma; /* comma when reference was set */
+ int count; /* only for ds: number of items */
+ int infile; /* index in infile[], current infile */
+ int done; /* if this reference has been computed */
+ int computed_value; /* value (only valid if done = true) */
+ int level; /* maximum stack level of labels to use */
+ char input[1]; /* variable size buffer containing formula */
+};
+
/* global variables */
/* mnemonics, used as argument to indx() in assemble */
-const char *mnemonics[]={
- "call","cpdr","cpir","djnz","halt","indr","inir","lddr","ldir","otdr","otir",
- "outd","outi","push","reti","retn","rlca","rrca","defb","defw","defs","adc",
- "add","and","bit","ccf","cpd","cpi","cpl","daa","dec","equ","exx","inc",
- "ind","ini","ldd","ldi","neg","nop","out","pop","res","ret","rla","rlc",
- "rld","rra","rrc","rrd","rst","sbc","scf","set","sla","sll","sli","sra",
- "srl","sub","xor","org","cp","di","ei","ex","im","in","jp","jr","ld","or",
- "rl","rr","db","dw","ds","include","if","else","endif",NULL
+const char *mnemonics[] = {
+ "call", "cpdr", "cpir", "djnz", "halt", "indr", "inir", "lddr", "ldir",
+ "otdr", "otir", "outd", "outi", "push", "reti", "retn", "rlca", "rrca",
+ "defb", "defw", "defs", "defm",
+ "adc", "add", "and", "bit", "ccf", "cpd", "cpi", "cpl", "daa", "dec", "equ",
+ "exx", "inc", "ind", "ini", "ldd", "ldi", "neg", "nop", "out", "pop",
+ "res", "ret", "rla", "rlc", "rld", "rra", "rrc", "rrd", "rst", "sbc",
+ "scf", "set", "sla", "sll", "sli", "sra", "srl", "sub", "xor", "org",
+ "cp", "di", "ei", "ex", "im", "in", "jp", "jr", "ld", "or", "rl", "rr",
+ "db", "dw", "ds", "dm",
+ "include", "incbin", "if", "else", "endif", "end", "macro", "endm",
+ "seek", NULL
};
/* linked lists */
static struct reference *firstreference = NULL;
static struct label *firstlabel = NULL, *lastlabel = NULL;
static struct name *firstname = NULL;
+static struct includedir *firstincludedir = NULL;
+static struct macro *firstmacro = NULL;
/* files */
-static FILE *realoutputfile, *outfile, *listfile, *labelfile;
+static FILE *realoutputfile, *outfile, *reallistfile, *listfile, *labelfile;
+static const char *realoutputfilename;
+static const char *labelfilename;
static struct infile *infile;
/* prefix for labels in labelfile */
static const char *labelprefix = "";
@@ -143,7 +196,7 @@ static int infilecount;
static int errors = 0;
/* current line, address and file */
-static int line = 0, addr = 0, file;
+static int addr = 0, file;
/* current number of characters in list file, for indentation */
static int listdepth;
@@ -170,7 +223,17 @@ static int baseaddr;
static char mem_delimiter;
/* line currently being parsed */
-static char buffer[BUFLEN];
+static char *buffer = NULL;
+
+/* if a macro is currently being defined */
+static int define_macro = 0;
+
+/* file (and macro) stack */
+static int sp;
+static struct stack stack[MAX_INCLUDE]; /* maximum level of includes */
+
+/* Produce output even with errors. */
+static int use_force = 0;
/* print an error message, including current line and file */
static void
@@ -178,9 +241,17 @@ printerr (const char *fmt, ...)
{
va_list l;
va_start (l, fmt);
- fprintf (stderr, "%s:%5d (%04X): ", infile[file].name, line, addr);
+ if ((sp < 0) || (stack[sp].name == 0))
+ {
+ fprintf (stderr,
+ "internal assembler error (null-pointer), sp == %i\n", sp);
+ exit (2);
+ }
+ fprintf (stderr, "%s%s:%d: ", stack[sp].dir ? stack[sp].dir->name : "",
+ stack[sp].name, stack[sp].line);
vfprintf (stderr, fmt, l);
va_end (l);
+ errors++;
}
/* skip over spaces in string */
@@ -189,7 +260,8 @@ delspc (const char *ptr)
{
while (*ptr && isspace (*ptr))
ptr++;
- if (*ptr ==';') ptr = "";
+ if (*ptr == ';')
+ ptr = "";
return ptr;
}
@@ -200,13 +272,21 @@ rd_comma (const char **p)
*p = delspc (*p);
if (**p != ',')
{
- printerr ("`,' expected. Remainder of line: %s.\n", *p);
- errors++;
+ printerr ("`,' expected. Remainder of line: %s\n", *p);
+ return;
}
*p = delspc ((*p) + 1);
}
-/* During assembly, most literals are not parsed. Instead, they are saved
+/* look ahead for a comma, no error if not found */
+static int
+has_argument (const char **p)
+{
+ const char *q = delspc (*p);
+ return (*q == ',');
+}
+
+/* During assembly, many literals are not parsed. Instead, they are saved
* until all labels are read. After that, they are parsed. This function
* is used during assembly, to find the place where the command continues. */
static void
@@ -221,8 +301,7 @@ skipword (const char **pos, char delimiter)
case '\0':
if (depth > 0)
{
- printerr ("Unexpected end of line.\n");
- errors++;
+ printerr ("unexpected end of line\n");
}
(*pos)--;
return;
@@ -234,24 +313,25 @@ skipword (const char **pos, char delimiter)
{
if (delimiter == ')')
return;
- printerr ("Unexpected `)'.\n");
- errors++;
+ printerr ("unexpected `)'\n");
}
break;
default:
if (delimiter == c && depth == 0)
- return;
+ {
+ return;
+ }
}
}
}
/* callback function for argument parser, used to open output files. */
static FILE *
-openfile (int *done, /* flag to check that a file is opened only once. */
- const char *type, /* name of filetype for error message */
- FILE *def, /* default value, in case "-" is specified */
- const char *name, /* filename to open */
- const char *flags) /* open flags */
+openfile (int *done, /* flag to check that a file is opened only once. */
+ const char *type, /* name of filetype for error message */
+ FILE * def, /* default value, in case "-" is specified */
+ const char *name, /* filename to open */
+ const char *flags) /* open flags */
{
FILE *retval;
if (*done)
@@ -260,7 +340,7 @@ openfile (int *done, /* flag to check that a file is opened only once. */
exit (1);
}
*done = 1;
- if (def && name && name[0] == '-' && name[1] == 0)
+ if (def && (!name || (name[0] == '-' && name[1] == 0)))
{
return def;
}
@@ -278,11 +358,49 @@ openfile (int *done, /* flag to check that a file is opened only once. */
return retval;
}
+/* open an included file, searching the path */
+static FILE *
+open_include_file (const char *name, struct includedir **dir,
+ const char *flags)
+{
+ FILE *result;
+ struct includedir *i;
+ /* always try the current directory first */
+ result = fopen (name, flags);
+ if (result)
+ {
+ if (dir)
+ *dir = NULL;
+ return result;
+ }
+ for (i = firstincludedir; i != NULL; i = i->next)
+ {
+ char *tmp = malloc (strlen (i->name) + strlen (name) + 1);
+ if (!tmp)
+ {
+ printerr ("not enough memory trying to open include file\n");
+ return NULL;
+ }
+ strcpy (tmp, i->name);
+ strcat (tmp, name);
+ result = fopen (tmp, flags);
+ free (tmp);
+ if (result)
+ {
+ if (dir)
+ *dir = i;
+ return result;
+ }
+ }
+ return NULL;
+}
+
/* queue a file to be opened for reading */
static void
open_infile (const char *name)
{
- if (!(infile = realloc (infile, sizeof (struct infile) * (infilecount + 1))))
+ infile = realloc (infile, sizeof (struct infile) * (infilecount + 1));
+ if (!infile)
{
fprintf (stderr, "Error: insufficient memory\n");
exit (1);
@@ -290,11 +408,84 @@ open_infile (const char *name)
/* only asm is currently supported */
infile[infilecount].type = FILETYPE_ASM;
infile[infilecount].name = name;
- if (verbose > 2)
+ if (verbose >= 5)
fprintf (stderr, "queued inputfile %s\n", infile[infilecount].name);
infilecount++;
}
+/* add a directory to the include search path */
+static void
+add_include (const char *name)
+{
+ struct includedir *i;
+ i = malloc (sizeof (struct includedir) + strlen (name) + 1);
+ if (!i)
+ {
+ fprintf (stderr, "Error: insufficient memory\n");
+ exit (1);
+ }
+ strcpy (i->name, name);
+ if (name[strlen (name) - 1] != '/')
+ strcat (i->name, "/");
+ i->next = firstincludedir;
+ firstincludedir = i;
+}
+
+static void
+try_use_real_file (FILE * real, FILE ** backup)
+{
+ fpos_t pos;
+ if (fgetpos (real, &pos) == 0)
+ {
+ *backup = real;
+ return;
+ }
+ if (!(*backup = tmpfile ()))
+ {
+ fprintf (stderr, "Error: Unable to open temporary file: %s\n",
+ strerror (errno));
+ exit (1);
+ }
+}
+
+static void
+flush_to_real_file (FILE * real, FILE * tmp)
+{
+ int l, size, len = 0;
+ char buf[BUFLEN];
+ if (tmp == real)
+ {
+ return;
+ }
+ rewind (tmp);
+ while (1)
+ {
+ clearerr (tmp);
+ errno = 0;
+ len = fread (buf, 1, BUFLEN, tmp);
+ if (len == 0 && feof (tmp))
+ break;
+ if (len <= 0)
+ {
+ fprintf (stderr, "error reading temp file: %s\n", strerror (errno));
+ exit (1);
+ }
+ l = 0;
+ while (l < len)
+ {
+ clearerr (real);
+ size = fwrite (&buf[l], 1, len - l, real);
+ if (size <= 0)
+ {
+ fprintf (stderr, "error writing final file: %s\n",
+ strerror (errno));
+ exit (1);
+ }
+ l += size;
+ }
+ }
+}
+
/* parse commandline arguments */
static void
parse_commandline (int argc, char **argv)
@@ -303,20 +494,24 @@ parse_commandline (int argc, char **argv)
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'V'},
{"verbose", no_argument, NULL, 'v'},
- {"list", required_argument, NULL, 'l'},
- {"label", required_argument, NULL, 'L'},
+ {"list", optional_argument, NULL, 'l'},
+ {"label", optional_argument, NULL, 'L'},
{"input", required_argument, NULL, 'i'},
{"output", required_argument, NULL, 'o'},
- {"label-prefix", required_argument, NULL, 'p'}
+ {"label-prefix", required_argument, NULL, 'p'},
+ {"includepath", required_argument, NULL, 'I'},
+ {"force", no_argument, NULL, 'f'},
+ {NULL, 0, NULL, 0}
};
- const char *short_opts = "hVvl:L:i:o:p:";
+ const char *short_opts = "hVvl:L:i:o:p:I:f";
int done = 0, i, out = 0;
infile = NULL;
while (!done)
{
- switch (getopt_long (argc, argv, short_opts, opts, NULL) )
+ switch (getopt_long (argc, argv, short_opts, opts, NULL))
{
- case 'h':
+ case 'h':
+ /* split in two, to avoid too long string constant */
printf ("Usage: %s [options] [input files]\n"
"\n"
"Possible options are:\n"
@@ -324,18 +519,21 @@ parse_commandline (int argc, char **argv)
"-V\t--version\tDisplay version information and exit.\n"
"-v\t--verbose\tBe verbose. "
"Specify again to be more verbose.\n"
- "-l\t--list\tWrite a list file.\n"
- "-L\t--label\tWrite a label file.\n"
- "-p\t-label-prefix\tprefix all labels with this prefix.\n"
- "-i\t--input\tSpecify an input file (-i may be omitted).\n"
+ "-l\t--list\t\tWrite a list file.\n"
+ "-L\t--label\t\tWrite a label file.\n", argv[0]);
+ printf ("-p\t--label-prefix\tprefix all labels with this prefix.\n"
+ "-i\t--input\t\tSpecify an input file (-i may be omitted).\n"
"-o\t--output\tSpecify the output file.\n"
+ "-I\t--includepath\tAdd a directory to the include path.\n"
"Please send bug reports and feature requests to "
- "<b.wijnen@phys.rug.nl>\n", argv[0]);
+ "<shevek@fmf.nl>\n");
exit (0);
case 'V':
printf ("Z80 assembler version " VERSION "\n"
- "Copyright (C) 2002-2003 Bas Wijnen "
- "<b.wijnen@phys.rug.nl>.\n"
+ "Copyright (C) 2002-2005 Bas Wijnen "
+ "<shevek@fmf.nl>.\n"
+ "Copyright (C) 2005 Jan Wilmans "
+ "<jw@dds.nl>.\n"
"This program comes with ABSOLUTELY NO WARRANTY.\n"
"You may distribute copies of the program under the terms\n"
"of the GNU General Public License as published by\n"
@@ -346,28 +544,40 @@ parse_commandline (int argc, char **argv)
exit (0);
case 'v':
verbose++;
- if (verbose > 2)
+ if (verbose >= 5)
fprintf (stderr, "Verbosity increased to level %d\n", verbose);
break;
case 'o':
- realoutputfile =
- openfile (&out, "output file", stdout, optarg, "wb");
- if (verbose > 2) fprintf (stderr, "Opened outputfile\n");
+ realoutputfile
+ = openfile (&out, "output file", stdout, optarg, "wb");
+ realoutputfilename = optarg;
+ if (verbose >= 5)
+ fprintf (stderr, "Opened outputfile\n");
break;
case 'i':
open_infile (optarg);
break;
case 'l':
- listfile = openfile (&havelist, "list file", NULL, optarg, "w");
- if (verbose > 2) fprintf (stderr, "Opened list file\n");
+ reallistfile
+ = openfile (&havelist, "list file", stderr, optarg, "w");
+ if (verbose >= 5)
+ fprintf (stderr, "Opened list file\n");
break;
case 'L':
- labelfile = openfile (&label, "label file", NULL, optarg, "w");
- if (verbose > 2) fprintf (stderr, "Opened label file\n");
+ labelfile = openfile (&label, "label file", stderr, optarg, "w");
+ labelfilename = optarg;
+ if (verbose >= 5)
+ fprintf (stderr, "Opened label file\n");
break;
case 'p':
labelprefix = optarg;
break;
+ case 'I':
+ add_include (optarg);
+ break;
+ case 'f':
+ use_force = 1;
+ break;
case -1:
done = 1;
break;
@@ -376,27 +586,15 @@ parse_commandline (int argc, char **argv)
break;
}
}
- for (i = optind; i < argc; ++i) open_infile (argv[i]);
- if (!infilecount) open_infile ("-");
+ for (i = optind; i < argc; ++i)
+ open_infile (argv[i]);
+ if (!infilecount)
+ open_infile ("-");
if (!out)
- realoutputfile = stdout;
- if (!(outfile = tmpfile ()))
- {
- fprintf (stderr, "Error: Unable to open temporary file: %s\n",
- strerror (errno));
- exit (1);
- }
-}
-
-/* return first differing character from two strings, or 0 if they are equal */
-static int
-compare (const char *a, const char *b, size_t size)
-{
- size_t i;
- int j, z;
- for (i = 0; i < size; ++i)
- if ( (j = tolower (z = *a++) - tolower (*b++) ) || !z ) return j;
- return 0;
+ realoutputfile = openfile (&out, "output file", stdout, "a.bin", "wb");
+ try_use_real_file (realoutputfile, &outfile);
+ if (havelist)
+ try_use_real_file (reallistfile, &listfile);
}
/* find any of the list[] entries as the start of ptr and return index */
@@ -409,8 +607,7 @@ indx (const char **ptr, const char **list, int error)
{
if (error)
{
- printerr ("Unexpected end of line.\n");
- errors++;
+ printerr ("unexpected end of line\n");
return 0;
}
else
@@ -421,31 +618,30 @@ indx (const char **ptr, const char **list, int error)
for (i = 0; list[i]; i++)
{
l = strlen (list[i]);
- if (list[i][0] && !compare (*ptr, list[i], l)
+ if (list[i][0] && !strncasecmp (*ptr, list[i], l)
&& (!isalnum ((*ptr)[l]) || !isalnum (list[i][l - 1])))
{
(*ptr) += l;
- if (verbose >= 2)
- fprintf (stderr, "%5d (%04x): Piece of code found:%s\n", line,
- addr, list[i]);
if (verbose >= 4)
- fprintf (stderr, "%5d (%04x): Remainder of line=%s.\n", line, addr,
- *ptr);
+ fprintf (stderr, "%5d (0x%04x): Piece of code found:%s\n",
+ stack[sp].line, addr, list[i]);
+ if (verbose >= 6)
+ fprintf (stderr, "%5d (0x%04x): Remainder of line=%s.\n",
+ stack[sp].line, addr, *ptr);
comma++;
return i + 1;
}
}
if (error)
{
- printerr ("Parse error. Remainder of line=%s\n", *ptr);
- if (verbose >= 1)
+ printerr ("parse error. Remainder of line=%s\n", *ptr);
+ if (verbose >= 3)
{
fprintf (stderr, "When looking for any of:\n");
for (i = 0; list[i]; i++)
fprintf (stderr, "%s\t", list[i]);
fprintf (stderr, "\n");
}
- errors++;
}
return 0;
}
@@ -457,57 +653,74 @@ readcommand (const char **p)
return indx (p, mnemonics, 0);
}
-/* try to read a label and store it in the list */
+static int rd_label (const char **p, int *exists, struct label **previous,
+ int level);
+
+/* try to read a label and optionally store it in the list */
static void
-readlabel (const char **p)
+readlabel (const char **p, int store)
{
- const char *c, *pos;
- int i;
- struct label *buf, *tmp, *prv;
- for (c = *p; *c && !strchr (" \r\n\t", *c); ++c) {}
+ const char *c, *d, *pos, *dummy;
+ int i, j;
+ struct label *buf, *previous, **thefirstlabel;
+ for (d = *p; *d && *d != ';'; ++d)
+ {
+ }
+ for (c = *p; !strchr (" \r\n\t", *c) && c < d; ++c)
+ {
+ }
pos = strchr (*p, ':');
- if (!pos || pos > c) return;
+ if (!pos || pos >= c)
+ return;
if (pos == *p)
{
- printerr ("Error: `:' found without a label.");
- errors++;
+ printerr ("`:' found without a label");
+ return;
+ }
+ if (!store)
+ {
+ *p = pos + 1;
return;
}
c = pos + 1;
- for (prv = NULL, tmp = firstlabel; tmp; prv = tmp, tmp = tmp->next)
+ dummy = *p;
+ j = rd_label (&dummy, &i, &previous, sp);
+ if (i || j)
{
- i = compare (tmp->name, *p, c - *p);
- if (i == 0)
- {
- printerr ( "Duplicate definition of label %s.\n", *p);
- errors++;
- *p = c + 1;
- return;
- }
- if (i > 0)
- break;
+ printerr ("duplicate definition of label %s\n", *p);
+ *p = c;
+ return;
}
if (NULL == (buf = malloc (sizeof (struct label) + c - *p)))
{
- printerr ("Not enough memory to store label %s.\n", *p);
- *p = c + 1;
+ printerr ("not enough memory to store label %s\n", *p);
+ *p = c;
return;
}
strncpy (buf->name, *p, c - *p - 1);
buf->name[c - *p - 1] = 0;
- if (verbose >= 1)
- fprintf (stderr, "%5d (%04x): Label found: %s\n", line, addr, buf->name);
- *p = c + 1;
+ if (verbose >= 3)
+ fprintf (stderr, "%5d (0x%04x): Label found: %s\n", stack[sp].line,
+ addr, buf->name);
+ *p = c;
buf->value = addr;
lastlabel = buf;
- buf->next = tmp;
- buf->prev = prv;
+ if (buf->name[0] == '.')
+ thefirstlabel = &stack[sp].labels;
+ else
+ thefirstlabel = &firstlabel;
+ if (previous)
+ buf->next = previous->next;
+ else
+ buf->next = *thefirstlabel;
+ buf->prev = previous;
buf->valid = 1;
buf->busy = 0;
+ buf->ref = NULL;
if (buf->prev)
buf->prev->next = buf;
else
- firstlabel = buf;
+ *thefirstlabel = buf;
if (buf->next)
buf->next->prev = buf;
}
@@ -516,8 +729,13 @@ static void new_reference (const char *data, int type, char delimiter,
int ds_count);
/* write one byte to the outfile, and add it to the list file as well */
-static void write_one_byte (int b, int list)
+static void
+write_one_byte (int b, int list)
{
+ if (verbose >= 4)
+ fprintf (stderr,
+ "%5d (0x%04x): write_one_byte called with argument 0x%02x\n",
+ stack[sp].line, addr, b);
b &= 0xff;
putc (b, outfile);
if (list && havelist)
@@ -532,26 +750,27 @@ static void write_one_byte (int b, int list)
static void
wrtb (int b)
{
- if (verbose >= 2)
- fprintf (stderr, "%5d (%04x): wrtb called with argument %2x\n", line, addr,
- b);
+ if (verbose >= 4)
+ fprintf (stderr, "%5d (0x%04x): wrtb called with argument 0x%02x\n",
+ stack[sp].line, addr, b);
if (indexed)
{
- if (verbose >= 3)
- fprintf (stderr, "%5d (%04x): writing indexed byte %2x\n", line, addr,
- indexed);
+ if (verbose >= 5)
+ fprintf (stderr, "%5d (0x%04x): writing indexed byte 0x%02x\n",
+ stack[sp].line, addr, indexed);
write_one_byte (indexed, 1);
indexed = 0;
}
if (writebyte)
{
- if (verbose >= 3)
- fprintf (stderr, "%5d (%04x): using a xor on byte because there is a "
- "writebyte.\n", line, addr);
+ if (verbose >= 5)
+ fprintf (stderr, "%5d (0x%04x): using a xor on byte because there is "
+ "a writebyte.\n", stack[sp].line, addr);
b ^= 0x40;
}
- if (verbose >= 3)
- fprintf (stderr, "%5d (%04x): writing byte %2x\n", line, addr, b);
+ if (verbose >= 5)
+ fprintf (stderr, "%5d (0x%04x): writing byte 0x%02x\n", stack[sp].line,
+ addr, b);
if (bitsetres && b != 0xCB)
{
new_reference (bitsetres, TYPE_BSR, ',', b);
@@ -563,17 +782,17 @@ wrtb (int b)
}
if (indexjmp)
{
- if (verbose >= 3)
- fprintf (stderr, "%5d (%04x): Making reference for index/jump %s\n",
- line, addr, indexjmp);
+ if (verbose >= 5)
+ fprintf (stderr, "%5d (0x%04x): Making reference for index/jump %s\n",
+ stack[sp].line, addr, indexjmp);
new_reference (indexjmp, TYPE_ABSB, ')', 1);
indexjmp = NULL;
}
if (writebyte)
{
- if (verbose >= 3)
- fprintf (stderr, "%5d (%04x): writing argument byte for padding\n",
- line, addr);
+ if (verbose >= 5)
+ fprintf (stderr, "%5d (0x%04x): writing argument byte for padding\n",
+ stack[sp].line, addr);
writebyte = 0;
new_reference (readbyte, TYPE_ABSB, mem_delimiter, 1);
}
@@ -598,25 +817,26 @@ rd_number (const char **p, const char **endp, int base)
{
int result = 0, i;
char *c, num[] = "0123456789abcdefghijklmnopqrstuvwxyz";
- if (verbose >= 4)
- fprintf (stderr, "%5d (%04x): Starting to read number of base %d"
- "(string=%s).\n", line, addr, base, *p);
+ if (verbose >= 6)
+ fprintf (stderr, "%5d (0x%04x): Starting to read number of base %d"
+ "(string=%s).\n", stack[sp].line, addr, base, *p);
num[base] = '\0';
*p = delspc (*p);
while (**p && (c = strchr (num, tolower (**p))))
{
i = c - num;
- if (verbose >= 5)
- fprintf (stderr, "%5d (%04x): Digit found:%1x.\n", line, addr, i);
+ if (verbose >= 7)
+ fprintf (stderr, "%5d (0x%04x): Digit found:%1x.\n", stack[sp].line,
+ addr, i);
result = result * base + i;
(*p)++;
}
- if ( endp )
+ if (endp)
*endp = *p;
*p = delspc (*p);
- if (verbose >= 5)
- fprintf (stderr, "%5d (%04x): rd_number returned %d (%04X).\n",
- line, addr, result, result);
+ if (verbose >= 7)
+ fprintf (stderr, "%5d (0x%04x): rd_number returned %d (%04x).\n",
+ stack[sp].line, addr, result, result);
return result;
}
@@ -624,20 +844,19 @@ static int
rd_otherbasenumber (const char **p)
{
char c;
- if (verbose >= 4)
- fprintf (stderr, "%5d (%04x): Starting to read basenumber (string=%s).\n",
- line, addr, *p);
+ if (verbose >= 6)
+ fprintf (stderr,
+ "%5d (0x%04x): Starting to read basenumber (string=%s).\n",
+ stack[sp].line, addr, *p);
(*p)++;
if (!**p)
{
- printerr ("Unexpected end of line after `@'.\n");
- errors++;
+ printerr ("unexpected end of line after `@'\n");
return 0;
}
if (**p == '0' || !isalnum (**p))
{
- printerr ("Base must be between 1 and z.\n");
- errors++;
+ printerr ("base must be between 1 and z\n");
return 0;
}
c = **p;
@@ -651,157 +870,221 @@ static int
rd_character (const char **p)
{
int i;
- if (verbose >= 4)
- fprintf (stderr, "%5d (%04x): Starting to read character (string=%s).\n",
- line, addr, *p);
- (*p)++;
+ if (verbose >= 6)
+ fprintf (stderr,
+ "%5d (0x%04x): Starting to read character (string=%s).\n",
+ stack[sp].line, addr, *p);
i = **p;
if (!i)
{
- printerr ("Unexpected end of line after opening quote.\n");
- errors++;
+ printerr ("unexpected end of line in string constant\n");
return 0;
}
if (i == '\\')
{
(*p)++;
- switch (**p)
+ if (**p >= '0' && **p <= '7')
{
- case 'n':
- i = 10;
- break;
- case 'r':
- i = 13;
- break;
- case 't':
- i = 9;
- break;
- case 'a':
- i = 7;
- break;
- case '\'':
- printerr ("Empty literal character.\n");
- errors++;
- return 0;
- case 0:
- printerr ("Unexpected end of line after "
- "opening opening quote and backslash.\n");
- errors++;
- return 0;
- default:
- i = **p;
+ int b, num_digits;
+ i = 0;
+ if ((*p)[1] >= '0' && (*p)[1] <= '7')
+ {
+ if (**p <= '3' && (*p)[2] >= '0' && (*p)[2] <= '7')
+ num_digits = 3;
+ else
+ num_digits = 2;
+ }
+ else
+ num_digits = 1;
+ for (b = 0; b < num_digits; ++b)
+ {
+ int bit = (*p)[num_digits - 1 - b] - '0';
+ i += (1 << (b * 3)) * bit;
+ }
+ *p += num_digits;
+ }
+ else
+ {
+ switch (**p)
+ {
+ case 'n':
+ i = 10;
+ break;
+ case 'r':
+ i = 13;
+ break;
+ case 't':
+ i = 9;
+ break;
+ case 'a':
+ i = 7;
+ break;
+ case '\'':
+ printerr ("empty literal character\n");
+ return 0;
+ case 0:
+ printerr ("unexpected end of line after "
+ "backslash in string constant\n");
+ return 0;
+ default:
+ i = **p;
+ }
+ (*p)++;
}
}
- (*p)++;
- if (**p != '\'')
- {
- printerr ("Missing closing quote.\n");
- errors++;
- return 0;
- }
- (*p)++;
- if (verbose >= 5)
- fprintf (stderr, "%5d (%04x): rd_character returned %d (%c).\n",
- line, addr, i, i);
+ else
+ (*p)++;
+ if (verbose >= 7)
+ fprintf (stderr, "%5d (0x%04x): rd_character returned %d (%c).\n",
+ stack[sp].line, addr, i, i);
return i;
}
-static int rd_expr (const char **p, char delimiter, int *valid);
+static int rd_expr (const char **p, char delimiter, int *valid, int level);
-static void compute_label (struct label *l)
+static int
+compute_ref (struct reference *ref, int allow_invalid)
{
- int value, valid;
- const char *c;
- if (l->busy) return; /* don't loop */
- l->busy = 1;
- c = l->addr;
- if (verbose >= 4)
- fprintf (stderr, "Trying to compute label %s.\n", l->name);
- value = rd_expr (&c, '\0', &valid);
- if (valid)
- {
- l->value = value;
- l->valid = 1;
- free (l->addr);
+ const char *ptr;
+ int valid = 0;
+ int backup_addr = addr;
+ int backup_comma = comma;
+ int backup_file = file;
+ int backup_sp = sp;
+ sp = ref->level;
+ addr = ref->addr;
+ comma = ref->comma;
+ file = ref->infile;
+ if (verbose >= 3)
+ fprintf (stderr, "%5d (0x%04x): Making reference to %s (done=%d, "
+ "computed=%d)\n",
+ stack[sp].line, addr, ref->input, ref->done,
+ ref->computed_value);
+ ptr = ref->input;
+ if (!ref->done)
+ {
+ ref->computed_value = rd_expr (&ptr, ref->delimiter,
+ allow_invalid ? &valid : NULL,
+ ref->level);
+ if (valid)
+ ref->done = 1;
}
- l->busy = 0;
+ if (verbose >= 4)
+ fprintf (stderr, "%5d (0x%04x): Reference is %d (0x%04x).\n",
+ stack[sp].line, addr, ref->computed_value, ref->computed_value);
+ sp = backup_sp;
+ addr = backup_addr;
+ comma = backup_comma;
+ file = backup_file;
+ return ref->computed_value;
}
static int
-rd_label (const char **p, int *exists)
+check_label (struct label *labels, const char **p, struct label **ret,
+ struct label **previous, int force_skip)
{
- int found = 0;
- const char *where = NULL;
struct label *l;
- if (exists) *exists = 0;
- if (verbose >= 4)
- fprintf (stderr, "%5d (%04x): Starting to read label (string=%s).\n", line,
- addr, *p);
- for (l = firstlabel; l; l = l->next)
+ const char *c;
+ unsigned s2;
+ *p = delspc (*p);
+ for (c = *p; isalnum (*c) || *c == '_' || *c == '.'; ++c)
{
- if (!strncmp (l->name, *p, strlen (l->name)))
+ }
+ s2 = c - *p;
+ for (l = labels; l; l = l->next)
+ {
+ unsigned s1, s;
+ int cmp;
+ s1 = strlen (l->name);
+ s = s1 < s2 ? s1 : s2;
+ cmp = strncmp (l->name, *p, s);
+ if (cmp > 0 || (cmp == 0 && s1 > s))
+ {
+ if (force_skip)
+ *p = c;
+ return 0;
+ }
+ if (cmp < 0 || s2 > s)
{
- const char *c;
- c = *p + strlen (l->name);
- if (!(isalnum (*c) || *c == '_'))
+ if (previous)
+ *previous = l;
+ continue;
+ }
+ *p = c;
+ /* if label is not valid, compute it */
+ if (l->ref)
+ {
+ compute_ref (l->ref, 1);
+ if (!l->ref->done)
{
- found = 1;
- where = *p;
- *p = delspc (c);
- /* if label is not valid, compute it */
- if (!l->valid) compute_label (l);
- if (!l->valid)
- {
- /* label was not valid, and isn't computable. tell the
- * caller that it doesn't exist, so it will try again later.
- * Just in case some other label matches the same input,
- * continue trying all the other labels. */
- if (verbose >= 4)
- fprintf (stderr,
- "%5d (%04x): returning invalid label %s.\n",
- line, addr, l->name);
- continue;
- }
- if (exists) *exists = 1;
- if (verbose >= 5)
- fprintf (stderr, "%5d (%04x): rd_label returned %d (%04X).\n",
- line, addr, l->value, l->value);
- return l->value;
+ /* label was not valid, and isn't computable. tell the
+ * caller that it doesn't exist, so it will try again later.
+ * Set ret to show actual existence. */
+ if (verbose >= 6)
+ fprintf (stderr,
+ "%5d (0x%04x): returning invalid label %s.\n",
+ stack[sp].line, addr, l->name);
+ *ret = l;
+ return 0;
}
}
+ *ret = l;
+ return 1;
}
+ if (force_skip)
+ *p = c;
+ return 0;
+}
+
+static int
+rd_label (const char **p, int *exists, struct label **previous, int level)
+{
+ struct label *l = NULL;
+ int s;
if (exists)
- {
- /* this was only a check for existance, skip the label */
- if (verbose >= 4)
- fprintf (stderr, "%5d (%04x): Returning invalid for unknown label.\n",
- line, addr);
- while (isalnum (**p) || **p == '_') ++*p;
+ *exists = 0;
+ if (previous)
+ *previous = NULL;
+ if (verbose >= 6)
+ fprintf (stderr, "%5d (0x%04x): Starting to read label (string=%s).\n",
+ stack[sp].line, addr, *p);
+ for (s = level; s >= 0; --s)
+ {
+ if (check_label (stack[s].labels, p, &l,
+ (**p == '.' && s == sp) ? previous : NULL, 0))
+ break;
}
- else
+ if (s < 0)
{
- if (found)
+ /* not yet found */
+ const char *old_p = *p;
+ if (!check_label (firstlabel, p, &l, **p != '.' ? previous : NULL, 1))
{
- printerr ("Uncomputable label found: %.*s.\n", *p, where - *p);
+ /* label does not exist, or is invalid. This is an error if there
+ * is no existance check. */
+ if (!exists)
+ printerr ("using undefined label %.*s\n", *p - old_p, old_p);
+ /* Return a value to discriminate between non-existing and invalid */
+ if (verbose >= 7)
+ fprintf (stderr, "rd_label returns invalid value\n");
+ return l != NULL;
}
- else
- {
- printerr ("Syntax error (label or number expected): %s.\n", *p);
- }
- errors++;
- *p = "";
}
- return 0;
+ if (exists)
+ *exists = 1;
+ if (verbose >= 7)
+ fprintf (stderr, "rd_label returns valid value 0x%x\n", l->value);
+ return l->value;
}
static int
-rd_value (const char **p, int *valid)
+rd_value (const char **p, int *valid, int level)
{
int sign = 1, not = 0, base, v;
const char *p0, *p1, *p2;
- if (verbose >= 4)
- fprintf (stderr, "%5d (%04x): Starting to read value (string=%s).\n", line,
- addr, *p);
+ if (verbose >= 6)
+ fprintf (stderr, "%5d (0x%04x): Starting to read value (string=%s).\n",
+ stack[sp].line, addr, *p);
*p = delspc (*p);
while (**p && strchr ("+-~", **p))
{
@@ -815,14 +1098,17 @@ rd_value (const char **p, int *valid)
base = 10; /* Default base for suffixless numbers */
switch (**p)
{
- int exist;
+ int exist, retval;
+ char quote;
case '(':
(*p)++;
- return not ^ (sign * rd_expr (p, ')', valid));
+ retval = not ^ (sign * rd_expr (p, ')', valid, level));
+ ++*p;
+ return retval;
case '0':
if ((*p)[1] == 'x')
{
- (*p)+=2;
+ (*p) += 2;
return not ^ (sign * rd_number (p, NULL, 0x10));
}
base = 8; /* If first digit it 0, assume octal unless suffix */
@@ -837,9 +1123,9 @@ rd_value (const char **p, int *valid)
case '8':
case '9':
p0 = *p;
- rd_number(p, &p1, 36); /* Advance to end of numeric string */
+ rd_number (p, &p1, 36); /* Advance to end of numeric string */
p1--; /* Last character in numeric string */
- switch ( *p1 )
+ switch (*p1)
{
case 'h':
case 'H':
@@ -863,286 +1149,340 @@ rd_value (const char **p, int *valid)
p1++;
break;
}
- v = rd_number(&p0, &p2, base);
- if ( p1 != p2 ) {
- printerr("invalid character in number: \'%c\'\n", *p2);
- errors++;
- }
+ v = rd_number (&p0, &p2, base);
+ if (p1 != p2)
+ {
+ printerr ("invalid character in number: \'%c\'\n", *p2);
+ }
return not ^ (sign * v);
case '$':
- (*p)++;
- return not ^ (sign * addr);
+ ++*p;
+ *p = delspc (*p);
+ p0 = *p;
+ v = rd_number (&p0, &p2, 0x10);
+ if (p2 == *p)
+ {
+ v = baseaddr;
+ }
+ else
+ *p = p2;
+ return not ^ (sign * v);
case '%':
(*p)++;
- return not ^ (sign * rd_number (p, NULL, 2) );
+ return not ^ (sign * rd_number (p, NULL, 2));
case '\'':
- return not ^ (sign * rd_character (p) );
+ case '"':
+ quote = **p;
+ ++*p;
+ retval = not ^ (sign * rd_character (p));
+ if (**p != quote)
+ {
+ printerr ("missing closing quote (%c)\n", quote);
+ return 0;
+ }
+ ++*p;
+ return retval;
case '@':
- return not ^ (sign * rd_otherbasenumber (p) );
- case '!':
- rd_label (p, &exist);
+ return not ^ (sign * rd_otherbasenumber (p));
+ case '?':
+ rd_label (p, &exist, NULL, level);
return not ^ (sign * exist);
+ case '&':
+ {
+ ++*p;
+ switch (**p)
+ {
+ case 'h':
+ case 'H':
+ base = 0x10;
+ break;
+ case 'o':
+ case 'O':
+ base = 010;
+ break;
+ case 'b':
+ case 'B':
+ base = 2;
+ break;
+ default:
+ printerr ("invalid literal starting with &%c\n", **p);
+ return 0;
+ }
+ ++*p;
+ return not ^ (sign * rd_number (p, NULL, base));
+ }
default:
- return not ^ (sign * rd_label (p, valid) );
+ return not ^ (sign * rd_label (p, valid, NULL, level));
}
}
static int
-rd_factor (const char **p, int *valid)
+rd_factor (const char **p, int *valid, int level)
{
/* read a factor of an expression */
int result;
- if (verbose >= 4)
- fprintf (stderr, "%5d (%04x): Starting to read factor (string=%s).\n",
- line, addr, *p);
- result = rd_value (p, valid);
+ if (verbose >= 6)
+ fprintf (stderr, "%5d (0x%04x): Starting to read factor (string=%s).\n",
+ stack[sp].line, addr, *p);
+ result = rd_value (p, valid, level);
*p = delspc (*p);
while (**p == '*' || **p == '/')
{
if (**p == '*')
{
(*p)++;
- result *= rd_value (p, valid);
+ result *= rd_value (p, valid, level);
}
else if (**p == '/')
{
(*p)++;
- result /= rd_value (p, valid);
+ result /= rd_value (p, valid, level);
}
*p = delspc (*p);
}
- if (verbose >= 5)
- fprintf (stderr, "%5d (%04x): rd_factor returned %d (%04X).\n",
- line, addr, result, result);
+ if (verbose >= 7)
+ fprintf (stderr, "%5d (0x%04x): rd_factor returned %d (%04x).\n",
+ stack[sp].line, addr, result, result);
return result;
}
static int
-rd_term (const char **p, int *valid)
+rd_term (const char **p, int *valid, int level)
{
/* read a term of an expression */
int result;
- if (verbose >= 4)
- fprintf (stderr, "%5d (%04x): Starting to read term (string=%s).\n", line,
- addr, *p);
- result = rd_factor (p, valid);
+ if (verbose >= 6)
+ fprintf (stderr, "%5d (0x%04x): Starting to read term (string=%s).\n",
+ stack[sp].line, addr, *p);
+ result = rd_factor (p, valid, level);
*p = delspc (*p);
while (**p == '+' || **p == '-')
{
if (**p == '+')
{
(*p)++;
- result += rd_factor (p, valid);
+ result += rd_factor (p, valid, level);
}
else if (**p == '-')
{
(*p)++;
- result -= rd_factor (p, valid);
+ result -= rd_factor (p, valid, level);
}
*p = delspc (*p);
}
- if (verbose >= 5)
- fprintf (stderr, "%5d (%04x): rd_term returned %d (%04X).\n",
- line, addr, result, result);
+ if (verbose >= 7)
+ fprintf (stderr, "%5d (0x%04x): rd_term returned %d (%04x).\n",
+ stack[sp].line, addr, result, result);
return result;
}
static int
-rd_expr_shift (const char **p, int *valid)
+rd_expr_shift (const char **p, int *valid, int level)
{
int result;
- if (verbose >= 4)
- fprintf (stderr, "%5d (%04x): Starting to read shift expression "
- "(string=%s).\n", line, addr, *p);
- result = rd_term (p, valid);
+ if (verbose >= 6)
+ fprintf (stderr, "%5d (0x%04x): Starting to read shift expression "
+ "(string=%s).\n", stack[sp].line, addr, *p);
+ result = rd_term (p, valid, level);
*p = delspc (*p);
- while ( (**p == '<' || **p == '>') && (*p)[1] == **p)
+ while ((**p == '<' || **p == '>') && (*p)[1] == **p)
{
if (**p == '<')
{
(*p) += 2;
- result <<= rd_term (p, valid);
+ result <<= rd_term (p, valid, level);
}
else if (**p == '>')
{
(*p) += 2;
- result >>= rd_term (p, valid);
+ result >>= rd_term (p, valid, level);
}
*p = delspc (*p);
}
- if (verbose >= 5)
- fprintf (stderr, "%5d (%04x): rd_shift returned %d (%04X).\n",
- line, addr, result, result);
+ if (verbose >= 7)
+ fprintf (stderr, "%5d (0x%04x): rd_shift returned %d (%04x).\n",
+ stack[sp].line, addr, result, result);
return result;
}
static int
-rd_expr_unequal (const char **p, int *valid)
+rd_expr_unequal (const char **p, int *valid, int level)
{
int result;
- if (verbose >= 4)
- fprintf (stderr, "%5d (%04x): Starting to read "
- "unequality expression (string=%s).\n", line, addr, *p);
- result = rd_expr_shift (p, valid);
+ if (verbose >= 6)
+ fprintf (stderr, "%5d (0x%04x): Starting to read "
+ "unequality expression (string=%s).\n", stack[sp].line, addr,
+ *p);
+ result = rd_expr_shift (p, valid, level);
*p = delspc (*p);
if (**p == '<' && (*p)[1] == '=')
{
(*p) += 2;
- return result <= rd_expr_unequal (p, valid);
+ return result <= rd_expr_unequal (p, valid, level);
}
else if (**p == '>' && (*p)[1] == '=')
{
(*p) += 2;
- return result >= rd_expr_unequal (p, valid);
+ return result >= rd_expr_unequal (p, valid, level);
}
if (**p == '<' && (*p)[1] != '<')
{
(*p)++;
- return result < rd_expr_unequal (p, valid);
+ return result < rd_expr_unequal (p, valid, level);
}
else if (**p == '>' && (*p)[1] != '>')
{
(*p)++;
- return result > rd_expr_unequal (p, valid);
+ return result > rd_expr_unequal (p, valid, level);
}
- if (verbose >= 5)
- fprintf (stderr, "%5d (%04x): rd_shift returned %d (%04X).\n",
- line, addr, result, result);
+ if (verbose >= 7)
+ fprintf (stderr, "%5d (0x%04x): rd_shift returned %d (%04x).\n",
+ stack[sp].line, addr, result, result);
return result;
}
static int
-rd_expr_equal (const char **p, int *valid)
+rd_expr_equal (const char **p, int *valid, int level)
{
int result;
- if (verbose >= 4)
- fprintf (stderr, "%5d (%04x): Starting to read equality epression "
- "(string=%s).\n", line, addr, *p);
- result = rd_expr_unequal (p, valid);
+ if (verbose >= 6)
+ fprintf (stderr, "%5d (0x%04x): Starting to read equality epression "
+ "(string=%s).\n", stack[sp].line, addr, *p);
+ result = rd_expr_unequal (p, valid, level);
*p = delspc (*p);
- if (**p == '=' && (*p)[1] == '=')
+ if (**p == '=')
{
- (*p) += 2;
- return result == rd_expr_equal (p, valid);
+ ++*p;
+ if (**p == '=')
+ ++ * p;
+ return result == rd_expr_equal (p, valid, level);
}
else if (**p == '!' && (*p)[1] == '=')
{
(*p) += 2;
- return result != rd_expr_equal (p, valid);
+ return result != rd_expr_equal (p, valid, level);
}
- if (verbose >= 5)
- fprintf (stderr, "%5d (%04x): rd_equal returned %d (%04X).\n",
- line, addr, result, result);
+ if (verbose >= 7)
+ fprintf (stderr, "%5d (0x%04x): rd_equal returned %d (%04x).\n",
+ stack[sp].line, addr, result, result);
return result;
}
static int
-rd_expr_and (const char **p, int *valid)
+rd_expr_and (const char **p, int *valid, int level)
{
int result;
- if (verbose >= 4)
- fprintf (stderr, "%5d (%04x): Starting to read and expression "
- "(string=%s).\n", line, addr, *p);
- result = rd_expr_equal (p, valid);
+ if (verbose >= 6)
+ fprintf (stderr, "%5d (0x%04x): Starting to read and expression "
+ "(string=%s).\n", stack[sp].line, addr, *p);
+ result = rd_expr_equal (p, valid, level);
*p = delspc (*p);
if (**p == '&')
{
(*p)++;
- result &= rd_expr_and (p, valid);
+ result &= rd_expr_and (p, valid, level);
}
- if (verbose >= 5)
- fprintf (stderr, "%5d (%04x): rd_expr_and returned %d (%04X).\n",
- line, addr, result, result);
+ if (verbose >= 7)
+ fprintf (stderr, "%5d (0x%04x): rd_expr_and returned %d (%04x).\n",
+ stack[sp].line, addr, result, result);
return result;
}
static int
-rd_expr_xor (const char **p, int *valid)
+rd_expr_xor (const char **p, int *valid, int level)
{
int result;
- if (verbose >= 4)
- fprintf (stderr, "%5d (%04x): Starting to read xor expression "
- "(string=%s).\n", line, addr, *p);
- result = rd_expr_and (p, valid);
- if (verbose >= 5)
- fprintf (stderr, "%5d (%04x): rd_expr_xor: rd_expr_and returned %d "
- "(%04X).\n", line, addr, result, result);
+ if (verbose >= 6)
+ fprintf (stderr, "%5d (0x%04x): Starting to read xor expression "
+ "(string=%s).\n", stack[sp].line, addr, *p);
+ result = rd_expr_and (p, valid, level);
+ if (verbose >= 7)
+ fprintf (stderr, "%5d (0x%04x): rd_expr_xor: rd_expr_and returned %d "
+ "(%04x).\n", stack[sp].line, addr, result, result);
*p = delspc (*p);
if (**p == '^')
{
(*p)++;
- result ^= rd_expr_xor (p, valid);
+ result ^= rd_expr_xor (p, valid, level);
}
- if (verbose >= 5)
- fprintf (stderr, "%5d (%04x): rd_expr_xor returned %d (%04X).\n",
- line, addr, result, result);
+ if (verbose >= 7)
+ fprintf (stderr, "%5d (0x%04x): rd_expr_xor returned %d (%04x).\n",
+ stack[sp].line, addr, result, result);
return result;
}
static int
-rd_expr_or (const char **p, int *valid)
+rd_expr_or (const char **p, int *valid, int level)
{
int result;
- if (verbose >= 4)
- fprintf (stderr, "%5d (%04x): Starting to read or expression "
- "(string=%s).\n", line, addr, *p);
- result = rd_expr_xor (p, valid);
- if (verbose >= 5)
- fprintf (stderr, "%5d (%04x): rd_expr_or: rd_expr_xor returned %d "
- "(%04X).\n", line, addr, result, result);
+ if (verbose >= 6)
+ fprintf (stderr, "%5d (0x%04x): Starting to read or expression "
+ "(string=%s).\n", stack[sp].line, addr, *p);
+ result = rd_expr_xor (p, valid, level);
+ if (verbose >= 7)
+ fprintf (stderr, "%5d (0x%04x): rd_expr_or: rd_expr_xor returned %d "
+ "(%04x).\n", stack[sp].line, addr, result, result);
*p = delspc (*p);
if (**p == '|')
{
(*p)++;
- result |= rd_expr_or (p, valid);
+ result |= rd_expr_or (p, valid, level);
}
- if (verbose >= 5)
- fprintf (stderr, "%5d (%04x): rd_expr_or returned %d (%04X).\n",
- line, addr, result, result);
+ if (verbose >= 7)
+ fprintf (stderr, "%5d (0x%04x): rd_expr_or returned %d (%04x).\n",
+ stack[sp].line, addr, result, result);
return result;
}
static int
-rd_expr (const char **p, char delimiter, int *valid)
+rd_expr (const char **p, char delimiter, int *valid, int level)
{
/* read an expression. delimiter can _not_ be '?' */
int result = 0;
- if (verbose >= 4)
- fprintf (stderr, "%5d (%04x): Starting to read expression (string=%s).\n",
- line, addr, *p);
- if (valid) *valid = 1;
+ if (verbose >= 6)
+ fprintf (stderr,
+ "%5d (0x%04x): Starting to read expression (string=%s).\n",
+ stack[sp].line, addr, *p);
+ if (valid)
+ *valid = 1;
*p = delspc (*p);
if (!**p || **p == delimiter)
{
- printerr ("Error: Expression expected (not %s)\n", *p);
- errors++;
+ printerr ("expression expected (not %s)\n", *p);
return 0;
}
- result = rd_expr_or (p, valid);
+ result = rd_expr_or (p, valid, level);
*p = delspc (*p);
if (**p == '?')
{
(*p)++;
if (result)
{
- result = rd_expr (p, ':', valid);
- if (**p) (*p)++;
- rd_expr (p, delimiter, valid);
+ result = rd_expr (p, ':', valid, level);
+ if (**p)
+ (*p)++;
+ rd_expr (p, delimiter, valid, level);
}
else
{
- rd_expr (p, ':', valid);
- if (**p) (*p)++;
- result = rd_expr (p, delimiter, valid);
+ rd_expr (p, ':', valid, level);
+ if (**p)
+ (*p)++;
+ result = rd_expr (p, delimiter, valid, level);
}
}
- if (verbose >= 5)
+ *p = delspc (*p);
+ if (**p && **p != delimiter)
{
- fprintf (stderr, "%5d (%04x): rd_expr returned %d (%04X).\n",
- line, addr, result, result);
+ printerr ("ignoring junk at end of expression: %s\n", *p);
+ }
+ if (verbose >= 7)
+ {
+ fprintf (stderr, "%5d (0x%04x): rd_expr returned %d (%04x).\n",
+ stack[sp].line, addr, result, result);
if (valid && !*valid)
- fprintf (stderr, "%5d (%04x): Returning invalid result.\n",
- line, addr);
+ fprintf (stderr, "%5d (0x%04x): Returning invalid result.\n",
+ stack[sp].line, addr);
}
return result;
}
@@ -1151,22 +1491,21 @@ static void wrt_ref (int val, int type, int count);
/* Create a new reference, to be resolved after assembling (so all labels are
* known.) */
-void
+static void
new_reference (const char *p, int type, char delimiter, int ds_count)
{
- struct reference *tmp;
+ struct reference *tmp = NULL;
long opos, lpos;
int valid, value;
const char *c;
c = p;
- value = rd_expr (&c, delimiter, &valid);
+ value = rd_expr (&c, delimiter, &valid, sp);
if (valid)
{
- if (verbose >= 3)
+ if (verbose >= 5)
{
- fprintf (stderr,
- "%5d (%04x): Using calculated value %d (%x) immediately.\n",
- line, addr, value, value);
+ fprintf (stderr, "%5d (0x%04x): Using calculated value %d (%x) "
+ "immediately.\n", stack[sp].line, addr, value, value);
}
}
else
@@ -1175,34 +1514,46 @@ new_reference (const char *p, int type, char delimiter, int ds_count)
*/
if (NULL == (tmp = malloc (sizeof (struct reference) + strlen (p))))
{
- printerr ("Warning: unable to allocate memory for reference %s.\n",
- p);
+ printerr ("unable to allocate memory for reference %s\n", p);
return;
}
opos = ftell (outfile);
lpos = havelist ? ftell (listfile) : 0;
- if (verbose >= 1)
- fprintf (stderr, "%5d (%04x): reference set to %s (delimiter=%c)\n",
- line, addr, p, delimiter);
+ if (verbose >= 3)
+ fprintf (stderr, "%5d (0x%04x): reference set to %s (delimiter=%c)\n",
+ stack[sp].line, addr, p, delimiter);
strcpy (tmp->input, p);
tmp->addr = baseaddr;
tmp->count = ds_count;
- tmp->line = line;
tmp->infile = file;
- tmp->comma = comma++;
+ tmp->comma = comma;
tmp->oseekpos = opos;
tmp->lseekpos = lpos;
tmp->delimiter = delimiter;
tmp->type = type;
tmp->next = firstreference;
- if (firstreference)
- firstreference->prev = tmp;
- tmp->prev = NULL;
- firstreference = tmp;
+ tmp->done = 0;
+ tmp->level = sp;
+ if (type != TYPE_LABEL)
+ {
+ if (firstreference)
+ firstreference->prev = tmp;
+ tmp->prev = NULL;
+ firstreference = tmp;
+ }
/* Dummy value which should not give warnings */
value = (type == TYPE_RELB) ? ds_count : 0;
}
- wrt_ref (value, type, ds_count);
+ if (type != TYPE_LABEL)
+ {
+ wrt_ref (value, type, ds_count);
+ }
+ else
+ {
+ lastlabel->ref = tmp;
+ lastlabel->valid = valid;
+ lastlabel->value = value;
+ }
}
/* write the last read word to file */
@@ -1225,7 +1576,8 @@ static int
rd_word (const char **p, char delimiter)
{
*p = delspc (*p);
- if (**p == 0) return 0;
+ if (**p == 0)
+ return 0;
readword = *p;
mem_delimiter = delimiter;
skipword (p, delimiter);
@@ -1237,7 +1589,8 @@ static int
rd_byte (const char **p, char delimiter)
{
*p = delspc (*p);
- if (**p == 0) return 0;
+ if (**p == 0)
+ return 0;
readbyte = *p;
writebyte = 1;
mem_delimiter = delimiter;
@@ -1280,7 +1633,7 @@ rd_ex1 (const char **p)
{
#define DE 2
#define AF 3
- const char *list[] = {"(sp)", "de", "af", NULL};
+ const char *list[] = { "(sp)", "de", "af", NULL };
return indx (p, list, 1);
}
@@ -1289,7 +1642,7 @@ static int
rd_in (const char **p)
{
#define A 8
- const char *list[] = {"b", "c", "d", "e", "h", "l", "f", "a", NULL};
+ const char *list[] = { "b", "c", "d", "e", "h", "l", "f", "a", NULL };
return indx (p, list, 1);
}
@@ -1297,7 +1650,7 @@ rd_in (const char **p)
static int
rd_out (const char **p)
{
- const char *list[] = {"b", "c", "d", "e", "h", "l", "0", "a", NULL};
+ const char *list[] = { "b", "c", "d", "e", "h", "l", "0", "a", NULL };
return indx (p, list, 1);
}
@@ -1307,17 +1660,17 @@ rd_nnc (const char **p)
{
#define C 1
int i;
- const char *list[] = {"(", NULL};
+ const char *list[] = { "(", NULL };
i = indx (p, list, 1);
- if (!i) return 0;
+ if (!i)
+ return 0;
*p = delspc (*p);
if (tolower (**p) == 'c')
{
*p = delspc ((*p) + 1);
if (**p != ')')
{
- printerr ("Missing closing parenthesis\n");
- errors++;
+ printerr ("missing closing parenthesis\n");
return 0;
}
(*p)++;
@@ -1328,8 +1681,7 @@ rd_nnc (const char **p)
*p = delspc ((*p) + 1);
if (**p != ',')
{
- printerr ("Missing ','\n");
- errors++;
+ printerr ("missing ','\n");
return 0;
}
*p = delspc ((*p) + 1);
@@ -1343,7 +1695,7 @@ rd_nnc (const char **p)
static int
rd_c (const char **p)
{
- const char *list[] = {"(c)", "(bc)", NULL};
+ const char *list[] = { "(c)", "(bc)", NULL };
return indx (p, list, 1);
}
@@ -1352,7 +1704,7 @@ static int
rd_a_hl (const char **p)
{
#define HL 2
- const char *list[] = {"a", "hl", NULL};
+ const char *list[] = { "a", "hl", NULL };
return indx (p, list, 1);
}
@@ -1385,7 +1737,8 @@ rd_ld (const char **p)
const char *list[] = {
"ixh", "ixl", "iyh", "iyl", "bc", "de", "hl", "sp", "ix",
"iy", "b", "c", "d", "e", "h", "l", "(hl)", "a", "i",
- "r", "(bc)", "(de)", "(ix", "(iy", "(", NULL};
+ "r", "(bc)", "(de)", "(ix", "(iy", "(", NULL
+ };
i = indx (p, list, 1);
if (!i)
return 0;
@@ -1423,7 +1776,8 @@ rd_jp (const char **p)
int i;
const char *list[] = {
"nz", "z", "nc", "c", "po", "pe", "p", "m", "(ix)", "(iy)",
- "(hl)", NULL};
+ "(hl)", NULL
+ };
i = indx (p, list, 0);
if (i < 9)
return i;
@@ -1437,7 +1791,7 @@ rd_jp (const char **p)
static int
rd_jr (const char **p)
{
- const char *list[] = {"nz", "z", "nc", "c", NULL};
+ const char *list[] = { "nz", "z", "nc", "c", NULL };
return indx (p, list, 0);
}
@@ -1445,7 +1799,7 @@ rd_jr (const char **p)
static int
rd_a (const char **p)
{
- const char *list[] = {"a", NULL};
+ const char *list[] = { "a", NULL };
return indx (p, list, 1);
}
@@ -1454,7 +1808,7 @@ static int
rd_stack (const char **p)
{
int i;
- const char *list[] = {"bc", "de", "hl", "af", "ix", "iy", NULL};
+ const char *list[] = { "bc", "de", "hl", "af", "ix", "iy", NULL };
i = indx (p, list, 1);
if (i < 5)
return i;
@@ -1467,7 +1821,7 @@ static int
rd_a_hlx (const char **p)
{
int i;
- const char *list[] = {"a", "hl", "ix", "iy", NULL};
+ const char *list[] = { "a", "hl", "ix", "iy", NULL };
i = indx (p, list, 1);
if (i < 2)
return i;
@@ -1477,11 +1831,48 @@ rd_a_hlx (const char **p)
return 2;
}
+/* read b,c,d,e,h,l,(hl),a,(ix+nn),(iy+nn),nn
+ * but now with extra hl or i[xy](15) for add-instruction
+ * and set variables accordingly */
+static int
+rd_r_add (const char **p)
+{
+#define addHL 15
+ int i;
+ const char *list[] = {
+ "ixl", "ixh", "iyl", "iyh", "b", "c", "d", "e", "h", "l",
+ "(hl)", "a", "(ix", "(iy", "hl", "ix", "iy", NULL
+ };
+ i = indx (p, list, 0);
+ if (!i) // not in list ? assume "nn"
+ {
+ rd_byte (p, '\0');
+ return 7;
+ }
+ if (i > 14) // 15,16,17
+ {
+ if (i > 15)
+ indexed = 0xDD + 0x20 * (i - 16);
+ return addHL;
+ }
+ if (i <= 4) // 8-bit access of ix/iy
+ {
+ indexed = 0xdd + 0x20 * (i > 2);
+ return 6 - (i & 1);
+ }
+ i -= 4;
+ if (i < 9)
+ return i;
+ indexed = 0xDD + 0x20 * (i - 9); // 16-bit access of ix/iy
+ rd_index (p);
+ return 7;
+}
+
/* read bc,de,hl, or sp */
static int
rd_rr_ (const char **p)
{
- const char *list[] = {"bc", "de", "hl", "sp", NULL};
+ const char *list[] = { "bc", "de", "hl", "sp", NULL };
return indx (p, list, 1);
}
@@ -1489,9 +1880,9 @@ rd_rr_ (const char **p)
static int
rd_rrxx (const char **p)
{
- const char *listx[] = {"bc", "de", "ix", "sp", NULL};
- const char *listy[] = {"bc", "de", "iy", "sp", NULL};
- const char *list[] = {"bc", "de", "hl", "sp", NULL};
+ const char *listx[] = { "bc", "de", "ix", "sp", NULL };
+ const char *listy[] = { "bc", "de", "iy", "sp", NULL };
+ const char *list[] = { "bc", "de", "hl", "sp", NULL };
switch (indexed)
{
case 0xDD:
@@ -1511,7 +1902,8 @@ rd_r (const char **p)
int i;
const char *list[] = {
"ixl", "ixh", "iyl", "iyh", "b", "c", "d", "e", "h", "l", "(hl)",
- "a", "(ix", "(iy", NULL};
+ "a", "(ix", "(iy", NULL
+ };
i = indx (p, list, 0);
if (!i)
{
@@ -1520,7 +1912,7 @@ rd_r (const char **p)
}
if (i <= 4)
{
- indexed = 0xdd + 0x20 * i > 2;
+ indexed = 0xdd + 0x20 * (i > 2);
return 6 - (i & 1);
}
i -= 4;
@@ -1537,7 +1929,8 @@ rd_r_ (const char **p)
{
int i;
const char *list[] = {
- "b", "c", "d", "e", "h", "l", "(hl)", "a", "(ix", "(iy", NULL};
+ "b", "c", "d", "e", "h", "l", "(hl)", "a", "(ix", "(iy", NULL
+ };
i = indx (p, list, 1);
if (i < 9)
return i;
@@ -1551,7 +1944,8 @@ static int
rd_0_7 (const char **p)
{
*p = delspc (*p);
- if (**p == 0 || **p == ';') return 0;
+ if (**p == 0 || **p == ';')
+ return 0;
bitsetres = *p;
skipword (p, ',');
return 1;
@@ -1561,7 +1955,7 @@ rd_0_7 (const char **p)
static int
rd_cc (const char **p)
{
- const char *list[] = {"nz", "z", "nc", "c", "po", "pe", "p", "m", NULL};
+ const char *list[] = { "nz", "z", "nc", "c", "po", "pe", "p", "m", NULL };
return indx (p, list, 0);
}
@@ -1571,8 +1965,9 @@ rd_r_rr (const char **p)
{
int i;
const char *list[] = {
- "iy", "ix", "sp", "hl", "de", "bc", "", "b", "c", "d", "e", "h",
- "l", "(hl)", "a", "(ix", "(iy", NULL};
+ "iy", "ix", "sp", "hl", "de", "bc", "", "b", "c", "d", "e", "h",
+ "l", "(hl)", "a", "(ix", "(iy", NULL
+ };
i = indx (p, list, 1);
if (!i)
return 0;
@@ -1592,7 +1987,7 @@ rd_r_rr (const char **p)
static int
rd_hl (const char **p)
{
- const char *list[] = {"hl", NULL};
+ const char *list[] = { "hl", NULL };
return indx (p, list, 1);
}
@@ -1601,7 +1996,7 @@ static int
rd_hlx (const char **p)
{
int i;
- const char *list[] = {"hl", "ix", "iy", NULL};
+ const char *list[] = { "hl", "ix", "iy", NULL };
i = indx (p, list, 1);
switch (i)
{
@@ -1619,7 +2014,7 @@ rd_hlx (const char **p)
static int
rd_af_ (const char **p)
{
- const char *list[] = {"af", NULL};
+ const char *list[] = { "af'", NULL };
return indx (p, list, 1);
}
@@ -1627,7 +2022,7 @@ rd_af_ (const char **p)
static int
rd_0_2 (const char **p)
{
- const char *list[] = {"0", "", "1", "2", NULL};
+ const char *list[] = { "0", "", "1", "2", NULL };
return indx (p, list, 1);
}
@@ -1636,7 +2031,7 @@ static int
rd_ld_hl (const char **p)
{
int i;
- const char *list[] = {"b", "c", "d", "e", "h", "l", "", "a", NULL};
+ const char *list[] = { "b", "c", "d", "e", "h", "l", "", "a", NULL };
i = indx (p, list, 0);
if (i)
return i;
@@ -1651,7 +2046,7 @@ rd_ld_nn (const char **p)
#define ld_nnHL 5
#define ld_nnA 6
int i;
- const char *list[] = {"bc", "de", "", "sp", "hl", "a", "ix", "iy", NULL};
+ const char *list[] = { "bc", "de", "", "sp", "hl", "a", "ix", "iy", NULL };
i = indx (p, list, 1);
if (i < 7)
return i;
@@ -1669,7 +2064,8 @@ rd_lda (const char **p)
int i;
const char *list[] = {
"(sp)", "(iy", "(de)", "(bc)", "(ix", "b", "c", "d", "e", "h",
- "l", "(hl)", "a", "i", "r", "(", NULL};
+ "l", "(hl)", "a", "i", "r", "(", NULL
+ };
i = indx (p, list, 0);
if (i == 2 || i == 5)
{
@@ -1696,7 +2092,8 @@ rd_ldbcdehla (const char **p)
int i;
const char *list[] = {
"b", "c", "d", "e", "h", "l", "(hl)", "a", "(ix", "(iy", "ixh",
- "ixl", "iyh", "iyl", NULL};
+ "ixl", "iyh", "iyl", NULL
+ };
i = indx (p, list, 0);
if (i > 10)
{
@@ -1704,8 +2101,7 @@ rd_ldbcdehla (const char **p)
x = 0xdd + 0x20 * (i > 12);
if (indexed && indexed != x)
{
- printerr ("Syntax error: illegal use of index registers.\n");
- errors++;
+ printerr ("illegal use of index registers\n");
return 0;
}
indexed = x;
@@ -1715,8 +2111,7 @@ rd_ldbcdehla (const char **p)
{
if (indexed)
{
- printerr ("Syntax error: illegal use of index registers.\n");
- errors++;
+ printerr ("illegal use of index registers\n");
return 0;
}
indexed = 0xDD + 0x20 * (i == 10);
@@ -1735,7 +2130,7 @@ rd_nn_nn (const char **p)
{
#define _NN 1
int i;
- const char *list[] = {"(", NULL};
+ const char *list[] = { "(", NULL };
i = indx (p, list, 0);
if (i)
{
@@ -1753,7 +2148,7 @@ rd_sp (const char **p)
#define SPNN 0
#define SPHL 1
int i;
- const char *list[] = {"(", "ix", "iy", "hl", NULL};
+ const char *list[] = { "(", "ix", "iy", "hl", NULL };
i = indx (p, list, 0);
switch (i)
{
@@ -1779,21 +2174,24 @@ wrt_ref (int val, int type, int count)
case TYPE_RST:
if ((val & 0x38) != val)
{
- printerr ("Error: incorrect RST value %d (%02x).\n", val, val);
- errors++;
+ printerr ("incorrect RST value %d (0x%02x)\n", val, val);
return;
}
write_one_byte (val + 0xC7, 1);
return;
case TYPE_ABSW:
write_one_byte (val & 0xff, 1);
- write_one_byte ( (val >> 8) & 0xff, 1);
+ write_one_byte ((val >> 8) & 0xff, 1);
return;
case TYPE_ABSB:
write_one_byte (val & 0xff, 1);
return;
case TYPE_DS:
- if (havelist) fprintf (listfile, " %02x...", val & 0xff);
+ if (havelist)
+ {
+ fprintf (listfile, " 0x%02x...", val & 0xff);
+ listdepth += 6;
+ }
while (count--)
{
write_one_byte (val & 0xff, 0);
@@ -1802,8 +2200,7 @@ wrt_ref (int val, int type, int count)
case TYPE_BSR:
if (val & ~7)
{
- printerr ("Error: incorrect BIT/SET/RES value %d.\n", val);
- errors++;
+ printerr ("incorrect BIT/SET/RES value %d\n", val);
return;
}
write_one_byte (0x08 * val + count, 1);
@@ -1812,29 +2209,193 @@ wrt_ref (int val, int type, int count)
val -= count;
if (val < -128 || val > 127)
{
- printerr ("Warning: relative jump out of range (%d).\n", val);
+ printerr ("relative jump out of range (%d)\n", val);
}
write_one_byte (val & 0xff, 1);
+ return;
+ case TYPE_LABEL:
+ printerr ("bug in the assembler: trying to write label reference. "
+ "Please report.\n");
+ return;
}
}
+static char *
+get_include_name (const char **ptr)
+{
+ int pos = 0;
+ char quote;
+ char *name;
+ *ptr = delspc (*ptr);
+ name = malloc (strlen (*ptr));
+ if (!name)
+ {
+ printerr ("unable to allocate memory for filename %.*s\n",
+ strlen (*ptr) - 1, *ptr);
+ return NULL;
+ }
+ if (!**ptr)
+ {
+ printerr ("include without filename\n");
+ free (name);
+ return NULL;
+ }
+ quote = *(*ptr)++;
+ while (**ptr != quote)
+ {
+ if (!**ptr)
+ {
+ printerr ("filename without closing quote (%c)\n", quote);
+ free (name);
+ return NULL;
+ }
+ name[pos++] = *(*ptr)++;
+ }
+ name[pos] = 0;
+ ++*ptr;
+ return name;
+}
+
+static int
+read_line (void)
+{
+ unsigned pos, newpos, size;
+ struct macro_arg *arg;
+ if (stack[sp].file)
+ {
+ FILE *f = stack[sp].file;
+ static char short_buffer[BUFLEN + 1];
+ if (buffer && buffer != short_buffer)
+ free (buffer);
+ buffer = NULL;
+ if (!fgets (short_buffer, BUFLEN + 1, f))
+ return 0;
+ if (strlen (short_buffer) < BUFLEN)
+ {
+ buffer = short_buffer;
+ return 1;
+ }
+ size = 2 * BUFLEN;
+ buffer = malloc (size + 1);
+ if (!buffer)
+ {
+ printerr ("out of memory reading line\n");
+ return 0;
+ }
+ memcpy (buffer, short_buffer, BUFLEN + 1);
+ while (1)
+ {
+ char *b;
+ if (!fgets (&buffer[size - BUFLEN], BUFLEN + 1, f)
+ || (buffer[strlen (buffer) - 1] == '\n'))
+ {
+ return 1;
+ }
+ size += BUFLEN;
+ b = realloc (buffer, size + 1);
+ if (!b)
+ {
+ printerr ("out of memory reading line\n");
+ return 0;
+ }
+ buffer = b;
+ }
+ }
+ /* macro line */
+ if (!stack[sp].macro_line)
+ {
+ unsigned i;
+ for (i = 0; i < stack[sp].macro->numargs; ++i)
+ free (stack[sp].macro_args[i]);
+ free (stack[sp].macro_args);
+ return 0;
+ }
+ size = strlen (stack[sp].macro_line->line) + 1;
+ for (arg = stack[sp].macro_line->args; arg; arg = arg->next)
+ size += strlen (stack[sp].macro_args[arg->which]);
+ buffer = malloc (size);
+ if (!buffer)
+ {
+ printerr ("out of memory\n");
+ return 0;
+ }
+ pos = 0;
+ newpos = 0;
+ for (arg = stack[sp].macro_line->args; arg; arg = arg->next)
+ {
+ memcpy (&buffer[newpos], &stack[sp].macro_line->line[pos],
+ arg->pos - pos);
+ newpos += arg->pos - pos;
+ strcpy (&buffer[newpos], stack[sp].macro_args[arg->which]);
+ newpos += strlen (stack[sp].macro_args[arg->which]);
+ pos = arg->pos + 1;
+ }
+ strcpy (&buffer[newpos], &stack[sp].macro_line->line[pos]);
+ stack[sp].macro_line = stack[sp].macro_line->next;
+ return 1;
+}
+
+static unsigned
+get_macro_args (const char **ptr, char ***ret_args, int allow_empty)
+{
+ unsigned numargs = 0;
+ *ret_args = NULL;
+ while (1)
+ {
+ char **args;
+ const char *c;
+ *ptr = delspc (*ptr);
+ if (!**ptr)
+ break;
+ c = *ptr;
+ for (; **ptr && !strchr (" \r\n\t,;", **ptr); ++*ptr)
+ {
+ }
+ if (*ptr == c && !allow_empty)
+ {
+ printerr ("empty macro argument\n");
+ break;
+ }
+ ++numargs;
+ args = realloc (*ret_args, sizeof (char *) * numargs);
+ if (!args)
+ {
+ printerr ("out of memory\n");
+ --numargs;
+ break;
+ }
+ *ret_args = args;
+ args[numargs - 1] = malloc (*ptr - c + 1);
+ if (!args[numargs - 1])
+ {
+ printerr ("out of memory\n");
+ --numargs;
+ break;
+ }
+ memcpy (args[numargs - 1], c, *ptr - c);
+ args[numargs - 1][*ptr - c] = 0;
+ }
+ return numargs;
+}
+
/* do the actual work */
static void
assemble (void)
{
int ifcount = 0, noifcount = 0;
const char *ptr;
+ struct label *l;
char *bufptr;
- struct reference *tmp;
- int r, s, shouldclose, sp; /* r,s for registers, sp is stack pointer */
- struct stack stack[MAX_INCLUDE]; /* maximum level of includes */
+ int r, s; /* registers */
/* continue assembling until the last input file is done */
for (file = 0; file < infilecount; ++file)
{
- sp = 0; /* clear stack */
+ int file_ended = 0;
+ sp = 0; /* clear stack */
stack[sp].line = 0;
- shouldclose = 0;
+ stack[sp].shouldclose = 0;
stack[sp].name = infile[file].name;
+ stack[sp].dir = NULL;
if (infile[file].name[0] == '-' && infile[file].name[1] == 0)
{
stack[sp].file = stdin;
@@ -1844,48 +2405,95 @@ assemble (void)
stack[sp].file = fopen (infile[file].name, "r");
if (!stack[sp].file)
{
- printerr ("Error: unable to open %s. skipping\n",
- infile[file].name);
- errors++;
+ printerr ("unable to open %s. skipping\n", infile[file].name);
continue;
}
- shouldclose = 1;
+ stack[sp].shouldclose = 1;
}
- if (havelist) fprintf (listfile, "# File %s\n", stack[sp].name);
- buffer[0] = 0;
+ if (havelist)
+ fprintf (listfile, "# File %s\n", stack[sp].name);
+ if (buffer)
+ buffer[0] = 0;
/* loop until this source file is done */
while (1)
{
int cmd, cont = 1;
if (havelist)
{
- if (buffer[0] != 0)
+ if (buffer && buffer[0] != 0)
{
int i, tabs;
- if (listdepth <= 8) tabs = 3;
- else if (listdepth <= 16) tabs = 2;
- else tabs = 1;
+ ptr = delspc (ptr);
+ if (*ptr != 0)
+ {
+ printerr ("ignoring junk at end of line: %s\n", ptr);
+ }
+ if (listdepth < 8)
+ tabs = 3;
+ else if (listdepth < 16)
+ tabs = 2;
+ else
+ tabs = 1;
for (i = 0; i < tabs; ++i)
fputc ('\t', listfile);
fprintf (listfile, "%s\n", buffer);
}
listdepth = 4;
}
- while (NULL == fgets (buffer, BUFLEN, stack[sp].file))
+ /* throw away the rest of the file after end */
+ if (file_ended)
+ {
+ while (read_line ())
+ {
+ if (havelist)
+ fprintf (listfile, "\t\t\t%s\n", buffer);
+ }
+ file_ended = 0;
+ }
+ while (!read_line ())
{
- if (verbose > 3) fprintf (stderr, "finished reading file %s\n",
- stack[sp].name);
- if (havelist) fprintf (listfile, "# End of file %s\n",
- stack[sp].name);
- if (shouldclose) fclose (stack[sp].file);
+ struct reference *ref;
+ struct label *next;
+ if (verbose >= 6)
+ fprintf (stderr, "finished reading file %s\n",
+ stack[sp].name);
+ if (havelist)
+ {
+ if (stack[sp].file)
+ fprintf (listfile, "# End of file %s\n", stack[sp].name);
+ else
+ fprintf (listfile, "# End of macro %s\n", stack[sp].name);
+ }
+ if (stack[sp].shouldclose)
+ fclose (stack[sp].file);
+ /* the top of stack is about to be popped off, throwing all
+ * local labels out of scope. All references at this level
+ * which aren't computable are errors. */
+ for (ref = firstreference; ref; ref = ref->next)
+ {
+ compute_ref (ref, 1);
+ if (ref->level == sp)
+ --ref->level;
+ }
+ /* Ok, now junk all local labels of the top stack level */
+ for (l = stack[sp].labels; l; l = next)
+ {
+ next = l->next;
+ if (l->ref)
+ free (l->ref);
+ free (l);
+ }
+ stack[sp].labels = NULL;
if (!sp--)
{
cont = 0;
break;
}
}
- if (!cont) break; /* break to next source file */
- if (havelist) fprintf (listfile, "%04X", addr);
+ if (!cont)
+ break; /* break to next source file */
+ if (havelist)
+ fprintf (listfile, "%04x", addr);
for (bufptr = buffer; (bufptr = strchr (bufptr, '\n'));)
*bufptr = ' ';
for (bufptr = buffer; (bufptr = strchr (bufptr, '\r'));)
@@ -1893,12 +2501,17 @@ assemble (void)
ptr = buffer;
lastlabel = NULL;
baseaddr = addr;
- line++;
+ ++stack[sp].line;
ptr = delspc (ptr);
- if (!*ptr) continue;
- if (!noifcount) readlabel (&ptr);
+ if (!*ptr)
+ continue;
+ if (!noifcount && !define_macro)
+ readlabel (&ptr, 1);
+ else
+ readlabel (&ptr, 0);
ptr = delspc (ptr);
- if (!*ptr) continue;
+ if (!*ptr)
+ continue;
comma = 0;
indexed = 0;
indexjmp = 0;
@@ -1919,15 +2532,79 @@ assemble (void)
noifcount = 0;
ifcount++;
}
+ break;
case ENDIF:
noifcount--;
}
+ ptr = "";
+ continue;
+ }
+ if (define_macro)
+ {
+ char *newptr;
+ struct macro_line **current_line;
+ for (current_line = &firstmacro->lines; *current_line;
+ current_line = &(*current_line)->next)
+ {
+ }
+ *current_line = malloc (sizeof (struct macro_line));
+ if (!*current_line)
+ {
+ printerr ("out of memory\n");
+ continue;
+ }
+ (*current_line)->next = NULL;
+ (*current_line)->args = NULL;
+ (*current_line)->line = malloc (strlen (buffer) + 1);
+ if (!(*current_line)->line)
+ {
+ printerr ("out of memory\n");
+ free (*current_line);
+ *current_line = NULL;
+ continue;
+ }
+ ptr = buffer;
+ newptr = (*current_line)->line;
+ while (*ptr)
+ {
+ unsigned p;
+ struct macro_arg **last_arg = &(*current_line)->args;
+ for (p = 0; p < firstmacro->numargs; ++p)
+ {
+ if (strncmp (ptr, firstmacro->args[p],
+ strlen (firstmacro->args[p])) == 0)
+ {
+ struct macro_arg *newarg;
+ newarg = malloc (sizeof (struct macro_arg));
+ if (!newarg)
+ {
+ printerr ("out of memory\n");
+ break;
+ }
+ newarg->next = NULL;
+ *last_arg = newarg;
+ last_arg = &newarg->next;
+ newarg->pos = newptr - (*current_line)->line;
+ newarg->which = p;
+ /* leave one character so two macros following each
+ * other keep their order. */
+ ptr += strlen (firstmacro->args[p]) - 1;
+ break;
+ }
+ }
+ *newptr++ = *ptr++;
+ }
+ *newptr = 0;
+ if (verbose >= 7)
+ fprintf (stderr, "added line to macro (cmd = %d): %s\n", cmd,
+ (*current_line)->line);
+ if (cmd == ENDM)
+ define_macro = 0;
continue;
}
switch (cmd)
{
- int i, valid;
- const char *c;
+ int i, have_quote;
case ADC:
if (!(r = rd_a_hl (&ptr)))
break;
@@ -1944,18 +2621,28 @@ assemble (void)
wrtb (0x88 + --r);
break;
case ADD:
- if (!(r = rd_a_hlx (&ptr)))
+ if (!(r = rd_r_add (&ptr)))
break;
- if (r == HL)
+ if (r == addHL)
{
if (!(r = rd_rrxx (&ptr)))
break;
- wrtb (0x09 + 0x10 * --r);
+ wrtb (0x09 + 0x10 * --r); // ADD HL/IX/IY, qq
break;
}
- if (!(r = rd_r (&ptr)))
- break;
- wrtb (0x80 + --r);
+ if (has_argument (&ptr))
+ {
+ if (r != A)
+ {
+ printerr ("parse error before: %s\n", ptr);
+ break;
+ }
+ if (!(r = rd_r (&ptr)))
+ break;
+ wrtb (0x80 + --r); // ADD A,r
+ break;
+ }
+ wrtb (0x80 + --r); // ADD r
break;
case AND:
if (!(r = rd_r (&ptr)))
@@ -2027,7 +2714,7 @@ assemble (void)
break;
case DJNZ:
wrtb (0x10);
- rd_wrt_jr (&ptr, '0');
+ rd_wrt_jr (&ptr, '\0');
break;
case EI:
wrtb (0xFB);
@@ -2035,28 +2722,11 @@ assemble (void)
case EQU:
if (!lastlabel)
{
- printerr ("EQU without label.\n");
- errors++;
+ printerr ("EQU without label\n");
break;
}
- c = ptr;
- lastlabel->value = rd_expr (&ptr, '\0', &valid);
- lastlabel->valid = 1;
- if (!valid)
- {
- lastlabel->addr = malloc (ptr - c + 1);
- if (lastlabel->addr == NULL)
- {
- printerr ("No memory to store label reference.\n");
- errors++;
- break;
- }
- strncpy (lastlabel->addr, c, ptr - c);
- lastlabel->addr[ptr - c] = 0;
- lastlabel->valid = 0;
- lastlabel->busy = 0;
- }
- if (verbose >= 2)
+ new_reference (ptr, TYPE_LABEL, 0, 0);
+ if (verbose >= 4)
{
if (lastlabel->valid)
fprintf (stderr, "Assigned value %d to label %s.\n",
@@ -2066,6 +2736,7 @@ assemble (void)
"Scheduled label %s for later computation.\n",
lastlabel->name);
}
+ ptr = "";
break;
case EX:
if (!(r = rd_ex1 (&ptr)))
@@ -2098,25 +2769,25 @@ assemble (void)
if (!(r = rd_0_2 (&ptr)))
break;
wrtb (0xED);
- wrtb (0x46 + 8 * r--);
+ wrtb (0x46 + 8 * --r);
break;
case IN:
if (!(r = rd_in (&ptr)))
break;
if (r == A)
{
- const char *tmp2;
+ const char *tmp;
if (!(r = rd_nnc (&ptr)))
break;
if (r == C)
{
wrtb (0xED);
- wrtb (0x40 + 8 * --r);
+ wrtb (0x40 + 8 * (A - 1));
break;
}
- tmp2 = readbyte;
+ tmp = readbyte;
wrtb (0xDB);
- new_reference (tmp2, TYPE_ABSB, ')', 1);
+ new_reference (tmp, TYPE_ABSB, ')', 1);
break;
}
if (!rd_c (&ptr))
@@ -2329,9 +3000,9 @@ assemble (void)
if (!rd_a (&ptr))
break;
{
- const char *tmp2 = readbyte;
+ const char *tmp = readbyte;
wrtb (0xD3);
- new_reference (tmp2, TYPE_ABSB, ')', 1);
+ new_reference (tmp, TYPE_ABSB, ')', 1);
}
break;
case OUTD:
@@ -2422,6 +3093,7 @@ assemble (void)
break;
case RST:
new_reference (ptr, TYPE_RST, '\0', 1);
+ ptr = "";
break;
case SBC:
if (!(r = rd_a_hl (&ptr)))
@@ -2476,6 +3148,16 @@ assemble (void)
case SUB:
if (!(r = rd_r (&ptr)))
break;
+ if (has_argument (&ptr)) // SUB A,r ?
+ {
+ if (r != A)
+ {
+ printerr ("parse error before: %s\n", ptr);
+ break;
+ }
+ if (!(r = rd_r (&ptr)))
+ break;
+ }
wrtb (0x90 + --r);
break;
case XOR:
@@ -2485,39 +3167,52 @@ assemble (void)
break;
case DEFB:
case DB:
+ case DEFM:
+ case DM:
ptr = delspc (ptr);
- if (*ptr != '"' && !(r = rd_byte (&ptr, ',')))
+ have_quote = (*ptr == '"' || *ptr == '\'');
+ if (!have_quote && !rd_byte (&ptr, ','))
break;
do
{
- if (*ptr == '"')
+ if (have_quote)
{
- while (*++ptr != '"')
+ int quote = *ptr;
+ if (listfile)
{
+ fprintf (listfile, " ..");
+ listdepth += 3;
+ }
+ ++ptr;
+ while (*ptr != quote)
+ {
+ write_one_byte (rd_character (&ptr), 0);
if (*ptr == 0)
{
- printerr ("Error: end of line in quoted "
- "string\n");
- errors++;
+ printerr ("end of line in quoted " "string\n");
break;
}
- wrtb (*ptr);
}
- if (!*ptr) break;
+ if (!*ptr)
+ break;
++ptr;
ptr = delspc (ptr);
- if (!*ptr) break;
+ if (!*ptr)
+ break;
if (*ptr++ != ',')
{
- printerr ("Error: expected end of line or ','");
- errors++;
+ printerr ("expected end of line or ',' (not %c)\n",
+ ptr[-1]);
break;
}
+ ptr = delspc (ptr);
continue;
}
new_reference (readbyte, TYPE_ABSB, ',', 1);
+ ptr = delspc (ptr);
}
- while ((r = rd_byte (&ptr, ',')));
+ while ((have_quote = (*ptr == '"' || *ptr == '\''))
+ || rd_byte (&ptr, ','));
writebyte = 0;
break;
case DEFW:
@@ -2532,113 +3227,130 @@ assemble (void)
break;
case DEFS:
case DS:
- r = rd_expr (&ptr, ',', NULL);
+ r = rd_expr (&ptr, ',', NULL, sp);
if (r < 0)
{
printerr ("ds should have its first argument >=0"
- " (not %d).\n", r);
- errors++;
+ " (not -0x%x)\n", -r);
break;
}
ptr = delspc (ptr);
if (*ptr)
{
rd_comma (&ptr);
+ readbyte = 0;
rd_byte (&ptr, '\0');
writebyte = 0;
new_reference (readbyte, TYPE_DS, '\0', r);
break;
}
- if (havelist) fprintf (listfile, " 00...");
- listdepth += 6;
+ if (havelist)
+ {
+ fprintf (listfile, " 00...");
+ listdepth += 6;
+ }
for (i = 0; i < r; i++)
{
write_one_byte (0, 0);
}
break;
+ case END:
+ file_ended = 1;
+ break;
case ORG:
- addr = rd_expr (&ptr, '\0', NULL);
+ addr = rd_expr (&ptr, '\0', NULL, sp);
break;
case INCLUDE:
if (sp + 1 >= MAX_INCLUDE)
{
printerr ("stack overflow (circular include?)");
- if (verbose > 2)
+ if (verbose >= 5)
{
int x;
fprintf (stderr, "Stack dump:\nframe line file\n");
for (x = 0; x < MAX_INCLUDE; ++x)
fprintf (stderr, "%5d %5d %s\n", x, stack[x].line,
- stack[x].name);
+ stack[x].name);
}
break;
}
- ptr = delspc (ptr);
{
- int pos = 0;
- char quote;
- struct name *nm,
- *name = malloc (sizeof (struct name) + strlen (ptr));
+ struct name *name;
+ char *nm = get_include_name (&ptr);
+ if (!nm)
+ break;
+ name = malloc (sizeof (struct name) + strlen (nm));
if (!name)
{
- printerr ("Unable to allocate memory for filename %s\n",
- name);
- errors++;
+ printerr ("out of memory while allocating name\n");
+ free (nm);
break;
}
- if (*ptr == ';' || !*ptr)
- {
- printerr ("include without filename\n");
- free (name);
- errors++;
- break;
- }
- quote = *ptr++;
- while (*ptr != quote)
- {
- if (!*ptr)
- {
- printerr ("filename without closing quote (%c)\n",
- quote);
- free (name);
- errors++;
- break;
- }
- name->name[pos++] = *ptr++;
- }
- name->name[pos] = 0;
- nm =
- realloc (name, sizeof (struct name) + strlen (name->name));
- if (nm) name = nm;
- sp++;
+ strcpy (name->name, nm);
+ free (nm);
+ ++sp;
stack[sp].name = name->name;
+ stack[sp].shouldclose = 1;
stack[sp].line = 0;
- stack[sp].file = fopen (name->name, "r");
+ stack[sp].file = open_include_file (name->name,
+ &stack[sp].dir, "r");
if (!stack[sp].file)
{
- printerr ("Unable to open file %s: %s\n",
- name->name, strerror (errno));
- errors++;
+ printerr ("unable to open file %s\n", name->name);
free (name);
- sp--;
+ --sp;
break;
}
name->next = firstname;
name->prev = NULL;
- if (name->next) name->next->prev = name;
+ if (name->next)
+ name->next->prev = name;
firstname = name;
- if (verbose > 1)
+ if (verbose >= 4)
fprintf (stderr, "Reading file %s\n", name->name);
}
break;
+ case INCBIN:
+ {
+ FILE *incfile;
+ char *name = get_include_name (&ptr);
+ if (!name)
+ break;
+ incfile = open_include_file (name, NULL, "rb");
+ if (!incfile)
+ {
+ printerr ("unable to open binary file %s\n", name);
+ free (name);
+ break;
+ }
+ while (1)
+ {
+ char filebuffer[4096];
+ size_t num = fread (filebuffer, 1, 4096, incfile);
+ if (num == 0)
+ break;
+ if (num != fwrite (filebuffer, 1, num, outfile))
+ {
+ printerr ("error including binary file %s: %s\n",
+ name, strerror (errno));
+ break;
+ }
+ addr += num;
+ }
+ fclose (incfile);
+ free (name);
+ break;
+ }
case IF:
- if (rd_expr (&ptr, '\0', NULL)) ifcount++; else noifcount++;
+ if (rd_expr (&ptr, '\0', NULL, sp))
+ ifcount++;
+ else
+ noifcount++;
break;
case ELSE:
if (ifcount == 0)
{
- printerr ("Error: else without if.\n");
- errors++;
+ printerr ("else without if\n");
break;
}
noifcount = 1;
@@ -2647,126 +3359,225 @@ assemble (void)
case ENDIF:
if (noifcount == 0 && ifcount == 0)
{
- printerr ("Error: endif without if.\n");
- errors++;
+ printerr ("endif without if\n");
break;
}
- if (noifcount) noifcount--; else ifcount--;
+ if (noifcount)
+ noifcount--;
+ else
+ ifcount--;
+ break;
+ case MACRO:
+ if (!lastlabel)
+ {
+ printerr ("macro without label\n");
+ break;
+ }
+ if (define_macro)
+ {
+ printerr ("nested macro definition\n");
+ break;
+ }
+ {
+ struct macro *m;
+ for (m = firstmacro; m; m = m->next)
+ {
+ if (strcmp (m->name, lastlabel->name) == 0)
+ {
+ printerr ("duplicate macro definition\n");
+ break;
+ }
+ }
+ m = malloc (sizeof (struct macro));
+ if (!m)
+ {
+ printerr ("out of memory\n");
+ break;
+ }
+ m->name = malloc (strlen (lastlabel->name) + 1);
+ if (!m->name)
+ {
+ printerr ("out of memory\n");
+ free (m);
+ break;
+ }
+ strcpy (m->name, lastlabel->name);
+ if (lastlabel->prev)
+ lastlabel->prev->next = lastlabel->next;
+ else
+ firstlabel = lastlabel->next;
+ if (lastlabel->next)
+ lastlabel->next->prev = lastlabel->prev;
+ free (lastlabel);
+ m->next = firstmacro;
+ firstmacro = m;
+ m->lines = NULL;
+ m->numargs = get_macro_args (&ptr, &m->args, 0);
+ define_macro = 1;
+ }
break;
+ case ENDM:
+ if (stack[sp].file)
+ printerr ("endm outside macro definition\n");
+ break;
+ case SEEK:
+ {
+ unsigned int seekaddr = rd_expr (&ptr, '\0', NULL, sp);
+ if (verbose >= 2)
+ {
+ fprintf (stderr, "%s%s:%d: ",
+ stack[sp].dir ? stack[sp].dir->name : "",
+ stack[sp].name, stack[sp].line);
+ fprintf (stderr, "[Message] seeking to 0x%0X \n",
+ seekaddr);
+ }
+ fseek (outfile, seekaddr, SEEK_SET);
+ break;
+ }
default:
- printerr ("Syntax error: command or comment "
- "expected (was %s).\n", ptr);
- errors++;
+ {
+ struct macro *m;
+ for (m = firstmacro; m; m = m->next)
+ {
+ if (strncmp (m->name, ptr, strlen (m->name)) == 0)
+ {
+ unsigned numargs;
+ if (sp + 1 >= MAX_INCLUDE)
+ {
+ printerr ("stack overflow (circular include?)\n");
+ if (verbose >= 5)
+ {
+ int x;
+ fprintf (stderr,
+ "Stack dump:\nframe line file\n");
+ for (x = 0; x < MAX_INCLUDE; ++x)
+ fprintf (stderr, "%5d %5d %s\n", x,
+ stack[x].line, stack[x].name);
+ }
+ break;
+ }
+ ++sp;
+ ptr += strlen (m->name);
+ numargs = get_macro_args (&ptr, &stack[sp].macro_args,
+ 1);
+ if (numargs != m->numargs)
+ {
+ unsigned a;
+ printerr ("invalid number of arguments for macro "
+ "(is %d, must be %d)\n", numargs,
+ m->numargs);
+ for (a = 0; a < numargs; ++a)
+ free (stack[sp].macro_args[a]);
+ free (stack[sp].macro_args);
+ break;
+ }
+ stack[sp].name = m->name;
+ stack[sp].file = NULL;
+ stack[sp].line = 0;
+ stack[sp].macro = m;
+ stack[sp].macro_line = m->lines;
+ stack[sp].shouldclose = 0;
+ stack[sp].dir = NULL;
+ break;
+ }
+ }
+ if (m)
+ break;
+ }
+ printerr ("command or comment expected (was %s)\n", ptr);
}
}
}
- if (ifcount || noifcount) printerr ("Reached EOF at IF level %d\n",
- ifcount + noifcount);
+ if (ifcount || noifcount)
+ {
+ printerr ("reached EOF at IF level %d\n", ifcount + noifcount);
+ }
if (havelist)
{
- fprintf (listfile, "%04X\n", addr);
+ fprintf (listfile, "%04x\n", addr);
}
{
struct reference *next;
+ struct reference *tmp;
for (tmp = firstreference; tmp; tmp = next)
{
int ref;
- char *c;
next = tmp->next;
fseek (outfile, tmp->oseekpos, SEEK_SET);
- if (havelist) fseek (listfile, tmp->lseekpos, SEEK_SET);
- addr = tmp->addr;
- line = tmp->line;
- comma = tmp->comma;
- file = tmp->infile;
- if ((c = strchr (tmp->input, '\n')))
- *c = 0;
- if (verbose >= 1)
- fprintf (stderr, "%5d (%04x): Making reference to %s.\n", line, addr,
- tmp->input);
- ptr = tmp->input;
- ref = rd_expr (&ptr, tmp->delimiter, NULL);
- if (verbose >= 2)
- fprintf (stderr, "%5d (%04x): Reference is %d (%04x).\n", line, addr,
- ref, ref);
+ if (havelist)
+ fseek (listfile, tmp->lseekpos, SEEK_SET);
+ ref = compute_ref (tmp, 0);
wrt_ref (ref, tmp->type, tmp->count);
free (tmp);
}
}
- if (havelist) fclose (listfile);
+ if (!errors || use_force)
+ {
+ flush_to_real_file (realoutputfile, outfile);
+ if (havelist)
+ flush_to_real_file (reallistfile, listfile);
+ }
+ /* write all labels */
if (label)
+ fseek (labelfile, 0, SEEK_END);
+ for (l = firstlabel; l; l = l->next)
{
- /* write all labels */
- struct label *l;
- for (l = firstlabel; l; l = l->next)
+ if (l->ref)
{
- if (!l->valid) compute_label (l);
- if (!l->valid)
- {
- printerr ("Label %s at end of code still uncomputable.\n",
- l->name);
- errors++;
- continue;
- }
- fprintf (labelfile, "%s%s:\tequ %04xh\n", labelprefix, l->name,
+ compute_ref (l->ref, 0);
+ }
+ if (label)
+ {
+ fprintf (labelfile, "%s%s:\tequ $%04x\n", labelprefix, l->name,
l->value);
}
- fclose (labelfile);
}
+ if (label)
+ fclose (labelfile);
while (firstlabel)
{
- struct label *l;
l = firstlabel->next;
free (firstlabel);
firstlabel = l;
}
- {
- int l, size, len = 0;
- rewind (outfile);
- while (1)
- {
- clearerr (outfile);
- errno = 0;
- len = fread (buffer, 1, BUFLEN, outfile);
- if (len == 0 && feof (outfile)) break;
- if (len <= 0)
- {
- fprintf (stderr, "error reading temp file: %s\n",
- strerror (errno));
- exit (1);
- }
- l = 0;
- while (l < len)
- {
- clearerr (realoutputfile);
- size = fwrite (&buffer[l], 1, len - l, realoutputfile);
- if (size <= 0)
- {
- fprintf (stderr, "error writing output file: %s\n",
- strerror (errno));
- exit (1);
- }
- l += size;
- }
- }
- }
fclose (outfile);
- fclose (realoutputfile);
+ if (outfile != realoutputfile)
+ fclose (realoutputfile);
+ if (havelist)
+ {
+ fclose (listfile);
+ if (listfile != reallistfile && reallistfile != stderr)
+ fclose (reallistfile);
+ }
free (infile);
}
int
main (int argc, char **argv)
{
+ /* default include file location */
+ add_include ("/usr/share/z80asm/headers/");
parse_commandline (argc, argv);
+ if (verbose >= 1)
+ fprintf (stderr, "Assembling....\n");
assemble ();
if (errors)
{
if (errors == 1)
fprintf (stderr, "*** 1 error found ***\n");
else
- fprintf (stderr, "*** %d error found ***\n", errors);
+ fprintf (stderr, "*** %d errors found ***\n", errors);
+ if (realoutputfile == outfile && !use_force)
+ {
+ unlink (realoutputfilename);
+ unlink (labelfilename);
+ }
return 1;
}
- else return 0;
+ else
+ {
+ if (verbose >= 1)
+ fprintf (stderr, "Assembly succesful.\n");
+ return 0;
+ }
}