Initial commit of z80asm (without Apple II mods.)
This commit is contained in:
parent
109a8caafa
commit
8696185cae
|
@ -0,0 +1,41 @@
|
|||
CFLAGS = -c -O
|
||||
LFLAGS = -s
|
||||
|
||||
OBJ = z80amain.o \
|
||||
z80atab.o \
|
||||
z80anum.o \
|
||||
z80aout.o \
|
||||
z80arfun.o \
|
||||
z80apfun.o \
|
||||
z80aopc.o \
|
||||
z80aglb.o
|
||||
|
||||
z80asm : $(OBJ)
|
||||
cc $(OBJ) $(LFLAGS) -o z80asm
|
||||
|
||||
z80amain.o : z80amain.c z80a.h z80aglb.h
|
||||
cc $(CFLAGS) z80amain.c
|
||||
|
||||
z80atab.o : z80atab.c z80a.h z80aglb.h
|
||||
cc $(CFLAGS) z80atab.c
|
||||
|
||||
z80anum.o : z80anum.c z80a.h z80aglb.h
|
||||
cc $(CFLAGS) z80anum.c
|
||||
|
||||
z80aout.o : z80aout.c z80a.h z80aglb.h
|
||||
cc $(CFLAGS) z80aout.c
|
||||
|
||||
z80arfun.o : z80arfun.c z80a.h z80aglb.h
|
||||
cc $(CFLAGS) z80arfun.c
|
||||
|
||||
z80apfun.o : z80apfun.c z80a.h z80aglb.h
|
||||
cc $(CFLAGS) z80apfun.c
|
||||
|
||||
z80aopc.o : z80aopc.c z80a.h
|
||||
cc $(CFLAGS) z80aopc.c
|
||||
|
||||
z80aglb.o : z80aglb.c z80a.h
|
||||
cc $(CFLAGS) z80aglb.c
|
||||
|
||||
clean:
|
||||
rm -f core *.o z80asm
|
|
@ -0,0 +1,78 @@
|
|||
Usage:
|
||||
|
||||
z80asm -ofile -f[b|m|h] -l[file] -s[n|a] -v -dsymbol ... file ...
|
||||
|
||||
A maximum of 512 source files is allowed. If the filename of a source
|
||||
doesn't have an extension the default extension ".asm" will be
|
||||
concated. Source file names may have a path, the maximum length of
|
||||
a full qualified filename is 128 characters.
|
||||
If one use relative paths, the extension must be given, because all
|
||||
after a "." would be used as extension!
|
||||
|
||||
Option o:
|
||||
To override the default name of the output file. Without this option
|
||||
the name of the output file becomes the name of the input file,
|
||||
but with the extension ".bin". The output file may have a path,
|
||||
the maximum length is limited to 128 characters.
|
||||
|
||||
Option f:
|
||||
Format of the output file:
|
||||
|
||||
-fb -> binary file
|
||||
-fm -> binary file with Mostek header
|
||||
-fh -> Intel hex
|
||||
|
||||
Option l:
|
||||
Without this option no list file will be generated. With -l a list
|
||||
file with the name of the source file but extension ".lis" will be
|
||||
generated. An optional file name with path (128 characters maximum)
|
||||
may be added to this option.
|
||||
|
||||
Option s:
|
||||
This option writes the unsorted symbol table (-s), sorted by name (-sn)
|
||||
or sorted by address (-sa) into the list file. This options works
|
||||
only, if option -l was given.
|
||||
|
||||
Option v:
|
||||
Verbose operation of the assembler.
|
||||
|
||||
Option d:
|
||||
With this option one can predefine symbols with a value of 0.
|
||||
The number of this option is not limited in the command line.
|
||||
|
||||
Pseudo Operations:
|
||||
|
||||
Definition of symbols and allocation of memory:
|
||||
|
||||
ORG <expression> - set program address
|
||||
<symbol> EQU <expression> - define constant symbol
|
||||
<symbol> DEFL <expression> - define variable symbol
|
||||
<symbol> DEFB <exp,'char',..> - write bytes in memory
|
||||
<symbol> DEFW <exp,exp..> - write words (16 bits) in memory
|
||||
<symbol> DEFM <'string'> - write character string in memory
|
||||
<symbol> DEFS <expression> - reserve space in memory
|
||||
|
||||
|
||||
Conditional assembly:
|
||||
|
||||
IFDEF <symbol> - assemble if symbol defined
|
||||
IFNDEF <symbol> - assemble if symbol not defined
|
||||
IFEQ <exp1,exp2> - assemble if equal
|
||||
IFNEQ <exp1,exp2> - assemble if not equal
|
||||
ELSE - else for all conditionals
|
||||
ENDIF - end of conditional assembly
|
||||
|
||||
|
||||
Manipulation of list file:
|
||||
|
||||
PAGE <expression> - number of lines/page
|
||||
EJECT - skip to new page
|
||||
LIST - listing on
|
||||
NOLIST - listing off
|
||||
TITLE <'string'> - define title for page header
|
||||
|
||||
|
||||
Others:
|
||||
|
||||
INCLUDE <filename> - include another source file
|
||||
PRINT <'string'> - print string to stdout in pass one
|
|
@ -0,0 +1,46 @@
|
|||
Lizenz fuer Z80-CPU Crossassembler
|
||||
|
||||
Das in dieser Lizenz beschriebene Programm ist ein durch Copyright
|
||||
geschuetztes Produkt. Das Programm darf unter folgenden Voraussetzungen
|
||||
mittels beliebiger Medien kopiert und weitergegeben werden:
|
||||
|
||||
1. Der Empfaenger erhaelt alle Quellen des Programmes inklusive
|
||||
dieser Lizenz.
|
||||
|
||||
2. Fuer die Uebertragung und Weitergabe des Programms darf eine
|
||||
angemessene Aufwandsentschaedigung verlangt werden. Das Programm
|
||||
selbst darf nicht ohne ausdrueckliche Genehmigung des Autors
|
||||
verkauft werden.
|
||||
|
||||
Nutzungsrechte fuer Anwender des Programms:
|
||||
|
||||
1. Dieses Programm darf fuer nicht kommerzielle Anwendungen
|
||||
kostenlos angewendet werden.
|
||||
|
||||
2. Fuer kommerzielle Anwendungen des Programms ist eine
|
||||
Nutzungsgebuehr mit dem Autor des Programms zu vereinbaren.
|
||||
Der Fairness wegen wird die Hoehe der Gebuehr hier nicht
|
||||
festgelegt, sie richtet sich nach dem jeweiligen Anwendungsfall.
|
||||
Grosse Unternehmen mit hohen Gewinnen zahlen in jedem Fall
|
||||
mehr, als ein einzelner, selbstaendiger Software Entwickler!
|
||||
|
||||
Veraenderungen des Programms:
|
||||
|
||||
Alle Programmteile duefern vom Anwender nur zwecks Beseitigung von
|
||||
Fehlern veraendert werden! Der Anwender ist verpflichtet, solche
|
||||
erforderlichen Aenderungen dem Autor mitzuteilen. Diese Massnahme soll
|
||||
eine Versionsvielfalt verhindern, und den Support der
|
||||
kommerziellen Anwender durch den Autor sicherstellen!
|
||||
|
||||
EIN VERSTOSS GEGEN DIE BEDINGUNGEN DIESER LIZENZ FUEHRT ZUM
|
||||
SOFORTIGEN VERLUST DES NUTZUNGSRECHTES DES PROGRAMMES!
|
||||
|
||||
DIESE SOFTWARE WIRD OHNE GARANTIE FUER EINE BESTIMMTE VERWENDUNG
|
||||
AUSGELIEFERT. DER AUTOR HAFTET WEDER FUER FEHLER IN DIESEM PROGRAMM,
|
||||
NOCH FUER FEHLER, ODER SCHAEDEN, DIE DURCH ANWENDUNG DIESES PROGRAMMES
|
||||
ENTSTEHEN.
|
||||
|
||||
Udo Munk Tel.: +49 2131 275348
|
||||
Oberstr. 21 E-Mail: udo@umunk.GUN.de
|
||||
4040 Neuss 1 ...!{mcshh,smurf,unido}!easix!umunk!udo
|
||||
Germany CompuServe: 100021,2515
|
|
@ -0,0 +1,41 @@
|
|||
License Agreement for Z80-CPU crossassembler
|
||||
|
||||
The program described in this license is copyrighted by the law of Germany.
|
||||
The program may be copied and shared under the following terms:
|
||||
|
||||
1. The user receives all the source-codes of the program including the license.
|
||||
|
||||
2. For the physical act of transfer and sharing of the package, a small fee may
|
||||
be demanded. The program itself must not be sold without the author's
|
||||
permission.
|
||||
|
||||
License to the user of the program:
|
||||
|
||||
1. This program may be used free of fee for non-comercial usages.
|
||||
|
||||
2. For comercial usage of the program, a fee must be amounted to the author.
|
||||
In cause of fairness, a big company will have to pay more for a license than
|
||||
a single software developer. So the amount of the fee must be negotiated
|
||||
with the autor of the program.
|
||||
|
||||
Modification of the program:
|
||||
|
||||
All program-parts may be only modified by the user for debugging. The user
|
||||
is bound to inform the author about those modifications. This should
|
||||
prevent an uncontrolled number of versions and ensure the support to
|
||||
comercial users through the author.
|
||||
|
||||
VIOLATIONS AGAINST THIS LICENSE RESULTS IN A LOSS OF RIGHTS TO USE
|
||||
THIS PROGRAM.
|
||||
|
||||
THE PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL
|
||||
THE AUTOR BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING ANY LOST PROFITS,
|
||||
LOST SAVINGS OR OTHER INCIDENTAL OR CONSEQUENTAL DAMAGES ARISING OUT OF
|
||||
THE USE OF THE PROGRAM.
|
||||
|
||||
Udo Munk voice: +49 2131 275348
|
||||
Oberstr. 21 mail : udo@umunk.GUN.de
|
||||
4040 Neuss 1 ...!{mcshh,smurf,unido}!easix!umunk!udo
|
||||
Germany CompuServe: 100021,2515
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* Z80 - Assembler
|
||||
* Copyright (C) 1987-1992 by Udo Munk
|
||||
*
|
||||
* History:
|
||||
* 17-SEP-1987 Development under Digital Research CP/M 2.2
|
||||
* 28-JUN-1988 Switched to Unix System V.3
|
||||
*/
|
||||
|
||||
/*
|
||||
* Rechner und Betriebssystem abhaengige Definitionen
|
||||
*/
|
||||
#define LENFN 128 /* max. Laenge von Filenamen */
|
||||
#define READA "r" /* file open mode read ascii */
|
||||
#define WRITEA "w" /* file open mode write ascii */
|
||||
#define WRITEB "w" /* file open mode write binary */
|
||||
|
||||
/*
|
||||
* Diverse Konstanten
|
||||
*/
|
||||
#define REL "1.1"
|
||||
#define COPYR "Copyright (C) 1988, 89, 90 by Udo Munk"
|
||||
#define SRCEXT ".asm" /* Filenamen-Extension der Quelle */
|
||||
#define OBJEXT ".bin" /* Filenamen-Extension des Object Code */
|
||||
#define LSTEXT ".lis" /* Filenamen-Extension des Listings */
|
||||
#define OUTBIN 1 /* Format der Objektdatei: binaer */
|
||||
#define OUTMOS 2 /* Mostek binaer */
|
||||
#define OUTHEX 3 /* Intel hex */
|
||||
#define OUTDEF OUTMOS /* Default-Format der Objektdatei */
|
||||
#define COMMENT ';' /* Kommentar-Zeichen */
|
||||
#define LINCOM '*' /* wenn in Spalte 1, Kommentarzeile */
|
||||
#define LABSEP ':' /* Label-Seperator */
|
||||
#define STRSEP '\'' /* String-Separator */
|
||||
#define ENDFILE "END" /* Ende der Quelle */
|
||||
#define MAXFN 512 /* max. Anzahl Quellen */
|
||||
#define MAXLINE 128 /* max. Laenge einer Zeile Quelle */
|
||||
#define PLENGTH 65 /* Default Anzahl Zeilen/Seite im Listing */
|
||||
#define SYMSIZE 8 /* max. Laenge Symbole */
|
||||
#define INCNEST 5 /* INCLUDE Verschachtelungstiefe */
|
||||
#define IFNEST 5 /* IF.. Verschachtelungstiefe */
|
||||
#define HASHSIZE 500 /* Anzahl Eintraege in Symbol-Hash-Array */
|
||||
#define OPCARRAY 256 /* Groesse des Arrays fuer generierte Ops */
|
||||
#define SYMINC 100 /* Anfangsgroesse des sortierten Symbol-Array */
|
||||
|
||||
/*
|
||||
* Struktur der OP-Code Tabelle
|
||||
*/
|
||||
struct opc {
|
||||
char *op_name; /* Op-Code Name */
|
||||
int (*op_fun) (); /* Pointer auf Funktion zur Codeerzeugung */
|
||||
int op_c1; /* erster Basis-OP-Code */
|
||||
int op_c2; /* zweiter Basis-OP-Code */
|
||||
};
|
||||
|
||||
/*
|
||||
* Struktur der Operanden Tabelle
|
||||
*/
|
||||
struct ope {
|
||||
char *ope_name; /* Operand Name */
|
||||
int ope_sym; /* Symbolischer Wert des Operanden */
|
||||
};
|
||||
|
||||
/*
|
||||
* Struktur der Symbol-Tabelleneintraege
|
||||
*/
|
||||
struct sym {
|
||||
char *sym_name; /* Symbol Name */
|
||||
int sym_wert; /* Symbol Wert */
|
||||
struct sym *sym_next; /* naechster Eintrag */
|
||||
};
|
||||
|
||||
/*
|
||||
* Struktur fuer verschachtelte INCLUDE's
|
||||
*/
|
||||
struct inc {
|
||||
unsigned inc_line; /* Zeilenzaehler fuers Listing */
|
||||
char *inc_fn; /* Filename der Datei mit INCLUDE */
|
||||
FILE *inc_fp; /* Filepointer der Datei mit INCLUDE */
|
||||
};
|
||||
|
||||
/*
|
||||
* Definition der Symbole fuer die Operanden.
|
||||
* Die Definitionen fuer Register A, B, C, D, H, L
|
||||
* und (HL) entsprechen den Bits in den Opcodes
|
||||
* und duerfen auf keinen Fall geaendert werden!
|
||||
*/
|
||||
#define REGB 0 /* Register B */
|
||||
#define REGC 1 /* Register C */
|
||||
#define REGD 2 /* Register D */
|
||||
#define REGE 3 /* Register E */
|
||||
#define REGH 4 /* Register H */
|
||||
#define REGL 5 /* Register L */
|
||||
#define REGIHL 6 /* Register indirekt HL */
|
||||
#define REGA 7 /* Register A */
|
||||
#define REGI 8 /* Register I */
|
||||
#define REGR 9 /* Register R */
|
||||
#define REGAF 10 /* Registerpaar AF */
|
||||
#define REGBC 11 /* Registerpaar BC */
|
||||
#define REGDE 12 /* Registerpaar DE */
|
||||
#define REGHL 13 /* Registerpaar HL */
|
||||
#define REGIX 14 /* Register IX */
|
||||
#define REGIY 15 /* Register IY */
|
||||
#define REGSP 16 /* Register SP */
|
||||
#define REGIBC 17 /* Register indirekt BC */
|
||||
#define REGIDE 18 /* Register indirekt DE */
|
||||
#define REGIIX 19 /* Register indirekt IX */
|
||||
#define REGIIY 20 /* Register indirekt IY */
|
||||
#define REGISP 21 /* Register indirekt SP */
|
||||
#define FLGNC 30 /* Flag no carry */
|
||||
#define FLGNZ 31 /* Flag not zerro */
|
||||
#define FLGZ 32 /* Flag zerro */
|
||||
#define FLGM 33 /* Flag minus */
|
||||
#define FLGP 34 /* Flag plus */
|
||||
#define FLGPE 35 /* Flag parrity even */
|
||||
#define FLGPO 36 /* Flag parrity odd */
|
||||
#define NOOPERA 98 /* kein Operand vorhanden */
|
||||
#define NOREG 99 /* Operand ist kein Register */
|
||||
|
||||
/*
|
||||
* Definition der Assembler-Fehler-Nummern, die
|
||||
* zu Fehlermeldungen im Listfile fuehren
|
||||
* (siehe asmerr)
|
||||
*/
|
||||
#define E_ILLOPC 0 /* illegaler Opcode */
|
||||
#define E_ILLOPE 1 /* illegaler Operand */
|
||||
#define E_MISOPE 2 /* fehlender Operand */
|
||||
#define E_MULSYM 3 /* mehrfach definiertes Symbol */
|
||||
#define E_UNDSYM 4 /* undefiniertes Symbol */
|
||||
#define E_VALOUT 5 /* Wert ausserhalb Bereich */
|
||||
#define E_MISPAR 6 /* Klammer fehlt */
|
||||
#define E_MISHYP 7 /* String Separator fehlt */
|
||||
#define E_MEMOVR 8 /* memory override (ORG) */
|
||||
#define E_MISIFF 9 /* fehlendes IF bei ELSE oder ENDIF */
|
||||
#define E_IFNEST 10 /* IF zu tief verschachtelt */
|
||||
#define E_MISEIF 11 /* fehlendes ENDIF */
|
||||
#define E_INCNEST 12 /* INCLUDE zu tief verschachtelt */
|
||||
|
||||
/*
|
||||
* Definition der Fehlernummern, die zum sofortigen
|
||||
* Abbruch des Programms fuehren (siehe fatal)
|
||||
*/
|
||||
#define F_OUTMEM 0 /* out of memory */
|
||||
#define F_USAGE 1 /* usage: .... */
|
||||
#define F_HALT 2 /* Assembly halted */
|
||||
#define F_FOPEN 3 /* can't open file */
|
||||
#define F_INTERN 4 /* internal error */
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Z80 - Assembler
|
||||
* Copyright (C) 1987-1992 by Udo Munk
|
||||
*
|
||||
* History:
|
||||
* 17-SEP-1987 Development under Digital Research CP/M 2.2
|
||||
* 28-JUN-1988 Switched to Unix System V.3
|
||||
*/
|
||||
|
||||
/*
|
||||
* Dieses Modul enthaelt alle globalen Variablen des
|
||||
* Assemblers, ausser der CPU spezifischen Tabellen.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "z80a.h"
|
||||
|
||||
char *infiles[MAXFN], /* Filenamen aller Quellen */
|
||||
objfn[LENFN + 1], /* Filename des Object Code */
|
||||
lstfn[LENFN + 1], /* Filename des Listing */
|
||||
*srcfn, /* Filename der gerade bearbeiteten Quelle */
|
||||
line[MAXLINE], /* Puffer fuer eine Zeile Quelle */
|
||||
tmp[MAXLINE], /* termoraerer Puffer */
|
||||
label[SYMSIZE+1], /* Puffer fuer extrahiertes Label */
|
||||
opcode[MAXLINE], /* Puffer fuer extrahierten Op-Code */
|
||||
operand[MAXLINE], /* Puffer fuer extrahierten Operanden */
|
||||
ops[OPCARRAY], /* Puffer fuer generierten Op-Code */
|
||||
title[MAXLINE]; /* Puffer fuer Titel der Quelle */
|
||||
|
||||
int list_flag, /* Flag fuer Option -l */
|
||||
sym_flag, /* Flag fuer Option -s */
|
||||
ver_flag, /* Flag fuer Option -v */
|
||||
pc, /* Programm-Counter */
|
||||
pass, /* Momentaner Durchlauf */
|
||||
iflevel, /* aktuelle Verschachtelungstiefe der IF's */
|
||||
gencode = 1, /* Flag fuer conditional Codegenerierung */
|
||||
errors, /* Zaehler fuer errors */
|
||||
errnum, /* Fehler Nummer in Pass 2 */
|
||||
sd_flag, /* List-Flag fuer PSEUDO Op-Codes */
|
||||
/* = 0: Adresse aus <val>, Daten aus <ops> */
|
||||
/* = 1: Adresse aus <sd_val>, Daten aus <ops> */
|
||||
/* = 2: keine Adresse, Daten aus <ops> */
|
||||
/* = 3: Adresse aus <sd_val>, keine Daten */
|
||||
/* = 4: ganze Zeile unterdruecken */
|
||||
sd_val, /* Ausgabewert fuer PSEUDO Op-Codes */
|
||||
prg_adr, /* Startadresse des Programms */
|
||||
prg_flag, /* Flag fuer prg_adr gueltig */
|
||||
out_form = OUTDEF, /* Format der Objektdatei */
|
||||
symsize; /* Groesse von symarray */
|
||||
|
||||
FILE *srcfp, /* Filepointer fuer aktuelle Quelle */
|
||||
*objfp, /* Filepointer fuer Object Code */
|
||||
*lstfp, /* Filepointer fuer Listing */
|
||||
*errfp; /* Filepointer fuer Fehler */
|
||||
/* abhaengig von -l lstfp oder stdout */
|
||||
|
||||
unsigned c_line, /* aktuelle Zeile der aktuellen Quelle */
|
||||
s_line, /* Zeilenzaehler fuers Listing */
|
||||
p_line, /* Anzahl gedruckter Zeilen auf der Seite */
|
||||
ppl = PLENGTH, /* Anzahl Zeilen/Seite */
|
||||
page; /* Seitenzaehler fuer Listing */
|
||||
|
||||
struct sym *symtab[HASHSIZE], /* Symboltabelle */
|
||||
**symarray; /* sortierte Symboltabelle */
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Z80 - Assembler
|
||||
* Copyright (C) 1987-1992 by Udo Munk
|
||||
*
|
||||
* History:
|
||||
* 17-SEP-1987 Development under Digital Research CP/M 2.2
|
||||
* 28-JUN-1988 Switched to Unix System V.3
|
||||
*/
|
||||
|
||||
/*
|
||||
* Extern Declaration der globalen Variablen
|
||||
*/
|
||||
|
||||
extern char *infiles[],
|
||||
objfn[],
|
||||
lstfn[],
|
||||
*srcfn,
|
||||
line[],
|
||||
tmp[],
|
||||
label[],
|
||||
opcode[],
|
||||
operand[],
|
||||
ops[],
|
||||
title[];
|
||||
|
||||
extern int list_flag,
|
||||
sym_flag,
|
||||
ver_flag,
|
||||
pc,
|
||||
pass,
|
||||
iflevel,
|
||||
gencode,
|
||||
errors,
|
||||
errnum,
|
||||
sd_flag,
|
||||
sd_val,
|
||||
prg_adr,
|
||||
prg_flag,
|
||||
out_form,
|
||||
symsize,
|
||||
no_opcodes,
|
||||
no_operands;
|
||||
|
||||
extern FILE *srcfp,
|
||||
*objfp,
|
||||
*lstfp,
|
||||
*errfp;
|
||||
|
||||
extern unsigned c_line,
|
||||
s_line,
|
||||
p_line,
|
||||
ppl,
|
||||
page;
|
||||
|
||||
extern struct sym *symtab[],
|
||||
**symarray;
|
||||
|
||||
extern struct opc opctab[];
|
||||
|
||||
extern struct ope opetab[];
|
|
@ -0,0 +1,498 @@
|
|||
/*
|
||||
* Z80 - Assembler
|
||||
* Copyright (C) 1987-1992 by Udo Munk
|
||||
*
|
||||
* History:
|
||||
* 17-SEP-1987 Development under Digital Research CP/M 2.2
|
||||
* 28-JUN-1988 Switched to Unix System V.3
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include "z80a.h"
|
||||
#include "z80aglb.h"
|
||||
|
||||
static char *errmsg[] = { /* Fehlermeldungen fuer fatal() */
|
||||
"out of memory: %s", /* 0 */
|
||||
"usage: z80asm -ofile -f[b|m|h] -l[file] -s[n|a] -v -dsymbol ... file ...",
|
||||
"Assembly halted", /* 2 */
|
||||
"can't open file %s", /* 3 */
|
||||
"internal error: %s" /* 4 */
|
||||
};
|
||||
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int len;
|
||||
|
||||
init();
|
||||
options(argc, argv);
|
||||
printf("Z80 - Assembler Release %s, %s\n", REL, COPYR);
|
||||
pass1();
|
||||
pass2();
|
||||
if (list_flag) {
|
||||
switch (sym_flag) {
|
||||
case 0: /* keine Symboltabelle */
|
||||
break;
|
||||
case 1: /* unsortierte Symboltabelle */
|
||||
lst_sym();
|
||||
break;
|
||||
case 2: /* nach Namen sortierte Symboltabelle */
|
||||
len = copy_sym();
|
||||
n_sort_sym(len);
|
||||
lst_sort_sym(len);
|
||||
break;
|
||||
case 3: /* nach Adressen sortierte Symboltabelle */
|
||||
len = copy_sym();
|
||||
a_sort_sym(len);
|
||||
lst_sort_sym(len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
fclose(lstfp);
|
||||
}
|
||||
return(errors);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialisierung
|
||||
*/
|
||||
init()
|
||||
{
|
||||
errfp = stdout;
|
||||
}
|
||||
|
||||
/*
|
||||
* Diese Funktion bearbeitet die beim Aufruf angegebenen Options.
|
||||
* Die uebergebenen Dateinamen werden in die entsprechenden
|
||||
* Strings uebernommen.
|
||||
*/
|
||||
options(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
register char *s, *t;
|
||||
register int i;
|
||||
char *malloc();
|
||||
|
||||
while (--argc > 0 && (*++argv)[0] == '-')
|
||||
for (s = argv[0]+1; *s != '\0'; s++)
|
||||
switch (*s) {
|
||||
case 'o':
|
||||
case 'O':
|
||||
if (*++s == '\0') {
|
||||
puts("name missing in option -o");
|
||||
usage();
|
||||
}
|
||||
get_fn(objfn, s, OBJEXT);
|
||||
s += (strlen(s) - 1);
|
||||
break;
|
||||
case 'l':
|
||||
case 'L':
|
||||
if (*(s + 1) != '\0') {
|
||||
get_fn(lstfn, ++s, LSTEXT);
|
||||
s += (strlen(s) - 1);
|
||||
}
|
||||
list_flag = 1;
|
||||
break;
|
||||
case 's':
|
||||
case 'S':
|
||||
if (*(s + 1) == '\0')
|
||||
sym_flag = 1;
|
||||
else if ((*(s + 1) == 'n') || (*(s + 1) == 'N'))
|
||||
sym_flag = 2;
|
||||
else if ((*(s + 1) == 'a') || (*(s + 1) == 'A'))
|
||||
sym_flag = 3;
|
||||
else {
|
||||
printf("unknown option -%s\n", s);
|
||||
usage();
|
||||
}
|
||||
s += (strlen(s) - 1);
|
||||
break;
|
||||
case 'f':
|
||||
case 'F':
|
||||
if ((*(s + 1) == 'b') || (*(s + 1) == 'B'))
|
||||
out_form = OUTBIN;
|
||||
else if ((*(s + 1) == 'm') || (*(s + 1) == 'M'))
|
||||
out_form = OUTMOS;
|
||||
else if ((*(s + 1) == 'h') || (*(s + 1) == 'H'))
|
||||
out_form = OUTHEX;
|
||||
else {
|
||||
printf("unknown option -%s\n", s);
|
||||
usage();
|
||||
}
|
||||
s += (strlen(s) - 1);
|
||||
break;
|
||||
case 'd':
|
||||
case 'D':
|
||||
if (*++s == '\0') {
|
||||
puts("name missing in option -d");
|
||||
usage();
|
||||
}
|
||||
t = tmp;
|
||||
while (*s)
|
||||
*t++ = islower(*s) ? toupper(*s++) : *s++;
|
||||
s--;
|
||||
*t = '\0';
|
||||
if (put_sym(tmp, 0))
|
||||
fatal(F_OUTMEM, "symbols");
|
||||
break;
|
||||
case 'v':
|
||||
case 'V':
|
||||
ver_flag = 1;
|
||||
break;
|
||||
default :
|
||||
printf("unknown option %c\n", *s);
|
||||
usage();
|
||||
}
|
||||
i = 0;
|
||||
while ((argc--) && (i < MAXFN)) {
|
||||
if ((infiles[i] = malloc(LENFN + 1)) == NULL)
|
||||
fatal(F_OUTMEM, "filenames");
|
||||
get_fn(infiles[i], *argv++, SRCEXT);
|
||||
i++;
|
||||
}
|
||||
if (i == 0) {
|
||||
printf("no input file given\n");
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* An den Argumenten in der Befehlszeile ist was falsch,
|
||||
* Gebrauchsanleitung ausgeben und abbrechen.
|
||||
*/
|
||||
usage()
|
||||
{
|
||||
fatal(F_USAGE, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fehlermeldung ausgeben und abbrechen
|
||||
*/
|
||||
fatal(i, arg)
|
||||
register int i;
|
||||
register char *arg;
|
||||
{
|
||||
void exit();
|
||||
|
||||
printf(errmsg[i], arg);
|
||||
putchar('\n');
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pass 1:
|
||||
* - Lauf ueber alle Quelldateien
|
||||
*/
|
||||
pass1()
|
||||
{
|
||||
register int fi;
|
||||
|
||||
pass = 1;
|
||||
pc = 0;
|
||||
fi = 0;
|
||||
if (!ver_flag)
|
||||
puts("Pass 1");
|
||||
open_o_files(infiles[fi]);
|
||||
while (infiles[fi] != NULL) {
|
||||
if (!ver_flag)
|
||||
printf(" Read %s\n", infiles[fi]);
|
||||
p1_file(infiles[fi]);
|
||||
fi++;
|
||||
}
|
||||
if (errors) {
|
||||
fclose(objfp);
|
||||
unlink(objfn);
|
||||
printf("%d error(s)\n", errors);
|
||||
fatal(F_HALT, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Pass 1:
|
||||
* - Lauf ueber eine Quelldatei
|
||||
*
|
||||
* Input: Name der zu bearbeitenden Quelldatei
|
||||
*/
|
||||
p1_file(fn)
|
||||
char *fn;
|
||||
{
|
||||
c_line = 0;
|
||||
srcfn = fn;
|
||||
if ((srcfp = fopen(fn, READA)) == NULL)
|
||||
fatal(F_FOPEN, fn);
|
||||
while (p1_line())
|
||||
;
|
||||
fclose(srcfp);
|
||||
if (iflevel)
|
||||
asmerr(E_MISEIF);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pass 1:
|
||||
* - Eine Zeile Quelle verarbeiten
|
||||
*
|
||||
* Output: 1 Zeile verarbeitet
|
||||
* 0 EOF erreicht
|
||||
*/
|
||||
p1_line()
|
||||
{
|
||||
register char *p;
|
||||
register int i;
|
||||
register struct opc *op;
|
||||
char *get_label(), *get_opcode(), *get_arg();
|
||||
struct opc *search_op();
|
||||
|
||||
if ((p = fgets(line, MAXLINE, srcfp)) == NULL)
|
||||
return(0);
|
||||
c_line++;
|
||||
p = get_label(label, p);
|
||||
p = get_opcode(opcode, p);
|
||||
p = get_arg(operand, p);
|
||||
if (strcmp(opcode, ENDFILE) == 0)
|
||||
return(0);
|
||||
if (*opcode) {
|
||||
if ((op = search_op(opcode)) != NULL) {
|
||||
i = (*op->op_fun)(op->op_c1, op->op_c2);
|
||||
if (gencode)
|
||||
pc += i;
|
||||
} else
|
||||
asmerr(E_ILLOPC);
|
||||
} else
|
||||
if (*label)
|
||||
put_label();
|
||||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pass 2:
|
||||
* - Lauf ueber alle Quelldateien
|
||||
*/
|
||||
pass2()
|
||||
{
|
||||
register int fi;
|
||||
|
||||
pass = 2;
|
||||
pc = 0;
|
||||
fi = 0;
|
||||
if (!ver_flag)
|
||||
puts("Pass 2");
|
||||
obj_header();
|
||||
while (infiles[fi] != NULL) {
|
||||
if (!ver_flag)
|
||||
printf(" Read %s\n", infiles[fi]);
|
||||
p2_file(infiles[fi]);
|
||||
fi++;
|
||||
}
|
||||
obj_end();
|
||||
fclose(objfp);
|
||||
printf("%d error(s)\n", errors);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pass 2:
|
||||
* - Lauf ueber eine Quelldatei
|
||||
*
|
||||
* Input: Name der zu bearbeitenden Quelldatei
|
||||
*/
|
||||
p2_file(fn)
|
||||
char *fn;
|
||||
{
|
||||
c_line = 0;
|
||||
srcfn = fn;
|
||||
if ((srcfp = fopen(fn, READA)) == NULL)
|
||||
fatal(F_FOPEN, fn);
|
||||
while (p2_line())
|
||||
;
|
||||
fclose(srcfp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pass 2:
|
||||
* - Eine Zeile Quelle verarbeiten
|
||||
*
|
||||
* Output: 1 Zeile verarbeitet
|
||||
* 0 EOF erreicht
|
||||
*/
|
||||
p2_line()
|
||||
{
|
||||
register char *p;
|
||||
register int op_count;
|
||||
register struct opc *op;
|
||||
char *get_label(), *get_opcode(), *get_arg();
|
||||
struct opc *search_op();
|
||||
|
||||
if ((p = fgets(line, MAXLINE, srcfp)) == NULL)
|
||||
return(0);
|
||||
c_line++;
|
||||
s_line++;
|
||||
p = get_label(label, p);
|
||||
p = get_opcode(opcode, p);
|
||||
p = get_arg(operand, p);
|
||||
if (strcmp(opcode, ENDFILE) == 0) {
|
||||
lst_line(pc, 0);
|
||||
return(0);
|
||||
}
|
||||
if (*opcode) {
|
||||
op = search_op(opcode);
|
||||
op_count = (*op->op_fun)(op->op_c1, op->op_c2);
|
||||
if (gencode) {
|
||||
lst_line(pc, op_count);
|
||||
obj_writeb(op_count);
|
||||
pc += op_count;
|
||||
} else {
|
||||
sd_flag = 2;
|
||||
lst_line(0, 0);
|
||||
}
|
||||
} else {
|
||||
sd_flag = 2;
|
||||
lst_line(0, 0);
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Oeffnen der Ausgabedateien: Objectdatei und bei Option
|
||||
* -l der Listdatei. Der Dateiname der Quelldatei wird
|
||||
* uebergeben. Die Dateinamen der Object- und Listdatei
|
||||
* werden, wenn nicht hinter den Optionen -l und -o angegeben,
|
||||
* aus dem Quelldateinamen erzeugt.
|
||||
*/
|
||||
open_o_files(source)
|
||||
register char *source;
|
||||
{
|
||||
char *strcpy(), *strcat(), *strrchr();
|
||||
register char *p;
|
||||
|
||||
if (*objfn == '\0')
|
||||
strcpy(objfn, source);
|
||||
if ((p = strrchr(objfn, '.')) != NULL)
|
||||
strcpy(p, OBJEXT);
|
||||
else
|
||||
strcat(objfn, OBJEXT);
|
||||
|
||||
if (out_form == OUTHEX)
|
||||
objfp = fopen(objfn, WRITEA);
|
||||
else
|
||||
objfp = fopen(objfn, WRITEB);
|
||||
if (objfp == NULL)
|
||||
fatal(F_FOPEN, objfn);
|
||||
if (list_flag) {
|
||||
if (*lstfn == '\0')
|
||||
strcpy(lstfn, source);
|
||||
if ((p = strrchr(lstfn, '.')) != NULL)
|
||||
strcpy(p, LSTEXT);
|
||||
else
|
||||
strcat(lstfn, LSTEXT);
|
||||
if ((lstfp = fopen(lstfn, WRITEA)) == NULL)
|
||||
fatal(F_FOPEN, lstfn);
|
||||
errfp = lstfp;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Einen Dateinamen in "dest" aus "src" und "ext" zusammenbauen
|
||||
*/
|
||||
get_fn(dest, src, ext)
|
||||
char *dest, *src, *ext;
|
||||
{
|
||||
char *strrchr(), *strcat();
|
||||
register int i;
|
||||
register char *sp, *dp;
|
||||
|
||||
i = 0;
|
||||
sp = src;
|
||||
dp = dest;
|
||||
while ((i++ < LENFN) && (*sp != '\0'))
|
||||
*dp++ = *sp++;
|
||||
*dp = '\0';
|
||||
if ((strrchr(dest,'.') == NULL) && (strlen(dest) <= (LENFN-strlen(ext))))
|
||||
strcat(dest, ext);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extrahieren der Labels, Konstanten und Variablen aus
|
||||
* einer Zeile Quelltext mit Umwandlung in Grosschrift
|
||||
* und Begrenzung der Laenge.
|
||||
*/
|
||||
char *get_label(s, l)
|
||||
register char *s, *l;
|
||||
{
|
||||
register int i;
|
||||
|
||||
i = 0;
|
||||
if (*l == LINCOM)
|
||||
goto comment;
|
||||
while (!isspace(*l) && *l != COMMENT && *l != LABSEP && i < SYMSIZE) {
|
||||
*s++ = islower(*l) ? toupper(*l++) : *l++;
|
||||
i++;
|
||||
}
|
||||
comment:
|
||||
*s = '\0';
|
||||
return(l);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extrahieren des Op-Codes aus einer Zeile Quelltext ab der
|
||||
* uebergebenen Position. Der String wird bei der Uebertragung
|
||||
* in Grosschrift umgewandelt.
|
||||
*/
|
||||
char *get_opcode(s, l)
|
||||
register char *s, *l;
|
||||
{
|
||||
if (*l == LINCOM)
|
||||
goto comment;
|
||||
while (!isspace(*l) && *l != COMMENT && *l != LABSEP)
|
||||
l++;
|
||||
if (*l == LABSEP)
|
||||
l++;
|
||||
while (*l == ' ' || *l == '\t')
|
||||
l++;
|
||||
while (!isspace(*l) && *l != COMMENT)
|
||||
*s++ = islower(*l) ? toupper(*l++) : *l++;
|
||||
comment:
|
||||
*s = '\0';
|
||||
return(l);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extrahieren des Operanden aus einer Zeile Quelltext ab der
|
||||
* uebergebenen Position. Der String wird bei der Uebertragung
|
||||
* in Grosschrift umgewandelt und Blanks sowie Tabs werden
|
||||
* ueberlesen. Strings, die in ' eingeschlossen sind, werden
|
||||
* ohne Aenderung kopiert.
|
||||
*/
|
||||
char *get_arg(s, l)
|
||||
register char *s, *l;
|
||||
{
|
||||
if (*l == LINCOM)
|
||||
goto comment;
|
||||
while (*l == ' ' || *l == '\t')
|
||||
l++;
|
||||
while (*l != '\n' && *l != COMMENT) {
|
||||
if (isspace(*l)) {
|
||||
l++;
|
||||
continue;
|
||||
}
|
||||
if (*l != STRSEP) {
|
||||
*s++ = islower(*l) ? toupper(*l) : *l;
|
||||
l++;
|
||||
continue;
|
||||
}
|
||||
*s++ = *l++;
|
||||
if (*(s - 2) == 'F') /* EX AF,AF' !!!!! */
|
||||
continue;
|
||||
while (*l != STRSEP) {
|
||||
if (*l == '\n' || *l == '\0' || *l == COMMENT)
|
||||
goto comment;
|
||||
*s++ = *l++;
|
||||
}
|
||||
*s++ = *l++;
|
||||
}
|
||||
comment:
|
||||
*s = '\0';
|
||||
return(l);
|
||||
}
|
|
@ -0,0 +1,317 @@
|
|||
/*
|
||||
* Z80 - Assembler
|
||||
* Copyright (C) 1987-1992 by Udo Munk
|
||||
*
|
||||
* History:
|
||||
* 17-SEP-1987 Development under Digital Research CP/M 2.2
|
||||
* 28-JUN-1988 Switched to Unix System V.3
|
||||
*/
|
||||
|
||||
/*
|
||||
* Dieses Modul enthaelt die numerischen
|
||||
* Rechen- und Umwandlungsfunktionen.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include "z80a.h"
|
||||
#include "z80aglb.h"
|
||||
|
||||
#ifndef isxdigit
|
||||
#define isxdigit(c) (isdigit(c) || (c>='a' && c<='f') || (c>='A' && c<='F'))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Definition Operatoren-Symbole fuer den Expression-Parser
|
||||
*/
|
||||
#define OPEDEC 1 /* Dezimalzahl */
|
||||
#define OPEHEX 2 /* Hexzahl */
|
||||
#define OPEOCT 3 /* Octalzahl */
|
||||
#define OPEBIN 4 /* Binaerzahl */
|
||||
#define OPESUB 5 /* arithmetisches - */
|
||||
#define OPEADD 6 /* arithmetisches + */
|
||||
#define OPEMUL 7 /* arithmetisches * */
|
||||
#define OPEDIV 8 /* arithmetisches / */
|
||||
#define OPEMOD 9 /* arithmetisches Modulo */
|
||||
#define OPESHL 10 /* logisches shift left */
|
||||
#define OPESHR 11 /* logisches shift right */
|
||||
#define OPELOR 12 /* logisches OR */
|
||||
#define OPELAN 13 /* logisches AND */
|
||||
#define OPEXOR 14 /* logisches XOR */
|
||||
#define OPECOM 15 /* logisches Komplement */
|
||||
#define OPESYM 99 /* Symbol */
|
||||
|
||||
/*
|
||||
* Rekursiver Expression-Parser
|
||||
*
|
||||
* Input: Pointer auf den restlichen Argument-String
|
||||
*
|
||||
* Output: berechneter Wert
|
||||
*/
|
||||
eval(s)
|
||||
register char *s;
|
||||
{
|
||||
register char *p;
|
||||
register int val;
|
||||
char word[MAXLINE];
|
||||
struct sym *sp, *get_sym();
|
||||
|
||||
val = 0;
|
||||
while (*s) {
|
||||
p = word;
|
||||
if (*s == '(') {
|
||||
s++;
|
||||
while (*s != ')') {
|
||||
if (*s == '\0') {
|
||||
asmerr(E_MISPAR);
|
||||
goto eval_break;
|
||||
}
|
||||
*p++ = *s++;
|
||||
}
|
||||
*p = '\0';
|
||||
s++;
|
||||
val = eval(word);
|
||||
continue;
|
||||
}
|
||||
if (*s == STRSEP) {
|
||||
s++;
|
||||
while (*s != STRSEP) {
|
||||
if (*s == '\n' || *s == '\0') {
|
||||
asmerr(E_MISHYP);
|
||||
goto hyp_error;
|
||||
}
|
||||
*p++ = *s++;
|
||||
}
|
||||
s++;
|
||||
hyp_error:
|
||||
*p = '\0';
|
||||
val = strval(word);
|
||||
continue;
|
||||
}
|
||||
if (isari(*s))
|
||||
*p++ = *s++;
|
||||
else
|
||||
while (!isspace(*s) && !isari(*s) && (*s != '\0'))
|
||||
*p++ = *s++;
|
||||
*p = '\0';
|
||||
switch (get_type(word)) {
|
||||
case OPESYM: /* Symbol */
|
||||
if (strcmp(word, "$") == 0) {
|
||||
val = pc;
|
||||
break;
|
||||
}
|
||||
if (strlen(word) > SYMSIZE)
|
||||
word[SYMSIZE] = '\0';
|
||||
if ((sp = get_sym(word)) != NULL)
|
||||
val = sp->sym_wert;
|
||||
else
|
||||
asmerr(E_UNDSYM);
|
||||
break;
|
||||
case OPEDEC: /* Dezimalzahl */
|
||||
val = atoi(word);
|
||||
break;
|
||||
case OPEHEX: /* Hexzahl */
|
||||
val = axtoi(word);
|
||||
break;
|
||||
case OPEBIN: /* Binaerzahl */
|
||||
val = abtoi(word);
|
||||
break;
|
||||
case OPEOCT: /* Oktalzahl */
|
||||
val = aotoi(word);
|
||||
break;
|
||||
case OPESUB: /* arithmetisches - */
|
||||
val -= eval(s);
|
||||
goto eval_break;
|
||||
case OPEADD: /* arithmetisches + */
|
||||
val += eval(s);
|
||||
goto eval_break;
|
||||
case OPEMUL: /* arithmetisches * */
|
||||
val *= eval(s);
|
||||
goto eval_break;
|
||||
case OPEDIV: /* arithmetisches / */
|
||||
val /= eval(s);
|
||||
goto eval_break;
|
||||
case OPEMOD: /* arithmetisches Modulo */
|
||||
val %= eval(s);
|
||||
goto eval_break;
|
||||
case OPESHL: /* logisches shift left */
|
||||
val <<= eval(s);
|
||||
goto eval_break;
|
||||
case OPESHR: /* logisches shift right */
|
||||
val >>= eval(s);
|
||||
goto eval_break;
|
||||
case OPELOR: /* logisches OR */
|
||||
val |= eval(s);
|
||||
goto eval_break;
|
||||
case OPELAN: /* logisches AND */
|
||||
val &= eval(s);
|
||||
goto eval_break;
|
||||
case OPEXOR: /* logisches XOR */
|
||||
val ^= eval(s);
|
||||
goto eval_break;
|
||||
case OPECOM: /* logisches Komplement */
|
||||
val = ~(eval(s));
|
||||
goto eval_break;
|
||||
}
|
||||
}
|
||||
eval_break:
|
||||
return(val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Operanden Typ-Bestimmung
|
||||
*
|
||||
* Input: Pointer auf zu bestimmenden String
|
||||
*
|
||||
* Output: Operanden Typ
|
||||
*/
|
||||
get_type(s)
|
||||
char *s;
|
||||
{
|
||||
if (isdigit(*s)) { /* numerischer Operand */
|
||||
if (isdigit(*(s + strlen(s) - 1))) /* Dezimalzahl */
|
||||
return(OPEDEC);
|
||||
else if (*(s + strlen(s) - 1) == 'H') /* Hexzahl */
|
||||
return(OPEHEX);
|
||||
else if (*(s + strlen(s) - 1) == 'B') /* Binaerzahl */
|
||||
return(OPEBIN);
|
||||
else if (*(s + strlen(s) - 1) == 'O') /* Oktalzahl */
|
||||
return(OPEOCT);
|
||||
} else if (*s == '-') /* arithmetischer Operand - */
|
||||
return(OPESUB);
|
||||
else if (*s == '+') /* arithmetischer Operand + */
|
||||
return(OPEADD);
|
||||
else if (*s == '*') /* arithmetischer Operand * */
|
||||
return(OPEMUL);
|
||||
else if (*s == '/') /* arithmetischer Operand / */
|
||||
return(OPEDIV);
|
||||
else if (*s == '%') /* arithmetisches Modulo */
|
||||
return(OPEMOD);
|
||||
else if (*s == '<') /* logisches shift left */
|
||||
return(OPESHL);
|
||||
else if (*s == '>') /* logisches shift rigth */
|
||||
return(OPESHR);
|
||||
else if (*s == '|') /* logisches OR */
|
||||
return(OPELOR);
|
||||
else if (*s == '&') /* logisches AND */
|
||||
return(OPELAN);
|
||||
else if (*s == '^') /* logisches XOR */
|
||||
return(OPEXOR);
|
||||
else if (*s == '~') /* logisches Komplement */
|
||||
return(OPECOM);
|
||||
return(OPESYM); /* Operand ist ein Symbol */
|
||||
}
|
||||
|
||||
/*
|
||||
* Die Funktion prueft einen Character auf die arithmetischen
|
||||
* Operatoren +, -, *, /, %, <, >, |, &, ~ und ^.
|
||||
*/
|
||||
isari(c)
|
||||
register int c;
|
||||
{
|
||||
return((c) == '+' || (c) == '-' || (c) == '*' ||
|
||||
(c) == '/' || (c) == '%' || (c) == '<' ||
|
||||
(c) == '>' || (c) == '|' || (c) == '&' ||
|
||||
(c) == '~' || (c) == '^');
|
||||
}
|
||||
|
||||
/*
|
||||
* Umwandlung eines ASCII-Strings mit einer Hexzahl in
|
||||
* einen Integer.
|
||||
* Format: nnnnH oder 0nnnnH wenn 1.Ziffer > 9
|
||||
*/
|
||||
axtoi(str)
|
||||
register char *str;
|
||||
{
|
||||
register int num;
|
||||
|
||||
num = 0;
|
||||
while (isxdigit(*str)) {
|
||||
num *= 16;
|
||||
num += *str - ((*str <= '9') ? '0' : '7');
|
||||
str++;
|
||||
}
|
||||
return(num);
|
||||
}
|
||||
|
||||
/*
|
||||
* Umwandlung eines ASCII-Strings mit einer Oktalzahl in
|
||||
* einen Integer.
|
||||
* Format: nnnnO
|
||||
*/
|
||||
aotoi(str)
|
||||
register char *str;
|
||||
{
|
||||
register int num;
|
||||
|
||||
num = 0;
|
||||
while ('0' <= *str && *str <= '7') {
|
||||
num *= 8;
|
||||
num += (*str++) - '0';
|
||||
}
|
||||
return(num);
|
||||
}
|
||||
|
||||
/*
|
||||
* Umwandlung eines ASCII-Strings mit einer Binaerzahl in
|
||||
* einen Integer.
|
||||
* Format: nnnnnnnnnnnnnnnnB
|
||||
*/
|
||||
abtoi(str)
|
||||
register char *str;
|
||||
{
|
||||
register int num;
|
||||
|
||||
num = 0;
|
||||
while ('0' <= *str && *str <= '1') {
|
||||
num *= 2;
|
||||
num += (*str++) - '0';
|
||||
}
|
||||
return(num);
|
||||
}
|
||||
|
||||
/*
|
||||
* Umwandlung eines ASCII-Strings in einen Integer.
|
||||
*/
|
||||
strval(str)
|
||||
register char *str;
|
||||
{
|
||||
register int num;
|
||||
|
||||
num = 0;
|
||||
while (*str) {
|
||||
num <<= 8;
|
||||
num += (int) *str++;
|
||||
}
|
||||
return(num);
|
||||
}
|
||||
|
||||
/*
|
||||
* Die Funktion prueft einen Wert auf -256 < Wert < 256
|
||||
* Output: Wert wenn im Bereich, sonst 0 und Fehlermeldung
|
||||
*/
|
||||
chk_v1(i)
|
||||
register int i;
|
||||
{
|
||||
if (i >= -255 && i <= 255)
|
||||
return(i);
|
||||
else {
|
||||
asmerr(E_VALOUT);
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Die Funktion prueft einen Wert auf -128 < Wert < 128
|
||||
* Output: Wert wenn im Bereich, sonst 0 und Fehlermeldung
|
||||
*/
|
||||
chk_v2(i)
|
||||
register int i;
|
||||
{
|
||||
if (i >= -127 && i <= 127)
|
||||
return(i);
|
||||
else {
|
||||
asmerr(E_VALOUT);
|
||||
return(0);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* Z80 - Assembler
|
||||
* Copyright (C) 1987-1992 by Udo Munk
|
||||
*
|
||||
* History:
|
||||
* 17-SEP-1987 Development under Digital Research CP/M 2.2
|
||||
* 28-JUN-1988 Switched to Unix System V.3
|
||||
*/
|
||||
|
||||
/*
|
||||
* Diese Modul enthaelt die Op-Code-Tabelle. In ihr
|
||||
* sind fuer jeden Z80 Op-Code und alle Pseudo-Op-Codes
|
||||
* ausser END Eintraege vorhanden. Die Tabelle muss
|
||||
* aufsteigend nach den Op-Code-Namen sortiert sein !
|
||||
*
|
||||
* Die zweite Tabelle im Modul enthaelt die Namen aller
|
||||
* reservierten Operanden (Register, Registerpaare und Flags.
|
||||
* Sie muss ebenfalls nach den Namen sortiert sein !
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "z80a.h"
|
||||
|
||||
/*
|
||||
* Die Funktionen zur Codegenerierung der einzelnen
|
||||
* Op-Codes muessen forward deklariert werden:
|
||||
*/
|
||||
extern int op_1b(), op_2b(), op_pupo(), op_ex(), op_ld();
|
||||
extern int op_call(), op_ret(), op_jp(), op_jr(), op_djnz(), op_rst();
|
||||
extern int op_add(), op_adc(), op_sub(), op_sbc(), op_cp();
|
||||
extern int op_inc(), op_dec(), op_or(), op_xor(), op_and();
|
||||
extern int op_rl(), op_rr(), op_sla(), op_sra(), op_srl(), op_rlc(), op_rrc();
|
||||
extern int op_out(), op_in(), op_im();
|
||||
extern int op_set(), op_res(), op_bit();
|
||||
extern int op_org(), op_dl(), op_equ();
|
||||
extern int op_ds(), op_db(), op_dw(), op_dm();
|
||||
extern int op_misc();
|
||||
extern int op_cond();
|
||||
extern int op_glob();
|
||||
|
||||
struct opc opctab[] = {
|
||||
{ "ADC", op_adc, 0, 0 },
|
||||
{ "ADD", op_add, 0, 0 },
|
||||
{ "AND", op_and, 0, 0 },
|
||||
{ "BIT", op_bit, 0, 0 },
|
||||
{ "CALL", op_call, 0, 0 },
|
||||
{ "CCF", op_1b, 0x3f, 0 },
|
||||
{ "CP", op_cp, 0, 0 },
|
||||
{ "CPD", op_2b, 0xed, 0xa9 },
|
||||
{ "CPDR", op_2b, 0xed, 0xb9 },
|
||||
{ "CPI", op_2b, 0xed, 0xa1 },
|
||||
{ "CPIR", op_2b, 0xed, 0xb1 },
|
||||
{ "CPL", op_1b, 0x2f, 0 },
|
||||
{ "DAA", op_1b, 0x27, 0 },
|
||||
{ "DEC", op_dec, 0, 0 },
|
||||
{ "DEFB", op_db, 0, 0 },
|
||||
{ "DEFL", op_dl, 0, 0 },
|
||||
{ "DEFM", op_dm, 0, 0 },
|
||||
{ "DEFS", op_ds, 0, 0 },
|
||||
{ "DEFW", op_dw, 0, 0 },
|
||||
{ "DI", op_1b, 0xf3, 0 },
|
||||
{ "DJNZ", op_djnz, 0, 0 },
|
||||
{ "EI", op_1b, 0xfb, 0 },
|
||||
{ "EJECT", op_misc, 1, 0 },
|
||||
{ "ELSE", op_cond, 98, 0 },
|
||||
{ "ENDIF", op_cond, 99, 0 },
|
||||
{ "EQU", op_equ, 0, 0 },
|
||||
{ "EX", op_ex, 0, 0 },
|
||||
{ "EXTRN", op_glob, 1, 0 },
|
||||
{ "EXX", op_1b, 0xd9, 0 },
|
||||
{ "HALT", op_1b, 0x76, 0 },
|
||||
{ "IFDEF", op_cond, 1, 0 },
|
||||
{ "IFEQ", op_cond, 3, 0 },
|
||||
{ "IFNDEF", op_cond, 2, 0 },
|
||||
{ "IFNEQ", op_cond, 4, 0 },
|
||||
{ "IM", op_im, 0, 0 },
|
||||
{ "IN", op_in, 0, 0 },
|
||||
{ "INC", op_inc, 0, 0 },
|
||||
{ "INCLUDE", op_misc, 6, 0 },
|
||||
{ "IND", op_2b, 0xed, 0xaa },
|
||||
{ "INDR", op_2b, 0xed, 0xba },
|
||||
{ "INI", op_2b, 0xed, 0xa2 },
|
||||
{ "INIR", op_2b, 0xed, 0xb2 },
|
||||
{ "JP", op_jp, 0, 0 },
|
||||
{ "JR", op_jr, 0, 0 },
|
||||
{ "LD", op_ld, 0, 0 },
|
||||
{ "LDD", op_2b, 0xed, 0xa8 },
|
||||
{ "LDDR", op_2b, 0xed, 0xb8 },
|
||||
{ "LDI", op_2b, 0xed, 0xa0 },
|
||||
{ "LDIR", op_2b, 0xed, 0xb0 },
|
||||
{ "LIST", op_misc, 2, 0 },
|
||||
{ "NEG", op_2b, 0xed, 0x44 },
|
||||
{ "NOLIST", op_misc, 3, 0 },
|
||||
{ "NOP", op_1b, 0, 0 },
|
||||
{ "OR", op_or, 0, 0 },
|
||||
{ "ORG", op_org, 0, 0 },
|
||||
{ "OTDR", op_2b, 0xed, 0xbb },
|
||||
{ "OTIR", op_2b, 0xed, 0xb3 },
|
||||
{ "OUT", op_out, 0, 0 },
|
||||
{ "OUTD", op_2b, 0xed, 0xab },
|
||||
{ "OUTI", op_2b, 0xed, 0xa3 },
|
||||
{ "PAGE", op_misc, 4, 0 },
|
||||
{ "POP", op_pupo, 1, 0 },
|
||||
{ "PRINT", op_misc, 5, 0 },
|
||||
{ "PUBLIC", op_glob, 2, 0 },
|
||||
{ "PUSH", op_pupo, 2, 0 },
|
||||
{ "RES", op_res, 0, 0 },
|
||||
{ "RET", op_ret, 0, 0 },
|
||||
{ "RETI", op_2b, 0xed, 0x4d },
|
||||
{ "RETN", op_2b, 0xed, 0x45 },
|
||||
{ "RL", op_rl, 0, 0 },
|
||||
{ "RLA", op_1b, 0x17, 0 },
|
||||
{ "RLC", op_rlc, 0, 0 },
|
||||
{ "RLCA", op_1b, 0x07, 0 },
|
||||
{ "RLD", op_2b, 0xed, 0x6f },
|
||||
{ "RR", op_rr, 0, 0 },
|
||||
{ "RRA", op_1b, 0x1f, 0 },
|
||||
{ "RRC", op_rrc, 0, 0 },
|
||||
{ "RRCA", op_1b, 0x0f, 0 },
|
||||
{ "RRD", op_2b, 0xed, 0x67 },
|
||||
{ "RST", op_rst, 0, 0 },
|
||||
{ "SBC", op_sbc, 0, 0 },
|
||||
{ "SCF", op_1b, 0x37, 0 },
|
||||
{ "SET", op_set, 0, 0 },
|
||||
{ "SLA", op_sla, 0, 0 },
|
||||
{ "SRA", op_sra, 0, 0 },
|
||||
{ "SRL", op_srl, 0, 0 },
|
||||
{ "SUB", op_sub, 0, 0 },
|
||||
{ "TITLE", op_misc, 7, 0 },
|
||||
{ "XOR", op_xor, 0, 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
* Die Anzahl der Eintraege in der Op-Code Tabelle wird fuer die
|
||||
* Suchfunktion search_op() in der Variablen no_opcodes abgelegt.
|
||||
*/
|
||||
int no_opcodes = sizeof(opctab) / sizeof(struct opc);
|
||||
|
||||
struct ope opetab[] = {
|
||||
{ "(BC)", REGIBC },
|
||||
{ "(DE)", REGIDE },
|
||||
{ "(HL)", REGIHL },
|
||||
{ "(IX)", REGIIX },
|
||||
{ "(IY)", REGIIY },
|
||||
{ "(SP)", REGISP },
|
||||
{ "A", REGA },
|
||||
{ "AF", REGAF },
|
||||
{ "B", REGB },
|
||||
{ "BC", REGBC },
|
||||
{ "C", REGC },
|
||||
{ "D", REGD },
|
||||
{ "DE", REGDE },
|
||||
{ "E", REGE },
|
||||
{ "H", REGH },
|
||||
{ "HL", REGHL },
|
||||
{ "I", REGI },
|
||||
{ "IX", REGIX },
|
||||
{ "IY", REGIY },
|
||||
{ "L", REGL },
|
||||
{ "M", FLGM },
|
||||
{ "NC", FLGNC },
|
||||
{ "NZ", FLGNZ },
|
||||
{ "P", FLGP },
|
||||
{ "PE", FLGPE },
|
||||
{ "PO", FLGPO },
|
||||
{ "R", REGR },
|
||||
{ "SP", REGSP },
|
||||
{ "Z", FLGZ }
|
||||
};
|
||||
|
||||
/*
|
||||
* Hier wird ebenfalls die Anzahl der Tabelleneintraege
|
||||
* bekannt gemacht.
|
||||
*/
|
||||
int no_operands = sizeof(opetab) / sizeof(struct ope);
|
|
@ -0,0 +1,361 @@
|
|||
/*
|
||||
* Z80 - Assembler
|
||||
* Copyright (C) 1987-1992 by Udo Munk
|
||||
*
|
||||
* History:
|
||||
* 17-SEP-1987 Development under Digital Research CP/M 2.2
|
||||
* 28-JUN-1988 Switched to Unix System V.3
|
||||
*/
|
||||
|
||||
/*
|
||||
* Dieses Modul enthaelt alle Funktionen, die Output
|
||||
* ins List-, Object- und Fehlerfile erzeugen.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "z80a.h"
|
||||
#include "z80aglb.h"
|
||||
|
||||
static char *errmsg[] = { /* Fehlermeldungen fuer asmerr() */
|
||||
"illegal opcode", /* 0 */
|
||||
"illegal operand", /* 1 */
|
||||
"missing operand", /* 2 */
|
||||
"multiply defined symbol", /* 3 */
|
||||
"undefined symbol", /* 4 */
|
||||
"value out of range", /* 5 */
|
||||
"missing )", /* 6 */
|
||||
"missing string separator", /* 7 */
|
||||
"memory override", /* 8 */
|
||||
"missing IF", /* 9 */
|
||||
"IF nesting to deep", /* 10 */
|
||||
"missing ENDIF", /* 11 */
|
||||
"INCLUDE nesting to deep" /* 12 */
|
||||
};
|
||||
|
||||
#define MAXHEX 32 /* maximale Anzahl Bytes/Hex-Record */
|
||||
|
||||
static unsigned short hex_adr; /* aktuelle Adresse Hex-Record */
|
||||
static int hex_cnt; /* aktuelle Anzahl Bytes im Hex-Puffer */
|
||||
|
||||
static unsigned char hex_buf[MAXHEX]; /* Code-Puffer fuer einen Hex-Record */
|
||||
static char hex_out[MAXHEX*2+11]; /* ASCII-Puffer fuer einen Hex-Record */
|
||||
|
||||
/*
|
||||
* Fehlermeldungen auf den Fehlerkanal (Listfile oder stdout)
|
||||
* ausgeben und Fehlerzaehler erhoehen.
|
||||
*/
|
||||
asmerr(i)
|
||||
register int i;
|
||||
{
|
||||
if (pass == 1) {
|
||||
fprintf(errfp, "Error in file: %s Line: %d\n", srcfn, c_line);
|
||||
fprintf(errfp, errmsg[i]);
|
||||
fprintf(errfp, "\n\n");
|
||||
} else
|
||||
errnum = i;
|
||||
errors++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Die Funktion beginnt eine neue Seite in der Listdatei
|
||||
*/
|
||||
lst_header()
|
||||
{
|
||||
fprintf(lstfp, "\fZ80-Assembler\t\tRelease %s\t\t\t\tPage %d\n", REL, ++page);
|
||||
fprintf(lstfp, "Source file: %s\n", srcfn);
|
||||
fprintf(lstfp, "Title: %s\n", title);
|
||||
p_line = 3;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ueberschrift fuer die Quellzeilen erzeugen
|
||||
*/
|
||||
lst_attl()
|
||||
{
|
||||
fprintf(lstfp, "\nLOC OBJECT CODE LINE STMT SOURCE CODE\n");
|
||||
p_line += 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Eine Zeile in der Listdatei erzeugen,
|
||||
* wenn Option -l gegeben.
|
||||
*/
|
||||
lst_line(val, opanz)
|
||||
register int val, opanz;
|
||||
{
|
||||
register int i;
|
||||
|
||||
if (!list_flag || sd_flag == 4) {
|
||||
sd_flag = 0;
|
||||
return;
|
||||
}
|
||||
if ((p_line >= ppl) || (c_line == 1)) {
|
||||
lst_header();
|
||||
lst_attl();
|
||||
}
|
||||
switch (sd_flag) {
|
||||
case 0:
|
||||
fprintf(lstfp, "%04x ", val & 0xffff);
|
||||
break;
|
||||
case 1:
|
||||
fprintf(lstfp, "%04x ", sd_val & 0xffff);
|
||||
break;
|
||||
case 2:
|
||||
fprintf(lstfp, " ");
|
||||
break;
|
||||
case 3:
|
||||
fprintf(lstfp, "%04x ", sd_val & 0xffff);
|
||||
goto no_data;
|
||||
default:
|
||||
fatal(F_INTERN, "illegal listflag for function lst_line");
|
||||
break;
|
||||
}
|
||||
if (opanz >= 1) fprintf(lstfp, "%02x ", ops[0] & 0xff);
|
||||
else fprintf(lstfp, " ");
|
||||
if (opanz >= 2) fprintf(lstfp, "%02x ", ops[1] & 0xff);
|
||||
else fprintf(lstfp, " ");
|
||||
if (opanz >= 3) fprintf(lstfp, "%02x ", ops[2] & 0xff);
|
||||
else fprintf(lstfp, " ");
|
||||
if (opanz >= 4) fprintf(lstfp, "%02x ", ops[3] & 0xff);
|
||||
else fprintf(lstfp, " ");
|
||||
no_data:
|
||||
fprintf(lstfp, "%6d %6d %s", c_line, s_line, line);
|
||||
if (errnum) {
|
||||
fprintf(errfp, "=> %s", errmsg[errnum]);
|
||||
putc('\n', errfp);
|
||||
errnum = 0;
|
||||
p_line++;
|
||||
}
|
||||
sd_flag = 0;
|
||||
p_line++;
|
||||
if (opanz > 4 && sd_flag == 0) {
|
||||
opanz -= 4;
|
||||
i = 4;
|
||||
sd_val = val;
|
||||
while (opanz > 0) {
|
||||
if (p_line >= ppl) {
|
||||
lst_header();
|
||||
lst_attl();
|
||||
}
|
||||
s_line++;
|
||||
sd_val += 4;
|
||||
fprintf(lstfp, "%04x ", sd_val & 0xffff);
|
||||
if (opanz-- > 0) fprintf(lstfp, "%02x ", ops[i++] & 0xff);
|
||||
else fprintf(lstfp, " ");
|
||||
if (opanz-- > 0) fprintf(lstfp, "%02x ", ops[i++] & 0xff);
|
||||
else fprintf(lstfp, " ");
|
||||
if (opanz-- > 0) fprintf(lstfp, "%02x ", ops[i++] & 0xff);
|
||||
else fprintf(lstfp, " ");
|
||||
if (opanz-- > 0) fprintf(lstfp, "%02x ", ops[i++] & 0xff);
|
||||
else fprintf(lstfp, " ");
|
||||
fprintf(lstfp, "%6d %6d\n", c_line, s_line);
|
||||
p_line++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Symboltabelle ins Listfile in der gespeicherten
|
||||
* Reihenfolge direkt aus der Hash-Tabelle ausgeben
|
||||
*/
|
||||
lst_sym()
|
||||
{
|
||||
register int i, j;
|
||||
register struct sym *np;
|
||||
char *strcpy();
|
||||
|
||||
p_line = j = 0;
|
||||
strcpy(title,"Symboltable");
|
||||
for (i = 0; i < HASHSIZE; i++) {
|
||||
if (symtab[i] != NULL) {
|
||||
for (np = symtab[i]; np != NULL; np = np->sym_next) {
|
||||
if (p_line == 0) {
|
||||
lst_header();
|
||||
fputs("\n", lstfp);
|
||||
p_line += 1;
|
||||
}
|
||||
fprintf(lstfp, "%-8s %04x\t", np->sym_name,
|
||||
np->sym_wert & 0xffff);
|
||||
if (++j == 4) {
|
||||
fprintf(lstfp, "\n");
|
||||
if (p_line++ >= ppl)
|
||||
p_line = 0;
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Sortierte Symboltabelle ins Listfile ausgeben
|
||||
*/
|
||||
lst_sort_sym(len)
|
||||
register int len;
|
||||
{
|
||||
register int i, j;
|
||||
char *strcpy();
|
||||
|
||||
p_line = i = j = 0;
|
||||
strcpy(title, "Symboltable");
|
||||
while (i < len) {
|
||||
if (p_line == 0) {
|
||||
lst_header();
|
||||
fputs("\n", lstfp);
|
||||
p_line += 1;
|
||||
}
|
||||
fprintf(lstfp, "%-8s %04x\t", symarray[i]->sym_name,
|
||||
symarray[i]->sym_wert & 0xffff);
|
||||
if (++j == 4) {
|
||||
fprintf(lstfp, "\n");
|
||||
if (p_line++ >= ppl)
|
||||
p_line = 0;
|
||||
j = 0;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Header-Record ins Objectfile ausgeben
|
||||
*/
|
||||
obj_header()
|
||||
{
|
||||
switch (out_form) {
|
||||
case OUTBIN:
|
||||
break;
|
||||
case OUTMOS:
|
||||
putc(0xff, objfp);
|
||||
putc(prg_adr & 0xff, objfp);
|
||||
putc(prg_adr >> 8, objfp);
|
||||
break;
|
||||
case OUTHEX:
|
||||
hex_adr = prg_adr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Ende-Record ins Objectfile ausgeben
|
||||
*/
|
||||
obj_end()
|
||||
{
|
||||
switch (out_form) {
|
||||
case OUTBIN:
|
||||
break;
|
||||
case OUTMOS:
|
||||
break;
|
||||
case OUTHEX:
|
||||
flush_hex();
|
||||
fprintf(objfp, ":0000000000\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Op-Codes in ops[] ins Objectfile ausgeben
|
||||
*/
|
||||
obj_writeb(opanz)
|
||||
register int opanz;
|
||||
{
|
||||
register int i;
|
||||
|
||||
switch (out_form) {
|
||||
case OUTBIN:
|
||||
fwrite(ops, 1, opanz, objfp);
|
||||
break;
|
||||
case OUTMOS:
|
||||
fwrite(ops, 1, opanz, objfp);
|
||||
break;
|
||||
case OUTHEX:
|
||||
for (i = 0; opanz; opanz--) {
|
||||
if (hex_cnt >= MAXHEX)
|
||||
flush_hex();
|
||||
hex_buf[hex_cnt++] = ops[i++];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* <count> Bytes mit 0xff ins Objectfile ausgeben
|
||||
*/
|
||||
obj_fill(count)
|
||||
register int count;
|
||||
{
|
||||
switch (out_form) {
|
||||
case OUTBIN:
|
||||
while (count--)
|
||||
putc(0xff, objfp);
|
||||
break;
|
||||
case OUTMOS:
|
||||
while (count--)
|
||||
putc(0xff, objfp);
|
||||
break;
|
||||
case OUTHEX:
|
||||
flush_hex();
|
||||
hex_adr += count;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Einen Hex-Record in ASCII erzeugen und ausgeben
|
||||
*/
|
||||
flush_hex()
|
||||
{
|
||||
char *p;
|
||||
register int i;
|
||||
|
||||
if (!hex_cnt)
|
||||
return;
|
||||
p = hex_out;
|
||||
*p++ = ':';
|
||||
btoh((unsigned char) hex_cnt, &p);
|
||||
btoh((unsigned char) (hex_adr >> 8), &p);
|
||||
btoh((unsigned char) (hex_adr & 0xff), &p);
|
||||
*p++ = '0';
|
||||
*p++ = '0';
|
||||
for (i = 0; i < hex_cnt; i++)
|
||||
btoh(hex_buf[i], &p);
|
||||
btoh((unsigned char) chksum(), &p);
|
||||
*p++ = '\n';
|
||||
*p = '\0';
|
||||
fwrite(hex_out, 1, strlen(hex_out), objfp);
|
||||
hex_adr += hex_cnt;
|
||||
hex_cnt = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ein unsigned char in ASCII-Hex umwandeln und an Adresse,
|
||||
* auf die p zeigt, ablegen. Der Pointer p wird dann um
|
||||
* zwei erhoeht.
|
||||
*/
|
||||
btoh(byte, p)
|
||||
unsigned char byte;
|
||||
register char **p;
|
||||
{
|
||||
register unsigned char c;
|
||||
|
||||
c = byte >> 4;
|
||||
*(*p)++ = (c < 10) ? (c + '0') : (c - 10 + 'A');
|
||||
c = byte & 0xf;
|
||||
*(*p)++ = (c < 10) ? (c + '0') : (c - 10 + 'A');
|
||||
}
|
||||
|
||||
/*
|
||||
* Pruefsumme fuer einen Intel-Hex-Record berechnen
|
||||
*/
|
||||
chksum()
|
||||
{
|
||||
register int i, j, sum;
|
||||
|
||||
sum = hex_cnt;
|
||||
sum += hex_adr >> 8;
|
||||
sum += hex_adr & 0xff;
|
||||
for (i = 0; i < hex_cnt; i++) {
|
||||
j = hex_buf[i];
|
||||
sum += j & 0xff;
|
||||
}
|
||||
return (0x100 - (sum & 0xff));
|
||||
}
|
|
@ -0,0 +1,442 @@
|
|||
/*
|
||||
* Z80 - Assembler
|
||||
* Copyright (C) 1987-1992 by Udo Munk
|
||||
*
|
||||
* History:
|
||||
* 17-SEP-1987 Development under Digital Research CP/M 2.2
|
||||
* 28-JUN-1988 Switched to Unix System V.3
|
||||
*/
|
||||
|
||||
/*
|
||||
* Dieses Modul enthaelt die Funktionen zur Bearbeitung
|
||||
* aller Pseudo-Op-Codes
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include "z80a.h"
|
||||
#include "z80aglb.h"
|
||||
|
||||
/*
|
||||
* Diese Funktion behandelt den Pseudo-Op-Code ORG
|
||||
*/
|
||||
op_org()
|
||||
{
|
||||
register int i;
|
||||
|
||||
if (!gencode)
|
||||
return(0);
|
||||
i = eval(operand);
|
||||
if (i < pc) {
|
||||
asmerr(E_MEMOVR);
|
||||
return(0);
|
||||
}
|
||||
if (pass == 1) { /* PASS 1 */
|
||||
if (!prg_flag) {
|
||||
prg_adr = i;
|
||||
prg_flag++;
|
||||
}
|
||||
} else { /* PASS 2 */
|
||||
if (++prg_flag > 2)
|
||||
obj_fill(i - pc);
|
||||
sd_flag = 2;
|
||||
}
|
||||
pc = i;
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Diese Funktion behandelt den Pseudo-Op-Code EQU
|
||||
*/
|
||||
op_equ()
|
||||
{
|
||||
struct sym *get_sym();
|
||||
|
||||
if (!gencode)
|
||||
return(0);
|
||||
if (pass == 1) { /* Pass 1 */
|
||||
if (get_sym(label) == NULL) {
|
||||
sd_val = eval(operand);
|
||||
if (put_sym(label, sd_val))
|
||||
fatal(F_OUTMEM, "symbols");
|
||||
} else
|
||||
asmerr(E_MULSYM);
|
||||
} else { /* Pass 2 */
|
||||
sd_flag = 1;
|
||||
sd_val = eval(operand);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Diese Funktion behandelt den Pseudo-Op-Code DEFL
|
||||
*/
|
||||
op_dl()
|
||||
{
|
||||
if (!gencode)
|
||||
return(0);
|
||||
sd_flag = 1;
|
||||
sd_val = eval(operand);
|
||||
if (put_sym(label, sd_val))
|
||||
fatal(F_OUTMEM, "symbols");
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Diese Funktion behandelt den Pseudo-Op-Code DEFS
|
||||
*/
|
||||
op_ds()
|
||||
{
|
||||
register int val;
|
||||
|
||||
if (!gencode)
|
||||
return(0);
|
||||
if (pass == 1)
|
||||
if (*label)
|
||||
put_label();
|
||||
sd_val = pc;
|
||||
sd_flag = 3;
|
||||
val = eval(operand);
|
||||
if (pass == 2)
|
||||
obj_fill(val);
|
||||
pc += val;
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Diese Funktion behandelt den Pseudo-Op-Code DEFB
|
||||
*/
|
||||
op_db()
|
||||
{
|
||||
register int i;
|
||||
register char *p;
|
||||
register char *s;
|
||||
|
||||
if (!gencode)
|
||||
return(0);
|
||||
i = 0;
|
||||
p = operand;
|
||||
if (pass == 1)
|
||||
if (*label)
|
||||
put_label();
|
||||
while (*p) {
|
||||
if (*p == STRSEP) {
|
||||
p++;
|
||||
while (*p != STRSEP) {
|
||||
if (*p == '\n' || *p == '\0') {
|
||||
asmerr(E_MISHYP);
|
||||
goto hyp_error;
|
||||
}
|
||||
ops[i++] = *p++;
|
||||
if (i >= OPCARRAY)
|
||||
fatal(F_INTERN, "Op-Code buffer overflow");
|
||||
}
|
||||
p++;
|
||||
} else {
|
||||
s = tmp;
|
||||
while (*p != ',' && *p != '\0')
|
||||
*s++ = *p++;
|
||||
*s = '\0';
|
||||
ops[i++] = eval(tmp);
|
||||
if (i >= OPCARRAY)
|
||||
fatal(F_INTERN, "Op-Code buffer overflow");
|
||||
}
|
||||
if (*p == ',')
|
||||
p++;
|
||||
}
|
||||
hyp_error:
|
||||
return(i);
|
||||
}
|
||||
|
||||
/*
|
||||
* Diese Funktion behandelt den Pseudo-Op-Code DEFM
|
||||
*/
|
||||
op_dm()
|
||||
{
|
||||
register int i;
|
||||
register char *p;
|
||||
|
||||
if (!gencode)
|
||||
return(0);
|
||||
i = 0;
|
||||
p = operand;
|
||||
if (pass == 1)
|
||||
if (*label)
|
||||
put_label();
|
||||
if (*p != STRSEP) {
|
||||
asmerr(E_MISHYP);
|
||||
return(0);
|
||||
}
|
||||
p++;
|
||||
while (*p != STRSEP) {
|
||||
if (*p == '\n' || *p == '\0') {
|
||||
asmerr(E_MISHYP);
|
||||
break;
|
||||
}
|
||||
ops[i++] = *p++;
|
||||
if (i >= OPCARRAY)
|
||||
fatal(F_INTERN, "Op-Code buffer overflow");
|
||||
}
|
||||
return(i);
|
||||
}
|
||||
|
||||
/*
|
||||
* Diese Funktion behandelt den Pseudo-Op-Code DEFW
|
||||
*/
|
||||
op_dw()
|
||||
{
|
||||
register int i, len, temp;
|
||||
register char *p;
|
||||
register char *s;
|
||||
|
||||
if (!gencode)
|
||||
return(0);
|
||||
p = operand;
|
||||
i = len = 0;
|
||||
if (pass == 1)
|
||||
if (*label)
|
||||
put_label();
|
||||
while (*p) {
|
||||
s = tmp;
|
||||
while (*p != ',' && *p != '\0')
|
||||
*s++ = *p++;
|
||||
*s = '\0';
|
||||
if (pass == 2) {
|
||||
temp = eval(tmp);
|
||||
ops[i++] = temp & 0xff;
|
||||
ops[i++] = temp >> 8;
|
||||
if (i >= OPCARRAY)
|
||||
fatal(F_INTERN, "Op-Code buffer overflow");
|
||||
}
|
||||
len += 2;
|
||||
if (*p == ',')
|
||||
p++;
|
||||
}
|
||||
return(len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Diese Funktion behandelt die Pseudo-Op-Codes
|
||||
* EJECT, LIST, NOLIST, PAGE, PRINT, TITLE, INCLUDE
|
||||
*/
|
||||
op_misc(op_code, dummy)
|
||||
int op_code, dummy;
|
||||
{
|
||||
register char *p, *d;
|
||||
static char fn[LENFN];
|
||||
static int incnest;
|
||||
static struct inc incl[INCNEST];
|
||||
|
||||
if (!gencode)
|
||||
return(0);
|
||||
sd_flag = 2;
|
||||
switch(op_code) {
|
||||
case 1: /* EJECT */
|
||||
if (pass == 2)
|
||||
p_line = ppl;
|
||||
break;
|
||||
case 2: /* LIST */
|
||||
if (pass == 2)
|
||||
list_flag = 1;
|
||||
break;
|
||||
case 3: /* NOLIST */
|
||||
if (pass == 2)
|
||||
list_flag = 0;
|
||||
break;
|
||||
case 4: /* PAGE */
|
||||
if (pass == 2)
|
||||
ppl = eval(operand);
|
||||
break;
|
||||
case 5: /* PRINT */
|
||||
if (pass == 1) {
|
||||
p = operand;
|
||||
while (*p) {
|
||||
if (*p != STRSEP)
|
||||
putchar(*p++);
|
||||
else
|
||||
p++;
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
break;
|
||||
case 6: /* INCLUDE */
|
||||
if (incnest >= INCNEST) {
|
||||
asmerr(E_INCNEST);
|
||||
break;
|
||||
}
|
||||
incl[incnest].inc_line = c_line;
|
||||
incl[incnest].inc_fn = srcfn;
|
||||
incl[incnest].inc_fp = srcfp;
|
||||
incnest++;
|
||||
p = line;
|
||||
d = fn;
|
||||
while(isspace(*p)) /* white space bis INCLUDE ueberlesen */
|
||||
p++;
|
||||
while(!isspace(*p)) /* INCLUDE ueberlesen */
|
||||
p++;
|
||||
while(isspace(*p)) /* white space bis Filename ueberlesen */
|
||||
p++;
|
||||
while(!isspace(*p) && *p != COMMENT) /* Filename uebernehmen */
|
||||
*d++ = *p++;
|
||||
*d = '\0';
|
||||
if (pass == 1) { /* PASS 1 */
|
||||
if (!ver_flag)
|
||||
printf(" Include %s\n", fn);
|
||||
p1_file(fn);
|
||||
} else { /* PASS 2 */
|
||||
sd_flag = 2;
|
||||
lst_line(0, 0);
|
||||
if (!ver_flag)
|
||||
printf(" Include %s\n", fn);
|
||||
p2_file(fn);
|
||||
}
|
||||
incnest--;
|
||||
c_line = incl[incnest].inc_line;
|
||||
srcfn = incl[incnest].inc_fn;
|
||||
srcfp = incl[incnest].inc_fp;
|
||||
printf(" Resume %s\n", srcfn);
|
||||
if (list_flag && (pass == 2)) {
|
||||
lst_header();
|
||||
lst_attl();
|
||||
}
|
||||
sd_flag = 4;
|
||||
break;
|
||||
case 7: /* TITLE */
|
||||
if (pass == 2) {
|
||||
p = line;
|
||||
d = title;
|
||||
while (isspace(*p)) /* white space bis TITLE ueberlesen */
|
||||
p++;
|
||||
while (!isspace(*p)) /* TITLE ueberlesen */
|
||||
p++;
|
||||
while (isspace(*p)) /* white space bis Titel ueberlesen */
|
||||
p++;
|
||||
if (*p == STRSEP)
|
||||
p++;
|
||||
while (*p != '\n' && *p != STRSEP && *p != COMMENT)
|
||||
*d++ = *p++;
|
||||
*d = '\0';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fatal(F_INTERN, "illegal opcode for function op_misc");
|
||||
break;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Diese Funktion behandelt die Pseudo-Op-Codes
|
||||
* IFDEF, IFNDEF, IFEQ, IFNEQ, ELSE, ENDIF
|
||||
*/
|
||||
op_cond(op_code, dummy)
|
||||
int op_code, dummy;
|
||||
{
|
||||
register char *p, *p1, *p2;
|
||||
static int condnest[IFNEST];
|
||||
struct sym *get_sym();
|
||||
char *strchr();
|
||||
|
||||
switch(op_code) {
|
||||
case 1: /* IFDEF */
|
||||
if (iflevel >= IFNEST) {
|
||||
asmerr(E_IFNEST);
|
||||
break;
|
||||
}
|
||||
condnest[iflevel++] = gencode;
|
||||
if (gencode)
|
||||
if (get_sym(operand) == NULL)
|
||||
gencode = 0;
|
||||
break;
|
||||
case 2: /* IFNDEF */
|
||||
if (iflevel >= IFNEST) {
|
||||
asmerr(E_IFNEST);
|
||||
break;
|
||||
}
|
||||
condnest[iflevel++] = gencode;
|
||||
if (gencode)
|
||||
if (get_sym(operand) != NULL)
|
||||
gencode = 0;
|
||||
break;
|
||||
case 3: /* IFEQ */
|
||||
if (iflevel >= IFNEST) {
|
||||
asmerr(E_IFNEST);
|
||||
break;
|
||||
}
|
||||
condnest[iflevel++] = gencode;
|
||||
p = operand;
|
||||
if (!*p || !(p1 = strchr(operand, ','))) {
|
||||
asmerr(E_MISOPE);
|
||||
break;
|
||||
}
|
||||
if (gencode) {
|
||||
p2 = tmp;
|
||||
while (*p != ',')
|
||||
*p2++ = *p++;
|
||||
*p2 = '\0';
|
||||
if (eval(tmp) != eval(++p1))
|
||||
gencode = 0;
|
||||
}
|
||||
break;
|
||||
case 4: /* IFNEQ */
|
||||
if (iflevel >= IFNEST) {
|
||||
asmerr(E_IFNEST);
|
||||
break;
|
||||
}
|
||||
condnest[iflevel++] = gencode;
|
||||
p = operand;
|
||||
if (!*p || !(p1 = strchr(operand, ','))) {
|
||||
asmerr(E_MISOPE);
|
||||
break;
|
||||
}
|
||||
if (gencode) {
|
||||
p2 = tmp;
|
||||
while (*p != ',')
|
||||
*p2++ = *p++;
|
||||
*p2 = '\0';
|
||||
if (eval(tmp) == eval(++p1))
|
||||
gencode = 0;
|
||||
}
|
||||
break;
|
||||
case 98: /* ELSE */
|
||||
if (!iflevel)
|
||||
asmerr(E_MISIFF);
|
||||
else
|
||||
if ((iflevel == 0) || (condnest[iflevel - 1] == 1))
|
||||
gencode = !gencode;
|
||||
break;
|
||||
case 99: /* ENDIF */
|
||||
if (!iflevel)
|
||||
asmerr(E_MISIFF);
|
||||
else
|
||||
gencode = condnest[--iflevel];
|
||||
break;
|
||||
default:
|
||||
fatal(F_INTERN, "illegal opcode for function op_cond");
|
||||
break;
|
||||
}
|
||||
sd_flag = 2;
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Diese Funktion behandelt die Pseudo-Op-Codes
|
||||
* EXTRN und PUBLIC
|
||||
*/
|
||||
op_glob(op_code, dummy)
|
||||
int op_code, dummy;
|
||||
{
|
||||
if (!gencode)
|
||||
return(0);
|
||||
sd_flag = 2;
|
||||
switch(op_code) {
|
||||
case 1: /* EXTRN */
|
||||
break;
|
||||
case 2: /* PUBLIC */
|
||||
break;
|
||||
default:
|
||||
fatal(F_INTERN, "illegal opcode for function op_glob");
|
||||
break;
|
||||
}
|
||||
return(0);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,272 @@
|
|||
/*
|
||||
* Z80 - Assembler
|
||||
* Copyright (C) 1987-1992 by Udo Munk
|
||||
*
|
||||
* History:
|
||||
* 17-SEP-1987 Development under Digital Research CP/M 2.2
|
||||
* 28-JUN-1988 Switched to Unix System V.3
|
||||
*/
|
||||
|
||||
/*
|
||||
* Dieses Modul enthaelt alle Operationen, die die
|
||||
* Tabellen durchsuchen oder veraendern.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "z80a.h"
|
||||
#include "z80aglb.h"
|
||||
|
||||
/* Die folgende Funktion fuehrt die binaere Suche
|
||||
* in der alphabetisch sortierten OP-Code-Tabelle
|
||||
* 'opctab' aus.
|
||||
*
|
||||
* Input: Zeiger auf String mit dem OP-Code
|
||||
*
|
||||
* Output: Zeiger auf das Tabellenelement oder
|
||||
* einen NULL-Pointer, wenn OP-Code
|
||||
* nicht gefunden
|
||||
*/
|
||||
struct opc *search_op(op_name)
|
||||
register char *op_name;
|
||||
{
|
||||
register int cond;
|
||||
register struct opc *low, *high, *mid;
|
||||
|
||||
low = &opctab[0];
|
||||
high = &opctab[no_opcodes - 1];
|
||||
while (low <= high) {
|
||||
mid = low + (high - low) / 2;
|
||||
if ((cond = strcmp(op_name, mid->op_name)) < 0)
|
||||
high = mid - 1;
|
||||
else if (cond > 0)
|
||||
low = mid + 1;
|
||||
else
|
||||
return(mid);
|
||||
}
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/* Die folgende Funktion fuehrt die binaere Suche
|
||||
* in der alphabetisch sortierten Operanden-Tabelle
|
||||
* 'opetab' aus.
|
||||
*
|
||||
* Input: Zeiger auf String mit dem Operanden
|
||||
*
|
||||
* Output: Symbol fuer den Operanden
|
||||
* NOOPERA, wenn Operand leer ist
|
||||
* NOREG, wenn Operand nicht gefunden
|
||||
*/
|
||||
get_reg(s)
|
||||
register char *s;
|
||||
{
|
||||
register int cond;
|
||||
register struct ope *low, *high, *mid;
|
||||
|
||||
if (s == NULL || *s == '\0')
|
||||
return(NOOPERA);
|
||||
low = &opetab[0];
|
||||
high = &opetab[no_operands - 1];
|
||||
while (low <= high) {
|
||||
mid = low + (high - low) / 2;
|
||||
if ((cond = strcmp(s, mid->ope_name)) < 0)
|
||||
high = mid - 1;
|
||||
else if (cond > 0)
|
||||
low = mid + 1;
|
||||
else
|
||||
return(mid->ope_sym);
|
||||
}
|
||||
return(NOREG);
|
||||
}
|
||||
|
||||
/* Die folgende Funktion fuehrt die Suche in der Symboltabelle
|
||||
* 'symtab' durch. Dazu wird ein HASH-Algorithmus verwendet.
|
||||
*
|
||||
* Input: Zeiger auf String mit dem Symbol
|
||||
*
|
||||
* Output: Zeiger auf das Tabellenelement oder
|
||||
* einen NULL-Pointer, wenn Symbol
|
||||
* nicht gefunden
|
||||
*/
|
||||
struct sym *get_sym(sym_name)
|
||||
register char *sym_name;
|
||||
{
|
||||
register struct sym *np;
|
||||
|
||||
for (np = symtab[hash(sym_name)]; np != NULL; np = np->sym_next)
|
||||
if (strcmp(sym_name, np->sym_name) == 0)
|
||||
return(np);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/* Die folgende Funktion traegt ein Symbol in die Symboltabelle
|
||||
* 'symtab' ein. Ist das Symbol in der Tabelle noch nicht
|
||||
* vorhanden, wird es neu angelegt, sonst wird 'sym_wert'
|
||||
* in den vorhandenen Eintrag uebernommen.
|
||||
* Fuer die Symboltabellen-Zugriffe wird ein HASH-Algorithmus
|
||||
* verwendet.
|
||||
*
|
||||
* Input: sym_name Zeiger auf String mit dem Symbol
|
||||
* sym_wert Wert des Symbols
|
||||
*
|
||||
* Output: 0 = eingetragen
|
||||
* 1 = kein Speicherplatz mehr frei
|
||||
*/
|
||||
put_sym(sym_name, sym_wert)
|
||||
char *sym_name;
|
||||
int sym_wert;
|
||||
{
|
||||
char *strsave(), *malloc();
|
||||
struct sym *get_sym();
|
||||
register int hashval;
|
||||
register struct sym *np;
|
||||
|
||||
if (!gencode)
|
||||
return(0);
|
||||
if ((np = get_sym(sym_name)) == NULL) {
|
||||
np = (struct sym *) malloc(sizeof (struct sym));
|
||||
if (np == NULL)
|
||||
return(1);
|
||||
if ((np->sym_name = strsave(sym_name)) == NULL)
|
||||
return(1);
|
||||
hashval = hash(sym_name);
|
||||
np->sym_next = symtab[hashval];
|
||||
symtab[hashval] = np;
|
||||
}
|
||||
np->sym_wert = sym_wert;
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Diese Funktion traegt ein Label in die Symboltabelle ein.
|
||||
* Vorher wird geprueft, ob dieses Symbol bereits vorhanden
|
||||
* ist, was zu einer entsprechenden Fehlermeldung fuehrt.
|
||||
*/
|
||||
put_label()
|
||||
{
|
||||
struct sym *get_sym();
|
||||
|
||||
if (get_sym(label) == NULL) {
|
||||
if (put_sym(label, pc))
|
||||
fatal(F_OUTMEM, "symbols");
|
||||
} else
|
||||
asmerr(E_MULSYM);
|
||||
}
|
||||
|
||||
/* Hier folget der HASH-Algorithmus selbst.
|
||||
*
|
||||
* Input: Zeiger auf String mit dem Namen
|
||||
*
|
||||
* Output: HASH-Wert
|
||||
*/
|
||||
hash(name)
|
||||
register char *name;
|
||||
{
|
||||
register int hashval;
|
||||
|
||||
for (hashval = 0; *name;)
|
||||
hashval += *name++;
|
||||
return(hashval % HASHSIZE);
|
||||
}
|
||||
|
||||
/* Diese Funktion kopiert einen String auf einen
|
||||
* angeforderten Speicherplatz.
|
||||
*
|
||||
* Input: Zeiger auf den String
|
||||
*
|
||||
* Output: Zeiger auf den Speicherplatz
|
||||
*/
|
||||
char *strsave(s)
|
||||
register char *s;
|
||||
{
|
||||
char *malloc(), *strcpy();
|
||||
register char *p;
|
||||
|
||||
if ((p = malloc((unsigned) strlen(s)+1)) != NULL)
|
||||
strcpy(p, s);
|
||||
return(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Diese Funktion kopiert alle Eintraege aus der
|
||||
* Symbol-Hashtabelle in ein dynamisch erzeugtes
|
||||
* Pointer-Array
|
||||
*/
|
||||
copy_sym()
|
||||
{
|
||||
char *malloc(), *realloc();
|
||||
register int i, j;
|
||||
register struct sym *np;
|
||||
|
||||
symarray = (struct sym **) malloc(SYMINC * sizeof(struct sym *));
|
||||
if (symarray == NULL)
|
||||
fatal(F_OUTMEM, "sorting symbol table");
|
||||
symsize = SYMINC;
|
||||
for (i = 0, j = 0; i < HASHSIZE; i++) {
|
||||
if (symtab[i] != NULL) {
|
||||
for (np = symtab[i]; np != NULL; np = np->sym_next) {
|
||||
symarray[j++] = np;
|
||||
if (j == symsize) {
|
||||
symarray = (struct sym **) realloc((char *) symarray, symsize * sizeof(struct sym *) + SYMINC * sizeof(struct sym *));
|
||||
if (symarray == NULL)
|
||||
fatal(F_OUTMEM, "sorting symbol table");
|
||||
symsize += SYMINC;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return(j);
|
||||
}
|
||||
|
||||
/*
|
||||
* Symboltabelle nach Namen sortieren
|
||||
*/
|
||||
n_sort_sym(len)
|
||||
register int len;
|
||||
{
|
||||
register int gap, i, j;
|
||||
register struct sym *temp;
|
||||
|
||||
for (gap = len/2; gap > 0; gap /= 2)
|
||||
for (i = gap; i < len; i++)
|
||||
for (j = i-gap; j >= 0; j -= gap) {
|
||||
if (strcmp(symarray[j]->sym_name, symarray[j+gap]->sym_name) <= 0)
|
||||
break;
|
||||
temp = symarray[j];
|
||||
symarray[j] = symarray[j+gap];
|
||||
symarray[j+gap] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Symboltabelle nach Adressen sortieren
|
||||
*/
|
||||
a_sort_sym(len)
|
||||
register int len;
|
||||
{
|
||||
register int gap, i, j;
|
||||
register struct sym *temp;
|
||||
|
||||
for (gap = len/2; gap > 0; gap /= 2)
|
||||
for (i = gap; i < len; i++)
|
||||
for (j = i-gap; j >= 0; j -= gap) {
|
||||
if (numcmp(symarray[j]->sym_wert, symarray[j+gap]->sym_wert) <= 0)
|
||||
break;
|
||||
temp = symarray[j];
|
||||
symarray[j] = symarray[j+gap];
|
||||
symarray[j+gap] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Vergleicht zwei 16-Bit Werte, Ergebnis wie strcmp
|
||||
*/
|
||||
numcmp(n1, n2)
|
||||
register int n1, n2;
|
||||
{
|
||||
if ((unsigned) (n1 & 0xffff) < (unsigned) (n2 & 0xffff))
|
||||
return(-1);
|
||||
else if ((unsigned) (n1 & 0xffff) > (unsigned) (n2 & 0xffff))
|
||||
return(1);
|
||||
else
|
||||
return(0);
|
||||
}
|
Loading…
Reference in New Issue