diff options
-rw-r--r-- | tools/z80asm/ChangeLog | 124 | ||||
-rw-r--r-- | tools/z80asm/Makefile | 20 | ||||
-rw-r--r-- | tools/z80asm/TODO | 1 | ||||
-rw-r--r-- | tools/z80asm/jr.diff | 81 | ||||
-rw-r--r-- | tools/z80asm/z80asm.c | 2197 |
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; + } } |