mirror of
https://github.com/open-simh/simtools.git
synced 2026-01-26 04:01:44 +00:00
Add 'crossassemblers/macro11/' from commit '2a14ffe2519589011ffc4050d5d4fd6591fb4c3c'
git-subtree-dir: crossassemblers/macro11 git-subtree-mainline:fc2c8875cagit-subtree-split:2a14ffe251command was: git subtree add --prefix=crossassemblers/macro11 git://github.com/Rhialto/macro11.git master
This commit is contained in:
45
crossassemblers/macro11/.indent.pro
vendored
Executable file
45
crossassemblers/macro11/.indent.pro
vendored
Executable file
@@ -0,0 +1,45 @@
|
||||
--blank-lines-after-commas
|
||||
--blank-lines-after-declarations
|
||||
--blank-lines-after-procedures
|
||||
--braces-on-if-line
|
||||
--braces-on-struct-decl-line
|
||||
--break-before-boolean-operator
|
||||
--break-function-decl-args
|
||||
--break-function-decl-args-end
|
||||
--case-indentation0
|
||||
--comment-indentation40
|
||||
--continuation-indentation8
|
||||
--continue-at-parentheses
|
||||
--cuddle-do-while
|
||||
--cuddle-else
|
||||
--declaration-indentation16
|
||||
--dont-break-procedure-type
|
||||
--dont-format-comments
|
||||
--indent-level4
|
||||
--honour-newlines
|
||||
--leave-optional-blank-lines
|
||||
--line-comments-indentation0
|
||||
--line-length112
|
||||
--no-blank-lines-before-block-comments
|
||||
--no-space-after-function-call-names
|
||||
--no-tabs
|
||||
--paren-indentation4
|
||||
--space-special-semicolon
|
||||
--tab-size8
|
||||
-T ADDR_MODE
|
||||
-T ARG
|
||||
-T BUFFER
|
||||
-T EX_TREE
|
||||
-T FILE
|
||||
-T MACRO
|
||||
-T MACRO_STREAM
|
||||
-T MLB
|
||||
-T MLBENT
|
||||
-T STACK
|
||||
-T STREAM
|
||||
-T SECTION
|
||||
-T SYMBOL
|
||||
-T SYMBOL_ITER
|
||||
-T SYMBOL_TABLE
|
||||
-T TEXT_COMPLEX
|
||||
-T TEXT_RLD
|
||||
51
crossassemblers/macro11/CHANGES
Normal file
51
crossassemblers/macro11/CHANGES
Normal file
@@ -0,0 +1,51 @@
|
||||
09.11.2015: Rhialto
|
||||
version 0.4:
|
||||
- Fixed various bugs. The most notable was extensive use-
|
||||
after-free in the expression tree, which crashed on NetBSD but
|
||||
apparently not on other systems.
|
||||
- Lots of changes to make this MACRO11 more like the MACRO11 of
|
||||
RSX-11M+ 4.6. I used Kermit-11 source files for comparison.
|
||||
"The Manual" I'm refering to is
|
||||
AA-KX10A-TC_PDP-11_MACRO-11_Reference_Manual_May88.pdf at
|
||||
www.bitsavers.org/pdf/dec/pdp11/rsx11/RSX11Mplus_V4.x/4a/ and
|
||||
I use an installed system to double-check.
|
||||
|
||||
----------- Joerg Hoppe's entries ------------------
|
||||
|
||||
19.4.2009: JH
|
||||
version 0.3
|
||||
- bugfix: Illegal labels and illegal opcodes are processed as
|
||||
"implied .WORD" directives.
|
||||
Expression errors in "do_word()" did not process any input character,
|
||||
so parser did go into an endless loop.
|
||||
- Switchable syntax extensions with -yxx options:
|
||||
symbol len can be adjusted with "-ysl" command line option.
|
||||
"-yus" option allows underscore "_" char in symbols.
|
||||
This was needed to process code generated by my favorite disassembler.
|
||||
- command line help added (-h option)
|
||||
|
||||
17.4.2009: JH
|
||||
version 0.3
|
||||
- ".INCLUDE" re-enabled
|
||||
- refactoring: big 6000+ lines "macro11.c" split into 10 modules.
|
||||
|
||||
15.4.2009: JH
|
||||
Begin rework by Joerg Hoppe (j_hoppe@t-online.de)
|
||||
All my changes are marked with "/*JH: .. */" comments
|
||||
|
||||
|
||||
----------- Richard Krebiehls entries ------------------
|
||||
|
||||
|
||||
15-July-2001
|
||||
version 0.2
|
||||
removed references to snprintf from dumpobj.c and
|
||||
mlb.c for portability
|
||||
fixed a type cast warning in dumpobj.c compare_gsdlines
|
||||
Removed strcasecmp from macro11.c for portability
|
||||
Removed references to wnewmem.c from makefile (isn't needed)
|
||||
makefile more compatible with non-gnu make and compiler
|
||||
main prints version 0.2
|
||||
|
||||
14-July-2001
|
||||
First release, version 0.1.
|
||||
30
crossassemblers/macro11/LICENSE
Normal file
30
crossassemblers/macro11/LICENSE
Normal file
@@ -0,0 +1,30 @@
|
||||
Copyright (c) 2001, Richard Krehbiel
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
o Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
o Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
o Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
82
crossassemblers/macro11/Makefile
Normal file
82
crossassemblers/macro11/Makefile
Normal file
@@ -0,0 +1,82 @@
|
||||
#####
|
||||
#
|
||||
# Makefile for macro11 and dumpobj
|
||||
#
|
||||
|
||||
WARNS ?= -Wall -Wshadow -Wextra -pedantic -Woverflow -Wstrict-overflow
|
||||
CFLAGS ?= -O -ggdb -std=gnu99 $(WARNS)
|
||||
|
||||
MACRO11_SRCS = macro11.c \
|
||||
assemble.c assemble_globals.c assemble_aux.c \
|
||||
extree.c listing.c macros.c parse.c rept_irpc.c symbols.c \
|
||||
mlb-rsx.c object.c stream2.c util.c rad50.c
|
||||
|
||||
MACRO11_OBJS = $(MACRO11_SRCS:.c=.o)
|
||||
|
||||
DUMPOBJ_SRCS = dumpobj.c rad50.c
|
||||
|
||||
DUMPOBJ_OBJS = $(DUMPOBJ_SRCS:.c=.o)
|
||||
|
||||
ALL_SRCS = $(MACRO11_SRCS) $(DUMPOBJ_SRCS)
|
||||
|
||||
all: macro11 dumpobj
|
||||
|
||||
tags: macro11 dumpobj
|
||||
ctags *.c *.h
|
||||
|
||||
macro11: git-info.h $(MACRO11_OBJS) Makefile
|
||||
$(CC) $(CFLAGS) -o macro11 $(MACRO11_OBJS) -lm
|
||||
|
||||
dumpobj: $(DUMPOBJ_OBJS) Makefile
|
||||
$(CC) $(CFLAGS) -o dumpobj $(DUMPOBJ_OBJS)
|
||||
|
||||
$(MACRO11_OBJS): Makefile
|
||||
$(DUMPOBJ_OBJS): Makefile
|
||||
|
||||
git-info.h:
|
||||
./make-git-info
|
||||
|
||||
# Bootstrap dependency on the git header file, which otherwise
|
||||
# gets generated too late.
|
||||
macro11.o: git-info.h
|
||||
|
||||
clean:
|
||||
-rm -f $(MACRO11_OBJS) $(DUMPOBJ_OBJS) macro11 dumpobj
|
||||
-rm -f *.d
|
||||
-rm -f git-info.h
|
||||
|
||||
# Since the only tests we have so far are for crashes,
|
||||
# just try to assemble. Later, we will need expected/actual tests.
|
||||
|
||||
# Test that all options requiring a value bail out if it's not present.
|
||||
argtests: macro11
|
||||
@ for OPT in -e -d -m -p -o -l -ysl ; do \
|
||||
./macro11 foo.mac $$OPT 2> /dev/null; \
|
||||
if (( $$? == 1 )); then echo PASS; else echo FAIL; fi; \
|
||||
echo " $$OPT missing value"; \
|
||||
./macro11 foo.mac $$OPT -v 2> /dev/null; \
|
||||
if (( $$? == 1 )); then echo PASS; else echo FAIL; fi; \
|
||||
echo " $$OPT fol. by option"; \
|
||||
done
|
||||
@ ./macro11 foo.mac $$OPT -x -v 2> /dev/null; \
|
||||
if (( $$? == 1 )); then echo PASS; else echo FAIL; fi; \
|
||||
echo " -x must be the last option"
|
||||
|
||||
tests: macro11 argtests
|
||||
@ ACTUAL=`./macro11 tests/test-undef.mac 2>&1`; \
|
||||
if [ "tests/test-undef.mac:1: ***ERROR MACRO .TTYOU not found" == "$$ACTUAL" ]; then echo PASS; else echo FAIL; fi; \
|
||||
echo " test-undef.mac"
|
||||
|
||||
# Automatic dependency generation
|
||||
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
-include $(ALL_SRCS:.c=.d)
|
||||
endif
|
||||
|
||||
# Make .d files as side effect of compiling .c to .o
|
||||
%.d %.o: %.c
|
||||
$(CC) $(CFLAGS) -c -o $*.o $<
|
||||
@set -e; rm -f $*.d; \
|
||||
$(CC) -MM $(CPPFLAGS) $< > $@.$$$$; \
|
||||
sed 's,\($*\)\.o[ :]*,\1.o \1.d : ,g' < $@.$$$$ > $*.d; \
|
||||
rm -f $@.$$$$
|
||||
169
crossassemblers/macro11/README
Normal file
169
crossassemblers/macro11/README
Normal file
@@ -0,0 +1,169 @@
|
||||
A MACRO-11 assembler for the PDP-11 in portable C source code.
|
||||
|
||||
Copyright (c) 2001, Richard Krehbiel
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
o Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
o Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
o Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
|
||||
modified 2009 by Joerg Hoppe,
|
||||
modified 2015 by Olaf 'Rhialto' Seibert.
|
||||
|
||||
Files:
|
||||
macro11.c Command line parsing and driving the passes.
|
||||
assemble.c Handles all of the opcodes and directives.
|
||||
assemble_aux.c Helper functions mostly called from assemble().
|
||||
assemble_globals.c Global variables for assemble().
|
||||
extree.c Expression tree: memory management and evaluation.
|
||||
listing.c Listing generation.
|
||||
macros.c Define macros and make them available as stream2s.
|
||||
parse.c Basic parsing for numbers, labels, strings, expressions
|
||||
rept_irpc.c stream2 subclass for processing .REPT and .IREPT.
|
||||
object.c Functions for writing RSX-11 compatible .OBJ files.
|
||||
mlb-rsx.c Classes (!) for reading RSX-11 macro libraries.
|
||||
mlb.c Classes (!) for reading RT-11 macro libraries.
|
||||
stream2.c Functions for managing input streams and buffers.
|
||||
rad50.c Functions for converting text to and from RAD50.
|
||||
util.c A few general utility fuctions.
|
||||
|
||||
macro11.h, object.h, mlb.h, stream2.h, rad50.h, util.h
|
||||
types and symbols exported from the associated sources.
|
||||
|
||||
dumpobj.c A program I wrote to examine the output from
|
||||
RT-11's MACRO.SAV program and compare it with my
|
||||
own output.
|
||||
|
||||
Makefile A GNU makefile for Linux; simple enough, it
|
||||
should be convertible to any Unix.
|
||||
Contains automatic dependency generation.
|
||||
|
||||
macro11.dsp, dumpobj.dsp, macro11.dsw
|
||||
Visual Studio 6 projects. Out of date.
|
||||
|
||||
README This file
|
||||
|
||||
LICENSE The copyright notice and license
|
||||
|
||||
CHANGES A list of changes from previous versions
|
||||
|
||||
TODO A list of things that may need fixing
|
||||
|
||||
|
||||
Notes:
|
||||
|
||||
Sorry, I am a believer in 4 column hardware tabs, for a number of
|
||||
reasons, mostly regarding editing convenience. (I did untabify this
|
||||
README file though.)
|
||||
|
||||
The bulk of Richard's development was done in Microsoft Visual Studio 6,
|
||||
but currently Olaf maintains it using a Unix (NetBSD) system. I build
|
||||
with gcc and a lot of warning options, and from time to time check with
|
||||
a Linux system which has a different gcc version, and clang. The Visual
|
||||
Studio project files are out of date.
|
||||
|
||||
Richard used the MACRO11 from RT-11 as reference, but I use the one
|
||||
from RSX-11M+. It turns out there are some small file format
|
||||
differences. I used the dumpobj command to compare the output of this
|
||||
macro11 with the reference version when assembling Kermit-11 source
|
||||
files, and currently there seem to be no significant differences.
|
||||
|
||||
The macro11 command line:
|
||||
|
||||
macro11 [options...] files...
|
||||
|
||||
Options:
|
||||
-v Prints program version.
|
||||
|
||||
-e opt .ENABL option. Implemented options are AMA, GBL,
|
||||
and also .LIST options ME, BEX, and
|
||||
MD, though the status of listing control is
|
||||
presently very poor.
|
||||
|
||||
-d opt .DSABL option; same options as -e.
|
||||
|
||||
-m macname Gives a macro library name.
|
||||
Up to 32 macro libraries may be specified, one per
|
||||
-m option.
|
||||
Note: unlike MACRO.SAV, SYSMAC.SML is not
|
||||
automatically included; you must name it.
|
||||
|
||||
-p macpath For any .MCALL <macro> directive, macro11 will
|
||||
first search -m macro libraries, then it will
|
||||
search the MCALL path for a file named <macro>.MAC
|
||||
to locate the body of the macro. The MCALL path
|
||||
is an environment variable containing directory
|
||||
names separated by delimiters (":" for Unix-style
|
||||
targets; ";" for Windows). The -p command line
|
||||
options appends a directory name to the MCALL
|
||||
path.
|
||||
|
||||
-I incpath For any .INCLUDE <file> directive, macro11 will
|
||||
search the INCLUDE path for a file named <file>
|
||||
to include. The INCLUDE path works like the MCALL
|
||||
path. If not specified at all, the default is the
|
||||
current directory. If <file> contains a drive
|
||||
and/or directory in RSX/RT-11 form
|
||||
(DEV:[DIR]FILE.EXT) then the search is also tried
|
||||
without DEV: and without DEV:[DIR].
|
||||
|
||||
-o objname Gives the name of the object file. No extension
|
||||
is assumed; if you want .OBJ you have to say it.
|
||||
With no -o option, no object file is generated.
|
||||
|
||||
-l lstname Gives the name of a listing file. The name "-"
|
||||
may be given to write the listing to stdout. No
|
||||
extension is assumed; if you want .LST you have to
|
||||
say it. With no -l option, no listing file is
|
||||
written.
|
||||
|
||||
-x Tells macro11 not to assemble anything, but rather
|
||||
to simply extract all the macros in all the -m
|
||||
macro libraries into individual .MAC files in the
|
||||
current directory. This should be the last option
|
||||
given, as none following will be processed.
|
||||
This also works for extracting an object library
|
||||
(.OLB) file.
|
||||
|
||||
Various options starting with -y enable extensions:
|
||||
|
||||
-ysl <num> Allow longer symbols up to the given length.
|
||||
The maximal allowed value is 64.
|
||||
|
||||
-yus Allow underscore in symbol names.
|
||||
|
||||
-yl1 Include the processing of the first pass in the
|
||||
listing file. This may be useful for finding
|
||||
phase errors.
|
||||
|
||||
files... Any number of input files. They will be assembled
|
||||
as if they were concatenated together.
|
||||
|
||||
|
||||
You may define the MCALL and INCLUDE environment variable prior to
|
||||
invoking macro11, as a path to directories containing macros or files to
|
||||
be included, respectively.
|
||||
63
crossassemblers/macro11/TODO
Normal file
63
crossassemblers/macro11/TODO
Normal file
@@ -0,0 +1,63 @@
|
||||
|
||||
listing format errors: ignore whitespace of input
|
||||
|
||||
documentation: print supported directives
|
||||
|
||||
---------------------------------------
|
||||
I was not able to locate a Macro-11 language reference manual any more
|
||||
recent than for RT11 version *3*, so I used that plus my recollection
|
||||
of more modern features. It was enough to get the RT11 V5.4 kernel
|
||||
built, plus a significant chunk of our own code.
|
||||
|
||||
The biggest missing feature is full featured listings. The .LIST and
|
||||
.NLIST directives are ignored, as is .SBTTL. No table of contents is
|
||||
accumulated or printed. No symbol cross referencing is done (most
|
||||
likely I'll just write a CTAGS file, not a cross reference listing).
|
||||
|
||||
Many errors still go unchecked. Off the top of my head, I recall that
|
||||
object and listing file output errors are ignored.
|
||||
|
||||
.FLT4 format may be inaccurate in the low bits. This is because IEEE
|
||||
64 bit format has two fewer mantissa bits than 64 bit PDP-11 format.
|
||||
Without writing soft-float routines, there's not much I can do abbout
|
||||
it.
|
||||
|
||||
Expression math is done in native width, almost certainly 32 bits.
|
||||
Truncation to 16 bits is done only for listing and output. This may
|
||||
make some output differ in the presence of 16-bit overflows and
|
||||
underflows. I don't think this needs fixing.
|
||||
|
||||
.REM blocks containing code can screw up .MACRO, .REPT, .IRP, .IRPC.
|
||||
read_body in macro11.c would need to be able to parse and ignore .REM
|
||||
blocks.
|
||||
|
||||
Need to search a path for the .INCLUDE directive. Right now it only
|
||||
takes a complete file name. And most likely, existing code will have
|
||||
RT-11 style file names; I don't know what to do about that, except put
|
||||
in a device name parser.
|
||||
|
||||
Possible enhancements:
|
||||
|
||||
It would be very simple to make macro11 resolve internal symbols with
|
||||
more that 6 significant characters. Even so, only the first 6 would
|
||||
be used for external symbols, and you have to be wary of existing code
|
||||
that used (for example) .LOOKU rather than .LOOKUP, since these two
|
||||
would become distinct.
|
||||
|
||||
SYM = 0
|
||||
MOV SYM(R0),R0 ; macro11 could optimize SYM(R0) into just (R0)
|
||||
|
||||
I dream of automatically fixing branches out of range. Easy when the
|
||||
destination is backwards, difficult when it's forwards. I have this
|
||||
idea: during the first assembly pass, all branches generate a long
|
||||
branch if the target symbol is undefined, otherwise an "optimized"
|
||||
branch (short or long) if the target is defined. Then keep a
|
||||
128-instruction FIFO of generated instructions. Each FIFO entry is
|
||||
tagged with context and symbol definition as they are pushed to the
|
||||
FIFO. When an instruction gets pulled from the FIFO because it's more
|
||||
than 128 words away, the FIFO is searched for long branches that point
|
||||
to this location; any such are shortened, and any symbols defined
|
||||
following their location in the stream are adjusted. In the second
|
||||
assembly pass, the FIFOs aren't used because all jump distances are
|
||||
known, and the right sized branch (JMP or Bcc) can be generated.
|
||||
|
||||
1652
crossassemblers/macro11/assemble.c
Normal file
1652
crossassemblers/macro11/assemble.c
Normal file
File diff suppressed because it is too large
Load Diff
19
crossassemblers/macro11/assemble.h
Normal file
19
crossassemblers/macro11/assemble.h
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
#ifndef ASSEMBLE__H
|
||||
#define ASSEMBLE__H
|
||||
|
||||
|
||||
#include "stream2.h"
|
||||
#include "object.h"
|
||||
|
||||
|
||||
|
||||
#define DOT (current_pc->value) /* Handy reference to the current location */
|
||||
|
||||
int assemble_stack(
|
||||
STACK *stack,
|
||||
TEXT_RLD *tr);
|
||||
int get_next_lsb(
|
||||
void);
|
||||
|
||||
#endif
|
||||
777
crossassemblers/macro11/assemble_aux.c
Normal file
777
crossassemblers/macro11/assemble_aux.c
Normal file
@@ -0,0 +1,777 @@
|
||||
|
||||
/*
|
||||
Smaller operators for assemble
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#include "assemble_aux.h" /* my own definitions */
|
||||
|
||||
#include "assemble_globals.h"
|
||||
#include "macros.h"
|
||||
#include "assemble.h"
|
||||
#include "listing.h"
|
||||
#include "symbols.h"
|
||||
#include "parse.h"
|
||||
|
||||
|
||||
/* Allocate a new section */
|
||||
|
||||
SECTION *new_section(
|
||||
void)
|
||||
{
|
||||
SECTION *sect = memcheck(malloc(sizeof(SECTION)));
|
||||
|
||||
sect->flags = 0;
|
||||
sect->size = 0;
|
||||
sect->pc = 0;
|
||||
sect->type = 0;
|
||||
sect->sector = 0;
|
||||
sect->label = NULL;
|
||||
return sect;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* This is called by places that are about to store some code, or
|
||||
which want to manually update DOT. */
|
||||
|
||||
void change_dot(
|
||||
TEXT_RLD *tr,
|
||||
int size)
|
||||
{
|
||||
if (size > 0) {
|
||||
if (last_dot_section != current_pc->section) {
|
||||
text_define_location(tr, current_pc->section->label, ¤t_pc->value);
|
||||
last_dot_section = current_pc->section;
|
||||
last_dot_addr = current_pc->value;
|
||||
}
|
||||
if (last_dot_addr != current_pc->value) {
|
||||
text_modify_location(tr, ¤t_pc->value);
|
||||
last_dot_addr = current_pc->value;
|
||||
}
|
||||
|
||||
/* Update for next time */
|
||||
last_dot_addr += size;
|
||||
}
|
||||
|
||||
if (DOT + size > current_pc->section->size)
|
||||
current_pc->section->size = DOT + size;
|
||||
}
|
||||
|
||||
/* store_word stores a word to the object file and lists it to the
|
||||
listing file */
|
||||
|
||||
int store_word(
|
||||
STREAM *str,
|
||||
TEXT_RLD *tr,
|
||||
int size,
|
||||
unsigned word)
|
||||
{
|
||||
change_dot(tr, size);
|
||||
list_word(str, DOT, word, size, "");
|
||||
return text_word(tr, &DOT, size, word);
|
||||
}
|
||||
|
||||
/* store_word stores a word to the object file and lists it to the
|
||||
listing file */
|
||||
|
||||
static int store_displaced_word(
|
||||
STREAM *str,
|
||||
TEXT_RLD *tr,
|
||||
int size,
|
||||
unsigned word)
|
||||
{
|
||||
change_dot(tr, size);
|
||||
list_word(str, DOT, word, size, "'");
|
||||
return text_displaced_word(tr, &DOT, size, word);
|
||||
}
|
||||
|
||||
static int store_global_displaced_offset_word(
|
||||
STREAM *str,
|
||||
TEXT_RLD *tr,
|
||||
int size,
|
||||
unsigned word,
|
||||
char *global)
|
||||
{
|
||||
change_dot(tr, size);
|
||||
list_word(str, DOT, word, size, "G");
|
||||
return text_global_displaced_offset_word(tr, &DOT, size, word, global);
|
||||
}
|
||||
|
||||
static int store_global_offset_word(
|
||||
STREAM *str,
|
||||
TEXT_RLD *tr,
|
||||
int size,
|
||||
unsigned word,
|
||||
char *global)
|
||||
{
|
||||
change_dot(tr, size);
|
||||
list_word(str, DOT, word, size, "G");
|
||||
return text_global_offset_word(tr, &DOT, size, word, global);
|
||||
}
|
||||
|
||||
static int store_internal_word(
|
||||
STREAM *str,
|
||||
TEXT_RLD *tr,
|
||||
int size,
|
||||
unsigned word)
|
||||
{
|
||||
change_dot(tr, size);
|
||||
list_word(str, DOT, word, size, "'");
|
||||
return text_internal_word(tr, &DOT, size, word);
|
||||
}
|
||||
|
||||
static int store_psect_displaced_offset_word(
|
||||
STREAM *str,
|
||||
TEXT_RLD *tr,
|
||||
int size,
|
||||
unsigned word,
|
||||
char *name)
|
||||
{
|
||||
change_dot(tr, size);
|
||||
list_word(str, DOT, word, size, "'");
|
||||
return text_psect_displaced_offset_word(tr, &DOT, size, word, name);
|
||||
}
|
||||
|
||||
static int store_psect_offset_word(
|
||||
STREAM *str,
|
||||
TEXT_RLD *tr,
|
||||
int size,
|
||||
unsigned word,
|
||||
char *name)
|
||||
{
|
||||
change_dot(tr, size);
|
||||
list_word(str, DOT, word, size, "'");
|
||||
return text_psect_offset_word(tr, &DOT, size, word, name);
|
||||
}
|
||||
|
||||
int store_limits(
|
||||
STREAM *str,
|
||||
TEXT_RLD *tr)
|
||||
{
|
||||
change_dot(tr, 4);
|
||||
list_word(str, DOT, 0, 2, "");
|
||||
list_word(str, DOT + 2, 0, 2, "");
|
||||
return text_limits(tr, &DOT);
|
||||
}
|
||||
|
||||
|
||||
/* free_addr_mode frees the storage consumed by an addr_mode */
|
||||
|
||||
void free_addr_mode(
|
||||
ADDR_MODE *mode)
|
||||
{
|
||||
if (mode->offset)
|
||||
free_tree(mode->offset);
|
||||
mode->offset = NULL;
|
||||
}
|
||||
|
||||
/* Get the register indicated by the expression */
|
||||
|
||||
unsigned get_register(
|
||||
EX_TREE *expr)
|
||||
{
|
||||
unsigned reg;
|
||||
|
||||
if (expr->type == EX_LIT && expr->data.lit <= 7) {
|
||||
reg = expr->data.lit;
|
||||
return reg;
|
||||
}
|
||||
|
||||
if (expr->type == EX_SYM && expr->data.symbol->section->type == SECTION_REGISTER) {
|
||||
reg = expr->data.symbol->value;
|
||||
return reg;
|
||||
}
|
||||
|
||||
return NO_REG;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
implicit_gbl is a self-recursive routine that adds undefined symbols
|
||||
to the "implicit globals" symbol table.
|
||||
*/
|
||||
|
||||
void implicit_gbl(
|
||||
EX_TREE *value)
|
||||
{
|
||||
if (pass)
|
||||
return; /* Only do this in first pass */
|
||||
|
||||
if (!enabl_gbl)
|
||||
return; /* Option not enabled, don't do it. */
|
||||
|
||||
switch (value->type) {
|
||||
case EX_UNDEFINED_SYM:
|
||||
{
|
||||
if (!(value->data.symbol->flags & SYMBOLFLAG_LOCAL)) { /* Unless it's a
|
||||
local symbol, */
|
||||
add_sym(value->data.symbol->label, 0, SYMBOLFLAG_GLOBAL, &absolute_section, &implicit_st);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EX_LIT:
|
||||
case EX_SYM:
|
||||
case EX_TEMP_SYM: // Impossible on this pass
|
||||
return;
|
||||
case EX_ADD:
|
||||
case EX_SUB:
|
||||
case EX_MUL:
|
||||
case EX_DIV:
|
||||
case EX_AND:
|
||||
case EX_OR:
|
||||
implicit_gbl(value->data.child.right);
|
||||
/* falls into... */
|
||||
case EX_COM:
|
||||
case EX_NEG:
|
||||
implicit_gbl(value->data.child.left);
|
||||
break;
|
||||
case EX_ERR:
|
||||
if (value->data.child.left)
|
||||
implicit_gbl(value->data.child.left);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Done between the first and second passes */
|
||||
/* Migrates the symbols from the "implicit" table into the main table. */
|
||||
|
||||
void migrate_implicit(
|
||||
void)
|
||||
{
|
||||
SYMBOL_ITER iter;
|
||||
SYMBOL *isym,
|
||||
*sym;
|
||||
|
||||
for (isym = first_sym(&implicit_st, &iter); isym != NULL; isym = next_sym(&implicit_st, &iter)) {
|
||||
sym = lookup_sym(isym->label, &symbol_st);
|
||||
if (sym) {
|
||||
continue; // It's already in there. Great.
|
||||
}
|
||||
isym->flags |= SYMBOLFLAG_IMPLICIT_GLOBAL;
|
||||
sym = add_sym(isym->label, isym->value, isym->flags, isym->section, &symbol_st);
|
||||
// Just one other thing - migrate the stmtno
|
||||
sym->stmtno = isym->stmtno;
|
||||
}
|
||||
}
|
||||
|
||||
int express_sym_offset(
|
||||
EX_TREE *value,
|
||||
SYMBOL **sym,
|
||||
unsigned *offset)
|
||||
{
|
||||
implicit_gbl(value); /* Translate tree's undefined syms
|
||||
into global syms */
|
||||
|
||||
/* Internally relocatable symbols will have been summed down into
|
||||
EX_TEMP_SYM's. */
|
||||
|
||||
if (value->type == EX_SYM || value->type == EX_TEMP_SYM) {
|
||||
*sym = value->data.symbol;
|
||||
*offset = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* What remains is external symbols. */
|
||||
|
||||
if (value->type == EX_ADD) {
|
||||
EX_TREE *left = value->data.child.left;
|
||||
EX_TREE *right = value->data.child.right;
|
||||
|
||||
if ((left->type != EX_SYM && left->type != EX_UNDEFINED_SYM) || right->type != EX_LIT)
|
||||
return 0; /* Failed. */
|
||||
*sym = left->data.symbol;
|
||||
*offset = right->data.lit;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (value->type == EX_SUB) {
|
||||
EX_TREE *left = value->data.child.left;
|
||||
EX_TREE *right = value->data.child.right;
|
||||
|
||||
if ((left->type != EX_SYM && left->type != EX_UNDEFINED_SYM) || right->type != EX_LIT)
|
||||
return 0; /* Failed. */
|
||||
*sym = left->data.symbol;
|
||||
*offset = (unsigned) -(int) (right->data.lit);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Translate an EX_TREE into a TEXT_COMPLEX suitable for encoding
|
||||
into the object file. */
|
||||
|
||||
int complex_tree(
|
||||
TEXT_COMPLEX *tx,
|
||||
EX_TREE *tree)
|
||||
{
|
||||
switch (tree->type) {
|
||||
case EX_LIT:
|
||||
text_complex_lit(tx, tree->data.lit);
|
||||
return 1;
|
||||
|
||||
case EX_TEMP_SYM:
|
||||
case EX_SYM:
|
||||
{
|
||||
SYMBOL *sym = tree->data.symbol;
|
||||
|
||||
if ((sym->flags & (SYMBOLFLAG_GLOBAL | SYMBOLFLAG_DEFINITION)) == SYMBOLFLAG_GLOBAL) {
|
||||
text_complex_global(tx, sym->label);
|
||||
} else {
|
||||
text_complex_psect(tx, sym->section->sector, sym->value);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
|
||||
case EX_COM:
|
||||
if (!complex_tree(tx, tree->data.child.left))
|
||||
return 0;
|
||||
text_complex_com(tx);
|
||||
return 1;
|
||||
|
||||
case EX_NEG:
|
||||
if (!complex_tree(tx, tree->data.child.left))
|
||||
return 0;
|
||||
text_complex_neg(tx);
|
||||
return 1;
|
||||
|
||||
case EX_ADD:
|
||||
if (!complex_tree(tx, tree->data.child.left))
|
||||
return 0;
|
||||
if (!complex_tree(tx, tree->data.child.right))
|
||||
return 0;
|
||||
text_complex_add(tx);
|
||||
return 1;
|
||||
|
||||
case EX_SUB:
|
||||
if (!complex_tree(tx, tree->data.child.left))
|
||||
return 0;
|
||||
if (!complex_tree(tx, tree->data.child.right))
|
||||
return 0;
|
||||
text_complex_sub(tx);
|
||||
return 1;
|
||||
|
||||
case EX_MUL:
|
||||
if (!complex_tree(tx, tree->data.child.left))
|
||||
return 0;
|
||||
if (!complex_tree(tx, tree->data.child.right))
|
||||
return 0;
|
||||
text_complex_mul(tx);
|
||||
return 1;
|
||||
|
||||
case EX_DIV:
|
||||
if (!complex_tree(tx, tree->data.child.left))
|
||||
return 0;
|
||||
if (!complex_tree(tx, tree->data.child.right))
|
||||
return 0;
|
||||
text_complex_div(tx);
|
||||
return 1;
|
||||
|
||||
case EX_AND:
|
||||
if (!complex_tree(tx, tree->data.child.left))
|
||||
return 0;
|
||||
if (!complex_tree(tx, tree->data.child.right))
|
||||
return 0;
|
||||
text_complex_and(tx);
|
||||
return 1;
|
||||
|
||||
case EX_OR:
|
||||
if (!complex_tree(tx, tree->data.child.left))
|
||||
return 0;
|
||||
if (!complex_tree(tx, tree->data.child.right))
|
||||
return 0;
|
||||
text_complex_or(tx);
|
||||
return 1;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* store a word which is represented by a complex expression. */
|
||||
|
||||
static void store_complex(
|
||||
STREAM *refstr,
|
||||
TEXT_RLD *tr,
|
||||
int size,
|
||||
EX_TREE *value)
|
||||
{
|
||||
TEXT_COMPLEX tx;
|
||||
|
||||
change_dot(tr, size); /* About to store - update DOT */
|
||||
|
||||
implicit_gbl(value); /* Turn undefined symbols into globals */
|
||||
|
||||
text_complex_begin(&tx); /* Open complex expression */
|
||||
|
||||
if (!complex_tree(&tx, value)) { /* Translate */
|
||||
report(refstr, "Invalid expression\n");
|
||||
store_word(refstr, tr, size, 0);
|
||||
} else {
|
||||
list_word(refstr, DOT, 0, size, "C");
|
||||
text_complex_commit(tr, &DOT, size, &tx, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* store_complex_displaced is the same as store_complex but uses the
|
||||
"displaced" RLD code */
|
||||
|
||||
static void store_complex_displaced(
|
||||
STREAM *refstr,
|
||||
TEXT_RLD *tr,
|
||||
int size,
|
||||
EX_TREE *value)
|
||||
{
|
||||
TEXT_COMPLEX tx;
|
||||
|
||||
change_dot(tr, size);
|
||||
|
||||
implicit_gbl(value); /* Turn undefined symbols into globals */
|
||||
|
||||
text_complex_begin(&tx);
|
||||
|
||||
if (!complex_tree(&tx, value)) {
|
||||
report(refstr, "Invalid expression\n");
|
||||
store_word(refstr, tr, size, 0);
|
||||
} else {
|
||||
list_word(refstr, DOT, 0, size, "C");
|
||||
text_complex_commit_displaced(tr, &DOT, size, &tx, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
mode_extension - writes the extension word required by an addressing
|
||||
mode */
|
||||
|
||||
void mode_extension(
|
||||
TEXT_RLD *tr,
|
||||
ADDR_MODE *mode,
|
||||
STREAM *str)
|
||||
{
|
||||
EX_TREE *value = mode->offset;
|
||||
SYMBOL *sym;
|
||||
unsigned offset;
|
||||
|
||||
/* Also frees the mode. */
|
||||
|
||||
if (value == NULL) {
|
||||
free_addr_mode(mode);
|
||||
return;
|
||||
}
|
||||
|
||||
if (value->type == EX_LIT) {
|
||||
if (mode->rel) /* PC-relative? */
|
||||
store_displaced_word(str, tr, 2, value->data.lit);
|
||||
else
|
||||
store_word(str, tr, 2, value->data.lit); /* Just a
|
||||
known
|
||||
value. */
|
||||
} else if (express_sym_offset(value, &sym, &offset)) {
|
||||
if ((sym->flags & (SYMBOLFLAG_GLOBAL | SYMBOLFLAG_DEFINITION)) == SYMBOLFLAG_GLOBAL) {
|
||||
/* Reference to a global symbol. */
|
||||
/* Global symbol plus offset */
|
||||
if (mode->rel)
|
||||
store_global_displaced_offset_word(str, tr, 2, offset, sym->label);
|
||||
else
|
||||
store_global_offset_word(str, tr, 2, offset, sym->label);
|
||||
} else {
|
||||
/* Relative to non-external symbol. */
|
||||
if (current_pc->section == sym->section) {
|
||||
/* In the same section */
|
||||
if (mode->rel) {
|
||||
/* I can compute this myself. */
|
||||
store_word(str, tr, 2, sym->value + offset - DOT - 2);
|
||||
} else
|
||||
store_internal_word(str, tr, 2, sym->value + offset);
|
||||
} else {
|
||||
/* In a different section */
|
||||
if (mode->rel)
|
||||
store_psect_displaced_offset_word(str, tr, 2, sym->value + offset, sym->section->label);
|
||||
else
|
||||
store_psect_offset_word(str, tr, 2, sym->value + offset, sym->section->label);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Complex relocation */
|
||||
|
||||
if (mode->rel)
|
||||
store_complex_displaced(str, tr, 2, mode->offset);
|
||||
else
|
||||
store_complex(str, tr, 2, mode->offset);
|
||||
}
|
||||
|
||||
free_addr_mode(mode);
|
||||
}
|
||||
|
||||
/* eval_defined - take an EX_TREE and returns TRUE if the tree
|
||||
represents "defined" symbols. */
|
||||
|
||||
int eval_defined(
|
||||
EX_TREE *value)
|
||||
{
|
||||
switch (value->type) {
|
||||
case EX_LIT:
|
||||
return 1;
|
||||
case EX_SYM:
|
||||
return 1;
|
||||
case EX_UNDEFINED_SYM:
|
||||
return 0;
|
||||
case EX_AND:
|
||||
return eval_defined(value->data.child.left) && eval_defined(value->data.child.right);
|
||||
case EX_OR:
|
||||
return eval_defined(value->data.child.left) || eval_defined(value->data.child.right);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* eval_undefined - take an EX_TREE and returns TRUE if it represents
|
||||
"undefined" symbols. */
|
||||
|
||||
int eval_undefined(
|
||||
EX_TREE *value)
|
||||
{
|
||||
switch (value->type) {
|
||||
case EX_UNDEFINED_SYM:
|
||||
return 1;
|
||||
case EX_SYM:
|
||||
return 0;
|
||||
case EX_AND:
|
||||
return eval_undefined(value->data.child.left) && eval_undefined(value->data.child.right);
|
||||
case EX_OR:
|
||||
return eval_undefined(value->data.child.left) || eval_undefined(value->data.child.right);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* push_cond - a new conditional (.IF) block has been activated. Push
|
||||
it's context. */
|
||||
|
||||
void push_cond(
|
||||
int ok,
|
||||
STREAM *str)
|
||||
{
|
||||
last_cond++;
|
||||
assert(last_cond < MAX_CONDS);
|
||||
conds[last_cond].ok = ok;
|
||||
conds[last_cond].file = memcheck(strdup(str->name));
|
||||
conds[last_cond].line = str->line;
|
||||
}
|
||||
|
||||
/*
|
||||
pop_cond - pop stacked conditionals. */
|
||||
|
||||
void pop_cond(
|
||||
int to)
|
||||
{
|
||||
while (last_cond > to) {
|
||||
free(conds[last_cond].file);
|
||||
last_cond--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* go_section - sets current_pc to a new program section */
|
||||
|
||||
void go_section(
|
||||
TEXT_RLD *tr,
|
||||
SECTION *sect)
|
||||
{
|
||||
(void)tr;
|
||||
|
||||
if (current_pc->section == sect)
|
||||
return; /* This is too easy */
|
||||
|
||||
/* save current PC value for old section */
|
||||
current_pc->section->pc = DOT;
|
||||
|
||||
/* Set current section and PC value */
|
||||
current_pc->section = sect;
|
||||
DOT = sect->pc;
|
||||
}
|
||||
|
||||
/*
|
||||
store_value - used to store a value represented by an expression
|
||||
tree into the object file. Used by do_word and .ASCII/.ASCIZ.
|
||||
*/
|
||||
|
||||
void store_value(
|
||||
STACK *stack,
|
||||
TEXT_RLD *tr,
|
||||
int size,
|
||||
EX_TREE *value)
|
||||
{
|
||||
SYMBOL *sym;
|
||||
unsigned offset;
|
||||
|
||||
implicit_gbl(value); /* turn undefined symbols into globals */
|
||||
|
||||
if (value->type == EX_LIT) {
|
||||
store_word(stack->top, tr, size, value->data.lit);
|
||||
} else if (!express_sym_offset(value, &sym, &offset)) {
|
||||
store_complex(stack->top, tr, size, value);
|
||||
} else {
|
||||
if ((sym->flags & (SYMBOLFLAG_GLOBAL | SYMBOLFLAG_DEFINITION)) == SYMBOLFLAG_GLOBAL) {
|
||||
store_global_offset_word(stack->top, tr, size, sym->value + offset, sym->label);
|
||||
} else if (sym->section != current_pc->section) {
|
||||
store_psect_offset_word(stack->top, tr, size, sym->value + offset, sym->section->label);
|
||||
} else {
|
||||
store_internal_word(stack->top, tr, size, sym->value + offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* do_word - used by .WORD, .BYTE, and implied .WORD. */
|
||||
|
||||
int do_word(
|
||||
STACK *stack,
|
||||
TEXT_RLD *tr,
|
||||
char *cp,
|
||||
int size)
|
||||
{
|
||||
int comma;
|
||||
|
||||
if (size == 2 && (DOT & 1)) {
|
||||
report(stack->top, ".WORD on odd boundary\n");
|
||||
store_word(stack->top, tr, 1, 0); /* Align it */
|
||||
}
|
||||
|
||||
cp = skipwhite(cp);
|
||||
|
||||
do {
|
||||
if (cp[0] == ',') {
|
||||
/* Empty expressions count as 0 */
|
||||
store_word(stack->top, tr, size, 0);
|
||||
} else {
|
||||
EX_TREE *value = parse_expr(cp, 0);
|
||||
|
||||
if (value->cp > cp) {
|
||||
store_value(stack, tr, size, value);
|
||||
|
||||
cp = value->cp;
|
||||
} else {
|
||||
report(stack->top, "Invalid expression in .WORD\n");
|
||||
cp = ""; /* force loop to end */
|
||||
}
|
||||
|
||||
free_tree(value);
|
||||
}
|
||||
} while (cp = skipdelim_comma(cp, &comma), !EOL(*cp));
|
||||
|
||||
if (comma) {
|
||||
/* Trailing empty expressions count as 0 */
|
||||
store_word(stack->top, tr, size, 0);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
check_branch - check branch distance.
|
||||
*/
|
||||
|
||||
int check_branch(
|
||||
STACK *stack,
|
||||
unsigned offset,
|
||||
int min,
|
||||
int max)
|
||||
{
|
||||
int s_offset;
|
||||
|
||||
/* Sign-extend */
|
||||
if (offset & 0100000)
|
||||
s_offset = offset | ~0177777;
|
||||
else
|
||||
s_offset = offset & 077777;
|
||||
if (s_offset > max || s_offset < min) {
|
||||
char temp[16];
|
||||
|
||||
/* printf can't do signed octal. */
|
||||
my_ltoa(s_offset, temp, 8);
|
||||
report(stack->top, "Branch target out of range (distance=%s)\n", temp);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* write_globals writes out the GSD prior to the second assembly pass */
|
||||
|
||||
void write_globals(
|
||||
FILE *obj)
|
||||
{
|
||||
GSD gsd;
|
||||
SYMBOL *sym;
|
||||
SECTION *psect;
|
||||
SYMBOL_ITER sym_iter;
|
||||
int isect;
|
||||
|
||||
if (obj == NULL) {
|
||||
for (isect = 0; isect < sector; isect++) {
|
||||
psect = sections[isect];
|
||||
|
||||
psect->sector = isect; /* Assign it a sector */
|
||||
psect->pc = 0; /* Reset its PC for second pass */
|
||||
}
|
||||
return; /* Nothing more to do if no OBJ file. */
|
||||
}
|
||||
|
||||
gsd_init(&gsd, obj);
|
||||
|
||||
gsd_mod(&gsd, module_name);
|
||||
|
||||
if (ident)
|
||||
gsd_ident(&gsd, ident);
|
||||
|
||||
/* write out each PSECT with it's global stuff */
|
||||
/* Sections must be written out in the order that they
|
||||
appear in the assembly file. */
|
||||
for (isect = 0; isect < sector; isect++) {
|
||||
psect = sections[isect];
|
||||
|
||||
gsd_psect(&gsd, psect->label, psect->flags, psect->size);
|
||||
psect->sector = isect; /* Assign it a sector */
|
||||
psect->pc = 0; /* Reset its PC for second pass */
|
||||
|
||||
sym = first_sym(&symbol_st, &sym_iter);
|
||||
while (sym) {
|
||||
if ((sym->flags & SYMBOLFLAG_GLOBAL) && sym->section == psect) {
|
||||
gsd_global(&gsd, sym->label,
|
||||
(sym->
|
||||
flags & SYMBOLFLAG_DEFINITION ? GLOBAL_DEF : 0) | ((sym->
|
||||
flags & SYMBOLFLAG_WEAK) ?
|
||||
GLOBAL_WEAK : 0)
|
||||
| ((sym->section->flags & PSECT_REL) ? GLOBAL_REL : 0) | 0100,
|
||||
/* Looks undefined, but add it in anyway */
|
||||
sym->value);
|
||||
}
|
||||
sym = next_sym(&symbol_st, &sym_iter);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now write out the transfer address */
|
||||
if (xfer_address->type == EX_LIT) {
|
||||
gsd_xfer(&gsd, ". ABS.", xfer_address->data.lit);
|
||||
} else {
|
||||
SYMBOL *lsym;
|
||||
unsigned offset;
|
||||
|
||||
if (!express_sym_offset(xfer_address, &lsym, &offset)) {
|
||||
report(NULL, "Illegal program transfer address\n");
|
||||
} else {
|
||||
gsd_xfer(&gsd, lsym->section->label, lsym->value + offset);
|
||||
}
|
||||
}
|
||||
|
||||
gsd_flush(&gsd);
|
||||
|
||||
gsd_end(&gsd);
|
||||
}
|
||||
91
crossassemblers/macro11/assemble_aux.h
Normal file
91
crossassemblers/macro11/assemble_aux.h
Normal file
@@ -0,0 +1,91 @@
|
||||
|
||||
#ifndef ASSEMBLE_AUX__H
|
||||
#define ASSEMBLE_AUX__H
|
||||
|
||||
#include "stream2.h"
|
||||
#include "object.h"
|
||||
#include "extree.h"
|
||||
|
||||
#define NO_REG 0777
|
||||
|
||||
|
||||
typedef struct addr_mode {
|
||||
unsigned type; /* The bits that represent the addressing mode */
|
||||
/* bits 0:2 are register number */
|
||||
/* bit 3 is indirect */
|
||||
/* bits 4:6 are mode, where 0=Rn, 1=(Rn)+,
|
||||
2=-(Rn), 3=offset(Rn) */
|
||||
int rel; /* the addressing mode is PC-relative */
|
||||
EX_TREE *offset; /* Expression giving the offset */
|
||||
} ADDR_MODE;
|
||||
|
||||
void push_cond(
|
||||
int ok,
|
||||
STREAM *str);
|
||||
void pop_cond(
|
||||
int to);
|
||||
|
||||
int express_sym_offset(
|
||||
EX_TREE *value,
|
||||
SYMBOL **sym,
|
||||
unsigned *offset);
|
||||
|
||||
void change_dot(
|
||||
TEXT_RLD *tr,
|
||||
int size);
|
||||
|
||||
int store_word(
|
||||
STREAM *str,
|
||||
TEXT_RLD *tr,
|
||||
int size,
|
||||
unsigned word);
|
||||
int store_limits(
|
||||
STREAM *str,
|
||||
TEXT_RLD *tr);
|
||||
void store_value(
|
||||
STACK *stack,
|
||||
TEXT_RLD *tr,
|
||||
int size,
|
||||
EX_TREE *value);
|
||||
|
||||
int do_word(
|
||||
STACK *stack,
|
||||
TEXT_RLD *tr,
|
||||
char *cp,
|
||||
int size);
|
||||
|
||||
SECTION *new_section(
|
||||
void);
|
||||
void go_section(
|
||||
TEXT_RLD *tr,
|
||||
SECTION *sect);
|
||||
|
||||
void free_addr_mode(
|
||||
ADDR_MODE *mode);
|
||||
|
||||
int eval_defined(
|
||||
EX_TREE *value);
|
||||
int eval_undefined(
|
||||
EX_TREE *value);
|
||||
|
||||
|
||||
void mode_extension(
|
||||
TEXT_RLD *tr,
|
||||
ADDR_MODE *mode,
|
||||
STREAM *str);
|
||||
int check_branch(
|
||||
STACK *stack,
|
||||
unsigned offset,
|
||||
int min,
|
||||
int max);
|
||||
unsigned get_register(
|
||||
EX_TREE *expr);
|
||||
|
||||
void write_globals(
|
||||
FILE *obj);
|
||||
void migrate_implicit(
|
||||
void);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
101
crossassemblers/macro11/assemble_globals.c
Normal file
101
crossassemblers/macro11/assemble_globals.c
Normal file
@@ -0,0 +1,101 @@
|
||||
|
||||
#define ASSEMBLE_GLOBALS__C
|
||||
|
||||
|
||||
#include "assemble_globals.h" /* own definitions */
|
||||
|
||||
#include "object.h"
|
||||
|
||||
|
||||
/* GLOBAL VARIABLES */
|
||||
int pass = 0; /* The current assembly pass. 0 = first pass */
|
||||
int stmtno = 0; /* The current source line number */
|
||||
int radix = 8; /* The current input conversion radix */
|
||||
|
||||
|
||||
int lsb = 0; /* The current local symbol section identifier */
|
||||
int lsb_used = 0; /* Whether there was a local symbol using this lsb */
|
||||
int next_lsb = 0; /* The number of the next local symbol block */
|
||||
int last_macro_lsb = 0; /* The last block in which a macro
|
||||
automatic label was created */
|
||||
|
||||
int last_locsym = 32768; /* The last local symbol number generated */
|
||||
|
||||
|
||||
int enabl_debug = 0; /* Whether assembler debugging is enabled */
|
||||
|
||||
int enabl_ama = 0; /* When set, chooses absolute (037) versus
|
||||
PC-relative */
|
||||
/* (067) addressing mode */
|
||||
int enabl_lsb = 0; /* When set, stops non-local symbol
|
||||
definitions from delimiting local
|
||||
symbol sections. */
|
||||
|
||||
int enabl_gbl = 1; /* Implicit definition of global symbols */
|
||||
|
||||
int enabl_lc = 1; /* If lowercase disabled, convert assembler
|
||||
source to upper case. */
|
||||
|
||||
int suppressed = 0; /* Assembly suppressed by failed conditional */
|
||||
|
||||
|
||||
MLB *mlbs[MAX_MLBS]; /* macro libraries specified on the
|
||||
command line */
|
||||
int nr_mlbs = 0; /* Number of macro libraries */
|
||||
|
||||
COND conds[MAX_CONDS]; /* Stack of recent conditions */
|
||||
int last_cond; /* 0 means no stacked cond. */
|
||||
|
||||
SECTION *sect_stack[SECT_STACK_SIZE]; /* 32 saved sections */
|
||||
int dot_stack[SECT_STACK_SIZE]; /* 32 saved sections */
|
||||
int sect_sp; /* Stack pointer */
|
||||
|
||||
char *module_name = NULL; /* The module name (taken from the 'TITLE'); */
|
||||
|
||||
char *ident = NULL; /* .IDENT name */
|
||||
|
||||
EX_TREE *xfer_address = NULL; /* The transfer address */
|
||||
|
||||
SYMBOL *current_pc; /* The current program counter */
|
||||
|
||||
unsigned last_dot_addr; /* Last coded PC... */
|
||||
SECTION *last_dot_section; /* ...and it's program section */
|
||||
|
||||
/* The following are dummy psects for symbols which have meaning to
|
||||
the assembler: */
|
||||
|
||||
SECTION register_section = {
|
||||
"", SECTION_REGISTER, 0, 0, 0, 0
|
||||
}; /* the section containing the registers */
|
||||
|
||||
SECTION pseudo_section = {
|
||||
"", SECTION_PSEUDO, 0, 0, 0, 0
|
||||
}; /* the section containing the
|
||||
pseudo-operations */
|
||||
|
||||
SECTION instruction_section = {
|
||||
". ABS.", SECTION_INSTRUCTION, 0, 0, 0, 0
|
||||
}; /* the section containing instructions */
|
||||
|
||||
SECTION macro_section = {
|
||||
"", SECTION_SYSTEM, 0, 0, 0, 0
|
||||
}; /* Section for macros */
|
||||
|
||||
/* These are real psects that get written out to the object file */
|
||||
|
||||
SECTION absolute_section = {
|
||||
". ABS.", SECTION_SYSTEM, PSECT_GBL | PSECT_COM, 0, 0, 0
|
||||
}; /* The default
|
||||
absolute section */
|
||||
|
||||
SECTION blank_section = {
|
||||
"", SECTION_SYSTEM, PSECT_REL, 0, 0, 1
|
||||
}; /* The default relocatable section */
|
||||
|
||||
SECTION *sections[256] = {
|
||||
/* Array of sections in the order they were
|
||||
defined */
|
||||
&absolute_section, &blank_section,
|
||||
};
|
||||
|
||||
int sector = 2; /* number of such sections */
|
||||
88
crossassemblers/macro11/assemble_globals.h
Normal file
88
crossassemblers/macro11/assemble_globals.h
Normal file
@@ -0,0 +1,88 @@
|
||||
|
||||
#ifndef ASSEMBLE_GLOBALS__H
|
||||
#define ASSEMBLE_GLOBALS__H
|
||||
|
||||
|
||||
#include "mlb.h"
|
||||
#include "symbols.h"
|
||||
#include "extree.h"
|
||||
|
||||
|
||||
|
||||
#define MAX_MLBS 32 /* number of macro libraries */
|
||||
|
||||
#define MAX_CONDS 256
|
||||
typedef struct cond {
|
||||
int ok; /* What the condition evaluated to */
|
||||
char *file; /* What file and line it occurred */
|
||||
int line;
|
||||
} COND;
|
||||
|
||||
#define SECT_STACK_SIZE 32
|
||||
|
||||
#ifndef ASSEMBLE_GLOBALS__C
|
||||
/* GLOBAL VARIABLES */
|
||||
extern int pass; /* The current assembly pass. 0 = first pass */
|
||||
extern int stmtno; /* The current source line number */
|
||||
extern int radix; /* The current input conversion radix */
|
||||
extern int lsb; /* The current local symbol section identifier */
|
||||
extern int lsb_used; /* Whether there was a local symbol using this lsb */
|
||||
extern int next_lsb; /* The number of the next local symbol block */
|
||||
extern int last_macro_lsb; /* The last block in which a macro
|
||||
automatic label was created */
|
||||
|
||||
extern int last_locsym; /* The last local symbol number generated */
|
||||
|
||||
extern int enabl_debug; /* Whether assembler debugging is enabled */
|
||||
|
||||
extern int enabl_ama; /* When set, chooses absolute (037) versus
|
||||
PC-relative */
|
||||
/* (067) addressing mode */
|
||||
extern int enabl_lsb; /* When set, stops non-local symbol
|
||||
definitions from delimiting local
|
||||
symbol sections. */
|
||||
|
||||
extern int enabl_gbl; /* Implicit definition of global symbols */
|
||||
|
||||
extern int enabl_lc; /* If lowercase disabled, convert assembler
|
||||
source to upper case. */
|
||||
extern int suppressed; /* Assembly suppressed by failed conditional */
|
||||
|
||||
extern MLB *mlbs[MAX_MLBS]; /* macro libraries specified on the command line */
|
||||
extern int nr_mlbs; /* Number of macro libraries */
|
||||
|
||||
extern COND conds[MAX_CONDS]; /* Stack of recent conditions */
|
||||
extern int last_cond; /* 0 means no stacked cond. */
|
||||
|
||||
extern SECTION *sect_stack[SECT_STACK_SIZE]; /* 32 saved sections */
|
||||
extern int dot_stack[SECT_STACK_SIZE]; /* 32 saved sections */
|
||||
extern int sect_sp; /* Stack pointer */
|
||||
|
||||
extern char *module_name; /* The module name (taken from the 'TITLE'); */
|
||||
|
||||
extern char *ident; /* .IDENT name */
|
||||
|
||||
extern EX_TREE *xfer_address; /* The transfer address */
|
||||
|
||||
extern SYMBOL *current_pc; /* The current program counter */
|
||||
|
||||
extern unsigned last_dot_addr; /* Last coded PC... */
|
||||
extern SECTION *last_dot_section; /* ...and it's program section */
|
||||
|
||||
/* The following are dummy psects for symbols which have meaning to
|
||||
the assembler: */
|
||||
extern SECTION register_section;
|
||||
extern SECTION pseudo_section; /* the section containing the pseudo-operations */
|
||||
extern SECTION instruction_section; /* the section containing instructions */
|
||||
extern SECTION macro_section; /* Section for macros */
|
||||
|
||||
/* These are real psects that get written out to the object file */
|
||||
extern SECTION absolute_section; /* The default absolute section */
|
||||
extern SECTION blank_section;
|
||||
extern SECTION *sections[256]; /* Array of sections in the order they were defined */
|
||||
extern int sector; /* number of such sections */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
745
crossassemblers/macro11/dumpobj.c
Normal file
745
crossassemblers/macro11/dumpobj.c
Normal file
@@ -0,0 +1,745 @@
|
||||
/* Dump and interpret an object file. */
|
||||
|
||||
/*
|
||||
Copyright (c) 2001, Richard Krehbiel
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
o Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
o Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
o Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "rad50.h"
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#define WORD(cp) ((*(cp) & 0xff) + ((*((cp)+1) & 0xff) << 8))
|
||||
|
||||
#define NPSECTS 256
|
||||
|
||||
int psectid = 0;
|
||||
char *psects[NPSECTS];
|
||||
FILE *bin = NULL;
|
||||
int badbin = 0;
|
||||
int xferad = 1;
|
||||
|
||||
char *readrec(
|
||||
FILE *fp,
|
||||
int *len)
|
||||
{
|
||||
int c,
|
||||
i;
|
||||
int chksum;
|
||||
char *buf;
|
||||
|
||||
chksum = 0;
|
||||
|
||||
#if RT11
|
||||
while (c = fgetc(fp), c != EOF && c == 0) ;
|
||||
|
||||
if (c == EOF)
|
||||
return NULL;
|
||||
|
||||
if (c != 1) {
|
||||
fprintf(stderr, "Improperly formatted OBJ file (1)\n");
|
||||
return NULL; /* Not a properly formatted file. */
|
||||
}
|
||||
|
||||
chksum -= c;
|
||||
|
||||
c = fgetc(fp);
|
||||
if (c != 0) {
|
||||
fprintf(stderr, "Improperly formatted OBJ file (2)\n");
|
||||
return NULL; /* Not properly formatted */
|
||||
}
|
||||
|
||||
chksum -= c; /* even though for 0 the checksum isn't changed... */
|
||||
#endif /* RT11 */
|
||||
|
||||
c = fgetc(fp);
|
||||
if (c == EOF) {
|
||||
#if RT11
|
||||
fprintf(stderr, "Improperly formatted OBJ file (3)\n");
|
||||
#endif /* RT11 */
|
||||
return NULL;
|
||||
}
|
||||
*len = c;
|
||||
|
||||
chksum -= c;
|
||||
|
||||
c = fgetc(fp);
|
||||
if (c == EOF) {
|
||||
fprintf(stderr, "Improperly formatted OBJ file (4)\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*len += (c << 8);
|
||||
|
||||
chksum -= c;
|
||||
|
||||
#if RT11
|
||||
*len -= 4; /* Subtract header and length bytes from length */
|
||||
#endif
|
||||
if (*len < 0) {
|
||||
fprintf(stderr, "Improperly formatted OBJ file (5)\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf = malloc(*len);
|
||||
if (buf == NULL) {
|
||||
fprintf(stderr, "Out of memory allocating %d bytes\n", *len);
|
||||
return NULL; /* Bad alloc */
|
||||
}
|
||||
|
||||
i = fread(buf, 1, *len, fp);
|
||||
if (i < *len) {
|
||||
free(buf);
|
||||
fprintf(stderr, "Improperly formatted OBJ file (6)\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < *len; i++)
|
||||
chksum -= (buf[i] & 0xff);
|
||||
|
||||
#if RT11
|
||||
c = fgetc(fp);
|
||||
c &= 0xff;
|
||||
chksum &= 0xff;
|
||||
|
||||
if (c != chksum) {
|
||||
free(buf);
|
||||
fprintf(stderr, "Bad record checksum, " "calculated=$%04x, recorded=$%04x\n", chksum, c);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
if (*len & 1) {
|
||||
/* skip 1 byte of padding */
|
||||
c = fgetc(fp);
|
||||
if (c == EOF) {
|
||||
free(buf);
|
||||
fprintf(stderr, "EOF where padding byte should be\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
#endif /* RT11 */
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void dump_bytes(
|
||||
char *buf,
|
||||
int len)
|
||||
{
|
||||
int i,
|
||||
j;
|
||||
|
||||
for (i = 0; i < len; i += 8) {
|
||||
printf("\t%3.3o: ", i);
|
||||
for (j = i; j < len && j < i + 8; j++)
|
||||
printf("%3.3o ", buf[j] & 0xff);
|
||||
|
||||
printf("%*s", (i + 8 - j) * 4, "");
|
||||
|
||||
for (j = i; j < len && j < i + 8; j++) {
|
||||
int c = buf[j] & 0xff;
|
||||
|
||||
if (!isprint(c))
|
||||
c = '.';
|
||||
putchar(c);
|
||||
}
|
||||
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
|
||||
void dump_words(
|
||||
unsigned addr,
|
||||
char *buf,
|
||||
int len)
|
||||
{
|
||||
int i,
|
||||
j;
|
||||
|
||||
for (i = 0; i < len; i += 8) {
|
||||
printf("\t%6.6o: ", addr);
|
||||
|
||||
for (j = i; j < len && j < i + 8; j += 2)
|
||||
if (len - j >= 2) {
|
||||
unsigned word = WORD(buf + j);
|
||||
|
||||
printf("%6.6o ", word);
|
||||
} else
|
||||
printf("%3.3o ", buf[j] & 0xff);
|
||||
|
||||
printf("%*s", (i + 8 - j) * 7 / 2, "");
|
||||
|
||||
for (j = i; j < len && j < i + 8; j++) {
|
||||
int c = buf[j] & 0xff;
|
||||
|
||||
if (!isprint(c))
|
||||
c = '.';
|
||||
putchar(c);
|
||||
}
|
||||
|
||||
putchar('\n');
|
||||
addr += 8;
|
||||
}
|
||||
}
|
||||
|
||||
void dump_bin(
|
||||
unsigned addr,
|
||||
char *buf,
|
||||
int len)
|
||||
{
|
||||
int chksum; /* Checksum is negative sum of all
|
||||
bytes including header and length */
|
||||
int FBR_LEAD1 = 1,
|
||||
FBR_LEAD2 = 0;
|
||||
int i;
|
||||
unsigned hdrlen = len + 6;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
fputc(0, bin);
|
||||
chksum = 0;
|
||||
if (fputc(FBR_LEAD1, bin) == EOF)
|
||||
return; /* All recs begin with 1,0 */
|
||||
chksum -= FBR_LEAD1;
|
||||
if (fputc(FBR_LEAD2, bin) == EOF)
|
||||
return;
|
||||
chksum -= FBR_LEAD2;
|
||||
|
||||
i = hdrlen & 0xff; /* length, lsb */
|
||||
chksum -= i;
|
||||
if (fputc(i, bin) == EOF)
|
||||
return;
|
||||
|
||||
i = (hdrlen >> 8) & 0xff; /* length, msb */
|
||||
chksum -= i;
|
||||
if (fputc(i, bin) == EOF)
|
||||
return;
|
||||
|
||||
i = addr & 0xff; /* origin, msb */
|
||||
chksum -= i;
|
||||
if (fputc(i, bin) == EOF)
|
||||
return;
|
||||
|
||||
i = (addr >> 8) & 0xff; /* origin, lsb */
|
||||
chksum -= i;
|
||||
if (fputc(i, bin) == EOF)
|
||||
return;
|
||||
|
||||
if ((len == 0) || (buf == NULL))
|
||||
return; /* end of tape block */
|
||||
|
||||
i = fwrite(buf, 1, len, bin);
|
||||
if (i < len)
|
||||
return;
|
||||
|
||||
while (len > 0) { /* All the data bytes */
|
||||
chksum -= *buf++ & 0xff;
|
||||
len--;
|
||||
}
|
||||
|
||||
chksum &= 0xff;
|
||||
|
||||
fputc(chksum, bin); /* Followed by the checksum byte */
|
||||
|
||||
return; /* Worked okay. */
|
||||
}
|
||||
|
||||
void trim(
|
||||
char *buf)
|
||||
{
|
||||
char *cp;
|
||||
|
||||
for (cp = buf + strlen(buf); cp > buf; cp--)
|
||||
if (cp[-1] != ' ')
|
||||
break;
|
||||
*cp = 0;
|
||||
}
|
||||
|
||||
char **all_gsds = NULL;
|
||||
int nr_gsds = 0;
|
||||
int gsdsize = 0;
|
||||
|
||||
void add_gsdline(
|
||||
char *line)
|
||||
{
|
||||
if (nr_gsds >= gsdsize || all_gsds == NULL) {
|
||||
gsdsize += 128;
|
||||
all_gsds = realloc(all_gsds, gsdsize * sizeof(char *));
|
||||
if (all_gsds == NULL) {
|
||||
fprintf(stderr, "Out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
all_gsds[nr_gsds++] = line;
|
||||
}
|
||||
|
||||
void got_gsd(
|
||||
char *cp,
|
||||
int len)
|
||||
{
|
||||
int i;
|
||||
char *gsdline;
|
||||
|
||||
for (i = 2; i < len; i += 8) {
|
||||
char name[8];
|
||||
unsigned value;
|
||||
unsigned flags;
|
||||
|
||||
gsdline = malloc(256);
|
||||
if (gsdline == NULL) {
|
||||
fprintf(stderr, "Out of memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
unrad50(WORD(cp + i), name);
|
||||
unrad50(WORD(cp + i + 2), name + 3);
|
||||
name[6] = 0;
|
||||
|
||||
value = WORD(cp + i + 6);
|
||||
flags = cp[i + 4] & 0xff;
|
||||
|
||||
switch (cp[i + 5] & 0xff) {
|
||||
case 0:
|
||||
sprintf(gsdline, "\tMODNAME %s=%o flags=%o\n", name, value, flags);
|
||||
break;
|
||||
case 1:
|
||||
sprintf(gsdline, "\tCSECT %s=%o flags=%o\n", name, value, flags);
|
||||
break;
|
||||
case 2:
|
||||
sprintf(gsdline, "\tISD %s=%o flags=%o\n", name, value, flags);
|
||||
break;
|
||||
case 3:
|
||||
sprintf(gsdline, "\tXFER %s=%o flags=%o\n", name, value, flags);
|
||||
xferad = value;
|
||||
break;
|
||||
case 4:
|
||||
sprintf(gsdline, "\tGLOBAL %s=%o %s%s%s %s flags=%o\n", name, value,
|
||||
flags & 01 ? "WEAK " : "",
|
||||
flags & 04 ? "LIB " : "",
|
||||
flags & 010 ? "DEF" : "REF",
|
||||
flags & 040 ? "REL" : "ABS",
|
||||
flags);
|
||||
break;
|
||||
case 5:
|
||||
sprintf(gsdline, "\tPSECT %s=%o %s%s %s %s %s %s %s flags=%o\n", name, value,
|
||||
flags & 01 ? "SAV " : "",
|
||||
flags & 02 ? "LIB " : "",
|
||||
flags & 04 ? "OVR" : "CON",
|
||||
flags & 020 ? "RO" : "RW",
|
||||
flags & 040 ? "REL" : "ABS",
|
||||
flags & 0100 ? "GBL" : "LCL",
|
||||
flags & 0200 ? "D" : "I",
|
||||
flags);
|
||||
psects[psectid] = strdup(name);
|
||||
trim(psects[psectid++]);
|
||||
psectid %= NPSECTS;
|
||||
break;
|
||||
case 6:
|
||||
sprintf(gsdline, "\tIDENT %s=%o flags=%o\n", name, value, flags);
|
||||
break;
|
||||
case 7:
|
||||
sprintf(gsdline, "\tVSECT %s=%o flags=%o\n", name, value, flags);
|
||||
break;
|
||||
case 010:
|
||||
sprintf(gsdline, "\tCompletion Routine Name %s=%o flags=%o\n", name, value, flags);
|
||||
break;
|
||||
default:
|
||||
sprintf(gsdline, "\t***Unknown GSD entry type %d flags=%o\n", cp[i + 5] & 0xff, flags);
|
||||
break;
|
||||
}
|
||||
|
||||
gsdline = realloc(gsdline, strlen(gsdline) + 1);
|
||||
add_gsdline(gsdline);
|
||||
}
|
||||
}
|
||||
|
||||
int compare_gsdlines(
|
||||
const void *p1,
|
||||
const void *p2)
|
||||
{
|
||||
const char *const *l1 = p1,
|
||||
*const *l2 = p2;
|
||||
|
||||
return strcmp(*l1, *l2);
|
||||
}
|
||||
|
||||
void got_endgsd(
|
||||
char *cp,
|
||||
int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
(void)cp;
|
||||
(void)len;
|
||||
|
||||
if (nr_gsds == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
qsort(all_gsds, nr_gsds, sizeof(char *), compare_gsdlines);
|
||||
|
||||
printf("GSD:\n");
|
||||
|
||||
for (i = 0; i < nr_gsds; i++) {
|
||||
fputs(all_gsds[i], stdout);
|
||||
free(all_gsds[i]);
|
||||
}
|
||||
|
||||
printf("ENDGSD\n");
|
||||
|
||||
free(all_gsds);
|
||||
all_gsds = NULL;
|
||||
nr_gsds = 0;
|
||||
gsdsize = 0;
|
||||
}
|
||||
|
||||
unsigned last_text_addr = 0;
|
||||
|
||||
void got_text(
|
||||
char *cp,
|
||||
int len)
|
||||
{
|
||||
unsigned addr = WORD(cp + 2);
|
||||
|
||||
last_text_addr = addr;
|
||||
|
||||
printf("TEXT ADDR=%o LEN=%o\n", last_text_addr, len - 4);
|
||||
|
||||
dump_words(last_text_addr, cp + 4, len - 4);
|
||||
|
||||
if (bin)
|
||||
dump_bin(last_text_addr, cp + 4, len - 4);
|
||||
}
|
||||
|
||||
void rad50name(
|
||||
char *cp,
|
||||
char *name)
|
||||
{
|
||||
unrad50(WORD(cp), name);
|
||||
unrad50(WORD(cp + 2), name + 3);
|
||||
name[6] = 0;
|
||||
trim(name);
|
||||
}
|
||||
|
||||
void got_rld(
|
||||
char *cp,
|
||||
int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("RLD\n");
|
||||
|
||||
for (i = 2; i < len;) {
|
||||
unsigned addr;
|
||||
unsigned word;
|
||||
unsigned disp = cp[i + 1] & 0xff;
|
||||
char name[8];
|
||||
char *byte;
|
||||
|
||||
addr = last_text_addr + disp - 4;
|
||||
|
||||
byte = "";
|
||||
if (cp[i] & 0200)
|
||||
byte = " byte";
|
||||
|
||||
switch (cp[i] & 0x7f) {
|
||||
case 01:
|
||||
printf("\tInternal%s %o=%o\n", byte, addr, WORD(cp + i + 2));
|
||||
i += 4;
|
||||
break;
|
||||
case 02:
|
||||
rad50name(cp + i + 2, name);
|
||||
printf("\tGlobal%s %o=%s\n", byte, addr, name);
|
||||
i += 6;
|
||||
break;
|
||||
case 03:
|
||||
printf("\tInternal displaced%s %o=%o\n", byte, addr, WORD(cp + i + 2));
|
||||
i += 4;
|
||||
badbin = 1;
|
||||
break;
|
||||
case 04:
|
||||
rad50name(cp + i + 2, name);
|
||||
printf("\tGlobal displaced%s %o=%s\n", byte, addr, name);
|
||||
i += 6;
|
||||
badbin = 1;
|
||||
break;
|
||||
case 05:
|
||||
rad50name(cp + i + 2, name);
|
||||
word = WORD(cp + i + 6);
|
||||
printf("\tGlobal plus offset%s %o=%s+%o\n", byte, addr, name, word);
|
||||
i += 8;
|
||||
badbin = 1;
|
||||
break;
|
||||
case 06:
|
||||
rad50name(cp + i + 2, name);
|
||||
word = WORD(cp + i + 6);
|
||||
printf("\tGlobal plus offset displaced%s %o=%s+%o\n", byte, addr, name, word);
|
||||
i += 8;
|
||||
badbin = 1;
|
||||
break;
|
||||
case 07:
|
||||
rad50name(cp + i + 2, name);
|
||||
word = WORD(cp + i + 6);
|
||||
printf("\tLocation counter definition %s+%o\n", name, word);
|
||||
i += 8;
|
||||
|
||||
last_text_addr = word;
|
||||
break;
|
||||
case 010:
|
||||
word = WORD(cp + i + 2);
|
||||
printf("\tLocation counter modification %o\n", word);
|
||||
i += 4;
|
||||
|
||||
last_text_addr = word;
|
||||
break;
|
||||
case 011:
|
||||
printf("\t.LIMIT %o\n", addr);
|
||||
i += 2;
|
||||
break;
|
||||
|
||||
case 012:
|
||||
rad50name(cp + i + 2, name);
|
||||
printf("\tPSECT%s %o=%s\n", byte, addr, name);
|
||||
i += 6;
|
||||
badbin = 1;
|
||||
break;
|
||||
case 014:
|
||||
rad50name(cp + i + 2, name);
|
||||
|
||||
printf("\tPSECT displaced%s %o=%s\n", byte, addr, name);
|
||||
i += 6;
|
||||
badbin = 1;
|
||||
break;
|
||||
case 015:
|
||||
rad50name(cp + i + 2, name);
|
||||
word = WORD(cp + i + 6);
|
||||
printf("\tPSECT plus offset%s %o=%s+%o\n", byte, addr, name, word);
|
||||
i += 8;
|
||||
badbin = 1;
|
||||
break;
|
||||
case 016:
|
||||
rad50name(cp + i + 2, name);
|
||||
word = WORD(cp + i + 6);
|
||||
printf("\tPSECT plus offset displaced%s %o=%s+%o\n", byte, addr, name, word);
|
||||
i += 8;
|
||||
badbin = 1;
|
||||
break;
|
||||
|
||||
case 017:
|
||||
badbin = 1;
|
||||
printf("\tComplex%s %o=", byte, addr);
|
||||
i += 2; {
|
||||
char *xp = cp + i;
|
||||
int size;
|
||||
|
||||
for (;;) {
|
||||
size = 1;
|
||||
switch (*xp) {
|
||||
case 000:
|
||||
fputs("nop ", stdout);
|
||||
break;
|
||||
case 001:
|
||||
fputs("+ ", stdout);
|
||||
break;
|
||||
case 002:
|
||||
fputs("- ", stdout);
|
||||
break;
|
||||
case 003:
|
||||
fputs("* ", stdout);
|
||||
break;
|
||||
case 004:
|
||||
fputs("/ ", stdout);
|
||||
break;
|
||||
case 005:
|
||||
fputs("& ", stdout);
|
||||
break;
|
||||
case 006:
|
||||
fputs("! ", stdout);
|
||||
break;
|
||||
case 010:
|
||||
fputs("neg ", stdout);
|
||||
break;
|
||||
case 011:
|
||||
fputs("^C ", stdout);
|
||||
break;
|
||||
case 012:
|
||||
fputs("store ", stdout);
|
||||
break;
|
||||
case 013:
|
||||
fputs("store{disp} ", stdout);
|
||||
break;
|
||||
|
||||
case 016:
|
||||
rad50name(xp + 1, name);
|
||||
printf("%s ", name);
|
||||
size = 5;
|
||||
break;
|
||||
|
||||
case 017:
|
||||
assert((xp[1] & 0377) < psectid);
|
||||
printf("%s:%o ", psects[xp[1] & 0377], WORD(xp + 2));
|
||||
size = 4;
|
||||
break;
|
||||
|
||||
case 020:
|
||||
printf("%o ", WORD(xp + 1));
|
||||
size = 3;
|
||||
break;
|
||||
default:
|
||||
printf("**UNKNOWN COMPLEX CODE** %o\n", *xp & 0377);
|
||||
return;
|
||||
}
|
||||
i += size;
|
||||
if (*xp == 012 || *xp == 013)
|
||||
break;
|
||||
xp += size;
|
||||
}
|
||||
fputc('\n', stdout);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
printf("\t***Unknown RLD code %o\n", cp[i] & 0xff);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void got_isd(
|
||||
char *cp,
|
||||
int len)
|
||||
{
|
||||
(void)cp;
|
||||
printf("ISD len=%o\n", len);
|
||||
}
|
||||
|
||||
void got_endmod(
|
||||
char *cp,
|
||||
int len)
|
||||
{
|
||||
(void)cp;
|
||||
(void)len;
|
||||
printf("ENDMOD\n");
|
||||
}
|
||||
|
||||
void got_libhdr(
|
||||
char *cp,
|
||||
int len)
|
||||
{
|
||||
(void)cp;
|
||||
(void)len;
|
||||
printf("LIBHDR\n");
|
||||
}
|
||||
|
||||
void got_libend(
|
||||
char *cp,
|
||||
int len)
|
||||
{
|
||||
(void)cp;
|
||||
(void)len;
|
||||
printf("LIBEND\n");
|
||||
}
|
||||
|
||||
int main(
|
||||
int argc,
|
||||
char *argv[])
|
||||
{
|
||||
int len;
|
||||
FILE *fp;
|
||||
char *cp;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Usage: dumpobj input.obj [ output.obj ]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fp = fopen(argv[1], "rb");
|
||||
if (fp == NULL)
|
||||
return EXIT_FAILURE;
|
||||
if (argc > 2 && argv[2]) {
|
||||
bin = fopen(argv[2], "wb");
|
||||
if (bin == NULL)
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
while ((cp = readrec(fp, &len)) != NULL) {
|
||||
switch (cp[0] & 0xff) {
|
||||
case 1:
|
||||
got_gsd(cp, len);
|
||||
break;
|
||||
case 2:
|
||||
got_endgsd(cp, len);
|
||||
break;
|
||||
case 3:
|
||||
got_text(cp, len);
|
||||
break;
|
||||
case 4:
|
||||
got_rld(cp, len);
|
||||
break;
|
||||
case 5:
|
||||
got_isd(cp, len);
|
||||
break;
|
||||
case 6:
|
||||
got_endmod(cp, len);
|
||||
break;
|
||||
case 7:
|
||||
got_libhdr(cp, len);
|
||||
break;
|
||||
case 8:
|
||||
got_libend(cp, len);
|
||||
break;
|
||||
default:
|
||||
printf("Unknown record type %o\n", cp[0] & 0xff);
|
||||
break;
|
||||
}
|
||||
|
||||
free(cp);
|
||||
}
|
||||
|
||||
if (bin) {
|
||||
dump_bin(xferad, NULL, 0);
|
||||
fclose(bin);
|
||||
if (badbin)
|
||||
fprintf(stderr, "Probable errors in binary file\n");
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
114
crossassemblers/macro11/dumpobj.dsp
Normal file
114
crossassemblers/macro11/dumpobj.dsp
Normal file
@@ -0,0 +1,114 @@
|
||||
# Microsoft Developer Studio Project File - Name="dumpobj" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||
|
||||
CFG=dumpobj - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "dumpobj.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "dumpobj.mak" CFG="dumpobj - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "dumpobj - Win32 Release" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "dumpobj - Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""$/macro11", BAAAAAAA"
|
||||
# PROP Scc_LocalPath "."
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "dumpobj - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "dumpobj___Release"
|
||||
# PROP Intermediate_Dir "dumpobj___Release"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
||||
|
||||
!ELSEIF "$(CFG)" == "dumpobj - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "Debug"
|
||||
# PROP BASE Intermediate_Dir "Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "dumpobj___Debug"
|
||||
# PROP Intermediate_Dir "dumpobj___Debug"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "dumpobj - Win32 Release"
|
||||
# Name "dumpobj - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\dumpobj.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Rad50.c
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Rad50.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\util.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Resource Files"
|
||||
|
||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
||||
775
crossassemblers/macro11/extree.c
Normal file
775
crossassemblers/macro11/extree.c
Normal file
@@ -0,0 +1,775 @@
|
||||
#define EXTREE__C
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "extree.h" /* my own definitions */
|
||||
|
||||
#include "util.h"
|
||||
#include "assemble_globals.h"
|
||||
#include "object.h"
|
||||
|
||||
|
||||
/* Diagnostic: print an expression tree. I used this in various
|
||||
places to help me diagnose parse problems, by putting in calls to
|
||||
print_tree when I didn't understand why something wasn't working.
|
||||
This is currently dead code, nothing calls it; but I don't want it
|
||||
to go away. Hopefully the compiler will realize when it's dead, and
|
||||
eliminate it. */
|
||||
|
||||
void print_tree(
|
||||
FILE *printfile,
|
||||
EX_TREE *tp,
|
||||
int depth)
|
||||
{
|
||||
SYMBOL *sym;
|
||||
|
||||
if (tp == NULL) {
|
||||
fprintf(printfile, "(null)");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (tp->type) {
|
||||
case EX_LIT:
|
||||
fprintf(printfile, "%o", tp->data.lit & 0177777);
|
||||
break;
|
||||
|
||||
case EX_SYM:
|
||||
case EX_TEMP_SYM:
|
||||
sym = tp->data.symbol;
|
||||
fprintf(printfile, "%s{%s%o:%s}", tp->data.symbol->label, symflags(sym), sym->value,
|
||||
sym->section->label);
|
||||
break;
|
||||
|
||||
case EX_UNDEFINED_SYM:
|
||||
fprintf(printfile, "%s{%o:undefined}", tp->data.symbol->label, tp->data.symbol->value);
|
||||
break;
|
||||
|
||||
case EX_COM:
|
||||
fprintf(printfile, "^C<");
|
||||
print_tree(printfile, tp->data.child.left, depth + 4);
|
||||
fprintf(printfile, ">");
|
||||
break;
|
||||
|
||||
case EX_NEG:
|
||||
fprintf(printfile, "-<");
|
||||
print_tree(printfile, tp->data.child.left, depth + 4);
|
||||
fputc('>', printfile);
|
||||
break;
|
||||
|
||||
case EX_ERR:
|
||||
fprintf(printfile, "{expression error}");
|
||||
if (tp->data.child.left) {
|
||||
fputc('<', printfile);
|
||||
print_tree(printfile, tp->data.child.left, depth + 4);
|
||||
fputc('>', printfile);
|
||||
}
|
||||
break;
|
||||
|
||||
case EX_ADD:
|
||||
fputc('<', printfile);
|
||||
print_tree(printfile, tp->data.child.left, depth + 4);
|
||||
fputc('+', printfile);
|
||||
print_tree(printfile, tp->data.child.right, depth + 4);
|
||||
fputc('>', printfile);
|
||||
break;
|
||||
|
||||
case EX_SUB:
|
||||
fputc('<', printfile);
|
||||
print_tree(printfile, tp->data.child.left, depth + 4);
|
||||
fputc('-', printfile);
|
||||
print_tree(printfile, tp->data.child.right, depth + 4);
|
||||
fputc('>', printfile);
|
||||
break;
|
||||
|
||||
case EX_MUL:
|
||||
fputc('<', printfile);
|
||||
print_tree(printfile, tp->data.child.left, depth + 4);
|
||||
fputc('*', printfile);
|
||||
print_tree(printfile, tp->data.child.right, depth + 4);
|
||||
fputc('>', printfile);
|
||||
break;
|
||||
|
||||
case EX_DIV:
|
||||
fputc('<', printfile);
|
||||
print_tree(printfile, tp->data.child.left, depth + 4);
|
||||
fputc('/', printfile);
|
||||
print_tree(printfile, tp->data.child.right, depth + 4);
|
||||
fputc('>', printfile);
|
||||
break;
|
||||
|
||||
case EX_AND:
|
||||
fputc('<', printfile);
|
||||
print_tree(printfile, tp->data.child.left, depth + 4);
|
||||
fputc('&', printfile);
|
||||
print_tree(printfile, tp->data.child.right, depth + 4);
|
||||
fputc('>', printfile);
|
||||
break;
|
||||
|
||||
case EX_OR:
|
||||
fputc('<', printfile);
|
||||
print_tree(printfile, tp->data.child.left, depth + 4);
|
||||
fputc('!', printfile);
|
||||
print_tree(printfile, tp->data.child.right, depth + 4);
|
||||
fputc('>', printfile);
|
||||
break;
|
||||
}
|
||||
|
||||
if (depth == 0)
|
||||
fputc('\n', printfile);
|
||||
}
|
||||
|
||||
/* free_tree frees an expression tree. */
|
||||
|
||||
void free_tree(
|
||||
EX_TREE *tp)
|
||||
{
|
||||
switch (tp->type) {
|
||||
case EX_UNDEFINED_SYM:
|
||||
case EX_TEMP_SYM:
|
||||
free(tp->data.symbol->label);
|
||||
free(tp->data.symbol);
|
||||
break;
|
||||
|
||||
case EX_LIT:
|
||||
case EX_SYM:
|
||||
break;
|
||||
|
||||
case EX_COM:
|
||||
case EX_NEG:
|
||||
free_tree(tp->data.child.left);
|
||||
break;
|
||||
|
||||
case EX_ERR:
|
||||
if (tp->data.child.left)
|
||||
free_tree(tp->data.child.left);
|
||||
break;
|
||||
|
||||
case EX_ADD:
|
||||
case EX_SUB:
|
||||
case EX_MUL:
|
||||
case EX_DIV:
|
||||
case EX_AND:
|
||||
case EX_OR:
|
||||
free_tree(tp->data.child.left);
|
||||
free_tree(tp->data.child.right);
|
||||
break;
|
||||
}
|
||||
free(tp);
|
||||
}
|
||||
|
||||
/* new_temp_sym allocates a new EX_TREE entry of type "TEMPORARY
|
||||
SYMBOL" (slight semantic difference from "UNDEFINED"). */
|
||||
|
||||
static EX_TREE *new_temp_sym(
|
||||
char *label,
|
||||
SECTION *section,
|
||||
unsigned value)
|
||||
{
|
||||
SYMBOL *sym;
|
||||
EX_TREE *tp;
|
||||
|
||||
sym = memcheck(malloc(sizeof(SYMBOL)));
|
||||
sym->label = memcheck(strdup(label));
|
||||
sym->flags = 0;
|
||||
sym->stmtno = stmtno;
|
||||
sym->next = NULL;
|
||||
sym->section = section;
|
||||
sym->value = value;
|
||||
|
||||
tp = new_ex_tree();
|
||||
tp->type = EX_TEMP_SYM;
|
||||
tp->data.symbol = sym;
|
||||
|
||||
return tp;
|
||||
}
|
||||
|
||||
SYMBOL *dup_symbol(
|
||||
SYMBOL *sym)
|
||||
{
|
||||
SYMBOL *res;
|
||||
|
||||
if (sym == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
res = memcheck(malloc(sizeof(SYMBOL)));
|
||||
res->label = memcheck(strdup(sym->label));
|
||||
res->flags = sym->flags;
|
||||
res->stmtno = sym->stmtno;
|
||||
res->next = NULL;
|
||||
res->section = sym->section;
|
||||
res->value = sym->value;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
EX_TREE *dup_tree(
|
||||
EX_TREE *tp)
|
||||
{
|
||||
EX_TREE *res = NULL;
|
||||
|
||||
if (tp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
res = new_ex_tree();
|
||||
res->type = tp->type;
|
||||
res->cp = tp->cp;
|
||||
|
||||
switch (tp->type) {
|
||||
case EX_UNDEFINED_SYM:
|
||||
case EX_TEMP_SYM:
|
||||
res->data.symbol = dup_symbol(tp->data.symbol);
|
||||
break;
|
||||
|
||||
/* The symbol reference in EX_SYM is not freed in free_tree() */
|
||||
case EX_SYM:
|
||||
res->data.symbol = tp->data.symbol;
|
||||
break;
|
||||
|
||||
case EX_LIT:
|
||||
res->data.lit = tp->data.lit;
|
||||
break;
|
||||
|
||||
case EX_COM:
|
||||
case EX_NEG:
|
||||
case EX_ERR:
|
||||
res->data.child.left = dup_tree(tp->data.child.left);
|
||||
break;
|
||||
|
||||
case EX_ADD:
|
||||
case EX_SUB:
|
||||
case EX_MUL:
|
||||
case EX_DIV:
|
||||
case EX_AND:
|
||||
case EX_OR:
|
||||
res->data.child.left = dup_tree(tp->data.child.left);
|
||||
res->data.child.right = dup_tree(tp->data.child.right);
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#define RELTYPE(tp) (((tp)->type == EX_SYM || (tp)->type == EX_TEMP_SYM) && \
|
||||
(tp)->data.symbol->section->flags & PSECT_REL)
|
||||
|
||||
/* evaluate "evaluates" an EX_TREE, ideally trying to produce a
|
||||
constant value, else a symbol plus an offset. */
|
||||
EX_TREE *evaluate(
|
||||
EX_TREE *tp,
|
||||
int undef)
|
||||
{
|
||||
EX_TREE *res;
|
||||
char *cp = tp->cp;
|
||||
|
||||
switch (tp->type) {
|
||||
case EX_SYM:
|
||||
{
|
||||
SYMBOL *sym = tp->data.symbol;
|
||||
|
||||
/* Change some symbols to "undefined" */
|
||||
|
||||
if (undef) {
|
||||
int change = 0;
|
||||
|
||||
/* I'd prefer this behavior, but MACRO.SAV is a bit too primitive. */
|
||||
#if 0
|
||||
/* A temporary symbol defined later is "undefined." */
|
||||
if (!(sym->flags & PERMANENT) && sym->stmtno > stmtno)
|
||||
change = 1;
|
||||
#endif
|
||||
|
||||
/* A global symbol with no assignment is "undefined." */
|
||||
/* Go figure. */
|
||||
if ((sym->flags & (SYMBOLFLAG_GLOBAL | SYMBOLFLAG_DEFINITION)) == SYMBOLFLAG_GLOBAL)
|
||||
change = 1;
|
||||
|
||||
if (change) {
|
||||
res = new_temp_sym(tp->data.symbol->label, tp->data.symbol->section,
|
||||
tp->data.symbol->value);
|
||||
res->type = EX_UNDEFINED_SYM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Turn defined absolute symbol to a literal */
|
||||
if (!(sym->section->flags & PSECT_REL)
|
||||
&& (sym->flags & (SYMBOLFLAG_GLOBAL | SYMBOLFLAG_DEFINITION)) != SYMBOLFLAG_GLOBAL
|
||||
&& sym->section->type != SECTION_REGISTER) {
|
||||
res = new_ex_lit(sym->value);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Make a temp copy of any reference to "." since it might
|
||||
change as complex relocatable expressions are written out
|
||||
*/
|
||||
if (strcmp(sym->label, ".") == 0) {
|
||||
res = new_temp_sym(".", sym->section, sym->value);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Copy other symbol reference verbatim. */
|
||||
res = dup_tree(tp);
|
||||
break;
|
||||
}
|
||||
|
||||
case EX_LIT:
|
||||
res = dup_tree(tp);
|
||||
break;
|
||||
|
||||
case EX_TEMP_SYM:
|
||||
case EX_UNDEFINED_SYM:
|
||||
/* Copy temp and undefined symbols */
|
||||
res = new_temp_sym(tp->data.symbol->label, tp->data.symbol->section, tp->data.symbol->value);
|
||||
res->type = tp->type;
|
||||
break;
|
||||
|
||||
case EX_COM:
|
||||
/* Complement */
|
||||
tp = evaluate(tp->data.child.left, undef);
|
||||
if (tp->type == EX_LIT) {
|
||||
/* Complement the literal */
|
||||
res = new_ex_lit(~tp->data.lit);
|
||||
free_tree(tp);
|
||||
} else {
|
||||
/* Copy verbatim. */
|
||||
res = new_ex_tree();
|
||||
res->type = EX_COM;
|
||||
res->cp = tp->cp;
|
||||
res->data.child.left = tp;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case EX_NEG:
|
||||
tp = evaluate(tp->data.child.left, undef);
|
||||
if (tp->type == EX_LIT) {
|
||||
/* negate literal */
|
||||
res = new_ex_lit((unsigned) -(int) tp->data.lit);
|
||||
free_tree(tp);
|
||||
} else if (tp->type == EX_TEMP_SYM ||
|
||||
(tp->type == EX_SYM &&
|
||||
(tp->data.symbol->flags & SYMBOLFLAG_DEFINITION))) {
|
||||
/* Make a temp sym with the negative value of the given
|
||||
sym (this works for symbols within relocatable sections
|
||||
too) */
|
||||
res = new_temp_sym("*TEMP", tp->data.symbol->section, (unsigned) -(int) tp->data.symbol->value);
|
||||
res->cp = tp->cp;
|
||||
free_tree(tp);
|
||||
} else {
|
||||
/* Copy verbatim. */
|
||||
res = new_ex_tree();
|
||||
res->type = EX_NEG;
|
||||
res->cp = tp->cp;
|
||||
res->data.child.left = tp;
|
||||
}
|
||||
break;
|
||||
|
||||
case EX_ERR:
|
||||
/* Copy */
|
||||
res = dup_tree(tp);
|
||||
break;
|
||||
|
||||
case EX_ADD:
|
||||
{
|
||||
EX_TREE *left,
|
||||
*right;
|
||||
|
||||
left = evaluate(tp->data.child.left, undef);
|
||||
right = evaluate(tp->data.child.right, undef);
|
||||
|
||||
/* Both literals? Sum them and return result. */
|
||||
if (left->type == EX_LIT && right->type == EX_LIT) {
|
||||
res = new_ex_lit(left->data.lit + right->data.lit);
|
||||
free_tree(left);
|
||||
free_tree(right);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Commutative: A+x == x+A.
|
||||
Simplify by putting the literal on the right */
|
||||
if (left->type == EX_LIT) {
|
||||
EX_TREE *temp = left;
|
||||
|
||||
left = right;
|
||||
right = temp;
|
||||
}
|
||||
|
||||
if (right->type == EX_LIT && /* Anything plus 0 == itself */
|
||||
right->data.lit == 0) {
|
||||
res = left;
|
||||
free_tree(right);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Relative symbol plus lit is replaced with a temp sym
|
||||
holding the sum */
|
||||
if (RELTYPE(left) && right->type == EX_LIT) {
|
||||
SYMBOL *sym = left->data.symbol;
|
||||
|
||||
res = new_temp_sym("*ADD", sym->section, sym->value + right->data.lit);
|
||||
free_tree(left);
|
||||
free_tree(right);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Associative: <A+x>+y == A+<x+y> */
|
||||
/* and if x+y is constant, I can do that math. */
|
||||
if (left->type == EX_ADD && right->type == EX_LIT) {
|
||||
EX_TREE *leftright = left->data.child.right;
|
||||
|
||||
if (leftright->type == EX_LIT) {
|
||||
/* Do the shuffle */
|
||||
res = left;
|
||||
leftright->data.lit += right->data.lit;
|
||||
free_tree(right);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Associative: <A-x>+y == A+<y-x> */
|
||||
/* and if y-x is constant, I can do that math. */
|
||||
if (left->type == EX_SUB && right->type == EX_LIT) {
|
||||
EX_TREE *leftright = left->data.child.right;
|
||||
|
||||
if (leftright->type == EX_LIT) {
|
||||
/* Do the shuffle */
|
||||
res = left;
|
||||
leftright->data.lit = right->data.lit - leftright->data.lit;
|
||||
free_tree(right);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Anything else returns verbatim */
|
||||
res = new_ex_bin(EX_ADD, left, right);
|
||||
}
|
||||
break;
|
||||
|
||||
case EX_SUB:
|
||||
{
|
||||
EX_TREE *left,
|
||||
*right;
|
||||
|
||||
left = evaluate(tp->data.child.left, undef);
|
||||
right = evaluate(tp->data.child.right, undef);
|
||||
|
||||
/* Both literals? Subtract them and return a lit. */
|
||||
if (left->type == EX_LIT && right->type == EX_LIT) {
|
||||
res = new_ex_lit(left->data.lit - right->data.lit);
|
||||
free_tree(left);
|
||||
free_tree(right);
|
||||
break;
|
||||
}
|
||||
|
||||
if (right->type == EX_LIT && /* Symbol minus 0 == symbol */
|
||||
right->data.lit == 0) {
|
||||
res = left;
|
||||
free_tree(right);
|
||||
break;
|
||||
}
|
||||
|
||||
/* A relocatable minus an absolute - make a new temp sym
|
||||
to represent that. */
|
||||
if (RELTYPE(left) && right->type == EX_LIT) {
|
||||
SYMBOL *sym = left->data.symbol;
|
||||
|
||||
res = new_temp_sym("*SUB", sym->section, sym->value - right->data.lit);
|
||||
free_tree(left);
|
||||
free_tree(right);
|
||||
break;
|
||||
}
|
||||
|
||||
if (RELTYPE(left) && RELTYPE(right) && left->data.symbol->section == right->data.symbol->section) {
|
||||
/* Two defined symbols in the same psect. Resolve
|
||||
their difference as a literal. */
|
||||
res = new_ex_lit(left->data.symbol->value - right->data.symbol->value);
|
||||
free_tree(left);
|
||||
free_tree(right);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Associative: <A+x>-y == A+<x-y> */
|
||||
/* and if x-y is constant, I can do that math. */
|
||||
if (left->type == EX_ADD && right->type == EX_LIT) {
|
||||
EX_TREE *leftright = left->data.child.right;
|
||||
|
||||
if (leftright->type == EX_LIT) {
|
||||
/* Do the shuffle */
|
||||
res = left;
|
||||
leftright->data.lit -= right->data.lit;
|
||||
free_tree(right);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Associative: <A-x>-y == A-<x+y> */
|
||||
/* and if x+y is constant, I can do that math. */
|
||||
if (left->type == EX_SUB && right->type == EX_LIT) {
|
||||
EX_TREE *leftright = left->data.child.right;
|
||||
|
||||
if (leftright->type == EX_LIT) {
|
||||
/* Do the shuffle */
|
||||
res = left;
|
||||
leftright->data.lit += right->data.lit;
|
||||
free_tree(right);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Anything else returns verbatim */
|
||||
res = new_ex_bin(EX_SUB, left, right);
|
||||
}
|
||||
break;
|
||||
|
||||
case EX_MUL:
|
||||
{
|
||||
EX_TREE *left,
|
||||
*right;
|
||||
|
||||
left = evaluate(tp->data.child.left, undef);
|
||||
right = evaluate(tp->data.child.right, undef);
|
||||
|
||||
/* Can only multiply if both are literals */
|
||||
if (left->type == EX_LIT && right->type == EX_LIT) {
|
||||
res = new_ex_lit(left->data.lit * right->data.lit);
|
||||
free_tree(left);
|
||||
free_tree(right);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Commutative: A*x == x*A.
|
||||
Simplify by putting the literal on the right */
|
||||
if (left->type == EX_LIT) {
|
||||
EX_TREE *temp = left;
|
||||
|
||||
left = right;
|
||||
right = temp;
|
||||
}
|
||||
|
||||
if (right->type == EX_LIT && /* Symbol times 1 == symbol */
|
||||
right->data.lit == 1) {
|
||||
res = left;
|
||||
free_tree(right);
|
||||
break;
|
||||
}
|
||||
|
||||
if (right->type == EX_LIT && /* Symbol times 0 == 0 */
|
||||
right->data.lit == 0) {
|
||||
res = right;
|
||||
free_tree(left);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Associative: <A*x>*y == A*<x*y> */
|
||||
/* If x*y is constant, I can do this math. */
|
||||
/* Is this safe? I will potentially be doing it */
|
||||
/* with greater accuracy than the target platform. */
|
||||
/* Hmmm. */
|
||||
|
||||
if (left->type == EX_MUL && right->type == EX_LIT) {
|
||||
EX_TREE *leftright = left->data.child.right;
|
||||
|
||||
if (leftright->type == EX_LIT) {
|
||||
/* Do the shuffle */
|
||||
res = left;
|
||||
leftright->data.lit *= right->data.lit;
|
||||
free_tree(right);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Anything else returns verbatim */
|
||||
res = new_ex_bin(EX_MUL, left, right);
|
||||
}
|
||||
break;
|
||||
|
||||
case EX_DIV:
|
||||
{
|
||||
EX_TREE *left,
|
||||
*right;
|
||||
|
||||
left = evaluate(tp->data.child.left, undef);
|
||||
right = evaluate(tp->data.child.right, undef);
|
||||
|
||||
/* Can only divide if both are literals */
|
||||
if (left->type == EX_LIT && right->type == EX_LIT) {
|
||||
res = new_ex_lit(left->data.lit / right->data.lit);
|
||||
free_tree(left);
|
||||
free_tree(right);
|
||||
break;
|
||||
}
|
||||
|
||||
if (right->type == EX_LIT && /* Symbol divided by 1 == symbol */
|
||||
right->data.lit == 1) {
|
||||
res = left;
|
||||
free_tree(right);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Anything else returns verbatim */
|
||||
res = new_ex_bin(EX_DIV, left, right);
|
||||
}
|
||||
break;
|
||||
|
||||
case EX_AND:
|
||||
{
|
||||
EX_TREE *left,
|
||||
*right;
|
||||
|
||||
left = evaluate(tp->data.child.left, undef);
|
||||
right = evaluate(tp->data.child.right, undef);
|
||||
|
||||
/* Operate if both are literals */
|
||||
if (left->type == EX_LIT && right->type == EX_LIT) {
|
||||
res = new_ex_lit(left->data.lit & right->data.lit);
|
||||
free_tree(left);
|
||||
free_tree(right);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Commutative: A&x == x&A.
|
||||
Simplify by putting the literal on the right */
|
||||
if (left->type == EX_LIT) {
|
||||
EX_TREE *temp = left;
|
||||
|
||||
left = right;
|
||||
right = temp;
|
||||
}
|
||||
|
||||
if (right->type == EX_LIT && /* Symbol AND 0 == 0 */
|
||||
right->data.lit == 0) {
|
||||
res = new_ex_lit(0);
|
||||
free_tree(left);
|
||||
free_tree(right);
|
||||
break;
|
||||
}
|
||||
|
||||
if (right->type == EX_LIT && /* Symbol AND 0177777 == symbol */
|
||||
right->data.lit == 0177777) {
|
||||
res = left;
|
||||
free_tree(right);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Anything else returns verbatim */
|
||||
res = new_ex_bin(EX_AND, left, right);
|
||||
}
|
||||
break;
|
||||
|
||||
case EX_OR:
|
||||
{
|
||||
EX_TREE *left,
|
||||
*right;
|
||||
|
||||
left = evaluate(tp->data.child.left, undef);
|
||||
right = evaluate(tp->data.child.right, undef);
|
||||
|
||||
/* Operate if both are literals */
|
||||
if (left->type == EX_LIT && right->type == EX_LIT) {
|
||||
res = new_ex_lit(left->data.lit | right->data.lit);
|
||||
free_tree(left);
|
||||
free_tree(right);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Commutative: A!x == x!A.
|
||||
Simplify by putting the literal on the right */
|
||||
if (left->type == EX_LIT) {
|
||||
EX_TREE *temp = left;
|
||||
|
||||
left = right;
|
||||
right = temp;
|
||||
}
|
||||
|
||||
if (right->type == EX_LIT && /* Symbol OR 0 == symbol */
|
||||
right->data.lit == 0) {
|
||||
res = left;
|
||||
free_tree(right);
|
||||
break;
|
||||
}
|
||||
|
||||
if (right->type == EX_LIT && /* Symbol OR 0177777 == 0177777 */
|
||||
right->data.lit == 0177777) {
|
||||
res = new_ex_lit(0177777);
|
||||
free_tree(left);
|
||||
free_tree(right);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Anything else returns verbatim */
|
||||
res = new_ex_bin(EX_OR, left, right);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Invalid tree\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
res->cp = cp;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* Allocate an EX_TREE */
|
||||
|
||||
EX_TREE *new_ex_tree(
|
||||
void)
|
||||
{
|
||||
EX_TREE *tr = memcheck(malloc(sizeof(EX_TREE)));
|
||||
|
||||
return tr;
|
||||
}
|
||||
|
||||
|
||||
/* Create an EX_TREE representing a parse error */
|
||||
|
||||
EX_TREE *ex_err(
|
||||
EX_TREE *tp,
|
||||
char *cp)
|
||||
{
|
||||
EX_TREE *errtp;
|
||||
|
||||
errtp = new_ex_tree();
|
||||
errtp->cp = cp;
|
||||
errtp->type = EX_ERR;
|
||||
errtp->data.child.left = tp;
|
||||
|
||||
return errtp;
|
||||
}
|
||||
|
||||
/* Create an EX_TREE representing a literal value */
|
||||
|
||||
EX_TREE *new_ex_lit(
|
||||
unsigned value)
|
||||
{
|
||||
EX_TREE *tp;
|
||||
|
||||
tp = new_ex_tree();
|
||||
tp->type = EX_LIT;
|
||||
tp->data.lit = value;
|
||||
|
||||
return tp;
|
||||
}
|
||||
|
||||
/* Create an EX_TREE representing a binary expression */
|
||||
|
||||
EX_TREE *new_ex_bin(
|
||||
int type,
|
||||
EX_TREE *left,
|
||||
EX_TREE *right)
|
||||
{
|
||||
EX_TREE *tp;
|
||||
|
||||
tp = new_ex_tree();
|
||||
tp->type = type;
|
||||
tp->data.child.left = left;
|
||||
tp->data.child.right = right;
|
||||
|
||||
return tp;
|
||||
}
|
||||
|
||||
70
crossassemblers/macro11/extree.h
Normal file
70
crossassemblers/macro11/extree.h
Normal file
@@ -0,0 +1,70 @@
|
||||
|
||||
#ifndef EXTREE__H
|
||||
#define EXTREE__H
|
||||
|
||||
#include "symbols.h"
|
||||
|
||||
typedef struct ex_tree {
|
||||
enum ex_type { EX_LIT = 1,
|
||||
/* Expression is a literal value */
|
||||
EX_SYM = 2,
|
||||
/* Expression has a symbol reference */
|
||||
EX_UNDEFINED_SYM = 3,
|
||||
/* Expression is undefined sym reference */
|
||||
EX_TEMP_SYM = 4,
|
||||
/* Expression is temp sym reference */
|
||||
|
||||
EX_COM = 5,
|
||||
/* One's complement */
|
||||
EX_NEG = 6,
|
||||
/* Negate */
|
||||
EX_ERR = 7,
|
||||
/* Expression with an error */
|
||||
|
||||
EX_ADD = 8,
|
||||
/* Add */
|
||||
EX_SUB = 9,
|
||||
/* Subtract */
|
||||
EX_MUL = 10,
|
||||
/* Multiply */
|
||||
EX_DIV = 11,
|
||||
/* Divide */
|
||||
EX_AND = 12,
|
||||
/* bitwise and */
|
||||
EX_OR = 13 /* bitwise or */
|
||||
} type;
|
||||
|
||||
char *cp; /* points to end of parsed expression */
|
||||
|
||||
union {
|
||||
struct {
|
||||
struct ex_tree *left,
|
||||
*right; /* Left, right children */
|
||||
} child;
|
||||
unsigned lit; /* Literal value */
|
||||
SYMBOL *symbol; /* Symbol reference */
|
||||
} data;
|
||||
} EX_TREE;
|
||||
|
||||
|
||||
EX_TREE *new_ex_tree(
|
||||
void);
|
||||
void free_tree(
|
||||
EX_TREE *tp);
|
||||
|
||||
EX_TREE *new_ex_lit(
|
||||
unsigned value);
|
||||
EX_TREE *ex_err(
|
||||
EX_TREE *tp,
|
||||
char *cp);
|
||||
EX_TREE *new_ex_bin(
|
||||
int type,
|
||||
EX_TREE *left,
|
||||
EX_TREE *right);
|
||||
|
||||
EX_TREE *evaluate(
|
||||
EX_TREE *tp,
|
||||
int undef);
|
||||
|
||||
|
||||
#endif
|
||||
184
crossassemblers/macro11/listing.c
Normal file
184
crossassemblers/macro11/listing.c
Normal file
@@ -0,0 +1,184 @@
|
||||
#define LISTING__C
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "listing.h" /* my own definitions */
|
||||
|
||||
#include "util.h"
|
||||
#include "assemble_globals.h"
|
||||
|
||||
|
||||
/* GLOBAL VARIABLES */
|
||||
|
||||
int list_md = 1; /* option to list macro/rept definition = yes */
|
||||
|
||||
int list_me = 1; /* option to list macro/rept expansion = yes */
|
||||
|
||||
int list_bex = 1; /* option to show binary */
|
||||
|
||||
int list_level = 1; /* Listing control level. .LIST
|
||||
increments; .NLIST decrements */
|
||||
|
||||
static char *listline; /* Source lines */
|
||||
|
||||
static char *binline; /* for octal expansion */
|
||||
|
||||
FILE *lstfile = NULL;
|
||||
|
||||
int list_pass_0 = 0;/* Also list what happens during the first pass */
|
||||
|
||||
|
||||
|
||||
/* do_list returns TRUE if listing is enabled. */
|
||||
|
||||
static int dolist(
|
||||
void)
|
||||
{
|
||||
int ok = lstfile != NULL &&
|
||||
(pass > 0 || list_pass_0) &&
|
||||
list_level > 0;
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
/* list_source saves a text line for later listing by list_flush */
|
||||
|
||||
void list_source(
|
||||
STREAM *str,
|
||||
char *cp)
|
||||
{
|
||||
if (dolist()) {
|
||||
int len = strcspn(cp, "\n");
|
||||
|
||||
/* Save the line text away for later... */
|
||||
if (listline)
|
||||
free(listline);
|
||||
listline = memcheck(malloc(len + 1));
|
||||
memcpy(listline, cp, len);
|
||||
listline[len] = 0;
|
||||
|
||||
if (!binline)
|
||||
binline = memcheck(malloc(sizeof(LSTFORMAT) + 16));
|
||||
|
||||
sprintf(binline, "%*s%*d", (int)SIZEOF_MEMBER(LSTFORMAT, flag), "", (int)SIZEOF_MEMBER(LSTFORMAT, line_number),
|
||||
str->line);
|
||||
}
|
||||
}
|
||||
|
||||
/* list_flush produces a buffered list line. */
|
||||
|
||||
void list_flush(
|
||||
void)
|
||||
{
|
||||
if (dolist()) {
|
||||
padto(binline, offsetof(LSTFORMAT, source));
|
||||
fputs(binline, lstfile);
|
||||
fputs(listline, lstfile);
|
||||
fputc('\n', lstfile);
|
||||
listline[0] = 0;
|
||||
binline[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* list_fit checks to see if a word will fit in the current listing
|
||||
line. If not, it flushes and prepares another line. */
|
||||
|
||||
static void list_fit(
|
||||
STREAM *str,
|
||||
unsigned addr)
|
||||
{
|
||||
size_t col1 = offsetof(LSTFORMAT, source);
|
||||
size_t col2 = offsetof(LSTFORMAT, pc);
|
||||
|
||||
if (strlen(binline) >= col1) {
|
||||
list_flush();
|
||||
listline[0] = 0;
|
||||
binline[0] = 0;
|
||||
sprintf(binline, "%*s %6.6o", (int)offsetof(LSTFORMAT, pc), "", addr);
|
||||
padto(binline, offsetof(LSTFORMAT, words));
|
||||
} else if (strlen(binline) <= col2) {
|
||||
sprintf(binline, "%*s%*d %6.6o", (int)SIZEOF_MEMBER(LSTFORMAT, flag), "",
|
||||
(int)SIZEOF_MEMBER(LSTFORMAT, line_number), str->line, addr);
|
||||
padto(binline, offsetof(LSTFORMAT, words));
|
||||
}
|
||||
}
|
||||
|
||||
/* list_value is used to show a computed value */
|
||||
|
||||
void list_value(
|
||||
STREAM *str,
|
||||
unsigned word)
|
||||
{
|
||||
if (dolist()) {
|
||||
/* Print the value and go */
|
||||
binline[0] = 0;
|
||||
sprintf(binline, "%*s%*d %6.6o", (int)SIZEOF_MEMBER(LSTFORMAT, flag), "",
|
||||
(int)SIZEOF_MEMBER(LSTFORMAT, line_number), str->line, word & 0177777);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print a word to the listing file */
|
||||
|
||||
void list_word(
|
||||
STREAM *str,
|
||||
unsigned addr,
|
||||
unsigned value,
|
||||
int size,
|
||||
char *flags)
|
||||
{
|
||||
if (dolist()) {
|
||||
list_fit(str, addr);
|
||||
if (size == 1)
|
||||
sprintf(binline + strlen(binline), " %3.3o%1.1s ", value & 0377, flags);
|
||||
else
|
||||
sprintf(binline + strlen(binline), "%6.6o%1.1s ", value & 0177777, flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Print just a line with the address to the listing file */
|
||||
|
||||
void list_location(
|
||||
STREAM *str,
|
||||
unsigned addr)
|
||||
{
|
||||
if (dolist()) {
|
||||
list_fit(str, addr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* reports errors */
|
||||
void report(
|
||||
STREAM *str,
|
||||
char *fmt,
|
||||
...)
|
||||
{
|
||||
va_list ap;
|
||||
char *name = "**";
|
||||
int line = 0;
|
||||
|
||||
if (!pass && list_pass_0 < 2)
|
||||
return; /* Don't report now. */
|
||||
|
||||
if (str) {
|
||||
name = str->name;
|
||||
line = str->line;
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s:%d: ***ERROR ", name, line);
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (lstfile) {
|
||||
fprintf(lstfile, "%s:%d: ***ERROR ", name, line);
|
||||
va_start(ap, fmt);
|
||||
vfprintf(lstfile, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
69
crossassemblers/macro11/listing.h
Normal file
69
crossassemblers/macro11/listing.h
Normal file
@@ -0,0 +1,69 @@
|
||||
|
||||
#ifndef LISTING__H
|
||||
#define LISTING__H
|
||||
|
||||
#include "stream2.h"
|
||||
|
||||
/*
|
||||
format of a listing line
|
||||
Interestingly, no instances of this struct are ever created.
|
||||
It lives to be a way to layout the format of a list line.
|
||||
I wonder if I should have bothered.
|
||||
*/
|
||||
|
||||
typedef struct lstformat {
|
||||
char flag[2]; /* Error flags */
|
||||
char line_number[6]; /* Line number */
|
||||
char pc[8]; /* Location */
|
||||
char words[8][3]; /* three instruction words */
|
||||
char source[1]; /* source line */
|
||||
} LSTFORMAT;
|
||||
|
||||
|
||||
/* GLOBAL VARIABLES */
|
||||
#ifndef LISTING__C
|
||||
extern int list_md; /* option to list macro/rept definition = yes */
|
||||
|
||||
extern int list_me; /* option to list macro/rept expansion = yes */
|
||||
|
||||
extern int list_bex; /* option to show binary */
|
||||
|
||||
extern int list_level; /* Listing control level. .LIST
|
||||
increments; .NLIST decrements */
|
||||
|
||||
extern FILE *lstfile;
|
||||
|
||||
extern int list_pass_0; /* Also list what happens during the first pass */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void list_word(
|
||||
STREAM *str,
|
||||
unsigned addr,
|
||||
unsigned value,
|
||||
int size,
|
||||
char *flags);
|
||||
|
||||
void list_value(
|
||||
STREAM *str,
|
||||
unsigned word);
|
||||
|
||||
void list_location(
|
||||
STREAM *str,
|
||||
unsigned word);
|
||||
|
||||
void list_source(
|
||||
STREAM *str,
|
||||
char *cp);
|
||||
|
||||
void list_flush(
|
||||
void);
|
||||
|
||||
void report(
|
||||
STREAM *str,
|
||||
char *fmt,
|
||||
...);
|
||||
|
||||
|
||||
#endif
|
||||
441
crossassemblers/macro11/macro11.c
Normal file
441
crossassemblers/macro11/macro11.c
Normal file
@@ -0,0 +1,441 @@
|
||||
#define MACRO11__C
|
||||
|
||||
|
||||
/*
|
||||
Assembler compatible with MACRO-11.
|
||||
|
||||
Copyright (c) 2001, Richard Krehbiel
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
o Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
o Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
o Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "macro11.h"
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#include "assemble_globals.h"
|
||||
#include "assemble.h"
|
||||
#include "assemble_aux.h"
|
||||
#include "listing.h"
|
||||
#include "object.h"
|
||||
#include "symbols.h"
|
||||
|
||||
#define stricmp strcasecmp
|
||||
|
||||
|
||||
/* enable_tf is called by command argument parsing to enable and
|
||||
disable named options. */
|
||||
|
||||
static void enable_tf(
|
||||
char *opt,
|
||||
int tf)
|
||||
{
|
||||
if (strcmp(opt, "AMA") == 0)
|
||||
enabl_ama = tf;
|
||||
else if (strcmp(opt, "GBL") == 0)
|
||||
enabl_gbl = tf;
|
||||
else if (strcmp(opt, "ME") == 0)
|
||||
list_me = tf;
|
||||
else if (strcmp(opt, "BEX") == 0)
|
||||
list_bex = tf;
|
||||
else if (strcmp(opt, "MD") == 0)
|
||||
list_md = tf;
|
||||
}
|
||||
|
||||
/*JH:*/
|
||||
static void print_version(
|
||||
FILE *strm)
|
||||
{
|
||||
fprintf(strm, "macro11 - portable MACRO11 assembler for DEC PDP-11\n");
|
||||
fprintf(strm, " Version %s\n", VERSIONSTR);
|
||||
fprintf(strm, " Copyright 2001 Richard Krehbiel,\n");
|
||||
fprintf(strm, " modified 2009 by Joerg Hoppe,\n");
|
||||
fprintf(strm, " modified 2015 by Olaf 'Rhialto' Seibert.\n");
|
||||
}
|
||||
|
||||
static void append_env(
|
||||
char *envname,
|
||||
char *value)
|
||||
{
|
||||
char *env = getenv(envname);
|
||||
char *temp;
|
||||
|
||||
if (env == NULL)
|
||||
env = "";
|
||||
|
||||
temp = memcheck(malloc(strlen(envname) +
|
||||
1 +
|
||||
strlen(env) +
|
||||
1 +
|
||||
strlen(value) +
|
||||
1));
|
||||
strcpy(temp, envname);
|
||||
strcat(temp, "=");
|
||||
strcat(temp, env);
|
||||
strcat(temp, PATHSEP);
|
||||
strcat(temp, value);
|
||||
putenv(temp);
|
||||
}
|
||||
|
||||
/*JH:*/
|
||||
static void print_help(
|
||||
void)
|
||||
{
|
||||
printf("\n");
|
||||
print_version(stdout);
|
||||
printf("\n");
|
||||
printf("Usage:\n");
|
||||
printf(" macro11 [-o <file>] [-l [<file>]] \n");
|
||||
printf(" [-h] [-v][-e <option>] [-d <option>]\n");
|
||||
printf(" [-ysl <num>] [-yus] \n");
|
||||
printf(" [-m <file>] [-p <directory>] [-x]\n");
|
||||
printf(" <inputfile> [<inputfile> ...]\n");
|
||||
printf("\n");
|
||||
printf("Arguments:\n");
|
||||
printf("<inputfile> MACRO11 source file(s) to assemble\n");
|
||||
printf("\n");
|
||||
printf("Options:\n");
|
||||
printf("-d disable <option> (see below)\n");
|
||||
printf("-e enable <option> (see below)\n");
|
||||
printf("-h print this help\n");
|
||||
printf("-l gives the listing file name (.LST)\n");
|
||||
printf(" -l - enables listing to stdout.\n");
|
||||
printf("-m load RT-11 compatible macro library from which\n");
|
||||
printf(" .MCALLed macros can be found.\n");
|
||||
printf(" Multiple allowed.\n");
|
||||
printf("-o gives the object file name (.OBJ)\n");
|
||||
printf("-p gives the name of a directory in which .MCALLed macros may be found.\n");
|
||||
printf(" Sets environment variable \"MCALL\".\n");
|
||||
printf("-I gives the name of a directory in which .included files may be found.\n");
|
||||
printf(" Sets environment variable \"INCLUDE\".\n");
|
||||
|
||||
printf("-v print version\n");
|
||||
printf(" Violates DEC standard, but sometimes needed\n");
|
||||
printf("-x invokes macro11 to expand the contents of the registered macro \n");
|
||||
printf(" libraries (see -m) into individual .MAC files in the current\n");
|
||||
printf(" directory. No assembly of input is done.\n");
|
||||
printf(" This must be the last command line option!\n");
|
||||
printf("-ysl Syntax extension: change length of symbols from \n");
|
||||
printf(" default = %d to larger values, max %d.\n", SYMMAX_DEFAULT, SYMMAX_MAX);
|
||||
printf("-yus Syntax extension: allow underscore \"_\" in symbols.\n");
|
||||
printf("-yl1 Extension: list the first pass too, not only the second.\n");
|
||||
printf("\n");
|
||||
printf("Options for -e and -d are:\n");
|
||||
printf("AMA (off) - absolute addressing (versus PC-relative)\n");
|
||||
printf(" See .ENABL AMA, .DSABL AMA\n");
|
||||
printf("GBL (on) - treat unresolved symbols as globals, linker must resolve.\n");
|
||||
printf(" If disabled, unresolved globals are errors.\n");
|
||||
printf(" See .ENABL GBL, .DSABL GBL\n");
|
||||
printf("ME (on) - list macro expansion (no func)\n");
|
||||
printf("BEX (on) - show binary (no func)\n");
|
||||
printf("MD (on) - list macro/rept definition\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void usage(char *message) {
|
||||
fputs(message, stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int main(
|
||||
int argc,
|
||||
char *argv[])
|
||||
{
|
||||
char *fnames[32];
|
||||
int nr_files = 0;
|
||||
FILE *obj = NULL;
|
||||
TEXT_RLD tr;
|
||||
char *objname = NULL;
|
||||
char *lstname = NULL;
|
||||
int arg;
|
||||
int i;
|
||||
STACK stack;
|
||||
int errcount;
|
||||
|
||||
if (argc <= 1) {
|
||||
print_help();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for (arg = 1; arg < argc; arg++)
|
||||
if (*argv[arg] == '-') {
|
||||
char *cp;
|
||||
|
||||
cp = argv[arg] + 1;
|
||||
if (!stricmp(cp, "h")) {
|
||||
print_help();
|
||||
} else if (!stricmp(cp, "v")) {
|
||||
print_version(stderr);
|
||||
} else if (!stricmp(cp, "e")) {
|
||||
/* Followed by options to enable */
|
||||
/* Since /SHOW and /ENABL option names don't overlap,
|
||||
I consolidate. */
|
||||
if(arg >= argc-1 || !isalpha((unsigned char)*argv[arg+1])) {
|
||||
usage("-e must be followed by an option to enable\n");
|
||||
}
|
||||
upcase(argv[++arg]);
|
||||
enable_tf(argv[arg], 1);
|
||||
} else if (!stricmp(cp, "d")) {
|
||||
/* Followed by an option to disable */
|
||||
if(arg >= argc-1 || !isalpha((unsigned char)*argv[arg+1])) {
|
||||
usage("-d must be followed by an option to disable\n");
|
||||
}
|
||||
upcase(argv[++arg]);
|
||||
enable_tf(argv[arg], 0);
|
||||
} else if (!stricmp(cp, "m")) {
|
||||
/* Macro library */
|
||||
/* This option gives the name of an RT-11 compatible
|
||||
macro library from which .MCALLed macros can be
|
||||
found. */
|
||||
if(arg >= argc-1 || *argv[arg+1] == '-') {
|
||||
usage("-m must be followed by a macro library file name\n");
|
||||
}
|
||||
arg++;
|
||||
int allow_olb = strcmp(argv[argc-1], "-x") == 0;
|
||||
mlbs[nr_mlbs] = mlb_open(argv[arg], allow_olb);
|
||||
if (mlbs[nr_mlbs] == NULL) {
|
||||
fprintf(stderr, "Unable to register macro library %s\n", argv[arg]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
nr_mlbs++;
|
||||
} else if (!stricmp(cp, "p")) {
|
||||
/* P for search path */
|
||||
/* The -p option gives the name of a directory in
|
||||
which .MCALLed macros may be found. */ {
|
||||
|
||||
if(arg >= argc-1 || *argv[arg+1] == '-') {
|
||||
usage("-p must be followed by a macro search directory\n");
|
||||
}
|
||||
|
||||
append_env("MCALL", argv[arg+1]);
|
||||
arg++;
|
||||
}
|
||||
} else if (!stricmp(cp, "I")) {
|
||||
/* I for include path */
|
||||
/* The -I option gives the name of a directory in
|
||||
which .included files may be found. */ {
|
||||
|
||||
if(arg >= argc-1 || *argv[arg+1] == '-') {
|
||||
usage("-I must be followed by a include file search directory\n");
|
||||
}
|
||||
append_env("INCLUDE", argv[arg+1]);
|
||||
|
||||
arg++;
|
||||
}
|
||||
} else if (!stricmp(cp, "o")) {
|
||||
/* The -o option gives the object file name (.OBJ) */
|
||||
if(arg >= argc-1 || *argv[arg+1] == '-') {
|
||||
usage("-o must be followed by the object file name\n");
|
||||
}
|
||||
++arg;
|
||||
objname = argv[arg];
|
||||
} else if (!stricmp(cp, "l")) {
|
||||
/* The option -l gives the listing file name (.LST) */
|
||||
/* -l - enables listing to stdout. */
|
||||
if(arg >= argc-1 ||
|
||||
(argv[arg+1][0] == '-' && argv[arg+1][1] != '\0')) {
|
||||
usage("-l must be followed by the listing file name (- for standard output)\n");
|
||||
}
|
||||
lstname = argv[++arg];
|
||||
if (strcmp(lstname, "-") == 0)
|
||||
lstfile = stdout;
|
||||
else
|
||||
lstfile = fopen(lstname, "w");
|
||||
} else if (!stricmp(cp, "x")) {
|
||||
/* The -x option invokes macro11 to expand the
|
||||
contents of the registered macro libraries (see -m)
|
||||
into individual .MAC files in the current
|
||||
directory. No assembly of input is done. This
|
||||
must be the last command line option. */
|
||||
int m;
|
||||
|
||||
if(arg != argc-1) {
|
||||
usage("-x must be the last option\n");
|
||||
}
|
||||
for (m = 0; m < nr_mlbs; m++)
|
||||
mlb_extract(mlbs[m]);
|
||||
return EXIT_SUCCESS;
|
||||
} else if (!stricmp(cp, "ysl")) {
|
||||
/* set symbol_len */
|
||||
if (arg >= argc-1) {
|
||||
usage("-s must be followed by a number\n");
|
||||
} else {
|
||||
char *s = argv[++arg];
|
||||
char *endp;
|
||||
int sl = strtol(s, &endp, 10);
|
||||
|
||||
if (*endp || sl < SYMMAX_DEFAULT || sl > SYMMAX_MAX) {
|
||||
usage("-s must be followed by a number\n");
|
||||
}
|
||||
symbol_len = sl;
|
||||
}
|
||||
} else if (!stricmp(cp, "yus")) {
|
||||
/* allow underscores */
|
||||
symbol_allow_underscores = 1;
|
||||
} else if (!stricmp(cp, "yl1")) {
|
||||
/* list the first pass, in addition to the second */
|
||||
list_pass_0++;
|
||||
} else if (!stricmp(cp, "yd")) {
|
||||
enabl_debug++;
|
||||
} else {
|
||||
fprintf(stderr, "Unknown option %s\n", argv[arg]);
|
||||
print_help();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
fnames[nr_files++] = argv[arg];
|
||||
}
|
||||
|
||||
if (objname) {
|
||||
obj = fopen(objname, "wb");
|
||||
if (obj == NULL)
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
add_symbols(&blank_section);
|
||||
|
||||
text_init(&tr, NULL, 0);
|
||||
|
||||
module_name = memcheck(strdup(".MAIN."));
|
||||
|
||||
xfer_address = new_ex_lit(1); /* The undefined transfer address */
|
||||
|
||||
stack_init(&stack);
|
||||
/* Push the files onto the input stream in reverse order */
|
||||
for (i = nr_files - 1; i >= 0; --i) {
|
||||
STREAM *str = new_file_stream(fnames[i]);
|
||||
|
||||
if (str == NULL) {
|
||||
report(NULL, "Unable to open file %s\n", fnames[i]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
stack_push(&stack, str);
|
||||
}
|
||||
|
||||
DOT = 0;
|
||||
current_pc->section = &blank_section;
|
||||
last_dot_section = NULL;
|
||||
pass = 0;
|
||||
stmtno = 0;
|
||||
lsb = 0;
|
||||
next_lsb = 1;
|
||||
lsb_used = 0;
|
||||
last_macro_lsb = -1;
|
||||
last_locsym = 32767;
|
||||
last_cond = -1;
|
||||
sect_sp = -1;
|
||||
suppressed = 0;
|
||||
|
||||
assemble_stack(&stack, &tr);
|
||||
|
||||
if (list_pass_0 && lstfile) {
|
||||
list_symbol_table();
|
||||
}
|
||||
#if 0
|
||||
if (enabl_debug > 1)
|
||||
dump_all_macros();
|
||||
#endif
|
||||
|
||||
assert(stack.top == NULL);
|
||||
|
||||
migrate_implicit(); /* Migrate the implicit globals */
|
||||
write_globals(obj); /* Write the global symbol dictionary */
|
||||
|
||||
#if 0
|
||||
sym_hist(&symbol_st, "symbol_st"); /* Draw a symbol table histogram */
|
||||
#endif
|
||||
|
||||
|
||||
text_init(&tr, obj, 0);
|
||||
|
||||
stack_init(&stack); /* Superfluous... */
|
||||
/* Re-push the files onto the input stream in reverse order */
|
||||
for (i = nr_files - 1; i >= 0; --i) {
|
||||
STREAM *str = new_file_stream(fnames[i]);
|
||||
|
||||
if (str == NULL) {
|
||||
report(NULL, "Unable to open file %s\n", fnames[i]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
stack_push(&stack, str);
|
||||
}
|
||||
|
||||
DOT = 0;
|
||||
|
||||
current_pc->section = &blank_section;
|
||||
last_dot_section = NULL;
|
||||
|
||||
pass = 1;
|
||||
stmtno = 0;
|
||||
lsb = 0;
|
||||
next_lsb = 1;
|
||||
lsb_used = 0;
|
||||
last_macro_lsb = -1;
|
||||
last_locsym = 32767;
|
||||
pop_cond(-1);
|
||||
sect_sp = -1;
|
||||
suppressed = 0;
|
||||
|
||||
errcount = assemble_stack(&stack, &tr);
|
||||
|
||||
text_flush(&tr);
|
||||
|
||||
while (last_cond >= 0) {
|
||||
report(NULL, "%s:%d: Unterminated conditional\n", conds[last_cond].file, conds[last_cond].line);
|
||||
pop_cond(last_cond - 1);
|
||||
errcount++;
|
||||
}
|
||||
|
||||
for (i = 0; i < nr_mlbs; i++)
|
||||
mlb_close(mlbs[i]);
|
||||
|
||||
write_endmod(obj);
|
||||
|
||||
if (obj != NULL)
|
||||
fclose(obj);
|
||||
|
||||
if (errcount > 0)
|
||||
fprintf(stderr, "%d Errors\n", errcount);
|
||||
|
||||
if (lstfile) {
|
||||
list_symbol_table();
|
||||
}
|
||||
|
||||
if (lstfile && strcmp(lstname, "-") != 0)
|
||||
fclose(lstfile);
|
||||
|
||||
return errcount > 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
180
crossassemblers/macro11/macro11.dsp
Normal file
180
crossassemblers/macro11/macro11.dsp
Normal file
@@ -0,0 +1,180 @@
|
||||
# Microsoft Developer Studio Project File - Name="macro11" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||
|
||||
CFG=macro11 - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "macro11.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "macro11.mak" CFG="macro11 - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "macro11 - Win32 Release" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE "macro11 - Win32 Debug" (based on "Win32 (x86) Console Application")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""$/macro11", BAAAAAAA"
|
||||
# PROP Scc_LocalPath "."
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "macro11 - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c
|
||||
# SUBTRACT CPP /YX
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
||||
# SUBTRACT LINK32 /profile
|
||||
# Begin Special Build Tool
|
||||
TargetPath=.\Release\macro11.exe
|
||||
SOURCE="$(InputPath)"
|
||||
PostBuild_Cmds=copy $(TargetPath) c:\bin
|
||||
# End Special Build Tool
|
||||
|
||||
!ELSEIF "$(CFG)" == "macro11 - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "Debug"
|
||||
# PROP BASE Intermediate_Dir "Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "MEM_DEBUG" /FR /FD /GZ /c
|
||||
# SUBTRACT CPP /YX
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||
# SUBTRACT LINK32 /profile
|
||||
# Begin Special Build Tool
|
||||
TargetPath=.\Debug\macro11.exe
|
||||
SOURCE="$(InputPath)"
|
||||
PostBuild_Cmds=copy $(TargetPath) c:\bin
|
||||
# End Special Build Tool
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "macro11 - Win32 Release"
|
||||
# Name "macro11 - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\macro11.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\mlb.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\object.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\rad50.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\stream2.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\util.c
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\macro11.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\mlb.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\object.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Rad50.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\stream2.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\util.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Resource Files"
|
||||
|
||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Changes
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\License
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Makefile
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Readme
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Todo
|
||||
# End Source File
|
||||
# End Target
|
||||
# End Project
|
||||
53
crossassemblers/macro11/macro11.dsw
Normal file
53
crossassemblers/macro11/macro11.dsw
Normal file
@@ -0,0 +1,53 @@
|
||||
Microsoft Developer Studio Workspace File, Format Version 6.00
|
||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "dumpobj"=.\dumpobj.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
begin source code control
|
||||
"$/macro11", BAAAAAAA
|
||||
.
|
||||
end source code control
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "macro11"=.\macro11.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
begin source code control
|
||||
"$/macro11", BAAAAAAA
|
||||
.
|
||||
end source code control
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Global:
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
begin source code control
|
||||
"$/macro11", BAAAAAAA
|
||||
.
|
||||
end source code control
|
||||
}}}
|
||||
|
||||
Package=<3>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
51
crossassemblers/macro11/macro11.h
Normal file
51
crossassemblers/macro11/macro11.h
Normal file
@@ -0,0 +1,51 @@
|
||||
#ifndef MACRO11_H
|
||||
#define MACRO11_H
|
||||
|
||||
#include "git-info.h"
|
||||
|
||||
#define BASE_VERSION "0.4"
|
||||
|
||||
#if defined(GIT_VERSION)
|
||||
#define VERSIONSTR BASE_VERSION" ("GIT_VERSION"\n\t"GIT_AUTHOR_DATE")"
|
||||
#else
|
||||
#define VERSIONSTR BASE_VERSION" (21 June 2015)"
|
||||
/*#define VERSIONSTR "0.3 (April 21, 2009)" */
|
||||
/*#define VERSIONSTR "0.2 July 15, 2001" */
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
Copyright (c) 2001, Richard Krehbiel
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
o Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
o Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
o Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#endif
|
||||
603
crossassemblers/macro11/macros.c
Normal file
603
crossassemblers/macro11/macros.c
Normal file
@@ -0,0 +1,603 @@
|
||||
|
||||
#define MACROS__C
|
||||
|
||||
|
||||
/*
|
||||
Dealing with MACROs
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "macros.h" /* my own definitions */
|
||||
|
||||
#include "util.h"
|
||||
#include "assemble_globals.h"
|
||||
#include "assemble_aux.h"
|
||||
#include "listing.h"
|
||||
#include "parse.h"
|
||||
#include "stream2.h"
|
||||
#include "symbols.h"
|
||||
|
||||
|
||||
/* Here's where I pretend I'm a C++ compiler. :-/ */
|
||||
|
||||
/* *** derive a MACRO_STREAM from a BUFFER_STREAM with a few other args */
|
||||
|
||||
|
||||
/* macro_stream_delete is called when a macro expansion is
|
||||
exhausted. The unique behavior is to unwind any stacked
|
||||
conditionals. This allows a nested .MEXIT to work. */
|
||||
|
||||
void macro_stream_delete(
|
||||
STREAM *str)
|
||||
{
|
||||
MACRO_STREAM *mstr = (MACRO_STREAM *) str;
|
||||
|
||||
pop_cond(mstr->cond);
|
||||
buffer_stream_delete(str);
|
||||
}
|
||||
|
||||
STREAM_VTBL macro_stream_vtbl = {
|
||||
macro_stream_delete, buffer_stream_gets, buffer_stream_rewind
|
||||
};
|
||||
|
||||
STREAM *new_macro_stream(
|
||||
STREAM *refstr,
|
||||
BUFFER *buf,
|
||||
MACRO *mac,
|
||||
int nargs)
|
||||
{
|
||||
MACRO_STREAM *mstr = memcheck(malloc(sizeof(MACRO_STREAM))); {
|
||||
char *name = memcheck(malloc(strlen(refstr->name) + 32));
|
||||
|
||||
sprintf(name, "%s:%d->%s", refstr->name, refstr->line, mac->sym.label);
|
||||
buffer_stream_construct(&mstr->bstr, buf, name);
|
||||
free(name);
|
||||
}
|
||||
|
||||
mstr->bstr.stream.vtbl = ¯o_stream_vtbl;
|
||||
mstr->nargs = nargs; /* for .NARG directive: nonkeyword arguments in call*/
|
||||
mstr->cond = last_cond;
|
||||
return &mstr->bstr.stream;
|
||||
}
|
||||
|
||||
/* read_body fetches the body of .MACRO, .REPT, .IRP, or .IRPC into a
|
||||
BUFFER. */
|
||||
|
||||
void read_body(
|
||||
STACK *stack,
|
||||
BUFFER *gb,
|
||||
char *name,
|
||||
int called)
|
||||
{
|
||||
int nest;
|
||||
|
||||
/* Read the stream in until the end marker is hit */
|
||||
|
||||
/* Note: "called" says that this body is being pulled from a macro
|
||||
library, and so under no circumstance should it be listed. */
|
||||
|
||||
nest = 1;
|
||||
for (;;) {
|
||||
SYMBOL *op;
|
||||
char *nextline;
|
||||
char *cp;
|
||||
|
||||
nextline = stack_gets(stack); /* Now read the line */
|
||||
if (nextline == NULL) { /* End of file. */
|
||||
report(stack->top, "Macro body of '%s' not closed\n", name);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!called && (list_level - 1 + list_md) > 0) {
|
||||
list_flush();
|
||||
list_source(stack->top, nextline);
|
||||
}
|
||||
|
||||
op = get_op(nextline, &cp);
|
||||
|
||||
if (op == NULL) { /* Not a pseudo-op */
|
||||
buffer_append_line(gb, nextline);
|
||||
continue;
|
||||
}
|
||||
if (op->section->type == SECTION_PSEUDO) {
|
||||
if (op->value == P_MACRO || op->value == P_REPT || op->value == P_IRP || op->value == P_IRPC) {
|
||||
nest++;
|
||||
}
|
||||
|
||||
if (op->value == P_ENDM || op->value == P_ENDR) {
|
||||
nest--;
|
||||
/* If there's a name on the .ENDM, then
|
||||
* check if the name matches the one on .MACRO.
|
||||
* See page 7-3.
|
||||
* Since we don't keep a stack of nested
|
||||
* .MACRO names, just check for the outer one.
|
||||
*/
|
||||
if (nest == 0 && name && op->value == P_ENDM) {
|
||||
cp = skipwhite(cp);
|
||||
if (!EOL(*cp)) {
|
||||
char *label = get_symbol(cp, &cp, NULL);
|
||||
|
||||
if (label) {
|
||||
if (strcmp(label, name) != 0) {
|
||||
report(stack->top, ".ENDM '%s' does not match .MACRO '%s'\n", label, name);
|
||||
}
|
||||
free(label);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nest == 0)
|
||||
return; /* All done. */
|
||||
}
|
||||
|
||||
buffer_append_line(gb, nextline);
|
||||
}
|
||||
}
|
||||
|
||||
/* Diagnostic: dumpmacro dumps a macro definition to stdout.
|
||||
I used this for debugging; it's not called at all right now, but
|
||||
I hate to delete good code. */
|
||||
|
||||
void dumpmacro(
|
||||
MACRO *mac,
|
||||
FILE *fp)
|
||||
{
|
||||
ARG *arg;
|
||||
|
||||
fprintf(fp, ".MACRO %s ", mac->sym.label);
|
||||
|
||||
for (arg = mac->args; arg != NULL; arg = arg->next) {
|
||||
fputs(arg->label, fp);
|
||||
if (arg->value) {
|
||||
fputc('=', fp);
|
||||
fputs(arg->value, fp);
|
||||
}
|
||||
fputc(' ', fp);
|
||||
}
|
||||
fputc('\n', fp);
|
||||
|
||||
fputs(mac->text->buffer, fp);
|
||||
|
||||
fputs(".ENDM\n", fp);
|
||||
}
|
||||
|
||||
/* defmacro - define a macro. */
|
||||
/* Also used by .MCALL to pull macro definitions from macro libraries */
|
||||
|
||||
MACRO *defmacro(
|
||||
char *cp,
|
||||
STACK *stack,
|
||||
int called)
|
||||
{
|
||||
MACRO *mac;
|
||||
ARG *arg,
|
||||
**argtail;
|
||||
char *label;
|
||||
|
||||
cp = skipwhite(cp);
|
||||
label = get_symbol(cp, &cp, NULL);
|
||||
if (label == NULL) {
|
||||
report(stack->top, "Invalid macro definition\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Allow redefinition of a macro; new definition replaces the old. */
|
||||
mac = (MACRO *) lookup_sym(label, ¯o_st);
|
||||
if (mac) {
|
||||
/* Remove from the symbol table... */
|
||||
remove_sym(&mac->sym, ¯o_st);
|
||||
free_macro(mac);
|
||||
}
|
||||
|
||||
mac = new_macro(label);
|
||||
|
||||
add_table(&mac->sym, ¯o_st);
|
||||
|
||||
argtail = &mac->args;
|
||||
cp = skipdelim(cp);
|
||||
|
||||
while (!EOL(*cp)) {
|
||||
arg = new_arg();
|
||||
arg->locsym = *cp == '?';
|
||||
if (arg->locsym) /* special argument flag? */
|
||||
cp++;
|
||||
arg->label = get_symbol(cp, &cp, NULL);
|
||||
if (arg->label == NULL) {
|
||||
/* It turns out that I have code which is badly formatted
|
||||
but which MACRO.SAV assembles. Sigh. */
|
||||
/* So, just quit defining arguments. */
|
||||
break;
|
||||
#if 0
|
||||
report(str, "Illegal macro argument\n");
|
||||
remove_sym(&mac->sym, ¯o_st);
|
||||
free_macro(mac);
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
cp = skipwhite(cp);
|
||||
if (*cp == '=') {
|
||||
/* Default substitution given */
|
||||
arg->value = getstring(cp + 1, &cp);
|
||||
if (arg->value == NULL) {
|
||||
report(stack->top, "Illegal macro argument\n");
|
||||
remove_sym(&mac->sym, ¯o_st);
|
||||
free_macro(mac);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Append to list of arguments */
|
||||
arg->next = NULL;
|
||||
*argtail = arg;
|
||||
argtail = &arg->next;
|
||||
|
||||
cp = skipdelim(cp);
|
||||
}
|
||||
|
||||
/* Read the stream in until the end marker is hit */ {
|
||||
BUFFER *gb;
|
||||
int levelmod = 0;
|
||||
|
||||
gb = new_buffer();
|
||||
|
||||
if (!called && !list_md) {
|
||||
list_level--;
|
||||
levelmod = 1;
|
||||
}
|
||||
|
||||
read_body(stack, gb, mac->sym.label, called);
|
||||
|
||||
list_level += levelmod;
|
||||
|
||||
if (mac->text != NULL) /* Discard old macro body */
|
||||
buffer_free(mac->text);
|
||||
|
||||
mac->text = gb;
|
||||
}
|
||||
|
||||
return mac;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Allocate a new ARG */
|
||||
|
||||
ARG *new_arg(
|
||||
void)
|
||||
{
|
||||
ARG *arg = memcheck(malloc(sizeof(ARG)));
|
||||
|
||||
arg->locsym = 0;
|
||||
arg->value = NULL;
|
||||
arg->next = NULL;
|
||||
arg->label = NULL;
|
||||
return arg;
|
||||
}
|
||||
|
||||
|
||||
/* Free a list of args (as for a macro, or a macro expansion) */
|
||||
|
||||
static void free_args(
|
||||
ARG *arg)
|
||||
{
|
||||
ARG *next;
|
||||
|
||||
while (arg) {
|
||||
next = arg->next;
|
||||
if (arg->label) {
|
||||
free(arg->label);
|
||||
arg->label = NULL;
|
||||
}
|
||||
if (arg->value) {
|
||||
free(arg->value);
|
||||
arg->value = NULL;
|
||||
}
|
||||
free(arg);
|
||||
arg = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* find_arg - looks for an arg with the given name in the given
|
||||
argument list */
|
||||
|
||||
static ARG *find_arg(
|
||||
ARG *arg,
|
||||
char *name)
|
||||
{
|
||||
for (; arg != NULL; arg = arg->next)
|
||||
if (strcmp(arg->label, name) == 0)
|
||||
return arg;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* subst_args - given a BUFFER and a list of args, generate a new
|
||||
BUFFER with argument replacement having taken place. */
|
||||
|
||||
BUFFER *subst_args(
|
||||
BUFFER *text,
|
||||
ARG *args)
|
||||
{
|
||||
char *in;
|
||||
char *begin;
|
||||
BUFFER *gb;
|
||||
char *label;
|
||||
ARG *arg;
|
||||
|
||||
gb = new_buffer();
|
||||
|
||||
/* Blindly look for argument symbols in the input. */
|
||||
/* Don't worry about quotes or comments. */
|
||||
|
||||
for (begin = in = text->buffer; in < text->buffer + text->length;) {
|
||||
char *next;
|
||||
|
||||
if (issym((unsigned char)*in)) {
|
||||
label = get_symbol(in, &next, NULL);
|
||||
if (label) {
|
||||
if ((arg = find_arg(args, label))) {
|
||||
/* An apostrophe may appear before or after the symbol. */
|
||||
/* In either case, remove it from the expansion. */
|
||||
|
||||
if (in > begin && in[-1] == '\'')
|
||||
in--; /* Don't copy it. */
|
||||
if (*next == '\'')
|
||||
next++;
|
||||
|
||||
/* Copy prior characters */
|
||||
buffer_appendn(gb, begin, (int) (in - begin));
|
||||
/* Copy replacement string */
|
||||
buffer_append_line(gb, arg->value);
|
||||
in = begin = next;
|
||||
--in; /* prepare for subsequent increment */
|
||||
}
|
||||
free(label);
|
||||
in = next;
|
||||
} else
|
||||
in++;
|
||||
} else
|
||||
in++;
|
||||
}
|
||||
|
||||
/* Append the rest of the text */
|
||||
buffer_appendn(gb, begin, (int) (in - begin));
|
||||
|
||||
return gb; /* Done. */
|
||||
}
|
||||
|
||||
/* eval_str - the language allows an argument expression to be given
|
||||
as "\expression" which means, evaluate the expression and
|
||||
substitute the numeric value in the current radix. */
|
||||
|
||||
char *eval_str(
|
||||
STREAM *refstr,
|
||||
char *arg)
|
||||
{
|
||||
EX_TREE *value = parse_expr(arg, 0);
|
||||
unsigned word = 0;
|
||||
char temp[10];
|
||||
|
||||
if (value->type != EX_LIT) {
|
||||
report(refstr, "Constant value required\n");
|
||||
} else
|
||||
word = value->data.lit;
|
||||
|
||||
free_tree(value);
|
||||
|
||||
/* printf can't do base 2. */
|
||||
my_ultoa(word & 0177777, temp, radix);
|
||||
free(arg);
|
||||
arg = memcheck(strdup(temp));
|
||||
return arg;
|
||||
}
|
||||
|
||||
/* getstring_macarg - parse a string that possibly starts with a backslash.
|
||||
* If so, performs expression evaluation.
|
||||
*
|
||||
* The current implementation over-accepts some input.
|
||||
*
|
||||
* MACRO V05.05:
|
||||
|
||||
.list me
|
||||
.macro test x
|
||||
.blkb x
|
||||
.endm
|
||||
|
||||
size = 10
|
||||
foo = 2
|
||||
|
||||
; likes:
|
||||
|
||||
test size
|
||||
test \size
|
||||
test \<size>
|
||||
test \<size + foo>
|
||||
test ^/size + foo/
|
||||
|
||||
; dislikes:
|
||||
|
||||
test <\size> ; arg is \size which could be ok in other cases
|
||||
test size + foo ; gets split at the space
|
||||
test /size + foo/ ; gets split at the space
|
||||
test \/size + foo/
|
||||
test \^/size + foo/ ; * accepted by this version
|
||||
|
||||
*/
|
||||
|
||||
char *getstring_macarg(
|
||||
STREAM *refstr,
|
||||
char *cp,
|
||||
char **endp)
|
||||
{
|
||||
if (cp[0] == '\\') {
|
||||
char *str = getstring(cp + 1, endp);
|
||||
return eval_str(refstr, str); /* Perform expression evaluation */
|
||||
} else {
|
||||
return getstring(cp, endp);
|
||||
}
|
||||
}
|
||||
|
||||
/* expandmacro - return a STREAM containing the expansion of a macro */
|
||||
|
||||
STREAM *expandmacro(
|
||||
STREAM *refstr,
|
||||
MACRO *mac,
|
||||
char *cp)
|
||||
{
|
||||
ARG *arg,
|
||||
*args,
|
||||
*macarg;
|
||||
char *label;
|
||||
STREAM *str;
|
||||
BUFFER *buf;
|
||||
int nargs;
|
||||
int onemore;
|
||||
|
||||
args = NULL;
|
||||
arg = NULL;
|
||||
nargs = 0; /* for the .NARG directive */
|
||||
onemore = 0;
|
||||
|
||||
/* Parse the arguments */
|
||||
|
||||
while (!EOL(*cp) || onemore) {
|
||||
char *nextcp;
|
||||
|
||||
/* Check for named argument */
|
||||
label = get_symbol(cp, &nextcp, NULL);
|
||||
if (label && (nextcp = skipwhite(nextcp), *nextcp == '=') && (macarg = find_arg(mac->args, label))) {
|
||||
/* Check if I've already got a value for it */
|
||||
if (find_arg(args, label) != NULL) {
|
||||
report(refstr, "Duplicate submission of keyword " "argument %s\n", label);
|
||||
free(label);
|
||||
free_args(args);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
arg = new_arg();
|
||||
arg->label = label;
|
||||
nextcp = skipwhite(nextcp + 1);
|
||||
arg->value = getstring_macarg(refstr, nextcp, &nextcp);
|
||||
} else {
|
||||
if (label)
|
||||
free(label);
|
||||
|
||||
/* Find correct positional argument */
|
||||
|
||||
for (macarg = mac->args; macarg != NULL; macarg = macarg->next) {
|
||||
if (find_arg(args, macarg->label) == NULL)
|
||||
break; /* This is the next positional arg */
|
||||
}
|
||||
|
||||
if (macarg == NULL)
|
||||
break; /* Don't pick up any more arguments. */
|
||||
|
||||
arg = new_arg();
|
||||
arg->label = memcheck(strdup(macarg->label)); /* Copy the name */
|
||||
arg->value = getstring_macarg(refstr, cp, &nextcp);
|
||||
nargs++; /* Count nonkeyword arguments only. */
|
||||
}
|
||||
|
||||
arg->next = args;
|
||||
args = arg;
|
||||
|
||||
/* If there is a trailing comma, there is an empty last argument */
|
||||
cp = skipdelim_comma(nextcp, &onemore);
|
||||
}
|
||||
|
||||
/* Now go back and fill in defaults */ {
|
||||
int locsym;
|
||||
|
||||
if (last_macro_lsb != lsb)
|
||||
locsym = last_locsym = 32768;
|
||||
else
|
||||
locsym = last_locsym;
|
||||
last_macro_lsb = lsb;
|
||||
|
||||
for (macarg = mac->args; macarg != NULL; macarg = macarg->next) {
|
||||
arg = find_arg(args, macarg->label);
|
||||
if (arg == NULL) {
|
||||
arg = new_arg();
|
||||
arg->label = memcheck(strdup(macarg->label));
|
||||
if (macarg->locsym) {
|
||||
char temp[32];
|
||||
|
||||
/* Here's where we generate local labels */
|
||||
sprintf(temp, "%d$", locsym++);
|
||||
arg->value = memcheck(strdup(temp));
|
||||
} else if (macarg->value) {
|
||||
arg->value = memcheck(strdup(macarg->value));
|
||||
} else
|
||||
arg->value = memcheck(strdup(""));
|
||||
|
||||
arg->next = args;
|
||||
args = arg;
|
||||
}
|
||||
}
|
||||
|
||||
last_locsym = locsym;
|
||||
}
|
||||
|
||||
buf = subst_args(mac->text, args);
|
||||
|
||||
str = new_macro_stream(refstr, buf, mac, nargs);
|
||||
|
||||
free_args(args);
|
||||
buffer_free(buf);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
/* dump_all_macros is a diagnostic function that's currently not
|
||||
used. I used it while debugging, and I haven't removed it. */
|
||||
|
||||
void dump_all_macros(
|
||||
void)
|
||||
{
|
||||
MACRO *mac;
|
||||
SYMBOL_ITER iter;
|
||||
|
||||
for (mac = (MACRO *) first_sym(¯o_st, &iter); mac != NULL; mac = (MACRO *) next_sym(¯o_st, &iter)) {
|
||||
dumpmacro(mac, lstfile);
|
||||
|
||||
fprintf(lstfile, "\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Allocate a new macro */
|
||||
|
||||
MACRO *new_macro(
|
||||
char *label)
|
||||
{
|
||||
MACRO *mac = memcheck(malloc(sizeof(MACRO)));
|
||||
|
||||
mac->sym.flags = 0;
|
||||
mac->sym.label = label;
|
||||
mac->sym.stmtno = stmtno;
|
||||
mac->sym.next = NULL;
|
||||
mac->sym.section = ¯o_section;
|
||||
mac->sym.value = 0;
|
||||
mac->args = NULL;
|
||||
mac->text = NULL;
|
||||
|
||||
return mac;
|
||||
}
|
||||
|
||||
/* free a macro, it's args, it's text, etc. */
|
||||
void free_macro(
|
||||
MACRO *mac)
|
||||
{
|
||||
if (mac->text) {
|
||||
free(mac->text);
|
||||
}
|
||||
free_args(mac->args);
|
||||
free_sym(&mac->sym);
|
||||
}
|
||||
72
crossassemblers/macro11/macros.h
Normal file
72
crossassemblers/macro11/macros.h
Normal file
@@ -0,0 +1,72 @@
|
||||
|
||||
#ifndef MACROS__H
|
||||
#define MACROS__H
|
||||
|
||||
/* Arguments given to macros or .IRP/.IRPC blocks */
|
||||
|
||||
#include "symbols.h"
|
||||
#include "stream2.h"
|
||||
|
||||
|
||||
typedef struct arg {
|
||||
struct arg *next; /* Pointer in arg list */
|
||||
int locsym; /* Whether arg represents an optional
|
||||
local symbol */
|
||||
char *label; /* Argument name */
|
||||
char *value; /* Default or active substitution */
|
||||
} ARG;
|
||||
|
||||
/* A MACRO is a superstructure surrounding a SYMBOL. */
|
||||
|
||||
typedef struct macro {
|
||||
SYMBOL sym; /* Surrounds a symbol, contains the macro
|
||||
name */
|
||||
ARG *args; /* The argument list */
|
||||
BUFFER *text; /* The macro text */
|
||||
} MACRO;
|
||||
|
||||
typedef struct macro_stream {
|
||||
BUFFER_STREAM bstr; /* Base class: buffer stream */
|
||||
int nargs; /* Add number-of-macro-arguments */
|
||||
int cond; /* Add saved conditional stack */
|
||||
} MACRO_STREAM;
|
||||
|
||||
|
||||
#ifndef MACROS__C
|
||||
extern STREAM_VTBL macro_stream_vtbl;
|
||||
#endif
|
||||
|
||||
MACRO *new_macro(
|
||||
char *label);
|
||||
void free_macro(
|
||||
MACRO *mac);
|
||||
|
||||
MACRO *defmacro(
|
||||
char *cp,
|
||||
STACK *stack,
|
||||
int called);
|
||||
|
||||
STREAM *expandmacro(
|
||||
STREAM *refstr,
|
||||
MACRO *mac,
|
||||
char *cp);
|
||||
|
||||
ARG *new_arg(
|
||||
void);
|
||||
|
||||
void read_body(
|
||||
STACK *stack,
|
||||
BUFFER *gb,
|
||||
char *name,
|
||||
int called);
|
||||
char *getstring_macarg(
|
||||
STREAM *refstr,
|
||||
char *cp,
|
||||
char **endp);
|
||||
BUFFER *subst_args(
|
||||
BUFFER *text,
|
||||
ARG *args);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
21
crossassemblers/macro11/make-git-info
Executable file
21
crossassemblers/macro11/make-git-info
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/bin/sh
|
||||
|
||||
desc=$(git describe --tags)
|
||||
|
||||
if [ "$desc" = "" ]
|
||||
then
|
||||
echo "#undef GIT_VERSION" > new-git-info.h
|
||||
else
|
||||
auth=$(git log -n 1 "--pretty=format:%an <%ae> %aD")
|
||||
|
||||
echo "#define GIT_VERSION "'"'"$desc"'"' >new-git-info.h
|
||||
echo "#define GIT_AUTHOR_DATE "'"'"$auth"'"' >>new-git-info.h
|
||||
fi
|
||||
|
||||
# move-if-different
|
||||
if diff new-git-info.h git-info.h >/dev/null 2>&1
|
||||
then
|
||||
rm new-git-info.h
|
||||
else
|
||||
mv new-git-info.h git-info.h
|
||||
fi
|
||||
487
crossassemblers/macro11/mlb-rsx.c
Normal file
487
crossassemblers/macro11/mlb-rsx.c
Normal file
@@ -0,0 +1,487 @@
|
||||
/*
|
||||
* Routines for reading from an RSX-11 M+ macro library (like RSXMAC.SML)
|
||||
*/
|
||||
/*
|
||||
Copyright (c) 2001, Richard Krehbiel
|
||||
Copyright (c) 2015, Olaf Seibert
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
o Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
o Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
o Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* OLB: Object LiBrary
|
||||
* MLB, SML: MacroLiBrary, System MacroLibrary.
|
||||
*/
|
||||
/*
|
||||
* The MLB file format is (mostly) documented in chapter 10 of
|
||||
* 3a/AA-JS15A-TC_RSX-11M-PLUS_4.0_Utilities_Manual_Aug87.pdf .
|
||||
*
|
||||
* Figure 10-3 (page 10-6):
|
||||
*
|
||||
* Library file header
|
||||
*
|
||||
* Byte offset (octal!)
|
||||
* +1 +0
|
||||
* +------------------------------+------------------------------+
|
||||
* |Nonzero ID (2) | Library type 0=OLB 1=MLB | 0
|
||||
* +------------------------------+------------------------------+
|
||||
* | LBR (Librarian) version | 2
|
||||
* +------------- -------------+
|
||||
* | IDENT format | 4
|
||||
* +------------------------------+------------------------------+
|
||||
* | Year | 6
|
||||
* +------------- -------------+
|
||||
* | Date and Month | 10
|
||||
* +------------- -------------+
|
||||
* | Time of Last Day | 12
|
||||
* +------------- -------------+
|
||||
* | Insert Hour | 14
|
||||
* +------------- -------------+
|
||||
* | Minute | 16
|
||||
* +------------- -------------+
|
||||
* | Second | 20
|
||||
* +------------------------------+------------------------------+
|
||||
* | Reserved | Size EPT entries | 22
|
||||
* +------------------------------+------------------------------+
|
||||
* | EPT starting relative block (Entry Point Table) | 24
|
||||
* +------------------------------+------------------------------+
|
||||
* | Nr of EPT entries allocated | 26
|
||||
* +------------------------------+------------------------------+
|
||||
* | Nr of EPT entries available | 30
|
||||
* +------------------------------+------------------------------+
|
||||
* | Reserved | Size MNT entries | 32
|
||||
* +------------------------------+------------------------------+
|
||||
* | MNT starting relative block (Module Name Table) | 34
|
||||
* +------------------------------+------------------------------+
|
||||
* | Nr of MNT entries allocated | 36
|
||||
* +------------------------------+------------------------------+
|
||||
* | Nr of MNT entries available | 40
|
||||
* +------------------------------+------------------------------+
|
||||
* | Logically Deleted | 42
|
||||
* +------------- -------------+
|
||||
* | Available (bytes) | 44
|
||||
* +------------------------------+------------------------------+
|
||||
* | Contiguous Space | 46
|
||||
* +------------- -------------+
|
||||
* | Available (bytes) | 50
|
||||
* +------------------------------+------------------------------+
|
||||
* | Next Insert Relative Block | 52
|
||||
* +------------- -------------+
|
||||
* | Start Byte Within Block | 54
|
||||
* +------------------------------+------------------------------+
|
||||
* | Default Insert Type for Universal Libraries (not for MLB) | 56
|
||||
* +------------------------------+------------------------------+
|
||||
*
|
||||
* Figure 10-5 (page 10-7):
|
||||
*
|
||||
* Format of Module Name Table (MNT) element:
|
||||
* Byte
|
||||
* +------------------------------+------------------------------+
|
||||
* | Module Name | 0
|
||||
* +------------- -------------+
|
||||
* | RAD50 | 2
|
||||
* +------------------------------+------------------------------+
|
||||
* | Address of module Relative Block | 4
|
||||
* +------------- -------------+
|
||||
* | header Byte in Block | 6
|
||||
* +------------------------------+------------------------------+
|
||||
*
|
||||
* Figure 10-6 (page 10-8):
|
||||
*
|
||||
* Module header format for
|
||||
* Object And Macro Libraries
|
||||
* Byte
|
||||
* 1=deleted module
|
||||
* +------------------------------+------------------------------+
|
||||
* | Attributes | Status 0=normal module | 0
|
||||
* +------------------------------+------------------------------+
|
||||
* ....
|
||||
*
|
||||
* The above layout is from the book but this seems to match my files:
|
||||
* +------------------------------+------------------------------+
|
||||
* | Attributes | 0
|
||||
* +------------------------------+------------------------------+
|
||||
* | Status 0=normal module 1=deleted module | 2
|
||||
* +------------------------------+------------------------------+
|
||||
* | Size Of Module high word | 4
|
||||
* +------------- -------------+
|
||||
* | (bytes) low word | 6
|
||||
* +------------------------------+------------------------------+
|
||||
* | Date Year | 10
|
||||
* +------------- -------------+
|
||||
* | Module Month | 12
|
||||
* +------------- -------------+
|
||||
* | Inserted Day | 14
|
||||
* +------------------------------+------------------------------+
|
||||
* | Type dependent Information | 16
|
||||
* +------------- -------------+
|
||||
* | (undefined for MLB) | 20
|
||||
* +------------------------------+------------------------------+
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "rad50.h"
|
||||
#include "stream2.h"
|
||||
#include "mlb.h"
|
||||
#include "util.h"
|
||||
|
||||
#define BLOCKSIZE 512
|
||||
|
||||
#define WORD(cp) ((*(cp) & 0xff) + ((*((cp)+1) & 0xff) << 8))
|
||||
|
||||
/* BYTEPOS calculates the byte position within the macro libray file. */
|
||||
|
||||
#define BYTEPOS(rec) (((WORD((rec)+4) & 32767) - 1) * BLOCKSIZE + \
|
||||
(WORD((rec)+6) & 511))
|
||||
|
||||
/* trim removes trailing blanks from a string. */
|
||||
static void trim(
|
||||
char *buf)
|
||||
{
|
||||
char *cp = buf + strlen(buf);
|
||||
|
||||
while (--cp >= buf && *cp == ' ')
|
||||
*cp = 0;
|
||||
}
|
||||
|
||||
/* mlb_open opens a file which is given to be a macro library. */
|
||||
/* Returns NULL on failure. */
|
||||
|
||||
MLB *mlb_open(
|
||||
char *name,
|
||||
int allow_objlib)
|
||||
{
|
||||
MLB *mlb = memcheck(malloc(sizeof(MLB)));
|
||||
char *buff;
|
||||
unsigned entsize;
|
||||
unsigned nr_entries;
|
||||
unsigned start_block;
|
||||
int i;
|
||||
|
||||
mlb->directory = NULL;
|
||||
|
||||
mlb->fp = fopen(name, "rb");
|
||||
if (mlb->fp == NULL) {
|
||||
mlb_close(mlb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buff = memcheck(malloc(060)); /* Size of MLB library header */
|
||||
|
||||
if (fread(buff, 1, 060, mlb->fp) < 060) {
|
||||
fprintf(stderr, "error: can't read full header\n");
|
||||
mlb_close(mlb);
|
||||
free(buff);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mlb->is_objlib = 0;
|
||||
if (allow_objlib && WORD(buff) == 01000) { /* Is it an object library? */
|
||||
mlb->is_objlib = 1;
|
||||
} else if (WORD(buff) != 01001) { /* Is this really a macro library? */
|
||||
fprintf(stderr, "error: first word not correct value\n");
|
||||
mlb_close(mlb); /* Nope. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
entsize = buff[032]; /* The size of each macro directory
|
||||
entry */
|
||||
nr_entries = WORD(buff + 036); /* The number of directory entries */
|
||||
start_block = WORD(buff + 034) - 1;/* The start RT-11 block of the
|
||||
directory */
|
||||
|
||||
if (entsize < 8) { /* Is this really a macro library? */
|
||||
mlb_close(mlb); /* Nope. */
|
||||
fprintf(stderr, "error: entsize too small: %d\n", entsize);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// fprintf(stderr, "entsize=%d, nr_entries=%d, start_block=%d\n",
|
||||
// entsize, nr_entries, start_block);
|
||||
free(buff); /* Done with that header. */
|
||||
|
||||
/* Allocate a buffer for the disk directory */
|
||||
buff = memcheck(malloc(nr_entries * entsize));
|
||||
fseek(mlb->fp, start_block * BLOCKSIZE, SEEK_SET); /* Go to the directory */
|
||||
|
||||
/* Read the disk directory */
|
||||
if (fread(buff, entsize, nr_entries, mlb->fp) < nr_entries) {
|
||||
mlb_close(mlb); /* Sorry, read error. */
|
||||
free(buff);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Shift occupied directory entries to the front of the array */
|
||||
{
|
||||
int j;
|
||||
|
||||
for (i = 0, j = nr_entries; i < j; i++) {
|
||||
char *ent1,
|
||||
*ent2;
|
||||
|
||||
ent1 = buff + (i * entsize);
|
||||
/* Unused entries have 0177777 0177777 for the RAD50 name,
|
||||
which is not legal RAD50. */
|
||||
if (WORD(ent1) == 0177777 && WORD(ent1 + 2) == 0177777) {
|
||||
while (--j > i
|
||||
&& (ent2 = buff + (j * entsize), WORD(ent2) == 0177777 && WORD(ent2 + 2) == 0177777)) ;
|
||||
if (j <= i)
|
||||
break; /* All done. */
|
||||
memcpy(ent1, ent2, entsize); /* Move used entry
|
||||
into unused entry's
|
||||
space */
|
||||
memset(ent2, 0377, entsize); /* Mark entry unused */
|
||||
} else {
|
||||
// fprintf(stderr, "entry %d: %02x%02x.%02x%02x\n",
|
||||
// i, ent1[5] & 0xFF, ent1[4] & 0xFF, ent1[7] & 0xFF, ent1[6] & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now i contains the actual number of entries. */
|
||||
|
||||
mlb->nentries = i;
|
||||
// fprintf(stderr, " mlb->nentries=%d\n", mlb->nentries);
|
||||
|
||||
/* Now, allocate my in-memory directory */
|
||||
mlb->directory = memcheck(malloc(sizeof(MLBENT) * mlb->nentries));
|
||||
memset(mlb->directory, 0, sizeof(MLBENT) * mlb->nentries);
|
||||
|
||||
/* Build in-memory directory */
|
||||
for (j = 0; j < i; j++) {
|
||||
char radname[16];
|
||||
char *ent;
|
||||
|
||||
ent = buff + (j * entsize);
|
||||
|
||||
unrad50(WORD(ent), radname);
|
||||
unrad50(WORD(ent + 2), radname + 3);
|
||||
radname[6] = 0;
|
||||
|
||||
// fprintf(stderr, "entry %d: \"%s\" %02x%02x.%02x%02x\n",
|
||||
// j, radname,
|
||||
// ent[5] & 0xFF, ent[4] & 0xFF, ent[7] & 0xFF, ent[6] & 0xFF);
|
||||
trim(radname);
|
||||
|
||||
mlb->directory[j].label = memcheck(strdup(radname));
|
||||
mlb->directory[j].position = BYTEPOS(ent);
|
||||
// fprintf(stderr, "entry %d: \"%s\" bytepos=%d\n", j, mlb->directory[j].label, mlb->directory[j].position);
|
||||
mlb->directory[j].length = -1;
|
||||
}
|
||||
|
||||
free(buff);
|
||||
}
|
||||
|
||||
/* Done. Return the struct that represents the opened MLB. */
|
||||
return mlb;
|
||||
}
|
||||
|
||||
/* mlb_close discards MLB and closes the file. */
|
||||
void mlb_close(
|
||||
MLB *mlb)
|
||||
{
|
||||
if (mlb) {
|
||||
int i;
|
||||
|
||||
if (mlb->directory) {
|
||||
for (i = 0; i < mlb->nentries; i++)
|
||||
if (mlb->directory[i].label)
|
||||
free(mlb->directory[i].label);
|
||||
free(mlb->directory);
|
||||
}
|
||||
if (mlb->fp)
|
||||
fclose(mlb->fp);
|
||||
|
||||
free(mlb);
|
||||
}
|
||||
}
|
||||
|
||||
/* mlb_entry returns a BUFFER containing the specified entry from the
|
||||
macro library, or NULL if not found. */
|
||||
|
||||
BUFFER *mlb_entry(
|
||||
MLB *mlb,
|
||||
char *name)
|
||||
{
|
||||
int i;
|
||||
MLBENT *ent;
|
||||
BUFFER *buf;
|
||||
char *bp;
|
||||
int c;
|
||||
unsigned char module_header[022];
|
||||
|
||||
for (i = 0; i < mlb->nentries; i++) {
|
||||
ent = &mlb->directory[i];
|
||||
if (strcmp(mlb->directory[i].label, name) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= mlb->nentries) {
|
||||
// fprintf(stderr, "mlb_entry: %s not found\n", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fseek(mlb->fp, ent->position, SEEK_SET);
|
||||
// fprintf(stderr, "mlb_entry: %s at position %ld\n", name, (long)ent->position);
|
||||
|
||||
#define MODULE_HEADER_SIZE 022
|
||||
|
||||
if (fread(module_header, MODULE_HEADER_SIZE, 1, mlb->fp) < 1) {
|
||||
// fprintf(stderr, "mlb_entry: %s at position %lx can't read 022 bytes\n", name, (long)ent->position);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// for (i = 0; i < MODULE_HEADER_SIZE; i++) {
|
||||
// fprintf(stderr, "%02x ", module_header[i]);
|
||||
// }
|
||||
// fprintf(stderr, "\n");
|
||||
ent->length = (WORD(module_header + 04) << 16) +
|
||||
WORD(module_header + 06);
|
||||
ent->length -= MODULE_HEADER_SIZE; /* length is including this header */
|
||||
// fprintf(stderr, "mlb_entry: %s at position %lx length = %d\n", name, (long)ent->position, ent->length);
|
||||
|
||||
if (module_header[02] == 1) {
|
||||
fprintf(stderr, "mlb_entry: %s at position %lx deleted entry\n", name, (long)ent->position);
|
||||
/* Deleted Entry */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a buffer to hold the text.
|
||||
* The text is always shorter than the on-disk size.
|
||||
*/
|
||||
buf = new_buffer();
|
||||
buffer_resize(buf, ent->length); /* Make it large enough */
|
||||
bp = buf->buffer;
|
||||
|
||||
/*
|
||||
* Check the file format: variable length records,
|
||||
* or stream of bytes.
|
||||
* Not sure if this check is the correct one; I've only
|
||||
* seen MLB and OLB files with var length records.
|
||||
*/
|
||||
|
||||
if (mlb->is_objlib) {
|
||||
/* In object libraries, copy the internal structure, since we
|
||||
* can consider them to be binary.
|
||||
*/
|
||||
i = fread(bp, 1, ent->length, mlb->fp);
|
||||
bp += i;
|
||||
} else if (module_header[0] & 0x10) {
|
||||
// fprintf(stderr, "mlb_entry: %s at position %lx variable length records\n", name, (long)ent->position);
|
||||
/* Variable length records with size before them */
|
||||
i = ent->length;
|
||||
while (i > 0) {
|
||||
int length;
|
||||
|
||||
// fprintf(stderr, "file offset:$%lx\n", (long)ftell(mlb->fp));
|
||||
c = fgetc(mlb->fp); /* Get low byte of length */
|
||||
length = c & 0xFF;
|
||||
c = fgetc(mlb->fp); /* Get high byte */
|
||||
length += (c & 0xFF) << 8;
|
||||
i -= 2;
|
||||
// fprintf(stderr, "line length: %d $%x\n", length, length);
|
||||
|
||||
/* Odd lengths are padded with an extra 0 byte */
|
||||
int padded = length & 1;
|
||||
if (length > i) {
|
||||
fprintf(stderr, "line length %d > remaining archive member %d\n", length, i);
|
||||
length = i;
|
||||
}
|
||||
|
||||
while (length > 0) {
|
||||
c = fgetc(mlb->fp); /* Get macro byte */
|
||||
//fprintf(stderr, "%02x %c length=%d\n", c, c, length);
|
||||
i--;
|
||||
length--;
|
||||
if (c == '\r' || c == 0) /* If it's a carriage return or 0,
|
||||
discard it. */
|
||||
continue;
|
||||
*bp++ = c;
|
||||
}
|
||||
*bp++ = '\n';
|
||||
if (padded) {
|
||||
c = fgetc(mlb->fp); /* Get pad byte; need not be 0. */
|
||||
//fprintf(stderr, "pad byte %02x %c length=%d\n", c, c, length);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// fprintf(stderr, "mlb_entry: %s at position %lx byte stream records\n", name, (long)ent->position);
|
||||
for (i = 0; i < ent->length; i++) {
|
||||
c = fgetc(mlb->fp); /* Get macro byte */
|
||||
if (c == '\r' || c == 0) /* If it's a carriage return or 0,
|
||||
discard it. */
|
||||
continue;
|
||||
*bp++ = c;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now resize that buffer to the length actually read. */
|
||||
buffer_resize(buf, (int) (bp - buf->buffer));
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* mlb_extract - walk thru a macro library and store its contents
|
||||
into files in the current directory.
|
||||
|
||||
See, I had decided not to bother writing macro library maintenance
|
||||
tools, since the user can call macros directly from the file
|
||||
system. But if you've already got a macro library without the
|
||||
sources, you can use this to extract the entries and maintain them
|
||||
in the file system from thence forward.
|
||||
*/
|
||||
|
||||
void mlb_extract(
|
||||
MLB *mlb)
|
||||
{
|
||||
int i;
|
||||
FILE *fp;
|
||||
BUFFER *buf;
|
||||
|
||||
for (i = 0; i < mlb->nentries; i++) {
|
||||
char name[32];
|
||||
|
||||
buf = mlb_entry(mlb, mlb->directory[i].label);
|
||||
if (buf != NULL) {
|
||||
char *suffix = mlb->is_objlib ? "OBJ" : "MAC";
|
||||
sprintf(name, "%s.%s", mlb->directory[i].label, suffix);
|
||||
fp = fopen(name, "w");
|
||||
int length = buf->length;
|
||||
fwrite(buf->buffer, 1, length, fp);
|
||||
fclose(fp);
|
||||
buffer_free(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
308
crossassemblers/macro11/mlb.c
Normal file
308
crossassemblers/macro11/mlb.c
Normal file
@@ -0,0 +1,308 @@
|
||||
/* Routines for reading from an RT-11 macro library (like SYSMAC.SML) */
|
||||
|
||||
/*
|
||||
Copyright (c) 2001, Richard Krehbiel
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
o Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
o Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
o Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "rad50.h"
|
||||
|
||||
#include "stream2.h"
|
||||
|
||||
#include "mlb.h"
|
||||
|
||||
#include "macro11.h"
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#define WORD(cp) ((*(cp) & 0xff) + ((*((cp)+1) & 0xff) << 8))
|
||||
|
||||
/* BYTEPOS calculates the byte position within the macro libray file.
|
||||
I use this to sort the entries by their start position, in order to
|
||||
be able to calculate the entries' sizes, which isn't actually
|
||||
stored in the directory. */
|
||||
|
||||
#define BYTEPOS(rec) ((WORD((rec)+4) & 32767) * 512 + (WORD((rec)+6) & 511))
|
||||
|
||||
/* compare_position is the qsort callback function that compares byte
|
||||
locations within the macro library */
|
||||
static int compare_position(
|
||||
const void *arg1,
|
||||
const void *arg2)
|
||||
{
|
||||
const char *c1 = arg1,
|
||||
*c2 = arg2;
|
||||
|
||||
if (BYTEPOS(c1) < BYTEPOS(c2))
|
||||
return -1;
|
||||
if (BYTEPOS(c1) > BYTEPOS(c2))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* trim removes trailing blanks from a string. */
|
||||
static void trim(
|
||||
char *buf)
|
||||
{
|
||||
char *cp = buf + strlen(buf);
|
||||
|
||||
while (--cp >= buf && *cp == ' ')
|
||||
*cp = 0;
|
||||
}
|
||||
|
||||
/* mlb_open opens a file which is given to be a macro library. */
|
||||
/* Returns NULL on failure. */
|
||||
|
||||
MLB *mlb_open(
|
||||
char *name)
|
||||
{
|
||||
MLB *mlb = memcheck(malloc(sizeof(MLB)));
|
||||
char *buff;
|
||||
unsigned entsize;
|
||||
unsigned nr_entries;
|
||||
unsigned start_block;
|
||||
int i;
|
||||
|
||||
mlb->directory = NULL;
|
||||
|
||||
mlb->fp = fopen(name, "rb");
|
||||
if (mlb->fp == NULL) {
|
||||
mlb_close(mlb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buff = memcheck(malloc(044)); /* Size of MLB library header */
|
||||
|
||||
if (fread(buff, 1, 044, mlb->fp) < 044) {
|
||||
mlb_close(mlb);
|
||||
free(buff);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (WORD(buff) != 01001) { /* Is this really a macro library? */
|
||||
mlb_close(mlb); /* Nope. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
entsize = WORD(buff + 032); /* The size of each macro directory
|
||||
entry */
|
||||
nr_entries = WORD(buff + 036); /* The number of directory entries */
|
||||
start_block = WORD(buff + 034); /* The start RT-11 block of the
|
||||
directory */
|
||||
|
||||
free(buff); /* Done with that header. */
|
||||
|
||||
/* Allocate a buffer for the disk directory */
|
||||
buff = memcheck(malloc(nr_entries * entsize));
|
||||
fseek(mlb->fp, start_block * 512, SEEK_SET); /* Go to the directory */
|
||||
|
||||
/* Read the disk directory */
|
||||
if (fread(buff, entsize, nr_entries, mlb->fp) < nr_entries) {
|
||||
mlb_close(mlb); /* Sorry, read error. */
|
||||
free(buff);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Shift occupied directory entries to the front of the array
|
||||
before sorting */
|
||||
{
|
||||
int j;
|
||||
|
||||
for (i = 0, j = nr_entries; i < j; i++) {
|
||||
char *ent1,
|
||||
*ent2;
|
||||
|
||||
ent1 = buff + (i * entsize);
|
||||
/* Unused entries have 0177777 0177777 for the RAD50 name,
|
||||
which is not legal RAD50. */
|
||||
if (WORD(ent1) == 0177777 && WORD(ent1 + 2) == 0177777) {
|
||||
while (--j > i
|
||||
&& (ent2 = buff + (j * entsize), WORD(ent2) == 0177777 && WORD(ent2 + 2) == 0177777)) ;
|
||||
if (j <= i)
|
||||
break; /* All done. */
|
||||
memcpy(ent1, ent2, entsize); /* Move used entry
|
||||
into unused entry's
|
||||
space */
|
||||
memset(ent2, 0377, entsize); /* Mark entry unused */
|
||||
}
|
||||
}
|
||||
|
||||
/* Now i contains the actual number of entries. */
|
||||
|
||||
mlb->nentries = i;
|
||||
|
||||
/* Sort the array by file position */
|
||||
|
||||
qsort(buff, i, entsize, compare_position);
|
||||
|
||||
/* Now, allocate my in-memory directory */
|
||||
mlb->directory = memcheck(malloc(sizeof(MLBENT) * mlb->nentries));
|
||||
memset(mlb->directory, 0, sizeof(MLBENT) * mlb->nentries);
|
||||
|
||||
/* Build in-memory directory */
|
||||
for (j = 0; j < i; j++) {
|
||||
char radname[16];
|
||||
char *ent;
|
||||
|
||||
ent = buff + (j * entsize);
|
||||
|
||||
unrad50(WORD(ent), radname);
|
||||
unrad50(WORD(ent + 2), radname + 3);
|
||||
radname[6] = 0;
|
||||
|
||||
trim(radname);
|
||||
|
||||
mlb->directory[j].label = memcheck(strdup(radname));
|
||||
mlb->directory[j].position = BYTEPOS(ent);
|
||||
if (j < i - 1) {
|
||||
mlb->directory[j].length = BYTEPOS(ent + entsize) - BYTEPOS(ent);
|
||||
} else {
|
||||
unsigned long max;
|
||||
char c;
|
||||
|
||||
fseek(mlb->fp, 0, SEEK_END);
|
||||
max = ftell(mlb->fp);
|
||||
/* Look for last non-zero */
|
||||
do {
|
||||
max--;
|
||||
fseek(mlb->fp, max, SEEK_SET);
|
||||
c = fgetc(mlb->fp);
|
||||
} while (max > 0 && c == 0);
|
||||
max++;
|
||||
mlb->directory[j].length = max - BYTEPOS(ent);
|
||||
}
|
||||
}
|
||||
|
||||
free(buff);
|
||||
}
|
||||
|
||||
/* Done. Return the struct that represents the opened MLB. */
|
||||
return mlb;
|
||||
}
|
||||
|
||||
/* mlb_close discards MLB and closes the file. */
|
||||
void mlb_close(
|
||||
MLB *mlb)
|
||||
{
|
||||
if (mlb) {
|
||||
int i;
|
||||
|
||||
if (mlb->directory) {
|
||||
for (i = 0; i < mlb->nentries; i++)
|
||||
if (mlb->directory[i].label)
|
||||
free(mlb->directory[i].label);
|
||||
free(mlb->directory);
|
||||
}
|
||||
if (mlb->fp)
|
||||
fclose(mlb->fp);
|
||||
|
||||
free(mlb);
|
||||
}
|
||||
}
|
||||
|
||||
/* mlb_entry returns a BUFFER containing the specified entry from the
|
||||
macro library, or NULL if not found. */
|
||||
|
||||
BUFFER *mlb_entry(
|
||||
MLB *mlb,
|
||||
char *name)
|
||||
{
|
||||
int i;
|
||||
MLBENT *ent;
|
||||
BUFFER *buf;
|
||||
char *bp;
|
||||
int c;
|
||||
|
||||
for (i = 0; i < mlb->nentries; i++) {
|
||||
ent = &mlb->directory[i];
|
||||
if (strcmp(mlb->directory[i].label, name) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= mlb->nentries)
|
||||
return NULL;
|
||||
|
||||
/* Allocate a buffer to hold the text */
|
||||
buf = new_buffer();
|
||||
buffer_resize(buf, ent->length + 1); /* Make it large enough */
|
||||
bp = buf->buffer;
|
||||
|
||||
fseek(mlb->fp, ent->position, SEEK_SET);
|
||||
|
||||
for (i = 0; i < ent->length; i++) {
|
||||
c = fgetc(mlb->fp); /* Get macro byte */
|
||||
if (c == '\r' || c == 0) /* If it's a carriage return or 0,
|
||||
discard it. */
|
||||
continue;
|
||||
*bp++ = c;
|
||||
}
|
||||
*bp++ = 0; /* Store trailing 0 delim */
|
||||
|
||||
/* Now resize that buffer to the length actually read. */
|
||||
buffer_resize(buf, (int) (bp - buf->buffer));
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* mlb_extract - walk thru a macro library and store it's contents
|
||||
into files in the current directory.
|
||||
|
||||
See, I had decided not to bother writing macro library maintenance
|
||||
tools, since the user can call macros directly from the file
|
||||
system. But if you've already got a macro library without the
|
||||
sources, you can use this to extract the entries and maintain them
|
||||
in the file system from thence forward.
|
||||
*/
|
||||
|
||||
void mlb_extract(
|
||||
MLB *mlb)
|
||||
{
|
||||
int i;
|
||||
FILE *fp;
|
||||
BUFFER *buf;
|
||||
|
||||
for (i = 0; i < mlb->nentries; i++) {
|
||||
char name[32];
|
||||
|
||||
buf = mlb_entry(mlb, mlb->directory[i].label);
|
||||
sprintf(name, "%s.MAC", mlb->directory[i].label);
|
||||
fp = fopen(name, "w");
|
||||
fwrite(buf->buffer, 1, buf->length, fp);
|
||||
fclose(fp);
|
||||
buffer_free(buf);
|
||||
}
|
||||
}
|
||||
67
crossassemblers/macro11/mlb.h
Normal file
67
crossassemblers/macro11/mlb.h
Normal file
@@ -0,0 +1,67 @@
|
||||
#ifndef MLB_H
|
||||
#define MLB_H
|
||||
|
||||
/*
|
||||
|
||||
Copyright (c) 2001, Richard Krehbiel
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
o Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
o Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
o Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "stream2.h"
|
||||
|
||||
/* Routines to open and read entries from a macro library */
|
||||
|
||||
typedef struct mlbent {
|
||||
char *label;
|
||||
unsigned long position;
|
||||
int length;
|
||||
} MLBENT;
|
||||
|
||||
typedef struct mlb {
|
||||
FILE *fp;
|
||||
MLBENT *directory;
|
||||
int nentries;
|
||||
int is_objlib; /* is really an object library */
|
||||
} MLB;
|
||||
|
||||
extern MLB *mlb_open(
|
||||
char *name,
|
||||
int allow_object_library);
|
||||
extern BUFFER *mlb_entry(
|
||||
MLB *mlb,
|
||||
char *name);
|
||||
extern void mlb_close(
|
||||
MLB *mlb);
|
||||
extern void mlb_extract(
|
||||
MLB *mlb);
|
||||
|
||||
#endif /* MLB_H */
|
||||
1011
crossassemblers/macro11/object.c
Normal file
1011
crossassemblers/macro11/object.c
Normal file
File diff suppressed because it is too large
Load Diff
310
crossassemblers/macro11/object.h
Normal file
310
crossassemblers/macro11/object.h
Normal file
@@ -0,0 +1,310 @@
|
||||
#ifndef OBJECT_H
|
||||
#define OBJECT_H
|
||||
|
||||
/* Object file constant definitions */
|
||||
|
||||
/*
|
||||
|
||||
Copyright (c) 2001, Richard Krehbiel
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
o Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
o Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
o Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define FBR_LEAD1 1 /* The byte value that defines the
|
||||
beginning of a formatted binary
|
||||
record */
|
||||
#define FBR_LEAD2 0 /* Followed by a 0 */
|
||||
/* Followed by two bytes length */
|
||||
/* Followed by (length-4) bytes data */
|
||||
/* Followed by a 1 byte checksum */
|
||||
/* which is the negative sum of all
|
||||
preceeding bytes */
|
||||
|
||||
#define OBJ_GSD 01 /* GSD (Global symbol directory) */
|
||||
#define OBJ_ENDGSD 02 /* ENDGSD */
|
||||
#define OBJ_TEXT 03 /* TEXT */
|
||||
#define OBJ_RLD 04 /* RLD (Relocation directory) */
|
||||
#define OBJ_ISD 05 /* ISD (Internal symbol directory,
|
||||
currently unused) */
|
||||
#define OBJ_ENDMOD 06 /* ENDMOD (End of object module) */
|
||||
#define OBJ_LIBHDR 07 /* LIBHDR (Object Library header) */
|
||||
#define OBJ_LIBEND 010 /* LIBEND (Object Library header end) */
|
||||
|
||||
#define GSD_MODNAME 00 /* Module name */
|
||||
#define GSD_CSECT 01 /* Control section name */
|
||||
#define GSD_ISN 02 /* Internal symbol name */
|
||||
#define GSD_XFER 03 /* Transfer address */
|
||||
#define GSD_GLOBAL 04 /* Global symbol definition/reference */
|
||||
#define GSD_PSECT 05 /* PSECT name */
|
||||
#define GSD_IDENT 06 /* IDENT */
|
||||
#define GSD_VSECT 07 /* VSECT (Virtual array declaration) */
|
||||
|
||||
#define GLOBAL_WEAK 01 /* GLOBAL is weak, else strong */
|
||||
#define GLOBAL_DEF 010 /* GLOBAL is definition, else reference */
|
||||
#define GLOBAL_REL 040 /* GLOBAL is relative, else absolute */
|
||||
|
||||
#define PSECT_SAV 001 /* PSECT is a root section, else overlay */
|
||||
#define PSECT_COM 004 /* PSECT is merged common area, else
|
||||
contatenated */
|
||||
#define PSECT_RO 020 /* PSECT is read-only, else R/W */
|
||||
#define PSECT_REL 040 /* PSECT is relative, else absolute
|
||||
(absolute implies PSECT_COM) */
|
||||
#define PSECT_GBL 0100 /* PSECT is overlay-global, else
|
||||
overlay-local */
|
||||
#define PSECT_DATA 0200 /* PSECT contains data, else instructions */
|
||||
|
||||
#define RLD_INT 01 /* "Internal relocation" */
|
||||
#define RLD_GLOBAL 02 /* "Global relocation" */
|
||||
#define RLD_INT_DISP 03 /* "Internal displaced" */
|
||||
#define RLD_GLOBAL_DISP 04 /* "Global displaced" */
|
||||
#define RLD_GLOBAL_OFFSET 05 /* "Global additive" */
|
||||
#define RLD_GLOBAL_OFFSET_DISP 06 /* "Global additive displaced" */
|
||||
#define RLD_LOCDEF 07 /* "Location counter definition" */
|
||||
#define RLD_LOCMOD 010 /* "Location counter modification" */
|
||||
#define RLD_LIMITS 011 /* ".LIMIT" */
|
||||
#define RLD_PSECT 012 /* "P-sect" */
|
||||
#define RLD_PSECT_DISP 014 /* "P-sect displaced" */
|
||||
#define RLD_PSECT_OFFSET 015 /* "P-sect additive" */
|
||||
#define RLD_PSECT_OFFSET_DISP 016 /* "P-sect additive displaced" */
|
||||
#define RLD_COMPLEX 017 /* "Complex" */
|
||||
|
||||
#define RLD_BYTE 0200 /* RLD modifies a byte, else a word */
|
||||
|
||||
/* Note: complex relocation is not well documented (in particular, no effort
|
||||
is made to define a section's "sector number"), but I'll just guess
|
||||
it's a stack language. */
|
||||
|
||||
#define CPLX_NOP 00 /* NOP - used for padding */
|
||||
#define CPLX_ADD 01
|
||||
#define CPLX_SUB 02
|
||||
#define CPLX_MUL 03
|
||||
#define CPLX_DIV 04
|
||||
#define CPLX_AND 05
|
||||
#define CPLX_OR 06
|
||||
#define CPLX_XOR 07
|
||||
#define CPLX_NEG 010
|
||||
#define CPLX_COM 011
|
||||
#define CPLX_STORE 012 /* Store result, terminate complex string. */
|
||||
#define CPLX_STORE_DISP 013 /* Store result PC-relative, terminate */
|
||||
#define CPLX_GLOBAL 016 /* Followed by four bytes RAD50 global name */
|
||||
#define CPLX_REL 017 /* Followed by one byte "sector
|
||||
number" and two bytes offset */
|
||||
#define CPLX_CONST 020 /* Followed by two bytes constant value */
|
||||
|
||||
typedef struct gsd {
|
||||
FILE *fp; /* The file assigned for output */
|
||||
char buf[122]; /* space for 15 GSD entries */
|
||||
int offset; /* Current buffer for GSD entries */
|
||||
} GSD;
|
||||
|
||||
void gsd_init(
|
||||
GSD * gsd,
|
||||
FILE *fp);
|
||||
int gsd_flush(
|
||||
GSD * gsd);
|
||||
int gsd_mod(
|
||||
GSD * gsd,
|
||||
char *modname);
|
||||
int gsd_csect(
|
||||
GSD * gsd,
|
||||
char *sectname,
|
||||
int size);
|
||||
int gsd_intname(
|
||||
GSD * gsd,
|
||||
char *name,
|
||||
unsigned value);
|
||||
int gsd_xfer(
|
||||
GSD * gsd,
|
||||
char *name,
|
||||
unsigned value);
|
||||
int gsd_global(
|
||||
GSD * gsd,
|
||||
char *name,
|
||||
int flags,
|
||||
unsigned value);
|
||||
int gsd_psect(
|
||||
GSD * gsd,
|
||||
char *name,
|
||||
int flags,
|
||||
int size);
|
||||
int gsd_ident(
|
||||
GSD * gsd,
|
||||
char *name);
|
||||
int gsd_virt(
|
||||
GSD * gsd,
|
||||
char *name,
|
||||
int size);
|
||||
int gsd_end(
|
||||
GSD * gsd);
|
||||
|
||||
typedef struct text_rld {
|
||||
FILE *fp; /* The object file, or NULL */
|
||||
char text[128]; /* text buffer */
|
||||
unsigned txt_addr; /* The base text address */
|
||||
int txt_offset; /* Current text offset */
|
||||
char rld[128]; /* RLD buffer */
|
||||
int rld_offset; /* Current RLD offset */
|
||||
} TEXT_RLD;
|
||||
|
||||
void text_init(
|
||||
TEXT_RLD *tr,
|
||||
FILE *fp,
|
||||
unsigned addr);
|
||||
int text_flush(
|
||||
TEXT_RLD *tr);
|
||||
int text_word(
|
||||
TEXT_RLD *tr,
|
||||
unsigned *addr,
|
||||
int size,
|
||||
unsigned word);
|
||||
int text_internal_word(
|
||||
TEXT_RLD *tr,
|
||||
unsigned *addr,
|
||||
int size,
|
||||
unsigned word);
|
||||
int text_global_word(
|
||||
TEXT_RLD *tr,
|
||||
unsigned *addr,
|
||||
int size,
|
||||
unsigned word,
|
||||
char *global);
|
||||
int text_displaced_word(
|
||||
TEXT_RLD *tr,
|
||||
unsigned *addr,
|
||||
int size,
|
||||
unsigned word);
|
||||
int text_global_displaced_word(
|
||||
TEXT_RLD *tr,
|
||||
unsigned *addr,
|
||||
int size,
|
||||
unsigned word,
|
||||
char *global);
|
||||
int text_global_offset_word(
|
||||
TEXT_RLD *tr,
|
||||
unsigned *addr,
|
||||
int size,
|
||||
unsigned word,
|
||||
char *global);
|
||||
int text_global_displaced_offset_word(
|
||||
TEXT_RLD *tr,
|
||||
unsigned *addr,
|
||||
int size,
|
||||
unsigned word,
|
||||
char *global);
|
||||
int text_define_location(
|
||||
TEXT_RLD *tr,
|
||||
char *name,
|
||||
unsigned *addr);
|
||||
int text_modify_location(
|
||||
TEXT_RLD *tr,
|
||||
unsigned *addr);
|
||||
int text_limits(
|
||||
TEXT_RLD *tr,
|
||||
unsigned *addr);
|
||||
int text_psect_word(
|
||||
TEXT_RLD *tr,
|
||||
unsigned *addr,
|
||||
int size,
|
||||
unsigned word,
|
||||
char *name);
|
||||
int text_psect_offset_word(
|
||||
TEXT_RLD *tr,
|
||||
unsigned *addr,
|
||||
int size,
|
||||
unsigned word,
|
||||
char *name);
|
||||
int text_psect_displaced_word(
|
||||
TEXT_RLD *tr,
|
||||
unsigned *addr,
|
||||
int size,
|
||||
unsigned word,
|
||||
char *name);
|
||||
int text_psect_displaced_offset_word(
|
||||
TEXT_RLD *tr,
|
||||
unsigned *addr,
|
||||
int size,
|
||||
unsigned word,
|
||||
char *name);
|
||||
|
||||
typedef struct text_complex {
|
||||
char accum[126];
|
||||
int len;
|
||||
} TEXT_COMPLEX;
|
||||
|
||||
void text_complex_begin(
|
||||
TEXT_COMPLEX *tx);
|
||||
int text_complex_add(
|
||||
TEXT_COMPLEX *tx);
|
||||
int text_complex_sub(
|
||||
TEXT_COMPLEX *tx);
|
||||
int text_complex_mul(
|
||||
TEXT_COMPLEX *tx);
|
||||
int text_complex_div(
|
||||
TEXT_COMPLEX *tx);
|
||||
int text_complex_and(
|
||||
TEXT_COMPLEX *tx);
|
||||
int text_complex_or(
|
||||
TEXT_COMPLEX *tx);
|
||||
int text_complex_xor(
|
||||
TEXT_COMPLEX *tx);
|
||||
int text_complex_com(
|
||||
TEXT_COMPLEX *tx);
|
||||
int text_complex_neg(
|
||||
TEXT_COMPLEX *tx);
|
||||
int text_complex_lit(
|
||||
TEXT_COMPLEX *tx,
|
||||
unsigned word);
|
||||
int text_complex_global(
|
||||
TEXT_COMPLEX *tx,
|
||||
char *name);
|
||||
int text_complex_psect(
|
||||
TEXT_COMPLEX *tx,
|
||||
unsigned sect,
|
||||
unsigned offset);
|
||||
int text_complex_commit(
|
||||
TEXT_RLD *tr,
|
||||
unsigned *addr,
|
||||
int size,
|
||||
TEXT_COMPLEX *tx,
|
||||
unsigned word);
|
||||
int text_complex_commit_displaced(
|
||||
TEXT_RLD *tr,
|
||||
unsigned *addr,
|
||||
int size,
|
||||
TEXT_COMPLEX *tx,
|
||||
unsigned word);
|
||||
|
||||
int write_endmod(
|
||||
FILE *fp);
|
||||
|
||||
#endif /* OBJECT_J */
|
||||
934
crossassemblers/macro11/parse.c
Normal file
934
crossassemblers/macro11/parse.c
Normal file
@@ -0,0 +1,934 @@
|
||||
#define PARSE__C
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "parse.h" /* my own definitions */
|
||||
|
||||
#include "util.h"
|
||||
#include "rad50.h"
|
||||
#include "listing.h"
|
||||
#include "assemble_globals.h"
|
||||
|
||||
|
||||
/* skipwhite - used everywhere to advance a char pointer past spaces */
|
||||
|
||||
char *skipwhite(
|
||||
char *cp)
|
||||
{
|
||||
while (*cp == ' ' || *cp == '\t')
|
||||
cp++;
|
||||
return cp;
|
||||
}
|
||||
|
||||
/* skipdelim - used everywhere to advance between tokens. Whitespace
|
||||
and one comma are allowed delims. */
|
||||
|
||||
char *skipdelim(
|
||||
char *cp)
|
||||
{
|
||||
cp = skipwhite(cp);
|
||||
if (*cp == ',')
|
||||
cp = skipwhite(cp + 1);
|
||||
return cp;
|
||||
}
|
||||
|
||||
/* skipdelim_comma - used to advance between tokens. Whitespace
|
||||
and one comma are allowed delims.
|
||||
Set *comma depending on whether a comma was skipped. */
|
||||
|
||||
char *skipdelim_comma(
|
||||
char *cp,
|
||||
int *comma)
|
||||
{
|
||||
cp = skipwhite(cp);
|
||||
if ((*comma = (*cp == ','))) {
|
||||
cp = skipwhite(cp + 1);
|
||||
}
|
||||
return cp;
|
||||
}
|
||||
|
||||
/* Parses a string from the input stream. */
|
||||
/* If not bracketed by <...> or ^/.../, then */
|
||||
/* the string is delimited by trailing comma or whitespace. */
|
||||
/* Allows nested <>'s */
|
||||
|
||||
char *getstring(
|
||||
char *cp,
|
||||
char **endp)
|
||||
{
|
||||
int len;
|
||||
int start;
|
||||
char *str;
|
||||
|
||||
if (!brackrange(cp, &start, &len, endp)) {
|
||||
start = 0;
|
||||
len = strcspn(cp, " \t\n,;");
|
||||
if (endp)
|
||||
*endp = cp + len;
|
||||
}
|
||||
|
||||
str = memcheck(malloc(len + 1));
|
||||
memcpy(str, cp + start, len);
|
||||
str[len] = 0;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/* Parses a string from the input stream for .include and .library.
|
||||
* These have a special kind of delimiters. It likes
|
||||
* .include /name/ ?name? \name\ "name"
|
||||
* but not
|
||||
* .include ^/name/ <name> name =name= :name:
|
||||
* .include :name: seems to be silently ignored.
|
||||
*
|
||||
* This should probably follow the exact same rules as .ASCII
|
||||
* although that is not mentioned in the manual,
|
||||
*/
|
||||
char *getstring_fn(
|
||||
char *cp,
|
||||
char **endp)
|
||||
{
|
||||
char endstr[4];
|
||||
int len;
|
||||
char *str;
|
||||
|
||||
switch (*cp) {
|
||||
case '<':
|
||||
case ':':
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!ispunct((unsigned char)*cp)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
endstr[0] = *cp;
|
||||
endstr[1] = '\n';
|
||||
endstr[2] = '\0';
|
||||
cp++;
|
||||
|
||||
len = strcspn(cp, endstr);
|
||||
|
||||
if (endp)
|
||||
*endp = cp + len + 1;
|
||||
|
||||
str = memcheck(malloc(len + 1));
|
||||
memcpy(str, cp, len);
|
||||
str[len] = 0;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/* Get what would be the operation code from the line. */
|
||||
/* Used to find the ends of streams without evaluating them, like
|
||||
finding the closing .ENDM on a macro definition */
|
||||
|
||||
SYMBOL *get_op(
|
||||
char *cp,
|
||||
char **endp)
|
||||
{
|
||||
int local;
|
||||
char *label;
|
||||
SYMBOL *op;
|
||||
|
||||
cp = skipwhite(cp);
|
||||
if (EOL(*cp))
|
||||
return NULL;
|
||||
|
||||
label = get_symbol(cp, &cp, &local);
|
||||
if (label == NULL)
|
||||
return NULL; /* No operation code. */
|
||||
|
||||
cp = skipwhite(cp);
|
||||
if (*cp == ':') { /* A label definition? */
|
||||
cp++;
|
||||
if (*cp == ':')
|
||||
cp++; /* Skip it */
|
||||
free(label);
|
||||
label = get_symbol(cp, &cp, NULL);
|
||||
if (label == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
op = lookup_sym(label, &system_st);
|
||||
free(label);
|
||||
|
||||
if (endp)
|
||||
*endp = cp;
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* get_mode - parse a general addressing mode. */
|
||||
|
||||
int get_mode(
|
||||
char *cp,
|
||||
char **endp,
|
||||
ADDR_MODE *mode)
|
||||
{
|
||||
EX_TREE *value;
|
||||
|
||||
mode->offset = NULL;
|
||||
mode->rel = 0;
|
||||
mode->type = 0;
|
||||
|
||||
cp = skipwhite(cp);
|
||||
|
||||
/* @ means "indirect," sets bit 3 */
|
||||
if (*cp == '@') {
|
||||
cp++;
|
||||
mode->type |= 010;
|
||||
}
|
||||
|
||||
/* Immediate modes #imm and @#imm */
|
||||
if (*cp == '#') {
|
||||
cp++;
|
||||
mode->type |= 027;
|
||||
mode->offset = parse_expr(cp, 0);
|
||||
if (endp)
|
||||
*endp = mode->offset->cp;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Check for -(Rn) */
|
||||
|
||||
if (*cp == '-') {
|
||||
char *tcp = skipwhite(cp + 1);
|
||||
|
||||
if (*tcp++ == '(') {
|
||||
unsigned reg;
|
||||
|
||||
/* It's -(Rn) */
|
||||
value = parse_expr(tcp, 0);
|
||||
reg = get_register(value);
|
||||
if (reg == NO_REG || (tcp = skipwhite(value->cp), *tcp++ != ')')) {
|
||||
free_tree(value);
|
||||
return FALSE;
|
||||
}
|
||||
mode->type |= 040 | reg;
|
||||
if (endp)
|
||||
*endp = tcp;
|
||||
free_tree(value);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for (Rn) */
|
||||
if (*cp == '(') {
|
||||
char *tcp;
|
||||
unsigned reg;
|
||||
|
||||
value = parse_expr(cp + 1, 0);
|
||||
reg = get_register(value);
|
||||
|
||||
if (reg == NO_REG || (tcp = skipwhite(value->cp), *tcp++ != ')')) {
|
||||
free_tree(value);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
tcp = skipwhite(tcp);
|
||||
if (*tcp == '+') {
|
||||
tcp++; /* It's (Rn)+ */
|
||||
if (endp)
|
||||
*endp = tcp;
|
||||
mode->type |= 020 | reg;
|
||||
free_tree(value);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (mode->type == 010) { /* For @(Rn) there's an implied 0 offset */
|
||||
mode->offset = new_ex_lit(0);
|
||||
mode->type |= 060 | reg;
|
||||
free_tree(value);
|
||||
if (endp)
|
||||
*endp = tcp;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
mode->type |= 010 | reg; /* Mode 10 is register indirect as
|
||||
in (Rn) */
|
||||
free_tree(value);
|
||||
if (endp)
|
||||
*endp = tcp;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Modes with an offset */
|
||||
|
||||
mode->offset = parse_expr(cp, 0);
|
||||
|
||||
cp = skipwhite(mode->offset->cp);
|
||||
|
||||
if (*cp == '(') {
|
||||
unsigned reg;
|
||||
|
||||
/* indirect register plus offset */
|
||||
value = parse_expr(cp + 1, 0);
|
||||
reg = get_register(value);
|
||||
if (reg == NO_REG || (cp = skipwhite(value->cp), *cp++ != ')')) {
|
||||
free_tree(value);
|
||||
return FALSE; /* Syntax error in addressing mode */
|
||||
}
|
||||
|
||||
mode->type |= 060 | reg;
|
||||
|
||||
free_tree(value);
|
||||
|
||||
if (endp)
|
||||
*endp = cp;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Plain old expression. */
|
||||
|
||||
if (endp)
|
||||
*endp = cp;
|
||||
|
||||
/* It might be a register, though. */
|
||||
if (mode->offset->type == EX_SYM) {
|
||||
SYMBOL *sym = mode->offset->data.symbol;
|
||||
|
||||
if (sym->section->type == SECTION_REGISTER) {
|
||||
free_tree(mode->offset);
|
||||
mode->offset = NULL;
|
||||
mode->type |= sym->value;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* It's either 067 (PC-relative) or 037 (absolute) mode, depending */
|
||||
/* on user option. */
|
||||
|
||||
if (mode->type & 010) { /* Have already noted indirection? */
|
||||
mode->type |= 067; /* If so, then PC-relative is the only
|
||||
option */
|
||||
mode->rel = 1; /* Note PC-relative */
|
||||
} else if (enabl_ama) { /* User asked for absolute adressing? */
|
||||
mode->type |= 037; /* Give it to him. */
|
||||
} else {
|
||||
mode->type |= 067; /* PC-relative */
|
||||
mode->rel = 1; /* Note PC-relative */
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Parse PDP-11 64-bit floating point format. */
|
||||
/* Give a pointer to "size" words to receive the result. */
|
||||
/* Note: there are probably degenerate cases that store incorrect
|
||||
results. For example, I think rounding up a FLT2 might cause
|
||||
exponent overflow. Sorry. */
|
||||
/* Note also that the full 49 bits of precision probably aren't
|
||||
available on the source platform, given the widespread application
|
||||
of IEEE floating point formats, so expect some differences. Sorry
|
||||
again. */
|
||||
|
||||
int parse_float(
|
||||
char *cp,
|
||||
char **endp,
|
||||
int size,
|
||||
unsigned *flt)
|
||||
{
|
||||
double d; /* value */
|
||||
double frac; /* fractional value */
|
||||
ulong64 ufrac; /* fraction converted to 49 bit
|
||||
unsigned integer */
|
||||
int i; /* Number of fields converted by sscanf */
|
||||
int n; /* Number of characters converted by sscanf */
|
||||
int sexp; /* Signed exponent */
|
||||
unsigned uexp; /* Unsigned excess-128 exponent */
|
||||
unsigned sign = 0; /* Sign mask */
|
||||
|
||||
i = sscanf(cp, "%lf%n", &d, &n);
|
||||
if (i == 0)
|
||||
return 0; /* Wasn't able to convert */
|
||||
|
||||
cp += n;
|
||||
if (endp)
|
||||
*endp = cp;
|
||||
|
||||
if (d == 0.0) {
|
||||
flt[0] = flt[1] = flt[2] = flt[3] = 0; /* All-bits-zero equals zero */
|
||||
return 1; /* Good job. */
|
||||
}
|
||||
|
||||
frac = frexp(d, &sexp); /* Separate into exponent and mantissa */
|
||||
if (sexp < -128 || sexp > 127)
|
||||
return 0; /* Exponent out of range. */
|
||||
|
||||
uexp = sexp + 128; /* Make excess-128 mode */
|
||||
uexp &= 0xff; /* express in 8 bits */
|
||||
|
||||
if (frac < 0) {
|
||||
sign = 0100000; /* Negative sign */
|
||||
frac = -frac; /* fix the mantissa */
|
||||
}
|
||||
|
||||
/* The following big literal is 2 to the 49th power: */
|
||||
ufrac = (ulong64) (frac * 72057594037927936.0); /* Align fraction bits */
|
||||
|
||||
/* Round from FLT4 to FLT2 */
|
||||
if (size < 4) {
|
||||
ufrac += 0x80000000; /* Round to nearest 32-bit
|
||||
representation */
|
||||
|
||||
if (ufrac > 0x200000000000) { /* Overflow? */
|
||||
ufrac >>= 1; /* Normalize */
|
||||
uexp--;
|
||||
}
|
||||
}
|
||||
|
||||
flt[0] = (unsigned) (sign | (uexp << 7) | ((ufrac >> 48) & 0x7F));
|
||||
if (size > 1) {
|
||||
flt[1] = (unsigned) ((ufrac >> 32) & 0xffff);
|
||||
if (size > 2) {
|
||||
flt[2] = (unsigned) ((ufrac >> 16) & 0xffff);
|
||||
flt[3] = (unsigned) ((ufrac >> 0) & 0xffff);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* The recursive-descent expression parser parse_expr. */
|
||||
|
||||
/* This parser was designed for expressions with operator precedence.
|
||||
However, MACRO-11 doesn't observe any sort of operator precedence.
|
||||
If you feel your source deserves better, give the operators
|
||||
appropriate precedence values right here. */
|
||||
|
||||
#define ADD_PREC 1
|
||||
#define MUL_PREC 1
|
||||
#define AND_PREC 1
|
||||
#define OR_PREC 1
|
||||
|
||||
EX_TREE *parse_unary(
|
||||
char *cp); /* Prototype for forward calls */
|
||||
|
||||
EX_TREE *parse_binary(
|
||||
char *cp,
|
||||
char term,
|
||||
int depth)
|
||||
{
|
||||
EX_TREE *leftp,
|
||||
*rightp,
|
||||
*tp;
|
||||
|
||||
leftp = parse_unary(cp);
|
||||
|
||||
while (leftp->type != EX_ERR) {
|
||||
cp = skipwhite(leftp->cp);
|
||||
|
||||
if (*cp == term)
|
||||
return leftp;
|
||||
|
||||
switch (*cp) {
|
||||
case '+':
|
||||
if (depth >= ADD_PREC)
|
||||
return leftp;
|
||||
|
||||
rightp = parse_binary(cp + 1, term, ADD_PREC);
|
||||
tp = new_ex_bin(EX_ADD, leftp, rightp);
|
||||
tp->cp = rightp->cp;
|
||||
leftp = tp;
|
||||
break;
|
||||
|
||||
case '-':
|
||||
if (depth >= ADD_PREC)
|
||||
return leftp;
|
||||
|
||||
rightp = parse_binary(cp + 1, term, ADD_PREC);
|
||||
tp = new_ex_bin(EX_SUB, leftp, rightp);
|
||||
tp->cp = rightp->cp;
|
||||
leftp = tp;
|
||||
break;
|
||||
|
||||
case '*':
|
||||
if (depth >= MUL_PREC)
|
||||
return leftp;
|
||||
|
||||
rightp = parse_binary(cp + 1, term, MUL_PREC);
|
||||
tp = new_ex_bin(EX_MUL, leftp, rightp);
|
||||
tp->cp = rightp->cp;
|
||||
leftp = tp;
|
||||
break;
|
||||
|
||||
case '/':
|
||||
if (depth >= MUL_PREC)
|
||||
return leftp;
|
||||
|
||||
rightp = parse_binary(cp + 1, term, MUL_PREC);
|
||||
tp = new_ex_bin(EX_DIV, leftp, rightp);
|
||||
tp->cp = rightp->cp;
|
||||
leftp = tp;
|
||||
break;
|
||||
|
||||
case '!':
|
||||
if (depth >= OR_PREC)
|
||||
return leftp;
|
||||
|
||||
rightp = parse_binary(cp + 1, term, OR_PREC);
|
||||
tp = new_ex_bin(EX_OR, leftp, rightp);
|
||||
tp->cp = rightp->cp;
|
||||
leftp = tp;
|
||||
break;
|
||||
|
||||
case '&':
|
||||
if (depth >= AND_PREC)
|
||||
return leftp;
|
||||
|
||||
rightp = parse_binary(cp + 1, term, AND_PREC);
|
||||
tp = new_ex_bin(EX_AND, leftp, rightp);
|
||||
tp->cp = rightp->cp;
|
||||
leftp = tp;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Some unknown character. Let caller decide if it's okay. */
|
||||
|
||||
return leftp;
|
||||
} /* end switch */
|
||||
} /* end while */
|
||||
|
||||
/* Can't be reached except by error. */
|
||||
return leftp;
|
||||
}
|
||||
|
||||
/* get_symbol is used all over the place to pull a symbol out of the
|
||||
text. */
|
||||
|
||||
char *get_symbol(
|
||||
char *cp,
|
||||
char **endp,
|
||||
int *islocal)
|
||||
{
|
||||
int len;
|
||||
char *symcp;
|
||||
int digits = 0;
|
||||
|
||||
cp = skipwhite(cp); /* Skip leading whitespace */
|
||||
|
||||
if (!issym((unsigned char)*cp))
|
||||
return NULL;
|
||||
|
||||
digits = 0;
|
||||
if (isdigit((unsigned char)*cp))
|
||||
digits = 2; /* Think about digit count */
|
||||
|
||||
for (symcp = cp + 1; issym((unsigned char)*symcp); symcp++) {
|
||||
if (!isdigit((unsigned char)*symcp)) /* Not a digit? */
|
||||
digits--; /* Make a note. */
|
||||
}
|
||||
|
||||
if (digits == 2)
|
||||
return NULL; /* Not a symbol, it's a digit string */
|
||||
|
||||
if (endp)
|
||||
*endp = symcp;
|
||||
|
||||
len = (int) (symcp - cp);
|
||||
|
||||
/* Now limit length */
|
||||
if (len > symbol_len)
|
||||
len = symbol_len;
|
||||
|
||||
symcp = memcheck(malloc(len + 1));
|
||||
|
||||
memcpy(symcp, cp, len);
|
||||
symcp[len] = 0;
|
||||
upcase(symcp);
|
||||
|
||||
if (islocal) {
|
||||
*islocal = 0;
|
||||
|
||||
/* Turn to local label format */
|
||||
if (digits == 1) {
|
||||
if (symcp[len - 1] == '$') {
|
||||
char *newsym = memcheck(malloc(32)); /* Overkill */
|
||||
|
||||
sprintf(newsym, "%ld$%d", strtol(symcp, NULL, 10), lsb);
|
||||
if (enabl_debug && lstfile) {
|
||||
fprintf(lstfile, "lsb %d: %s -> %s\n",
|
||||
lsb, symcp, newsym);
|
||||
}
|
||||
free(symcp);
|
||||
symcp = newsym;
|
||||
if (islocal)
|
||||
*islocal = SYMBOLFLAG_LOCAL;
|
||||
lsb_used++;
|
||||
} else {
|
||||
free(symcp);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* disallow local label format */
|
||||
if (isdigit((unsigned char)*symcp)) {
|
||||
free(symcp);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return symcp;
|
||||
}
|
||||
|
||||
/*
|
||||
brackrange is used to find a range of text which may or may not be
|
||||
bracketed.
|
||||
If the brackets are <>, then nested brackets are detected.
|
||||
If the brackets are of the form ^/.../ no detection of nesting is
|
||||
attempted.
|
||||
Using brackets ^<...< will mess this routine up. What in the world
|
||||
are you thinking?
|
||||
*/
|
||||
|
||||
int brackrange(
|
||||
char *cp,
|
||||
int *start,
|
||||
int *length,
|
||||
char **endp)
|
||||
{
|
||||
char endstr[6];
|
||||
int endlen;
|
||||
int nest;
|
||||
int len;
|
||||
|
||||
switch (*cp) {
|
||||
case '^':
|
||||
endstr[0] = cp[1];
|
||||
strcpy(endstr + 1, "\n");
|
||||
*start = 2;
|
||||
endlen = 1;
|
||||
break;
|
||||
case '<':
|
||||
strcpy(endstr, "<>\n");
|
||||
endlen = 1;
|
||||
*start = 1;
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
cp += *start;
|
||||
|
||||
len = 0;
|
||||
if (endstr[1] == '>') { /* <>\n */
|
||||
nest = 1;
|
||||
while (nest) {
|
||||
int sublen;
|
||||
|
||||
sublen = strcspn(cp + len, endstr);
|
||||
if (cp[len + sublen] == '<') {
|
||||
nest++;
|
||||
sublen++; /* avoid infinite loop when sublen == 0 */
|
||||
} else {
|
||||
nest--;
|
||||
if (nest > 0 && cp[len + sublen] == '>')
|
||||
sublen++; /* avoid infinite loop when sublen == 0 */
|
||||
}
|
||||
len += sublen;
|
||||
if (sublen == 0)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
int sublen;
|
||||
|
||||
sublen = strcspn(cp + len, endstr);
|
||||
len += sublen;
|
||||
}
|
||||
|
||||
*length = len;
|
||||
if (endp)
|
||||
*endp = cp + len + endlen;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* parse_unary parses out a unary operator or leaf expression. */
|
||||
|
||||
EX_TREE *parse_unary(
|
||||
char *cp)
|
||||
{
|
||||
EX_TREE *tp;
|
||||
|
||||
/* Skip leading whitespace */
|
||||
cp = skipwhite(cp);
|
||||
|
||||
if (*cp == '%') { /* Register notation */
|
||||
unsigned reg;
|
||||
|
||||
cp++;
|
||||
reg = strtoul(cp, &cp, 8);
|
||||
if (reg > 7)
|
||||
return ex_err(NULL, cp);
|
||||
|
||||
/* This returns references to the built-in register symbols */
|
||||
tp = new_ex_tree();
|
||||
tp->type = EX_SYM;
|
||||
tp->data.symbol = reg_sym[reg];
|
||||
tp->cp = cp;
|
||||
return tp;
|
||||
}
|
||||
|
||||
/* Unary negate */
|
||||
if (*cp == '-') {
|
||||
tp = new_ex_tree();
|
||||
tp->type = EX_NEG;
|
||||
tp->data.child.left = parse_unary(cp + 1);
|
||||
tp->cp = tp->data.child.left->cp;
|
||||
return tp;
|
||||
}
|
||||
|
||||
/* Unary + I can ignore. */
|
||||
if (*cp == '+')
|
||||
return parse_unary(cp + 1);
|
||||
|
||||
if (*cp == '^') {
|
||||
int save_radix;
|
||||
|
||||
switch (tolower((unsigned char)cp[1])) {
|
||||
case 'c':
|
||||
/* ^C, ones complement */
|
||||
tp = new_ex_tree();
|
||||
tp->type = EX_COM;
|
||||
tp->data.child.left = parse_unary(cp + 2);
|
||||
tp->cp = tp->data.child.left->cp;
|
||||
return tp;
|
||||
case 'b':
|
||||
/* ^B, binary radix modifier */
|
||||
save_radix = radix;
|
||||
radix = 2;
|
||||
tp = parse_unary(cp + 2);
|
||||
radix = save_radix;
|
||||
return tp;
|
||||
case 'o':
|
||||
/* ^O, octal radix modifier */
|
||||
save_radix = radix;
|
||||
radix = 8;
|
||||
tp = parse_unary(cp + 2);
|
||||
radix = save_radix;
|
||||
return tp;
|
||||
case 'd':
|
||||
/* ^D, decimal radix modifier */
|
||||
save_radix = radix;
|
||||
radix = 10;
|
||||
tp = parse_unary(cp + 2);
|
||||
radix = save_radix;
|
||||
return tp;
|
||||
case 'x':
|
||||
/* ^X, hexadecimal radix modifier */
|
||||
save_radix = radix;
|
||||
radix = 16;
|
||||
tp = parse_unary(cp + 2);
|
||||
radix = save_radix;
|
||||
return tp;
|
||||
case 'r':
|
||||
/* ^R, RAD50 literal */ {
|
||||
int start,
|
||||
len;
|
||||
char *endcp;
|
||||
unsigned value;
|
||||
|
||||
cp += 2; /* bracketed range is an extension */
|
||||
if (brackrange(cp, &start, &len, &endcp))
|
||||
value = rad50(cp + start, NULL);
|
||||
else
|
||||
value = rad50(cp, &endcp);
|
||||
tp = new_ex_lit(value);
|
||||
tp->cp = endcp;
|
||||
return tp;
|
||||
}
|
||||
case 'f':
|
||||
/* ^F, single-word floating point literal indicator */ {
|
||||
unsigned flt[1];
|
||||
char *endcp;
|
||||
|
||||
if (!parse_float(cp + 2, &endcp, 1, flt)) {
|
||||
tp = ex_err(NULL, cp + 2);
|
||||
} else {
|
||||
tp = new_ex_lit(flt[0]);
|
||||
tp->cp = endcp;
|
||||
}
|
||||
return tp;
|
||||
}
|
||||
}
|
||||
|
||||
if (ispunct((unsigned char)cp[1])) {
|
||||
char *ecp;
|
||||
|
||||
/* oddly-bracketed expression like this: ^/expression/ */
|
||||
tp = parse_binary(cp + 2, cp[1], 0);
|
||||
ecp = skipwhite(tp->cp);
|
||||
|
||||
if (*ecp != cp[1])
|
||||
return ex_err(tp, ecp);
|
||||
|
||||
tp->cp = ecp + 1;
|
||||
return tp;
|
||||
}
|
||||
}
|
||||
|
||||
/* Bracketed subexpression */
|
||||
if (*cp == '<') {
|
||||
char *ecp;
|
||||
|
||||
tp = parse_binary(cp + 1, '>', 0);
|
||||
ecp = skipwhite(tp->cp);
|
||||
if (*ecp != '>')
|
||||
return ex_err(tp, ecp);
|
||||
|
||||
tp->cp = ecp + 1;
|
||||
return tp;
|
||||
}
|
||||
|
||||
/* Check for ASCII constants */
|
||||
|
||||
if (*cp == '\'') {
|
||||
/* 'x single ASCII character */
|
||||
cp++;
|
||||
tp = new_ex_lit(*cp & 0xff);
|
||||
tp->cp = ++cp;
|
||||
return tp;
|
||||
}
|
||||
|
||||
if (*cp == '\"') {
|
||||
/* "xx ASCII character pair */
|
||||
cp++;
|
||||
tp = new_ex_lit((cp[0] & 0xff) | ((cp[1] & 0xff) << 8));
|
||||
tp->cp = cp + 2;
|
||||
return tp;
|
||||
}
|
||||
|
||||
/* Numeric constants are trickier than they need to be, */
|
||||
/* since local labels start with a digit too. */
|
||||
if (isdigit((unsigned char)*cp)) {
|
||||
char *label;
|
||||
int local;
|
||||
|
||||
if ((label = get_symbol(cp, NULL, &local)) == NULL) {
|
||||
char *endcp;
|
||||
unsigned long value;
|
||||
int rad = radix;
|
||||
|
||||
/* get_symbol returning NULL assures me that it's not a
|
||||
local label. */
|
||||
|
||||
/* Look for a trailing period, to indicate decimal... */
|
||||
for (endcp = cp; isdigit((unsigned char)*endcp); endcp++) ;
|
||||
if (*endcp == '.')
|
||||
rad = 10;
|
||||
|
||||
value = strtoul(cp, &endcp, rad);
|
||||
if (*endcp == '.')
|
||||
endcp++;
|
||||
|
||||
tp = new_ex_lit(value);
|
||||
tp->cp = endcp;
|
||||
|
||||
return tp;
|
||||
}
|
||||
|
||||
free(label);
|
||||
}
|
||||
|
||||
/* Now check for a symbol */
|
||||
{
|
||||
char *label;
|
||||
int local;
|
||||
SYMBOL *sym;
|
||||
|
||||
/* Optimization opportunity: I don't really need to call
|
||||
get_symbol a second time. */
|
||||
|
||||
if (!(label = get_symbol(cp, &cp, &local))) {
|
||||
cp++; /*JH: eat first char of illegal label, else endless loop on implied .WORD */
|
||||
tp = ex_err(NULL, cp); /* Not a valid label. */
|
||||
return tp;
|
||||
}
|
||||
|
||||
sym = lookup_sym(label, &symbol_st);
|
||||
if (sym == NULL) {
|
||||
/* A symbol from the "PST", which means an instruction
|
||||
code. */
|
||||
sym = lookup_sym(label, &system_st);
|
||||
}
|
||||
|
||||
if (sym != NULL) {
|
||||
tp = new_ex_tree();
|
||||
tp->cp = cp;
|
||||
tp->type = EX_SYM;
|
||||
tp->data.symbol = sym;
|
||||
|
||||
free(label);
|
||||
return tp;
|
||||
}
|
||||
|
||||
/* The symbol was not found. Create an "undefined symbol"
|
||||
reference. */
|
||||
sym = memcheck(malloc(sizeof(SYMBOL)));
|
||||
sym->label = label;
|
||||
sym->flags = SYMBOLFLAG_UNDEFINED | local;
|
||||
sym->stmtno = stmtno;
|
||||
sym->next = NULL;
|
||||
sym->section = &absolute_section;
|
||||
sym->value = 0;
|
||||
|
||||
tp = new_ex_tree();
|
||||
tp->cp = cp;
|
||||
tp->type = EX_UNDEFINED_SYM;
|
||||
tp->data.symbol = sym;
|
||||
|
||||
return tp;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
parse_expr - this gets called everywhere. It parses and evaluates
|
||||
an arithmetic expression.
|
||||
*/
|
||||
|
||||
EX_TREE *parse_expr(
|
||||
char *cp,
|
||||
int undef)
|
||||
{
|
||||
EX_TREE *expr;
|
||||
EX_TREE *value;
|
||||
|
||||
expr = parse_binary(cp, 0, 0); /* Parse into a tree */
|
||||
value = evaluate(expr, undef); /* Perform the arithmetic */
|
||||
value->cp = expr->cp; /* Pointer to end of text is part of
|
||||
the rootmost node */
|
||||
free_tree(expr); /* Discard parse in favor of
|
||||
evaluation */
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
parse_unary_expr It parses and evaluates
|
||||
an arithmetic expression but only a unary: (op)value or <expr>.
|
||||
In particular, it doesn't try to divide in <lf>/SOH/.
|
||||
*/
|
||||
|
||||
EX_TREE *parse_unary_expr(
|
||||
char *cp,
|
||||
int undef)
|
||||
{
|
||||
EX_TREE *expr;
|
||||
EX_TREE *value;
|
||||
|
||||
expr = parse_unary(cp); /* Parse into a tree */
|
||||
value = evaluate(expr, undef); /* Perform the arithmetic */
|
||||
value->cp = expr->cp; /* Pointer to end of text is part of
|
||||
the rootmost node */
|
||||
free_tree(expr); /* Discard parse in favor of
|
||||
evaluation */
|
||||
|
||||
return value;
|
||||
}
|
||||
63
crossassemblers/macro11/parse.h
Normal file
63
crossassemblers/macro11/parse.h
Normal file
@@ -0,0 +1,63 @@
|
||||
|
||||
#ifndef PARSE__H
|
||||
#define PARSE__H
|
||||
|
||||
#include "symbols.h"
|
||||
#include "assemble_aux.h" /* ADDR_MODE */
|
||||
|
||||
|
||||
// is char 'c' part of a symbol?
|
||||
#define issym(c) (isalpha(c) || isdigit(c) \
|
||||
|| (c) == '.' || (c) == '$' \
|
||||
|| (symbol_allow_underscores && (c) == '_'))
|
||||
|
||||
|
||||
char *skipwhite(
|
||||
char *cp);
|
||||
char *skipdelim(
|
||||
char *cp);
|
||||
char *skipdelim_comma(
|
||||
char *cp,
|
||||
int *comma);
|
||||
|
||||
SYMBOL *get_op(
|
||||
char *cp,
|
||||
char **endp);
|
||||
char *getstring(
|
||||
char *cp,
|
||||
char **endp);
|
||||
char *getstring_fn(
|
||||
char *cp,
|
||||
char **endp);
|
||||
char *get_symbol(
|
||||
char *cp,
|
||||
char **endp,
|
||||
int *islocal);
|
||||
int get_mode(
|
||||
char *cp,
|
||||
char **endp,
|
||||
ADDR_MODE *mode);
|
||||
|
||||
EX_TREE *parse_expr(
|
||||
char *cp,
|
||||
int undef);
|
||||
EX_TREE *parse_unary_expr(
|
||||
char *cp,
|
||||
int undef);
|
||||
int parse_float(
|
||||
char *cp,
|
||||
char **endp,
|
||||
int size,
|
||||
unsigned *flt);
|
||||
|
||||
int brackrange(
|
||||
char *cp,
|
||||
int *start,
|
||||
int *length,
|
||||
char **endp);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
160
crossassemblers/macro11/rad50.c
Normal file
160
crossassemblers/macro11/rad50.c
Normal file
@@ -0,0 +1,160 @@
|
||||
/* Functions to convert RAD50 to or from ASCII. */
|
||||
|
||||
/*
|
||||
Copyright (c) 2001, Richard Krehbiel
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
o Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
o Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
o Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "rad50.h"
|
||||
|
||||
static char radtbl[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$. 0123456789";
|
||||
|
||||
/* rad50 converts from 0 to 3 ASCII (or EBCDIC, if your compiler is so
|
||||
inclined) characters into a RAD50 word. */
|
||||
|
||||
unsigned rad50(
|
||||
char *cp,
|
||||
char **endp)
|
||||
{
|
||||
unsigned long acc = 0;
|
||||
char *rp;
|
||||
|
||||
if (endp)
|
||||
*endp = cp;
|
||||
|
||||
if (!*cp) /* Got to check for end-of-string manually, because strchr will call it a hit. :-/ */
|
||||
return acc;
|
||||
|
||||
rp = strchr(radtbl, toupper((unsigned char)*cp));
|
||||
if (rp == NULL) /* Not a RAD50 character */
|
||||
return acc;
|
||||
acc = ((int) (rp - radtbl)) * 03100; /* Convert */
|
||||
cp++;
|
||||
|
||||
/* Now, do the same thing two more times... */
|
||||
|
||||
if (endp)
|
||||
*endp = cp;
|
||||
if (!*cp)
|
||||
return acc;
|
||||
rp = strchr(radtbl, toupper((unsigned char)*cp));
|
||||
if (rp == NULL)
|
||||
return acc;
|
||||
acc += ((int) (rp - radtbl)) * 050;
|
||||
|
||||
cp++;
|
||||
if (endp)
|
||||
*endp = cp;
|
||||
if (!*cp)
|
||||
return acc;
|
||||
rp = strchr(radtbl, toupper((unsigned char)*cp));
|
||||
if (rp == NULL)
|
||||
return acc;
|
||||
acc += (int) (rp - radtbl);
|
||||
|
||||
cp++;
|
||||
if (endp)
|
||||
*endp = cp;
|
||||
|
||||
return acc; /* Done. */
|
||||
}
|
||||
|
||||
/* rad50x2 - converts from 0 to 6 characters into two words of RAD50. */
|
||||
|
||||
void rad50x2(
|
||||
char *cp,
|
||||
unsigned *rp)
|
||||
{
|
||||
*rp++ = rad50(cp, &cp);
|
||||
*rp = 0;
|
||||
if (*cp)
|
||||
*rp = rad50(cp, &cp);
|
||||
}
|
||||
|
||||
/* unrad50 - converts a RAD50 word to three characters of ASCII. */
|
||||
|
||||
void unrad50(
|
||||
unsigned word,
|
||||
char *cp)
|
||||
{
|
||||
if (word < 0175000) { /* Is it legal RAD50? */
|
||||
cp[0] = radtbl[word / 03100];
|
||||
cp[1] = radtbl[(word / 050) % 050];
|
||||
cp[2] = radtbl[word % 050];
|
||||
} else
|
||||
cp[0] = cp[1] = cp[2] = ' ';
|
||||
}
|
||||
|
||||
/* ascii2rad50 - convert a single character to a RAD50 character */
|
||||
|
||||
int ascii2rad50(
|
||||
char c)
|
||||
{
|
||||
char *rp;
|
||||
|
||||
if (c == '\0') /* Not a RAD50 character */
|
||||
return -1;
|
||||
rp = strchr(radtbl, toupper((unsigned char)c));
|
||||
if (rp == NULL) /* Not a RAD50 character */
|
||||
return -1;
|
||||
return (int) (rp - radtbl); /* Convert */
|
||||
}
|
||||
|
||||
/* packrad50word - packs up to 3 characters into a RAD50 word.
|
||||
*
|
||||
* The characters should be in the range [0, 050),
|
||||
* such as having been converted by ascii2rad50().
|
||||
*/
|
||||
|
||||
unsigned packrad50word(
|
||||
char *cp,
|
||||
int len)
|
||||
{
|
||||
unsigned long acc = 0;
|
||||
|
||||
if (len >= 1) {
|
||||
acc += (cp[0] % 050) * 050 * 050;
|
||||
}
|
||||
if (len >= 2) {
|
||||
acc += (cp[1] % 050) * 050;
|
||||
}
|
||||
if (len >= 3) {
|
||||
acc += cp[2] % 050;
|
||||
}
|
||||
|
||||
return acc;
|
||||
}
|
||||
56
crossassemblers/macro11/rad50.h
Normal file
56
crossassemblers/macro11/rad50.h
Normal file
@@ -0,0 +1,56 @@
|
||||
#ifndef RAD50_H
|
||||
#define RAD50_H
|
||||
|
||||
/*
|
||||
Copyright (c) 2001, Richard Krehbiel
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
o Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
o Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
o Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
*/
|
||||
|
||||
extern unsigned rad50(
|
||||
char *cp,
|
||||
char **endp);
|
||||
|
||||
extern void rad50x2(
|
||||
char *cp,
|
||||
unsigned *rp);
|
||||
|
||||
extern void unrad50(
|
||||
unsigned word,
|
||||
char *cp);
|
||||
|
||||
int ascii2rad50(
|
||||
char c);
|
||||
|
||||
unsigned packrad50word(
|
||||
char *cp,
|
||||
int len);
|
||||
|
||||
#endif /* RAD50_H */
|
||||
370
crossassemblers/macro11/rept_irpc.c
Normal file
370
crossassemblers/macro11/rept_irpc.c
Normal file
@@ -0,0 +1,370 @@
|
||||
#define REPT_IRPC__C
|
||||
|
||||
/*
|
||||
.REPT
|
||||
.IRPC streams
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "rept_irpc.h" /* my own definitions */
|
||||
|
||||
#include "util.h"
|
||||
#include "assemble_aux.h"
|
||||
#include "parse.h"
|
||||
#include "listing.h"
|
||||
#include "macros.h"
|
||||
#include "assemble_globals.h"
|
||||
|
||||
|
||||
/* *** implement REPT_STREAM */
|
||||
|
||||
typedef struct rept_stream {
|
||||
BUFFER_STREAM bstr;
|
||||
int count; /* The current repeat countdown */
|
||||
int savecond; /* conditional stack level at time of
|
||||
expansion */
|
||||
} REPT_STREAM;
|
||||
|
||||
/* rept_stream_gets gets a line from a repeat stream. At the end of
|
||||
each count, the coutdown is decreated and the stream is reset to
|
||||
it's beginning. */
|
||||
|
||||
char *rept_stream_gets(
|
||||
STREAM *str)
|
||||
{
|
||||
REPT_STREAM *rstr = (REPT_STREAM *) str;
|
||||
char *cp;
|
||||
|
||||
for (;;) {
|
||||
if ((cp = buffer_stream_gets(str)) != NULL)
|
||||
return cp;
|
||||
|
||||
if (--rstr->count <= 0)
|
||||
return NULL;
|
||||
|
||||
buffer_stream_rewind(str);
|
||||
}
|
||||
}
|
||||
|
||||
/* rept_stream_delete unwinds nested conditionals like .MEXIT does. */
|
||||
|
||||
void rept_stream_delete(
|
||||
STREAM *str)
|
||||
{
|
||||
REPT_STREAM *rstr = (REPT_STREAM *) str;
|
||||
|
||||
pop_cond(rstr->savecond); /* complete unterminated
|
||||
conditionals */
|
||||
buffer_stream_delete(&rstr->bstr.stream);
|
||||
}
|
||||
|
||||
/* The VTBL */
|
||||
|
||||
STREAM_VTBL rept_stream_vtbl = {
|
||||
rept_stream_delete, rept_stream_gets, buffer_stream_rewind
|
||||
};
|
||||
|
||||
/* expand_rept is called when a .REPT is encountered in the input. */
|
||||
|
||||
STREAM *expand_rept(
|
||||
STACK *stack,
|
||||
char *cp)
|
||||
{
|
||||
EX_TREE *value;
|
||||
BUFFER *gb;
|
||||
REPT_STREAM *rstr;
|
||||
int levelmod;
|
||||
|
||||
value = parse_expr(cp, 0);
|
||||
if (value->type != EX_LIT) {
|
||||
report(stack->top, ".REPT value must be constant\n");
|
||||
free_tree(value);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gb = new_buffer();
|
||||
|
||||
levelmod = 0;
|
||||
if (!list_md) {
|
||||
list_level--;
|
||||
levelmod = 1;
|
||||
}
|
||||
|
||||
read_body(stack, gb, NULL, FALSE);
|
||||
|
||||
list_level += levelmod;
|
||||
|
||||
rstr = memcheck(malloc(sizeof(REPT_STREAM))); {
|
||||
char *name = memcheck(malloc(strlen(stack->top->name) + 32));
|
||||
|
||||
sprintf(name, "%s:%d->.REPT", stack->top->name, stack->top->line);
|
||||
buffer_stream_construct(&rstr->bstr, gb, name);
|
||||
free(name);
|
||||
}
|
||||
|
||||
rstr->count = value->data.lit;
|
||||
rstr->bstr.stream.vtbl = &rept_stream_vtbl;
|
||||
rstr->savecond = last_cond;
|
||||
|
||||
buffer_free(gb);
|
||||
free_tree(value);
|
||||
|
||||
return &rstr->bstr.stream;
|
||||
}
|
||||
|
||||
/* *** implement IRP_STREAM */
|
||||
|
||||
typedef struct irp_stream {
|
||||
BUFFER_STREAM bstr;
|
||||
char *label; /* The substitution label */
|
||||
char *items; /* The substitution items (in source code
|
||||
format) */
|
||||
int offset; /* Current offset into "items" */
|
||||
BUFFER *body; /* Original body */
|
||||
int savecond; /* Saved conditional level */
|
||||
} IRP_STREAM;
|
||||
|
||||
/* irp_stream_gets expands the IRP as the stream is read. */
|
||||
/* Each time an iteration is exhausted, the next iteration is
|
||||
generated. */
|
||||
|
||||
char *irp_stream_gets(
|
||||
STREAM *str)
|
||||
{
|
||||
IRP_STREAM *istr = (IRP_STREAM *) str;
|
||||
char *cp;
|
||||
BUFFER *buf;
|
||||
ARG *arg;
|
||||
|
||||
for (;;) {
|
||||
if ((cp = buffer_stream_gets(str)) != NULL)
|
||||
return cp;
|
||||
|
||||
cp = istr->items + istr->offset;
|
||||
|
||||
if (!*cp)
|
||||
return NULL; /* No more items. EOF. */
|
||||
|
||||
arg = new_arg();
|
||||
arg->next = NULL;
|
||||
arg->locsym = 0;
|
||||
arg->label = istr->label;
|
||||
arg->value = getstring_macarg(str, cp, &cp);
|
||||
cp = skipdelim(cp);
|
||||
istr->offset = (int) (cp - istr->items);
|
||||
|
||||
buf = subst_args(istr->body, arg);
|
||||
|
||||
free(arg->value);
|
||||
free(arg);
|
||||
buffer_stream_set_buffer(&istr->bstr, buf);
|
||||
buffer_free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
/* irp_stream_delete - also pops the conditional stack */
|
||||
|
||||
void irp_stream_delete(
|
||||
STREAM *str)
|
||||
{
|
||||
IRP_STREAM *istr = (IRP_STREAM *) str;
|
||||
|
||||
pop_cond(istr->savecond); /* complete unterminated
|
||||
conditionals */
|
||||
|
||||
buffer_free(istr->body);
|
||||
free(istr->items);
|
||||
free(istr->label);
|
||||
buffer_stream_delete(str);
|
||||
}
|
||||
|
||||
STREAM_VTBL irp_stream_vtbl = {
|
||||
irp_stream_delete, irp_stream_gets, buffer_stream_rewind
|
||||
};
|
||||
|
||||
/* expand_irp is called when a .IRP is encountered in the input. */
|
||||
|
||||
STREAM *expand_irp(
|
||||
STACK *stack,
|
||||
char *cp)
|
||||
{
|
||||
char *label,
|
||||
*items;
|
||||
BUFFER *gb;
|
||||
int levelmod = 0;
|
||||
IRP_STREAM *str;
|
||||
|
||||
label = get_symbol(cp, &cp, NULL);
|
||||
if (!label) {
|
||||
report(stack->top, "Illegal .IRP syntax\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cp = skipdelim(cp);
|
||||
|
||||
items = getstring(cp, &cp);
|
||||
if (!items) {
|
||||
report(stack->top, "Illegal .IRP syntax\n");
|
||||
free(label);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gb = new_buffer();
|
||||
|
||||
levelmod = 0;
|
||||
if (!list_md) {
|
||||
list_level--;
|
||||
levelmod++;
|
||||
}
|
||||
|
||||
read_body(stack, gb, NULL, FALSE);
|
||||
|
||||
list_level += levelmod;
|
||||
|
||||
str = memcheck(malloc(sizeof(IRP_STREAM))); {
|
||||
char *name = memcheck(malloc(strlen(stack->top->name) + 32));
|
||||
|
||||
sprintf(name, "%s:%d->.IRP", stack->top->name, stack->top->line);
|
||||
buffer_stream_construct(&str->bstr, NULL, name);
|
||||
free(name);
|
||||
}
|
||||
|
||||
str->bstr.stream.vtbl = &irp_stream_vtbl;
|
||||
|
||||
str->body = gb;
|
||||
str->items = items;
|
||||
str->offset = 0;
|
||||
str->label = label;
|
||||
str->savecond = last_cond;
|
||||
|
||||
return &str->bstr.stream;
|
||||
}
|
||||
|
||||
|
||||
/* *** implement IRPC_STREAM */
|
||||
|
||||
typedef struct irpc_stream {
|
||||
BUFFER_STREAM bstr;
|
||||
char *label; /* The substitution label */
|
||||
char *items; /* The substitution items (in source code
|
||||
format) */
|
||||
int offset; /* Current offset in "items" */
|
||||
BUFFER *body; /* Original body */
|
||||
int savecond; /* conditional stack at invocation */
|
||||
} IRPC_STREAM;
|
||||
|
||||
/* irpc_stream_gets - same comments apply as with irp_stream_gets, but
|
||||
the substitution is character-by-character */
|
||||
|
||||
char *irpc_stream_gets(
|
||||
STREAM *str)
|
||||
{
|
||||
IRPC_STREAM *istr = (IRPC_STREAM *) str;
|
||||
char *cp;
|
||||
BUFFER *buf;
|
||||
ARG *arg;
|
||||
|
||||
for (;;) {
|
||||
if ((cp = buffer_stream_gets(str)) != NULL)
|
||||
return cp;
|
||||
|
||||
cp = istr->items + istr->offset;
|
||||
|
||||
if (!*cp)
|
||||
return NULL; /* No more items. EOF. */
|
||||
|
||||
arg = new_arg();
|
||||
arg->next = NULL;
|
||||
arg->locsym = 0;
|
||||
arg->label = istr->label;
|
||||
arg->value = memcheck(malloc(2));
|
||||
arg->value[0] = *cp++;
|
||||
arg->value[1] = 0;
|
||||
istr->offset = (int) (cp - istr->items);
|
||||
|
||||
buf = subst_args(istr->body, arg);
|
||||
|
||||
free(arg->value);
|
||||
free(arg);
|
||||
buffer_stream_set_buffer(&istr->bstr, buf);
|
||||
buffer_free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
/* irpc_stream_delete - also pops contidionals */
|
||||
|
||||
void irpc_stream_delete(
|
||||
STREAM *str)
|
||||
{
|
||||
IRPC_STREAM *istr = (IRPC_STREAM *) str;
|
||||
|
||||
pop_cond(istr->savecond); /* complete unterminated
|
||||
conditionals */
|
||||
buffer_free(istr->body);
|
||||
free(istr->items);
|
||||
free(istr->label);
|
||||
buffer_stream_delete(str);
|
||||
}
|
||||
|
||||
STREAM_VTBL irpc_stream_vtbl = {
|
||||
irpc_stream_delete, irpc_stream_gets, buffer_stream_rewind
|
||||
};
|
||||
|
||||
/* expand_irpc - called when .IRPC is encountered in the input */
|
||||
|
||||
STREAM *expand_irpc(
|
||||
STACK *stack,
|
||||
char *cp)
|
||||
{
|
||||
char *label,
|
||||
*items;
|
||||
BUFFER *gb;
|
||||
int levelmod = 0;
|
||||
IRPC_STREAM *str;
|
||||
|
||||
label = get_symbol(cp, &cp, NULL);
|
||||
if (!label) {
|
||||
report(stack->top, "Illegal .IRPC syntax\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cp = skipdelim(cp);
|
||||
|
||||
items = getstring(cp, &cp);
|
||||
if (!items) {
|
||||
report(stack->top, "Illegal .IRPC syntax\n");
|
||||
free(label);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gb = new_buffer();
|
||||
|
||||
levelmod = 0;
|
||||
if (!list_md) {
|
||||
list_level--;
|
||||
levelmod++;
|
||||
}
|
||||
|
||||
read_body(stack, gb, NULL, FALSE);
|
||||
|
||||
list_level += levelmod;
|
||||
|
||||
str = memcheck(malloc(sizeof(IRPC_STREAM))); {
|
||||
char *name = memcheck(malloc(strlen(stack->top->name) + 32));
|
||||
|
||||
sprintf(name, "%s:%d->.IRPC", stack->top->name, stack->top->line);
|
||||
buffer_stream_construct(&str->bstr, NULL, name);
|
||||
free(name);
|
||||
}
|
||||
|
||||
str->bstr.stream.vtbl = &irpc_stream_vtbl;
|
||||
str->body = gb;
|
||||
str->items = items;
|
||||
str->offset = 0;
|
||||
str->label = label;
|
||||
str->savecond = last_cond;
|
||||
|
||||
return &str->bstr.stream;
|
||||
}
|
||||
26
crossassemblers/macro11/rept_irpc.h
Normal file
26
crossassemblers/macro11/rept_irpc.h
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
#ifndef REPT_IRPC__H
|
||||
#define REPT_IRPC__H
|
||||
|
||||
#include "stream2.h"
|
||||
|
||||
|
||||
#ifndef REPT_IRPC__C
|
||||
extern STREAM_VTBL rept_stream_vtbl;
|
||||
extern STREAM_VTBL irp_stream_vtbl;
|
||||
extern STREAM_VTBL irpc_stream_vtbl;
|
||||
#endif
|
||||
|
||||
STREAM *expand_rept(
|
||||
STACK *stack,
|
||||
char *cp);
|
||||
|
||||
STREAM *expand_irp(
|
||||
STACK *stack,
|
||||
char *cp);
|
||||
|
||||
STREAM *expand_irpc(
|
||||
STACK *stack,
|
||||
char *cp);
|
||||
|
||||
#endif
|
||||
411
crossassemblers/macro11/stream2.c
Normal file
411
crossassemblers/macro11/stream2.c
Normal file
@@ -0,0 +1,411 @@
|
||||
/* functions for managing a stack of file and buffer input streams. */
|
||||
|
||||
/*
|
||||
|
||||
Copyright (c) 2001, Richard Krehbiel
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
o Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
o Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
o Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#include "stream2.h"
|
||||
|
||||
/* BUFFER functions */
|
||||
|
||||
/* new_buffer allocates a new buffer */
|
||||
|
||||
BUFFER *new_buffer(
|
||||
void)
|
||||
{
|
||||
BUFFER *buf = memcheck(malloc(sizeof(BUFFER)));
|
||||
|
||||
buf->length = 0;
|
||||
buf->size = 0;
|
||||
buf->use = 1;
|
||||
buf->buffer = NULL;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* buffer_resize makes the buffer at least the requested size. */
|
||||
/* If the buffer is already larger, then it will attempt */
|
||||
/* to shrink it. */
|
||||
|
||||
void buffer_resize(
|
||||
BUFFER *buff,
|
||||
int size)
|
||||
{
|
||||
buff->size = size;
|
||||
buff->length = size;
|
||||
|
||||
if (size == 0) {
|
||||
free(buff->buffer);
|
||||
buff->buffer = NULL;
|
||||
} else {
|
||||
if (buff->buffer == NULL)
|
||||
buff->buffer = memcheck(malloc(buff->size));
|
||||
else
|
||||
buff->buffer = memcheck(realloc(buff->buffer, buff->size));
|
||||
}
|
||||
}
|
||||
|
||||
/* buffer_clone makes a copy of a buffer */
|
||||
/* Basically it increases the use count */
|
||||
|
||||
BUFFER *buffer_clone(
|
||||
BUFFER *from)
|
||||
{
|
||||
if (from)
|
||||
from->use++;
|
||||
return from;
|
||||
}
|
||||
|
||||
/* buffer_free frees a buffer */
|
||||
/* It decreases the use count, and if zero, */
|
||||
/* frees the memory. */
|
||||
|
||||
void buffer_free(
|
||||
BUFFER *buf)
|
||||
{
|
||||
if (buf) {
|
||||
if (--(buf->use) == 0) {
|
||||
free(buf->buffer);
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Append characters to the buffer. */
|
||||
|
||||
void buffer_appendn(
|
||||
BUFFER *buf,
|
||||
char *str,
|
||||
int len)
|
||||
{
|
||||
int needed = buf->length + len + 1;
|
||||
|
||||
if (needed >= buf->size) {
|
||||
buf->size = needed + GROWBUF_INCR;
|
||||
|
||||
if (buf->buffer == NULL)
|
||||
buf->buffer = memcheck(malloc(buf->size));
|
||||
else
|
||||
buf->buffer = memcheck(realloc(buf->buffer, buf->size));
|
||||
}
|
||||
|
||||
memcpy(buf->buffer + buf->length, str, len);
|
||||
buf->length += len;
|
||||
buf->buffer[buf->length] = 0;
|
||||
}
|
||||
|
||||
/* append a text line (zero or newline-delimited) */
|
||||
|
||||
void buffer_append_line(
|
||||
BUFFER *buf,
|
||||
char *str)
|
||||
{
|
||||
char *nl;
|
||||
|
||||
if ((nl = strchr(str, '\n')) != NULL)
|
||||
buffer_appendn(buf, str, (int) (nl - str + 1));
|
||||
else
|
||||
buffer_appendn(buf, str, strlen(str));
|
||||
}
|
||||
|
||||
/* Base STREAM class methods */
|
||||
|
||||
/* stream_construct initializes a newly allocated STREAM */
|
||||
|
||||
void stream_construct(
|
||||
STREAM *str,
|
||||
char *name)
|
||||
{
|
||||
str->line = 0;
|
||||
str->name = memcheck(strdup(name));
|
||||
str->next = NULL;
|
||||
str->vtbl = NULL;
|
||||
}
|
||||
|
||||
/* stream_delete destroys and deletes (frees) a STREAM */
|
||||
|
||||
void stream_delete(
|
||||
STREAM *str)
|
||||
{
|
||||
free(str->name);
|
||||
free(str);
|
||||
}
|
||||
|
||||
/* *** class BUFFER_STREAM implementation */
|
||||
|
||||
/* STREAM::gets for a buffer stream */
|
||||
|
||||
char *buffer_stream_gets(
|
||||
STREAM *str)
|
||||
{
|
||||
char *nl;
|
||||
char *cp;
|
||||
BUFFER_STREAM *bstr = (BUFFER_STREAM *) str;
|
||||
BUFFER *buf = bstr->buffer;
|
||||
|
||||
if (buf == NULL)
|
||||
return NULL; /* No buffer */
|
||||
|
||||
if (bstr->offset >= buf->length)
|
||||
return NULL;
|
||||
|
||||
cp = buf->buffer + bstr->offset;
|
||||
|
||||
/* Find the next line in preparation for the next call */
|
||||
|
||||
nl = memchr(cp, '\n', buf->length - bstr->offset);
|
||||
|
||||
if (nl)
|
||||
nl++;
|
||||
|
||||
bstr->offset = (int) (nl - buf->buffer);
|
||||
str->line++;
|
||||
|
||||
return cp;
|
||||
}
|
||||
|
||||
/* STREAM::close for a buffer stream */
|
||||
|
||||
void buffer_stream_delete(
|
||||
STREAM *str)
|
||||
{
|
||||
BUFFER_STREAM *bstr = (BUFFER_STREAM *) str;
|
||||
|
||||
buffer_free(bstr->buffer);
|
||||
stream_delete(str);
|
||||
}
|
||||
|
||||
/* STREAM::rewind for a buffer stream */
|
||||
|
||||
void buffer_stream_rewind(
|
||||
STREAM *str)
|
||||
{
|
||||
BUFFER_STREAM *bstr = (BUFFER_STREAM *) str;
|
||||
|
||||
bstr->offset = 0;
|
||||
str->line = 0;
|
||||
}
|
||||
|
||||
/* BUFFER_STREAM vtbl */
|
||||
|
||||
STREAM_VTBL buffer_stream_vtbl = {
|
||||
buffer_stream_delete, buffer_stream_gets, buffer_stream_rewind
|
||||
};
|
||||
|
||||
void buffer_stream_construct(
|
||||
BUFFER_STREAM * bstr,
|
||||
BUFFER *buf,
|
||||
char *name)
|
||||
{
|
||||
bstr->stream.vtbl = &buffer_stream_vtbl;
|
||||
|
||||
bstr->stream.name = memcheck(strdup(name));
|
||||
|
||||
bstr->buffer = buffer_clone(buf);
|
||||
bstr->offset = 0;
|
||||
bstr->stream.line = 0;
|
||||
}
|
||||
|
||||
void buffer_stream_set_buffer(
|
||||
BUFFER_STREAM * bstr,
|
||||
BUFFER *buf)
|
||||
{
|
||||
if (bstr->buffer)
|
||||
buffer_free(bstr->buffer);
|
||||
bstr->buffer = buffer_clone(buf);
|
||||
bstr->offset = 0;
|
||||
}
|
||||
|
||||
/* new_buffer_stream clones the given buffer, gives it the name, */
|
||||
/* and creates a BUFFER_STREAM to reference it */
|
||||
|
||||
STREAM *new_buffer_stream(
|
||||
BUFFER *buf,
|
||||
char *name)
|
||||
{
|
||||
BUFFER_STREAM *bstr = memcheck(malloc(sizeof(BUFFER_STREAM)));
|
||||
|
||||
buffer_stream_construct(bstr, buf, name);
|
||||
return &bstr->stream;
|
||||
}
|
||||
|
||||
/* *** FILE_STREAM implementation */
|
||||
|
||||
/* Implement STREAM::gets for a file stream */
|
||||
|
||||
static char *file_gets(
|
||||
STREAM *str)
|
||||
{
|
||||
int i,
|
||||
c;
|
||||
FILE_STREAM *fstr = (FILE_STREAM *) str;
|
||||
|
||||
if (fstr->fp == NULL)
|
||||
return NULL;
|
||||
|
||||
if (feof(fstr->fp))
|
||||
return NULL;
|
||||
|
||||
/* Read single characters, end of line when '\n' or '\f' hit */
|
||||
|
||||
i = 0;
|
||||
while (c = fgetc(fstr->fp), c != '\n' && c != '\f' && c != EOF) {
|
||||
if (c == 0)
|
||||
continue; /* Don't buffer zeros */
|
||||
if (c == '\r')
|
||||
continue; /* Don't buffer carriage returns either */
|
||||
if (i < STREAM_BUFFER_SIZE - 2)
|
||||
fstr->buffer[i++] = c;
|
||||
}
|
||||
|
||||
fstr->buffer[i++] = '\n'; /* Silently transform formfeeds
|
||||
into newlines */
|
||||
fstr->buffer[i] = 0;
|
||||
|
||||
if (c == '\n')
|
||||
fstr->stream.line++; /* Count a line */
|
||||
|
||||
return fstr->buffer;
|
||||
}
|
||||
|
||||
/* Implement STREAM::destroy for a file stream */
|
||||
|
||||
void file_destroy(
|
||||
STREAM *str)
|
||||
{
|
||||
FILE_STREAM *fstr = (FILE_STREAM *) str;
|
||||
|
||||
fclose(fstr->fp);
|
||||
free(fstr->buffer);
|
||||
stream_delete(str);
|
||||
}
|
||||
|
||||
/* Implement STREAM::rewind for a file stream */
|
||||
|
||||
void file_rewind(
|
||||
STREAM *str)
|
||||
{
|
||||
FILE_STREAM *fstr = (FILE_STREAM *) str;
|
||||
|
||||
rewind(fstr->fp);
|
||||
str->line = 0;
|
||||
}
|
||||
|
||||
static STREAM_VTBL file_stream_vtbl = {
|
||||
file_destroy, file_gets, file_rewind
|
||||
};
|
||||
|
||||
/* Prepare and open a stream from a file. */
|
||||
|
||||
STREAM *new_file_stream(
|
||||
char *filename)
|
||||
{
|
||||
FILE *fp;
|
||||
FILE_STREAM *str;
|
||||
|
||||
fp = fopen(filename, "r");
|
||||
if (fp == NULL)
|
||||
return NULL;
|
||||
|
||||
str = memcheck(malloc(sizeof(FILE_STREAM)));
|
||||
|
||||
str->stream.vtbl = &file_stream_vtbl;
|
||||
str->stream.name = memcheck(strdup(filename));
|
||||
str->buffer = memcheck(malloc(STREAM_BUFFER_SIZE));
|
||||
str->fp = fp;
|
||||
str->stream.line = 0;
|
||||
|
||||
return &str->stream;
|
||||
}
|
||||
|
||||
/* STACK functions */
|
||||
|
||||
/* stack_init prepares a stack */
|
||||
|
||||
void stack_init(
|
||||
STACK *stack)
|
||||
{
|
||||
stack->top = NULL; /* Too simple */
|
||||
}
|
||||
|
||||
/* stack_pop removes and deletes the topmost STRAM on the stack */
|
||||
|
||||
void stack_pop(
|
||||
STACK *stack)
|
||||
{
|
||||
STREAM *top = stack->top;
|
||||
STREAM *next = top->next;
|
||||
|
||||
top->vtbl->delete(top);
|
||||
stack->top = next;
|
||||
}
|
||||
|
||||
/* stack_push pushes a STREAM onto the top of the stack */
|
||||
|
||||
void stack_push(
|
||||
STACK *stack,
|
||||
STREAM *str)
|
||||
{
|
||||
str->next = stack->top;
|
||||
stack->top = str;
|
||||
}
|
||||
|
||||
/* stack_gets calls vtbl->gets for the topmost stack entry. When
|
||||
topmost streams indicate they're exhausted, they are popped and
|
||||
deleted, until the stack is exhausted. */
|
||||
|
||||
char *stack_gets(
|
||||
STACK *stack)
|
||||
{
|
||||
char *line;
|
||||
|
||||
if (stack->top == NULL)
|
||||
return NULL;
|
||||
|
||||
while ((line = stack->top->vtbl->gets(stack->top)) == NULL) {
|
||||
stack_pop(stack);
|
||||
if (stack->top == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
137
crossassemblers/macro11/stream2.h
Normal file
137
crossassemblers/macro11/stream2.h
Normal file
@@ -0,0 +1,137 @@
|
||||
#ifndef STREAM2_H
|
||||
#define STREAM2_H
|
||||
|
||||
/*
|
||||
|
||||
Copyright (c) 2001, Richard Krehbiel
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
o Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
o Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
o Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
||||
struct stream;
|
||||
|
||||
typedef struct stream_vtbl {
|
||||
void (
|
||||
*delete) (
|
||||
struct stream * stream); /* Destructor */
|
||||
char *(
|
||||
*gets) (
|
||||
struct stream * stream); /* "gets" function */
|
||||
void (
|
||||
*rewind) (
|
||||
struct stream * stream); /* "rewind" function */
|
||||
} STREAM_VTBL;
|
||||
|
||||
typedef struct stream {
|
||||
STREAM_VTBL *vtbl; /* Pointer to dispatch table */
|
||||
char *name; /* Stream name */
|
||||
int line; /* Current line number in stream */
|
||||
struct stream *next; /* Next stream in stack */
|
||||
} STREAM;
|
||||
|
||||
typedef struct file_stream {
|
||||
STREAM stream; /* Base class */
|
||||
FILE *fp; /* File pointer */
|
||||
char *buffer; /* Line buffer */
|
||||
} FILE_STREAM;
|
||||
|
||||
typedef struct buffer {
|
||||
char *buffer; /* Pointer to text */
|
||||
int size; /* Size of buffer */
|
||||
int length; /* Occupied size of buffer */
|
||||
int use; /* Number of users of buffer */
|
||||
} BUFFER;
|
||||
|
||||
#define GROWBUF_INCR 1024 /* Buffers grow by leaps and bounds */
|
||||
|
||||
typedef struct buffer_stream {
|
||||
STREAM stream; /* Base class */
|
||||
BUFFER *buffer; /* text buffer */
|
||||
int offset; /* Current read offset */
|
||||
} BUFFER_STREAM;
|
||||
|
||||
typedef struct stack {
|
||||
STREAM *top; /* Top of stacked stream pieces */
|
||||
} STACK;
|
||||
|
||||
#define STREAM_BUFFER_SIZE 1024 /* This limits the max size of an input line. */
|
||||
BUFFER *new_buffer(
|
||||
void);
|
||||
BUFFER *buffer_clone(
|
||||
BUFFER *from);
|
||||
void buffer_resize(
|
||||
BUFFER *buff,
|
||||
int size);
|
||||
void buffer_free(
|
||||
BUFFER *buf);
|
||||
void buffer_appendn(
|
||||
BUFFER *buf,
|
||||
char *str,
|
||||
int len);
|
||||
void buffer_append_line(
|
||||
BUFFER *buf,
|
||||
char *str);
|
||||
|
||||
STREAM *new_buffer_stream(
|
||||
BUFFER *buf,
|
||||
char *name);
|
||||
void buffer_stream_set_buffer(
|
||||
BUFFER_STREAM * bstr,
|
||||
BUFFER *buf);
|
||||
|
||||
/* Provide these so that macro11 can derive from a BUFFER_STREAM */
|
||||
extern STREAM_VTBL buffer_stream_vtbl;
|
||||
void buffer_stream_construct(
|
||||
BUFFER_STREAM * bstr,
|
||||
BUFFER *buf,
|
||||
char *name);
|
||||
char *buffer_stream_gets(
|
||||
STREAM *str);
|
||||
void buffer_stream_delete(
|
||||
STREAM *str);
|
||||
void buffer_stream_rewind(
|
||||
STREAM *str);
|
||||
|
||||
STREAM *new_file_stream(
|
||||
char *filename);
|
||||
|
||||
void stack_init(
|
||||
STACK *stack);
|
||||
void stack_push(
|
||||
STACK *stack,
|
||||
STREAM *str);
|
||||
void stack_pop(
|
||||
STACK *stack);
|
||||
char *stack_gets(
|
||||
STACK *stack);
|
||||
|
||||
#endif /* STREAM2_H */
|
||||
609
crossassemblers/macro11/symbols.c
Normal file
609
crossassemblers/macro11/symbols.c
Normal file
@@ -0,0 +1,609 @@
|
||||
|
||||
#define SYMBOLS__C
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "symbols.h" /* my own definitions */
|
||||
|
||||
#include "util.h"
|
||||
#include "assemble_globals.h"
|
||||
#include "listing.h"
|
||||
#include "object.h"
|
||||
|
||||
/* GLOBALS */
|
||||
int symbol_len = SYMMAX_DEFAULT; /* max. len of symbols. default = 6 */
|
||||
int symbol_allow_underscores = 0; /* allow "_" in symbol names */
|
||||
|
||||
SYMBOL *reg_sym[8]; /* Keep the register symbols in a handy array */
|
||||
|
||||
|
||||
SYMBOL_TABLE system_st; /* System symbols (Instructions,
|
||||
pseudo-ops, registers) */
|
||||
|
||||
SYMBOL_TABLE section_st; /* Program sections */
|
||||
|
||||
SYMBOL_TABLE symbol_st; /* User symbols */
|
||||
|
||||
SYMBOL_TABLE macro_st; /* Macros */
|
||||
|
||||
SYMBOL_TABLE implicit_st; /* The symbols which may be implicit globals */
|
||||
|
||||
|
||||
void list_section(SECTION *sec);
|
||||
|
||||
/* hash_name hashes a name into a value from 0-HASH_SIZE */
|
||||
|
||||
int hash_name(
|
||||
char *label)
|
||||
{
|
||||
unsigned accum = 0;
|
||||
|
||||
while (*label)
|
||||
accum = (accum << 1) ^ *label++;
|
||||
|
||||
accum %= HASH_SIZE;
|
||||
|
||||
return accum;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Diagnostic: symflags returns a char* which gives flags I can use to
|
||||
show the context of a symbol. */
|
||||
|
||||
char *symflags(
|
||||
SYMBOL *sym)
|
||||
{
|
||||
static char temp[8];
|
||||
char *fp = temp;
|
||||
|
||||
if (sym->flags & SYMBOLFLAG_GLOBAL)
|
||||
*fp++ = 'G';
|
||||
if (sym->flags & SYMBOLFLAG_PERMANENT)
|
||||
*fp++ = 'P';
|
||||
if (sym->flags & SYMBOLFLAG_DEFINITION)
|
||||
*fp++ = 'D';
|
||||
*fp = 0;
|
||||
return fp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Allocate a new symbol. Does not add it to any symbol table. */
|
||||
|
||||
static SYMBOL *new_sym(
|
||||
char *label)
|
||||
{
|
||||
SYMBOL *sym = memcheck(malloc(sizeof(SYMBOL)));
|
||||
|
||||
sym->label = memcheck(strdup(label));
|
||||
sym->section = NULL;
|
||||
sym->value = 0;
|
||||
sym->flags = 0;
|
||||
return sym;
|
||||
}
|
||||
|
||||
/* Free a symbol. Does not remove it from any symbol table. */
|
||||
|
||||
void free_sym(
|
||||
SYMBOL *sym)
|
||||
{
|
||||
if (sym->label) {
|
||||
free(sym->label);
|
||||
sym->label = NULL;
|
||||
}
|
||||
free(sym);
|
||||
}
|
||||
|
||||
/* remove_sym removes a symbol from it's symbol table. */
|
||||
|
||||
void remove_sym(
|
||||
SYMBOL *sym,
|
||||
SYMBOL_TABLE *table)
|
||||
{
|
||||
SYMBOL **prevp,
|
||||
*symp;
|
||||
int hash;
|
||||
|
||||
hash = hash_name(sym->label);
|
||||
prevp = &table->hash[hash];
|
||||
while (symp = *prevp, symp != NULL && symp != sym)
|
||||
prevp = &symp->next;
|
||||
|
||||
if (symp)
|
||||
*prevp = sym->next;
|
||||
}
|
||||
|
||||
/* lookup_sym finds a symbol in a table */
|
||||
|
||||
SYMBOL *lookup_sym(
|
||||
char *label,
|
||||
SYMBOL_TABLE *table)
|
||||
{
|
||||
unsigned hash;
|
||||
SYMBOL *sym;
|
||||
|
||||
hash = hash_name(label);
|
||||
|
||||
sym = table->hash[hash];
|
||||
while (sym && strcmp(sym->label, label) != 0)
|
||||
sym = sym->next;
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
/* next_sym - returns the next symbol from a symbol table. Must be
|
||||
preceeded by first_sym. Returns NULL after the last symbol. */
|
||||
|
||||
SYMBOL *next_sym(
|
||||
SYMBOL_TABLE *table,
|
||||
SYMBOL_ITER *iter)
|
||||
{
|
||||
if (iter->current)
|
||||
iter->current = iter->current->next;
|
||||
|
||||
while (iter->current == NULL) {
|
||||
if (iter->subscript >= HASH_SIZE)
|
||||
return NULL; /* No more symbols. */
|
||||
iter->current = table->hash[iter->subscript];
|
||||
iter->subscript++;
|
||||
}
|
||||
|
||||
return iter->current; /* Got a symbol. */
|
||||
}
|
||||
|
||||
/* first_sym - returns the first symbol from a symbol table. Symbols
|
||||
are stored in random order. */
|
||||
|
||||
SYMBOL *first_sym(
|
||||
SYMBOL_TABLE *table,
|
||||
SYMBOL_ITER *iter)
|
||||
{
|
||||
iter->subscript = 0;
|
||||
iter->current = NULL;
|
||||
return next_sym(table, iter);
|
||||
}
|
||||
|
||||
/* add_table - add a symbol to a symbol table. */
|
||||
|
||||
void add_table(
|
||||
SYMBOL *sym,
|
||||
SYMBOL_TABLE *table)
|
||||
{
|
||||
int hash = hash_name(sym->label);
|
||||
|
||||
sym->next = table->hash[hash];
|
||||
table->hash[hash] = sym;
|
||||
}
|
||||
|
||||
/* add_sym - used throughout to add or update symbols in a symbol
|
||||
table. */
|
||||
|
||||
SYMBOL *add_sym(
|
||||
char *labelraw,
|
||||
unsigned value,
|
||||
unsigned flags,
|
||||
SECTION *section,
|
||||
SYMBOL_TABLE *table)
|
||||
{
|
||||
SYMBOL *sym;
|
||||
char label[SYMMAX_MAX + 1]; // big size
|
||||
|
||||
if (isdigit((unsigned char)labelraw[0])) {
|
||||
// Don't truncate local labels
|
||||
strncpy(label, labelraw, SYMMAX_MAX);
|
||||
label[SYMMAX_MAX] = 0;
|
||||
} else {
|
||||
//JH: truncate symbol to SYMMAX
|
||||
strncpy(label, labelraw, symbol_len);
|
||||
label[symbol_len] = 0;
|
||||
}
|
||||
|
||||
sym = lookup_sym(label, table);
|
||||
if (sym != NULL) {
|
||||
// A symbol registered as "undefined" can be changed.
|
||||
|
||||
if ((sym->flags & SYMBOLFLAG_UNDEFINED) && !(flags & SYMBOLFLAG_UNDEFINED)) {
|
||||
sym->flags &= ~(SYMBOLFLAG_PERMANENT | SYMBOLFLAG_UNDEFINED);
|
||||
}
|
||||
|
||||
/* Check for compatible definition */
|
||||
else if (sym->section == section && sym->value == value) {
|
||||
sym->flags |= flags; /* Merge flags quietly */
|
||||
return sym; /* 's okay */
|
||||
}
|
||||
|
||||
if (!(sym->flags & SYMBOLFLAG_PERMANENT)) {
|
||||
/* permit redefinition */
|
||||
sym->value = value;
|
||||
sym->flags |= flags;
|
||||
sym->section = section;
|
||||
return sym;
|
||||
}
|
||||
|
||||
return NULL; /* Bad symbol redefinition */
|
||||
}
|
||||
|
||||
sym = new_sym(label);
|
||||
sym->flags = flags;
|
||||
sym->stmtno = stmtno;
|
||||
sym->section = section;
|
||||
sym->value = value;
|
||||
|
||||
add_table(sym, table);
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
/* add_symbols adds all the internal symbols. */
|
||||
|
||||
void add_symbols(
|
||||
SECTION *current_section)
|
||||
{
|
||||
current_pc = add_sym(".", 0, 0, current_section, &symbol_st);
|
||||
|
||||
reg_sym[0] = add_sym("R0", 0, 0, ®ister_section, &system_st);
|
||||
reg_sym[1] = add_sym("R1", 1, 0, ®ister_section, &system_st);
|
||||
reg_sym[2] = add_sym("R2", 2, 0, ®ister_section, &system_st);
|
||||
reg_sym[3] = add_sym("R3", 3, 0, ®ister_section, &system_st);
|
||||
reg_sym[4] = add_sym("R4", 4, 0, ®ister_section, &system_st);
|
||||
reg_sym[5] = add_sym("R5", 5, 0, ®ister_section, &system_st);
|
||||
reg_sym[6] = add_sym("SP", 6, 0, ®ister_section, &system_st);
|
||||
reg_sym[7] = add_sym("PC", 7, 0, ®ister_section, &system_st);
|
||||
|
||||
//JH: symbols longer than current SYMMAX will be truncated. SYMMAX=6 is minimum!
|
||||
add_sym(".ASCII", P_ASCII, 0, &pseudo_section, &system_st);
|
||||
add_sym(".ASCIZ", P_ASCIZ, 0, &pseudo_section, &system_st);
|
||||
add_sym(".ASECT", P_ASECT, 0, &pseudo_section, &system_st);
|
||||
add_sym(".BLKB", P_BLKB, 0, &pseudo_section, &system_st);
|
||||
add_sym(".BLKW", P_BLKW, 0, &pseudo_section, &system_st);
|
||||
add_sym(".BYTE", P_BYTE, 0, &pseudo_section, &system_st);
|
||||
add_sym(".CSECT", P_CSECT, 0, &pseudo_section, &system_st);
|
||||
add_sym(".DSABL", P_DSABL, 0, &pseudo_section, &system_st);
|
||||
add_sym(".ENABL", P_ENABL, 0, &pseudo_section, &system_st);
|
||||
add_sym(".END", P_END, 0, &pseudo_section, &system_st);
|
||||
add_sym(".ENDC", P_ENDC, 0, &pseudo_section, &system_st);
|
||||
add_sym(".ENDM", P_ENDM, 0, &pseudo_section, &system_st);
|
||||
add_sym(".ENDR", P_ENDR, 0, &pseudo_section, &system_st);
|
||||
add_sym(".EOT", P_EOT, 0, &pseudo_section, &system_st);
|
||||
add_sym(".ERROR", P_ERROR, 0, &pseudo_section, &system_st);
|
||||
add_sym(".EVEN", P_EVEN, 0, &pseudo_section, &system_st);
|
||||
add_sym(".FLT2", P_FLT2, 0, &pseudo_section, &system_st);
|
||||
add_sym(".FLT4", P_FLT4, 0, &pseudo_section, &system_st);
|
||||
add_sym(".GLOBL", P_GLOBL, 0, &pseudo_section, &system_st);
|
||||
add_sym(".IDENT", P_IDENT, 0, &pseudo_section, &system_st);
|
||||
add_sym(".IF", P_IF, 0, &pseudo_section, &system_st);
|
||||
add_sym(".IFDF", P_IFDF, 0, &pseudo_section, &system_st);
|
||||
add_sym(".IFNDF", P_IFDF, 0, &pseudo_section, &system_st);
|
||||
add_sym(".IFF", P_IFF, 0, &pseudo_section, &system_st);
|
||||
add_sym(".IFT", P_IFT, 0, &pseudo_section, &system_st);
|
||||
add_sym(".IFTF", P_IFTF, 0, &pseudo_section, &system_st);
|
||||
add_sym(".IIF", P_IIF, 0, &pseudo_section, &system_st);
|
||||
add_sym(".INCLUDE", P_INCLUDE, 0, &pseudo_section, &system_st);
|
||||
add_sym(".IRP", P_IRP, 0, &pseudo_section, &system_st);
|
||||
add_sym(".IRPC", P_IRPC, 0, &pseudo_section, &system_st);
|
||||
add_sym(".LIBRARY", P_LIBRARY, 0, &pseudo_section, &system_st);
|
||||
add_sym(".LIMIT", P_LIMIT, 0, &pseudo_section, &system_st);
|
||||
add_sym(".LIST", P_LIST, 0, &pseudo_section, &system_st);
|
||||
add_sym(".MCALL", P_MCALL, 0, &pseudo_section, &system_st);
|
||||
add_sym(".MEXIT", P_MEXIT, 0, &pseudo_section, &system_st);
|
||||
add_sym(".NARG", P_NARG, 0, &pseudo_section, &system_st);
|
||||
add_sym(".NCHR", P_NCHR, 0, &pseudo_section, &system_st);
|
||||
add_sym(".NLIST", P_NLIST, 0, &pseudo_section, &system_st);
|
||||
add_sym(".NTYPE", P_NTYPE, 0, &pseudo_section, &system_st);
|
||||
add_sym(".ODD", P_ODD, 0, &pseudo_section, &system_st);
|
||||
add_sym(".PACKED", P_PACKED, 0, &pseudo_section, &system_st);
|
||||
add_sym(".PAGE", P_PAGE, 0, &pseudo_section, &system_st);
|
||||
add_sym(".PRINT", P_PRINT, 0, &pseudo_section, &system_st);
|
||||
add_sym(".PSECT", P_PSECT, 0, &pseudo_section, &system_st);
|
||||
add_sym(".RADIX", P_RADIX, 0, &pseudo_section, &system_st);
|
||||
add_sym(".RAD50", P_RAD50, 0, &pseudo_section, &system_st);
|
||||
add_sym(".REM", P_REM, 0, &pseudo_section, &system_st);
|
||||
add_sym(".REPT", P_REPT, 0, &pseudo_section, &system_st);
|
||||
add_sym(".RESTORE", P_RESTORE, 0, &pseudo_section, &system_st);
|
||||
add_sym(".SAVE", P_SAVE, 0, &pseudo_section, &system_st);
|
||||
add_sym(".SBTTL", P_SBTTL, 0, &pseudo_section, &system_st);
|
||||
add_sym(".TITLE", P_TITLE, 0, &pseudo_section, &system_st);
|
||||
add_sym(".WORD", P_WORD, 0, &pseudo_section, &system_st);
|
||||
add_sym(".MACRO", P_MACRO, 0, &pseudo_section, &system_st);
|
||||
add_sym(".WEAK", P_WEAK, 0, &pseudo_section, &system_st);
|
||||
|
||||
add_sym("ADC", I_ADC, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("ADCB", I_ADCB, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("ADD", I_ADD, OC_2GEN, &instruction_section, &system_st);
|
||||
add_sym("ASH", I_ASH, OC_ASH, &instruction_section, &system_st);
|
||||
add_sym("ASHC", I_ASHC, OC_ASH, &instruction_section, &system_st);
|
||||
add_sym("ASL", I_ASL, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("ASLB", I_ASLB, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("ASR", I_ASR, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("ASRB", I_ASRB, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("BCC", I_BCC, OC_BR, &instruction_section, &system_st);
|
||||
add_sym("BCS", I_BCS, OC_BR, &instruction_section, &system_st);
|
||||
add_sym("BEQ", I_BEQ, OC_BR, &instruction_section, &system_st);
|
||||
add_sym("BGE", I_BGE, OC_BR, &instruction_section, &system_st);
|
||||
add_sym("BGT", I_BGT, OC_BR, &instruction_section, &system_st);
|
||||
add_sym("BHI", I_BHI, OC_BR, &instruction_section, &system_st);
|
||||
add_sym("BHIS", I_BHIS, OC_BR, &instruction_section, &system_st);
|
||||
add_sym("BIC", I_BIC, OC_2GEN, &instruction_section, &system_st);
|
||||
add_sym("BICB", I_BICB, OC_2GEN, &instruction_section, &system_st);
|
||||
add_sym("BIS", I_BIS, OC_2GEN, &instruction_section, &system_st);
|
||||
add_sym("BISB", I_BISB, OC_2GEN, &instruction_section, &system_st);
|
||||
add_sym("BIT", I_BIT, OC_2GEN, &instruction_section, &system_st);
|
||||
add_sym("BITB", I_BITB, OC_2GEN, &instruction_section, &system_st);
|
||||
add_sym("BLE", I_BLE, OC_BR, &instruction_section, &system_st);
|
||||
add_sym("BLO", I_BLO, OC_BR, &instruction_section, &system_st);
|
||||
add_sym("BLOS", I_BLOS, OC_BR, &instruction_section, &system_st);
|
||||
add_sym("BLT", I_BLT, OC_BR, &instruction_section, &system_st);
|
||||
add_sym("BMI", I_BMI, OC_BR, &instruction_section, &system_st);
|
||||
add_sym("BNE", I_BNE, OC_BR, &instruction_section, &system_st);
|
||||
add_sym("BPL", I_BPL, OC_BR, &instruction_section, &system_st);
|
||||
add_sym("BPT", I_BPT, OC_NONE, &instruction_section, &system_st);
|
||||
add_sym("BR", I_BR, OC_BR, &instruction_section, &system_st);
|
||||
add_sym("BVC", I_BVC, OC_BR, &instruction_section, &system_st);
|
||||
add_sym("BVS", I_BVS, OC_BR, &instruction_section, &system_st);
|
||||
add_sym("CALL", I_CALL, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("CALLR", I_CALLR, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("CCC", I_CCC, OC_NONE, &instruction_section, &system_st);
|
||||
add_sym("CLC", I_CLC, OC_NONE, &instruction_section, &system_st);
|
||||
add_sym("CLN", I_CLN, OC_NONE, &instruction_section, &system_st);
|
||||
add_sym("CLR", I_CLR, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("CLRB", I_CLRB, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("CLV", I_CLV, OC_NONE, &instruction_section, &system_st);
|
||||
add_sym("CLZ", I_CLZ, OC_NONE, &instruction_section, &system_st);
|
||||
add_sym("CMP", I_CMP, OC_2GEN, &instruction_section, &system_st);
|
||||
add_sym("CMPB", I_CMPB, OC_2GEN, &instruction_section, &system_st);
|
||||
add_sym("COM", I_COM, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("COMB", I_COMB, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("DEC", I_DEC, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("DECB", I_DECB, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("DIV", I_DIV, OC_ASH, &instruction_section, &system_st);
|
||||
add_sym("EMT", I_EMT, OC_MARK, &instruction_section, &system_st);
|
||||
add_sym("FADD", I_FADD, OC_1REG, &instruction_section, &system_st);
|
||||
add_sym("FDIV", I_FDIV, OC_1REG, &instruction_section, &system_st);
|
||||
add_sym("FMUL", I_FMUL, OC_1REG, &instruction_section, &system_st);
|
||||
add_sym("FSUB", I_FSUB, OC_1REG, &instruction_section, &system_st);
|
||||
add_sym("HALT", I_HALT, OC_NONE, &instruction_section, &system_st);
|
||||
add_sym("INC", I_INC, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("INCB", I_INCB, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("IOT", I_IOT, OC_NONE, &instruction_section, &system_st);
|
||||
add_sym("JMP", I_JMP, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("JSR", I_JSR, OC_JSR, &instruction_section, &system_st);
|
||||
add_sym("MARK", I_MARK, OC_MARK, &instruction_section, &system_st);
|
||||
add_sym("MED6X", I_MED6X, OC_NONE, &instruction_section, &system_st);
|
||||
add_sym("MED74C", I_MED74C, OC_NONE, &instruction_section, &system_st);
|
||||
add_sym("MFPD", I_MFPD, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("MFPI", I_MFPI, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("MFPS", I_MFPS, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("MOV", I_MOV, OC_2GEN, &instruction_section, &system_st);
|
||||
add_sym("MOVB", I_MOVB, OC_2GEN, &instruction_section, &system_st);
|
||||
add_sym("MTPD", I_MTPD, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("MTPI", I_MTPI, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("MTPS", I_MTPS, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("MUL", I_MUL, OC_ASH, &instruction_section, &system_st);
|
||||
add_sym("NEG", I_NEG, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("NEGB", I_NEGB, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("NOP", I_NOP, OC_NONE, &instruction_section, &system_st);
|
||||
add_sym("RESET", I_RESET, OC_NONE, &instruction_section, &system_st);
|
||||
add_sym("RETURN", I_RETURN, OC_NONE, &instruction_section, &system_st);
|
||||
add_sym("ROL", I_ROL, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("ROLB", I_ROLB, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("ROR", I_ROR, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("RORB", I_RORB, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("RTI", I_RTI, OC_NONE, &instruction_section, &system_st);
|
||||
add_sym("RTS", I_RTS, OC_1REG, &instruction_section, &system_st);
|
||||
add_sym("RTT", I_RTT, OC_NONE, &instruction_section, &system_st);
|
||||
add_sym("SBC", I_SBC, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("SBCB", I_SBCB, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("SCC", I_SCC, OC_NONE, &instruction_section, &system_st);
|
||||
add_sym("SEC", I_SEC, OC_NONE, &instruction_section, &system_st);
|
||||
add_sym("SEN", I_SEN, OC_NONE, &instruction_section, &system_st);
|
||||
add_sym("SEV", I_SEV, OC_NONE, &instruction_section, &system_st);
|
||||
add_sym("SEZ", I_SEZ, OC_NONE, &instruction_section, &system_st);
|
||||
add_sym("SOB", I_SOB, OC_SOB, &instruction_section, &system_st);
|
||||
add_sym("SPL", I_SPL, OC_1REG, &instruction_section, &system_st);
|
||||
add_sym("SUB", I_SUB, OC_2GEN, &instruction_section, &system_st);
|
||||
add_sym("SWAB", I_SWAB, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("SXT", I_SXT, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("TRAP", I_TRAP, OC_MARK, &instruction_section, &system_st);
|
||||
add_sym("TST", I_TST, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("TSTB", I_TSTB, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("WAIT", I_WAIT, OC_NONE, &instruction_section, &system_st);
|
||||
add_sym("XFC", I_XFC, OC_NONE, &instruction_section, &system_st);
|
||||
add_sym("XOR", I_XOR, OC_JSR, &instruction_section, &system_st);
|
||||
add_sym("MFPT", I_MFPT, OC_NONE, &instruction_section, &system_st);
|
||||
|
||||
add_sym("ABSD", I_ABSD, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("ABSF", I_ABSF, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("ADDD", I_ADDD, OC_1FIS, &instruction_section, &system_st);
|
||||
add_sym("ADDF", I_ADDF, OC_1FIS, &instruction_section, &system_st);
|
||||
add_sym("CFCC", I_CFCC, OC_NONE, &instruction_section, &system_st);
|
||||
add_sym("CLRD", I_CLRD, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("CLRF", I_CLRF, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("CMPD", I_CMPD, OC_1FIS, &instruction_section, &system_st);
|
||||
add_sym("CMPF", I_CMPF, OC_1FIS, &instruction_section, &system_st);
|
||||
add_sym("DIVD", I_DIVD, OC_1FIS, &instruction_section, &system_st);
|
||||
add_sym("DIVF", I_DIVF, OC_1FIS, &instruction_section, &system_st);
|
||||
add_sym("LDCDF", I_LDCDF, OC_1FIS, &instruction_section, &system_st);
|
||||
add_sym("LDCID", I_LDCID, OC_1FIS, &instruction_section, &system_st);
|
||||
add_sym("LDCIF", I_LDCIF, OC_1FIS, &instruction_section, &system_st);
|
||||
add_sym("LDCLD", I_LDCLD, OC_1FIS, &instruction_section, &system_st);
|
||||
add_sym("LDCLF", I_LDCLF, OC_1FIS, &instruction_section, &system_st);
|
||||
add_sym("LDD", I_LDD, OC_1FIS, &instruction_section, &system_st);
|
||||
add_sym("LDEXP", I_LDEXP, OC_1FIS, &instruction_section, &system_st);
|
||||
add_sym("LDF", I_LDF, OC_1FIS, &instruction_section, &system_st);
|
||||
add_sym("LDFPS", I_LDFPS, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("MODD", I_MODD, OC_1FIS, &instruction_section, &system_st);
|
||||
add_sym("MODF", I_MODF, OC_1FIS, &instruction_section, &system_st);
|
||||
add_sym("MULD", I_MULD, OC_1FIS, &instruction_section, &system_st);
|
||||
add_sym("MULF", I_MULF, OC_1FIS, &instruction_section, &system_st);
|
||||
add_sym("NEGD", I_NEGD, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("NEGF", I_NEGF, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("SETD", I_SETD, OC_NONE, &instruction_section, &system_st);
|
||||
add_sym("SETF", I_SETF, OC_NONE, &instruction_section, &system_st);
|
||||
add_sym("SETI", I_SETI, OC_NONE, &instruction_section, &system_st);
|
||||
add_sym("SETL", I_SETL, OC_NONE, &instruction_section, &system_st);
|
||||
add_sym("STA0", I_STA0, OC_NONE, &instruction_section, &system_st);
|
||||
add_sym("STB0", I_STB0, OC_NONE, &instruction_section, &system_st);
|
||||
add_sym("STCDF", I_STCDF, OC_2FIS, &instruction_section, &system_st);
|
||||
add_sym("STCDI", I_STCDI, OC_2FIS, &instruction_section, &system_st);
|
||||
add_sym("STCDL", I_STCDL, OC_2FIS, &instruction_section, &system_st);
|
||||
add_sym("STCFD", I_STCFD, OC_2FIS, &instruction_section, &system_st);
|
||||
add_sym("STCFI", I_STCFI, OC_2FIS, &instruction_section, &system_st);
|
||||
add_sym("STCFL", I_STCFL, OC_2FIS, &instruction_section, &system_st);
|
||||
add_sym("STD", I_STD, OC_2FIS, &instruction_section, &system_st);
|
||||
add_sym("STEXP", I_STEXP, OC_2FIS, &instruction_section, &system_st);
|
||||
add_sym("STF", I_STF, OC_2FIS, &instruction_section, &system_st);
|
||||
add_sym("STFPS", I_STFPS, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("STST", I_STST, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("SUBD", I_SUBD, OC_1FIS, &instruction_section, &system_st);
|
||||
add_sym("SUBF", I_SUBF, OC_1FIS, &instruction_section, &system_st);
|
||||
add_sym("TSTD", I_TSTD, OC_1GEN, &instruction_section, &system_st);
|
||||
add_sym("TSTF", I_TSTF, OC_1GEN, &instruction_section, &system_st);
|
||||
|
||||
/* FIXME: The CIS instructions are missing! */
|
||||
|
||||
add_sym(current_section->label, 0, 0, current_section, §ion_st);
|
||||
}
|
||||
|
||||
/* sym_hist is a diagnostic function that prints a histogram of the
|
||||
hash table useage of a symbol table. I used this to try to tune
|
||||
the hash function for better spread. It's not used now. */
|
||||
|
||||
void sym_hist(
|
||||
SYMBOL_TABLE *st,
|
||||
char *name)
|
||||
{
|
||||
int i;
|
||||
SYMBOL *sym;
|
||||
|
||||
fprintf(lstfile, "Histogram for symbol table %s\n", name);
|
||||
for (i = 0; i < 1023; i++) {
|
||||
fprintf(lstfile, "%4d: ", i);
|
||||
for (sym = st->hash[i]; sym != NULL; sym = sym->next)
|
||||
fputc('#', lstfile);
|
||||
fputc('\n', lstfile);
|
||||
}
|
||||
}
|
||||
|
||||
static int symbol_compar(
|
||||
const void *a,
|
||||
const void *b)
|
||||
{
|
||||
SYMBOL *sa = *(SYMBOL **)a;
|
||||
SYMBOL *sb = *(SYMBOL **)b;
|
||||
|
||||
return strcmp(sa->label, sb->label);
|
||||
}
|
||||
|
||||
void list_symbol_table(
|
||||
void)
|
||||
{
|
||||
SYMBOL_ITER iter;
|
||||
SYMBOL *sym;
|
||||
int skip_locals = 0;
|
||||
int longest_symbol = symbol_len;
|
||||
|
||||
fprintf(lstfile,"\n\nSymbol table\n\n");
|
||||
|
||||
/* Count the symbols in the table */
|
||||
int nsyms = 0;
|
||||
for (sym = first_sym(&symbol_st, &iter); sym != NULL; sym = next_sym(&symbol_st, &iter)) {
|
||||
if (skip_locals && sym->flags & SYMBOLFLAG_LOCAL) {
|
||||
continue;
|
||||
}
|
||||
nsyms++;
|
||||
int len = strlen(sym->label);
|
||||
if (len > longest_symbol) {
|
||||
longest_symbol = len;
|
||||
}
|
||||
}
|
||||
|
||||
/* Sort them by name */
|
||||
SYMBOL **symbols = malloc(nsyms * sizeof (SYMBOL *));
|
||||
SYMBOL **symbolp = symbols;
|
||||
|
||||
for (sym = first_sym(&symbol_st, &iter); sym != NULL; sym = next_sym(&symbol_st, &iter)) {
|
||||
if (skip_locals && sym->flags & SYMBOLFLAG_LOCAL) {
|
||||
continue;
|
||||
}
|
||||
*symbolp++ = sym;
|
||||
}
|
||||
|
||||
qsort(symbols, nsyms, sizeof(SYMBOL *), symbol_compar);
|
||||
|
||||
symbolp = symbols;
|
||||
|
||||
/* Print the listing in NCOLS columns. */
|
||||
int ncols = (132 / (longest_symbol + 18));
|
||||
int nlines = (nsyms + ncols - 1) / ncols;
|
||||
int line;
|
||||
/*
|
||||
* DIRER$ 004562RGX 006
|
||||
* ^ ^ ^ ^-- for R symbols: program segment number
|
||||
* | | +-- Flags: R = relocatable
|
||||
* | | G = global
|
||||
* | | X = implicit global
|
||||
* | | L = local
|
||||
* | | W = weak
|
||||
* | +- value, ****** for if it was not a definition
|
||||
* +- label name
|
||||
*/
|
||||
|
||||
for (line = 0; line < nlines; line++) {
|
||||
int i;
|
||||
for (i = line; i < nsyms; i += nlines) {
|
||||
sym = symbols[i];
|
||||
|
||||
fprintf(lstfile,"%-*s", longest_symbol, sym->label);
|
||||
fprintf(lstfile,"%c", (sym->section->flags & PSECT_REL) ? ' ' : '=');
|
||||
if (!(sym->flags & SYMBOLFLAG_DEFINITION)) {
|
||||
fprintf(lstfile,"******");
|
||||
} else {
|
||||
fprintf(lstfile,"%06o", sym->value & 0177777);
|
||||
}
|
||||
fprintf(lstfile,"%c", (sym->section->flags & PSECT_REL) ? 'R' : ' ');
|
||||
fprintf(lstfile,"%c", (sym->flags & SYMBOLFLAG_GLOBAL) ? 'G' : ' ');
|
||||
fprintf(lstfile,"%c", (sym->flags & SYMBOLFLAG_IMPLICIT_GLOBAL) ? 'X' : ' ');
|
||||
fprintf(lstfile,"%c", (sym->flags & SYMBOLFLAG_LOCAL) ? 'L' : ' ');
|
||||
fprintf(lstfile,"%c", (sym->flags & SYMBOLFLAG_WEAK) ? 'W' : ' ');
|
||||
if (sym->section->sector != 0) {
|
||||
fprintf(lstfile," %03d ", sym->section->sector);
|
||||
} else {
|
||||
fprintf(lstfile," ");
|
||||
}
|
||||
}
|
||||
fprintf(lstfile,"\n");
|
||||
}
|
||||
|
||||
/* List sections */
|
||||
|
||||
fprintf(lstfile,"\n\nProgram sections:\n\n");
|
||||
|
||||
int i;
|
||||
for (i = 0; i < sector; i++) {
|
||||
list_section(sections[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void list_section(
|
||||
SECTION *sec)
|
||||
{
|
||||
if (sec == NULL) {
|
||||
fprintf(lstfile, "(null)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int flags = sec->flags;
|
||||
|
||||
fprintf(lstfile, "%-6s %06o %03d ",
|
||||
sec->label, sec->size & 0177777, sec->sector);
|
||||
fprintf(lstfile, "(%s,%s,%s,%s,%s,%s)\n",
|
||||
(flags & PSECT_RO) ? "RO" : "RW",
|
||||
(flags & PSECT_DATA) ? "D" : "I",
|
||||
(flags & PSECT_GBL) ? "GBL" : "LCL",
|
||||
(flags & PSECT_REL) ? "REL" : "ABS",
|
||||
(flags & PSECT_COM) ? "OVR" : "CON",
|
||||
(flags & PSECT_SAV) ? "SAV" : "NOSAV");
|
||||
}
|
||||
366
crossassemblers/macro11/symbols.h
Normal file
366
crossassemblers/macro11/symbols.h
Normal file
@@ -0,0 +1,366 @@
|
||||
|
||||
#ifndef SYMBOLS__H
|
||||
#define SYMBOLS__H
|
||||
|
||||
/* max symbol_len can be adjusted between SYMMAX_DEFAULT and SYMMAX_MAX*/
|
||||
#define SYMMAX_DEFAULT 6 /* I will honor this many character symbols */
|
||||
|
||||
#define SYMMAX_MAX 64
|
||||
|
||||
|
||||
/* Program sections: */
|
||||
typedef struct section {
|
||||
char *label; /* Section name */
|
||||
unsigned type; /* Section type */
|
||||
#define SECTION_USER 1 /* user-defined */
|
||||
#define SECTION_SYSTEM 2 /* A system symbol (like "."; value is an enum) */
|
||||
#define SECTION_INSTRUCTION 3 /* An instruction code (like "MOV"; value is an enum) */
|
||||
#define SECTION_PSEUDO 4 /* A pseudo-op (.PSECT, .TITLE, .MACRO, .IF; value is an enum) */
|
||||
#define SECTION_REGISTER 5 /* Symbol is a register (value 0=$0, value 1=$1, ... $7) */
|
||||
#define SECTION_USERMACRO 6 /* Symbol is a user macro */
|
||||
|
||||
unsigned flags; /* Flags, defined in object.h */
|
||||
unsigned pc; /* Current offset in the section */
|
||||
unsigned size; /* Current section size */
|
||||
unsigned sector; /* Used for complex relocation, and naught else */
|
||||
} SECTION;
|
||||
|
||||
/* Symbol table entries */
|
||||
|
||||
typedef struct symbol {
|
||||
char *label; /* Symbol name */
|
||||
unsigned value; /* Symbol value */
|
||||
int stmtno; /* Statement number of symbol's definition */
|
||||
unsigned flags; /* Symbol flags */
|
||||
#define SYMBOLFLAG_PERMANENT 1 /* Symbol may not be redefined */
|
||||
#define SYMBOLFLAG_GLOBAL 2 /* Symbol is global */
|
||||
#define SYMBOLFLAG_WEAK 4 /* Symbol definition is weak */
|
||||
#define SYMBOLFLAG_DEFINITION 8 /* Symbol is a global definition, not reference */
|
||||
#define SYMBOLFLAG_UNDEFINED 16 /* Symbol is a phony, undefined */
|
||||
#define SYMBOLFLAG_LOCAL 32 /* Set if this is a local label (i.e. 10$) */
|
||||
#define SYMBOLFLAG_IMPLICIT_GLOBAL 64 /* If migrated from implicit global table to
|
||||
* normal symbol table */
|
||||
|
||||
SECTION *section; /* Section in which this symbol is defined */
|
||||
struct symbol *next; /* Next symbol with the same hash value */
|
||||
} SYMBOL;
|
||||
|
||||
|
||||
|
||||
|
||||
enum pseudo_ops { P_ASCII,
|
||||
P_ASCIZ,
|
||||
P_ASECT,
|
||||
P_BLKB,
|
||||
P_BLKW,
|
||||
P_BYTE,
|
||||
P_CSECT,
|
||||
P_DSABL,
|
||||
P_ENABL,
|
||||
P_END,
|
||||
P_ENDC,
|
||||
P_ENDM,
|
||||
P_ENDR,
|
||||
P_EOT,
|
||||
P_ERROR,
|
||||
P_EVEN,
|
||||
P_FLT2,
|
||||
P_FLT4,
|
||||
P_GLOBL,
|
||||
P_IDENT,
|
||||
P_IF,
|
||||
P_IFF,
|
||||
P_IFT,
|
||||
P_IFTF,
|
||||
P_IIF,
|
||||
P_IRP,
|
||||
P_IRPC,
|
||||
P_LIBRARY,
|
||||
P_LIMIT,
|
||||
P_LIST,
|
||||
P_MCALL,
|
||||
P_MEXIT,
|
||||
P_NARG,
|
||||
P_NCHR,
|
||||
P_NLIST,
|
||||
P_NTYPE,
|
||||
P_ODD,
|
||||
P_PACKED,
|
||||
P_PAGE,
|
||||
P_PRINT,
|
||||
P_PSECT,
|
||||
P_RADIX,
|
||||
P_RAD50,
|
||||
P_REM,
|
||||
P_REPT,
|
||||
P_RESTORE,
|
||||
P_SAVE,
|
||||
P_SBTTL,
|
||||
P_TITLE,
|
||||
P_WORD,
|
||||
P_MACRO,
|
||||
P_INCLUDE,
|
||||
P_WEAK,
|
||||
P_IFDF
|
||||
};
|
||||
|
||||
enum instruction_ops { I_ADC = 0005500,
|
||||
I_ADCB = 0105500,
|
||||
I_ADD = 0060000,
|
||||
I_ASH = 0072000,
|
||||
I_ASHC = 0073000,
|
||||
I_ASL = 0006300,
|
||||
I_ASLB = 0106300,
|
||||
I_ASR = 0006200,
|
||||
I_ASRB = 0106200,
|
||||
I_BCC = 0103000,
|
||||
I_BCS = 0103400,
|
||||
I_BEQ = 0001400,
|
||||
I_BGE = 0002000,
|
||||
I_BGT = 0003000,
|
||||
I_BHI = 0101000,
|
||||
I_BHIS = 0103000,
|
||||
I_BIC = 0040000,
|
||||
I_BICB = 0140000,
|
||||
I_BIS = 0050000,
|
||||
I_BISB = 0150000,
|
||||
I_BIT = 0030000,
|
||||
I_BITB = 0130000,
|
||||
I_BLE = 0003400,
|
||||
I_BLO = 0103400,
|
||||
I_BLOS = 0101400,
|
||||
I_BLT = 0002400,
|
||||
I_BMI = 0100400,
|
||||
I_BNE = 0001000,
|
||||
I_BPL = 0100000,
|
||||
I_BPT = 0000003,
|
||||
I_BR = 0000400,
|
||||
I_BVC = 0102000,
|
||||
I_BVS = 0102400,
|
||||
I_CALL = 0004700,
|
||||
I_CALLR = 0000100,
|
||||
I_CCC = 0000257,
|
||||
I_CLC = 0000241,
|
||||
I_CLN = 0000250,
|
||||
I_CLR = 0005000,
|
||||
I_CLRB = 0105000,
|
||||
I_CLV = 0000242,
|
||||
I_CLZ = 0000244,
|
||||
I_CMP = 0020000,
|
||||
I_CMPB = 0120000,
|
||||
I_COM = 0005100,
|
||||
I_COMB = 0105100,
|
||||
I_DEC = 0005300,
|
||||
I_DECB = 0105300,
|
||||
I_DIV = 0071000,
|
||||
I_EMT = 0104000,
|
||||
I_FADD = 0075000,
|
||||
I_FDIV = 0075030,
|
||||
I_FMUL = 0075020,
|
||||
I_FSUB = 0075010,
|
||||
I_HALT = 0000000,
|
||||
I_INC = 0005200,
|
||||
I_INCB = 0105200,
|
||||
I_IOT = 0000004,
|
||||
I_JMP = 0000100,
|
||||
I_JSR = 0004000,
|
||||
I_MARK = 0006400,
|
||||
I_MED6X = 0076600,
|
||||
I_MED74C = 0076601,
|
||||
I_MFPD = 0106500,
|
||||
I_MFPI = 0006500,
|
||||
I_MFPS = 0106700,
|
||||
I_MOV = 0010000,
|
||||
I_MOVB = 0110000,
|
||||
I_MTPD = 0106600,
|
||||
I_MTPI = 0006600,
|
||||
I_MTPS = 0106400,
|
||||
I_MUL = 0070000,
|
||||
I_NEG = 0005400,
|
||||
I_NEGB = 0105400,
|
||||
I_NOP = 0000240,
|
||||
I_RESET = 0000005,
|
||||
I_RETURN = 0000207,
|
||||
I_ROL = 0006100,
|
||||
I_ROLB = 0106100,
|
||||
I_ROR = 0006000,
|
||||
I_RORB = 0106000,
|
||||
I_RTI = 0000002,
|
||||
I_RTS = 0000200,
|
||||
I_RTT = 0000006,
|
||||
I_SBC = 0005600,
|
||||
I_SBCB = 0105600,
|
||||
I_SCC = 0000277,
|
||||
I_SEC = 0000261,
|
||||
I_SEN = 0000270,
|
||||
I_SEV = 0000262,
|
||||
I_SEZ = 0000264,
|
||||
I_SOB = 0077000,
|
||||
I_SPL = 0000230,
|
||||
I_SUB = 0160000,
|
||||
I_SWAB = 0000300,
|
||||
I_SXT = 0006700,
|
||||
I_TRAP = 0104400,
|
||||
I_TST = 0005700,
|
||||
I_TSTB = 0105700,
|
||||
I_WAIT = 0000001,
|
||||
I_XFC = 0076700,
|
||||
I_XOR = 0074000,
|
||||
I_MFPT = 0000007,
|
||||
/* CIS not implemented - maybe later */
|
||||
/* FPU */
|
||||
I_ABSD = 0170600,
|
||||
I_ABSF = 0170600,
|
||||
I_ADDD = 0172000,
|
||||
I_ADDF = 0172000,
|
||||
I_CFCC = 0170000,
|
||||
I_CLRD = 0170400,
|
||||
I_CLRF = 0170400,
|
||||
I_CMPD = 0173400,
|
||||
I_CMPF = 0173400,
|
||||
I_DIVD = 0174400,
|
||||
I_DIVF = 0174400,
|
||||
I_LDCDF = 0177400,
|
||||
I_LDCFD = 0177400,
|
||||
I_LDCID = 0177000,
|
||||
I_LDCIF = 0177000,
|
||||
I_LDCLD = 0177000,
|
||||
I_LDCLF = 0177000,
|
||||
I_LDD = 0172400,
|
||||
I_LDEXP = 0176400,
|
||||
I_LDF = 0172400,
|
||||
I_LDFPS = 0170100,
|
||||
I_MODD = 0171400,
|
||||
I_MODF = 0171400,
|
||||
I_MULD = 0171000,
|
||||
I_MULF = 0171000,
|
||||
I_NEGD = 0170700,
|
||||
I_NEGF = 0170700,
|
||||
I_SETD = 0170011,
|
||||
I_SETF = 0170001,
|
||||
I_SETI = 0170002,
|
||||
I_SETL = 0170012,
|
||||
I_STA0 = 0170005,
|
||||
I_STB0 = 0170006,
|
||||
I_STCDF = 0176000,
|
||||
I_STCDI = 0175400,
|
||||
I_STCDL = 0175400,
|
||||
I_STCFD = 0176000,
|
||||
I_STCFI = 0175400,
|
||||
I_STCFL = 0175400,
|
||||
I_STD = 0174000,
|
||||
I_STEXP = 0175000,
|
||||
I_STF = 0174000,
|
||||
I_STFPS = 0170200,
|
||||
I_STST = 0170300,
|
||||
I_SUBD = 0173000,
|
||||
I_SUBF = 0173000,
|
||||
I_TSTD = 0170500,
|
||||
I_TSTF = 0170500
|
||||
};
|
||||
|
||||
enum operand_codes { OC_MASK = 0xff00,
|
||||
/* mask over flags for operand types */
|
||||
OC_NONE = 0x0000,
|
||||
/* No operands */
|
||||
OC_1GEN = 0x0100,
|
||||
/* One general operand (CLR, TST, etc.) */
|
||||
OC_2GEN = 0x0200,
|
||||
/* Two general operand (MOV, CMP, etc.) */
|
||||
OC_BR = 0x0300,
|
||||
/* Branch */
|
||||
OC_ASH = 0x0400,
|
||||
/* ASH and ASHC (one gen, one reg) */
|
||||
OC_MARK = 0x0500,
|
||||
/* MARK instruction operand */
|
||||
OC_JSR = 0x0600,
|
||||
/* JSR, XOR (one reg, one gen) */
|
||||
OC_1REG = 0x0700,
|
||||
/* FADD, FSUB, FMUL, FDIV, RTS */
|
||||
OC_SOB = 0x0800,
|
||||
/* SOB */
|
||||
OC_1FIS = 0x0900,
|
||||
/* FIS (reg, gen) */
|
||||
OC_2FIS = 0x0a00,
|
||||
/* FIS (gen, reg) */
|
||||
OC__LAST = 0xff00
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* symbol tables */
|
||||
|
||||
#define HASH_SIZE 1023
|
||||
|
||||
typedef struct symbol_table {
|
||||
SYMBOL *hash[HASH_SIZE];
|
||||
} SYMBOL_TABLE;
|
||||
|
||||
|
||||
/* SYMBOL_ITER is used for iterating thru a symbol table. */
|
||||
typedef struct symbol_iter {
|
||||
int subscript; /* Current hash subscript */
|
||||
SYMBOL *current; /* Current symbol */
|
||||
} SYMBOL_ITER;
|
||||
|
||||
|
||||
#ifndef SYMBOLS__C
|
||||
|
||||
extern int symbol_len; /* max. len of symbols. default = 6 */
|
||||
extern int symbol_allow_underscores; /* allow "_" in symbol names */
|
||||
|
||||
extern SYMBOL *reg_sym[8]; /* Keep the register symbols in a handy array */
|
||||
|
||||
extern SYMBOL_TABLE system_st; /* System symbols (Instructions,
|
||||
pseudo-ops, registers) */
|
||||
|
||||
extern SYMBOL_TABLE section_st; /* Program sections */
|
||||
|
||||
extern SYMBOL_TABLE symbol_st; /* User symbols */
|
||||
|
||||
extern SYMBOL_TABLE macro_st; /* Macros */
|
||||
|
||||
extern SYMBOL_TABLE implicit_st; /* The symbols which may be implicit globals */
|
||||
|
||||
#endif
|
||||
|
||||
int hash_name(
|
||||
char *label);
|
||||
|
||||
SYMBOL *add_sym(
|
||||
char *label,
|
||||
unsigned value,
|
||||
unsigned flags,
|
||||
SECTION *section,
|
||||
SYMBOL_TABLE *table);
|
||||
SYMBOL *first_sym(
|
||||
SYMBOL_TABLE *table,
|
||||
SYMBOL_ITER *iter);
|
||||
|
||||
SYMBOL *lookup_sym(
|
||||
char *label,
|
||||
SYMBOL_TABLE *table);
|
||||
SYMBOL *next_sym(
|
||||
SYMBOL_TABLE *table,
|
||||
SYMBOL_ITER *iter);
|
||||
void free_sym(
|
||||
SYMBOL *sym);
|
||||
|
||||
void remove_sym(
|
||||
SYMBOL *sym,
|
||||
SYMBOL_TABLE *table);
|
||||
|
||||
char *symflags(
|
||||
SYMBOL *sym);
|
||||
|
||||
void add_table(
|
||||
SYMBOL *sym,
|
||||
SYMBOL_TABLE *table);
|
||||
|
||||
|
||||
void add_symbols(
|
||||
SECTION *current_section);
|
||||
|
||||
void list_symbol_table(
|
||||
void);
|
||||
#endif
|
||||
39
crossassemblers/macro11/tests/RunTests
Executable file
39
crossassemblers/macro11/tests/RunTests
Executable file
@@ -0,0 +1,39 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Run some regression test cases.
|
||||
#
|
||||
# If there is a .lst.ok file, it compares the listing.
|
||||
# If there is a .objd.ok file, it compares the result of dumpobj.
|
||||
#
|
||||
|
||||
TESTS="test-asciz \
|
||||
test-backpatch \
|
||||
test-bsl-mac-arg \
|
||||
test-complex-reloc \
|
||||
test-endm \
|
||||
test-impword \
|
||||
test-include \
|
||||
test-jmp \
|
||||
test-locals \
|
||||
test-macro-comma \
|
||||
test-prec \
|
||||
test-psect \
|
||||
test-rad50 \
|
||||
test-undef \
|
||||
test-word-comma"
|
||||
|
||||
for t in $TESTS
|
||||
do
|
||||
../macro11 -l "$t".lst -o "$t".obj "$t".mac 2>/dev/null
|
||||
|
||||
if [ -e "$t".lst.ok ]
|
||||
then
|
||||
diff -u "$t".lst.ok "$t".lst
|
||||
fi
|
||||
|
||||
if [ -e "$t".objd.ok ]
|
||||
then
|
||||
../dumpobj "$t".obj >"$t".objd
|
||||
diff -u "$t".objd.ok "$t".objd
|
||||
fi
|
||||
done
|
||||
5
crossassemblers/macro11/tests/incl.mac
Normal file
5
crossassemblers/macro11/tests/incl.mac
Normal file
@@ -0,0 +1,5 @@
|
||||
;;;;;
|
||||
;
|
||||
; file to be included
|
||||
|
||||
.word 1 ; to show it is included
|
||||
60
crossassemblers/macro11/tests/test-asciz.lst.ok
Normal file
60
crossassemblers/macro11/tests/test-asciz.lst.ok
Normal file
@@ -0,0 +1,60 @@
|
||||
1 ;;;;;
|
||||
2 ;
|
||||
3 ; Test delimiters of .ASCII and .ASCIZ
|
||||
4
|
||||
5 000015 CR = 13.
|
||||
6 000012 LF = 10.
|
||||
7 000001 SOH = 1
|
||||
8
|
||||
9 000000 015 012 074 .asciz <cr><lf>/<SOH>/ ; 2 bytes and a string
|
||||
000003 123 117 110
|
||||
000006 076 000
|
||||
10 000010 074 143 162 .asciz /<cr><lf><SOH>/ ; only a string
|
||||
000013 076 074 154
|
||||
000016 146 076 074
|
||||
000021 123 117 110
|
||||
000024 076 000
|
||||
11 000026 074 143 162 .asciz |<cr><lf><SOH>| ; the same string
|
||||
000031 076 074 154
|
||||
000034 146 076 074
|
||||
000037 123 117 110
|
||||
000042 076 000
|
||||
12 000044 015 012 001 .ascii <cr><lf><SOH> ; 3 bytes
|
||||
13
|
||||
14 000047 101 102 103 .asciz ;ABC;/DEF/ ; ABCDEF, not recommended practice
|
||||
000052 104 105 106
|
||||
000055 000
|
||||
15 000056 101 102 103 .asciz /ABC/;DEF; ; ABC, not recommended practice
|
||||
000061 000
|
||||
16 000062 101 102 103 .asciz /ABC/=DEF= ; ABCDEF, not recommended practice
|
||||
000065 104 105 106
|
||||
000070 000
|
||||
test-asciz.mac:17: ***ERROR Complex expression cannot be assigned to a symbol
|
||||
17 .asciz =DEF= ; syntax error: assignment
|
||||
test-asciz.mac:18: ***ERROR Complex expression cannot be assigned to a symbol
|
||||
18 .asciz =###= ; syntax error: assignment
|
||||
test-asciz.mac:19: ***ERROR .WORD on odd boundary
|
||||
test-asciz.mac:19: ***ERROR Invalid expression
|
||||
19 000071 000 000001 000000 .asciz :SOH: ; syntax error: colon not allowed
|
||||
test-asciz.mac:20: ***ERROR Illegal symbol definition .ASCIZ
|
||||
test-asciz.mac:20: ***ERROR Invalid expression
|
||||
test-asciz.mac:20: ***ERROR Invalid expression
|
||||
test-asciz.mac:20: ***ERROR Invalid expression
|
||||
test-asciz.mac:20: ***ERROR Invalid expression
|
||||
20 000076 000000 000000 000000 .asciz :###: ; syntax error: colon not allowed
|
||||
000104 000000
|
||||
21 000106 043 043 043 .asciz ^###^ ; previous versions of this macro11
|
||||
000111 000
|
||||
22 ; used ^/.../ quoting as an extension; however this should be ^...^.
|
||||
22
|
||||
|
||||
|
||||
Symbol table
|
||||
|
||||
. ******R 001 .ASCIZ 000071R 001 CR =000015 LF =000012 SOH =000001
|
||||
|
||||
|
||||
Program sections:
|
||||
|
||||
. ABS. 000000 000 (RW,I,GBL,ABS,OVR,NOSAV)
|
||||
000112 001 (RW,I,LCL,REL,CON,NOSAV)
|
||||
22
crossassemblers/macro11/tests/test-asciz.mac
Normal file
22
crossassemblers/macro11/tests/test-asciz.mac
Normal file
@@ -0,0 +1,22 @@
|
||||
;;;;;
|
||||
;
|
||||
; Test delimiters of .ASCII and .ASCIZ
|
||||
|
||||
CR = 13.
|
||||
LF = 10.
|
||||
SOH = 1
|
||||
|
||||
.asciz <cr><lf>/<SOH>/ ; 2 bytes and a string
|
||||
.asciz /<cr><lf><SOH>/ ; only a string
|
||||
.asciz |<cr><lf><SOH>| ; the same string
|
||||
.ascii <cr><lf><SOH> ; 3 bytes
|
||||
|
||||
.asciz ;ABC;/DEF/ ; ABCDEF, not recommended practice
|
||||
.asciz /ABC/;DEF; ; ABC, not recommended practice
|
||||
.asciz /ABC/=DEF= ; ABCDEF, not recommended practice
|
||||
.asciz =DEF= ; syntax error: assignment
|
||||
.asciz =###= ; syntax error: assignment
|
||||
.asciz :SOH: ; syntax error: colon not allowed
|
||||
.asciz :###: ; syntax error: colon not allowed
|
||||
.asciz ^###^ ; previous versions of this macro11
|
||||
; used ^/.../ quoting as an extension; however this should be ^...^.
|
||||
30
crossassemblers/macro11/tests/test-backpatch.lst.ok
Normal file
30
crossassemblers/macro11/tests/test-backpatch.lst.ok
Normal file
@@ -0,0 +1,30 @@
|
||||
1 ;;;;
|
||||
2 ;
|
||||
3 ; Test backpatching (seen in Kermit sources).
|
||||
4
|
||||
5 000000 .psect modinf ,ro,d,lcl,rel,con
|
||||
6
|
||||
7 000000 label = .
|
||||
8 000000 .blkb 50 ; create some data
|
||||
9
|
||||
10 000050 050 051 052 .byte 50,51,52 ; and some more
|
||||
11 .save ; we're at 53 now
|
||||
12 000053 .psect modinf
|
||||
13 000006 . = label + 6
|
||||
14 000006 000006 .word 6 ; stored at 6
|
||||
15 000053 .restore ; . gets restored to 53
|
||||
16 000053 053 .byte 53
|
||||
17
|
||||
17
|
||||
|
||||
|
||||
Symbol table
|
||||
|
||||
. ******R 002 LABEL 000000R 002
|
||||
|
||||
|
||||
Program sections:
|
||||
|
||||
. ABS. 000000 000 (RW,I,GBL,ABS,OVR,NOSAV)
|
||||
000000 001 (RW,I,LCL,REL,CON,NOSAV)
|
||||
MODINF 000054 002 (RO,D,LCL,REL,CON,NOSAV)
|
||||
17
crossassemblers/macro11/tests/test-backpatch.mac
Normal file
17
crossassemblers/macro11/tests/test-backpatch.mac
Normal file
@@ -0,0 +1,17 @@
|
||||
;;;;
|
||||
;
|
||||
; Test backpatching (seen in Kermit sources).
|
||||
|
||||
.psect modinf ,ro,d,lcl,rel,con
|
||||
|
||||
label = .
|
||||
.blkb 50 ; create some data
|
||||
|
||||
.byte 50,51,52 ; and some more
|
||||
.save ; we're at 53 now
|
||||
.psect modinf
|
||||
. = label + 6
|
||||
.word 6 ; stored at 6
|
||||
.restore ; . gets restored to 53
|
||||
.byte 53
|
||||
|
||||
49
crossassemblers/macro11/tests/test-bsl-mac-arg.lst.ok
Normal file
49
crossassemblers/macro11/tests/test-bsl-mac-arg.lst.ok
Normal file
@@ -0,0 +1,49 @@
|
||||
1 .list me
|
||||
2 .macro test x
|
||||
3 .blkb x ; test some directive that wants an expression
|
||||
4 .endm
|
||||
5
|
||||
6 000010 size = 10
|
||||
7 000002 foo = 2
|
||||
8
|
||||
9 ; likes:
|
||||
10
|
||||
11 000000 test size ; not replaced by "10"
|
||||
1 000000 .blkb size ; test some directive that wants an expression
|
||||
12 000010 test \size ; replaced by "10"
|
||||
1 000010 .blkb 10 ; test some directive that wants an expression
|
||||
13 000020 test \<size> ; ditto
|
||||
1 000020 .blkb 10 ; test some directive that wants an expression
|
||||
14 000030 test \<size + foo> ; replaced by "12"
|
||||
1 000030 .blkb 12 ; test some directive that wants an expression
|
||||
15 000042 test ^/size + foo/ ; arg is "size + foo", not "12"
|
||||
1 000042 .blkb size + foo ; test some directive that wants an expression
|
||||
16
|
||||
17 ; dislikes:
|
||||
18
|
||||
19 000054 test <\size> ; parameter is \size, which might be ok for
|
||||
test-bsl-mac-arg.mac:19->TEST:1: ***ERROR Argument to .BLKB/.BLKW must be constant
|
||||
1 .blkb \size ; test some directive that wants an expression
|
||||
20 ; macros where the argument is used differently.
|
||||
21 000054 test size + foo ; gets split at the space
|
||||
1 000054 .blkb size ; test some directive that wants an expression
|
||||
22 000064 test /size + foo/ ; gets split at the space
|
||||
test-bsl-mac-arg.mac:22->TEST:1: ***ERROR Argument to .BLKB/.BLKW must be constant
|
||||
1 .blkb /size ; test some directive that wants an expression
|
||||
test-bsl-mac-arg.mac:23: ***ERROR Constant value required
|
||||
23 000064 test \/size + foo/ ; invalid expression with division operator
|
||||
1 000064 .blkb 0 ; test some directive that wants an expression
|
||||
24 000064 test \^/size + foo/ ; original dislikes this, but we accept it.
|
||||
1 000064 .blkb 12 ; test some directive that wants an expression
|
||||
24
|
||||
|
||||
|
||||
Symbol table
|
||||
|
||||
. ******R 001 FOO =000002 SIZE =000010
|
||||
|
||||
|
||||
Program sections:
|
||||
|
||||
. ABS. 000000 000 (RW,I,GBL,ABS,OVR,NOSAV)
|
||||
000076 001 (RW,I,LCL,REL,CON,NOSAV)
|
||||
24
crossassemblers/macro11/tests/test-bsl-mac-arg.mac
Normal file
24
crossassemblers/macro11/tests/test-bsl-mac-arg.mac
Normal file
@@ -0,0 +1,24 @@
|
||||
.list me
|
||||
.macro test x
|
||||
.blkb x ; test some directive that wants an expression
|
||||
.endm
|
||||
|
||||
size = 10
|
||||
foo = 2
|
||||
|
||||
; likes:
|
||||
|
||||
test size ; not replaced by "10"
|
||||
test \size ; replaced by "10"
|
||||
test \<size> ; ditto
|
||||
test \<size + foo> ; replaced by "12"
|
||||
test ^/size + foo/ ; arg is "size + foo", not "12"
|
||||
|
||||
; dislikes:
|
||||
|
||||
test <\size> ; parameter is \size, which might be ok for
|
||||
; macros where the argument is used differently.
|
||||
test size + foo ; gets split at the space
|
||||
test /size + foo/ ; gets split at the space
|
||||
test \/size + foo/ ; invalid expression with division operator
|
||||
test \^/size + foo/ ; original dislikes this, but we accept it.
|
||||
14
crossassemblers/macro11/tests/test-complex-reloc.mac
Normal file
14
crossassemblers/macro11/tests/test-complex-reloc.mac
Normal file
@@ -0,0 +1,14 @@
|
||||
; test complex relocations
|
||||
|
||||
; .globl IE.ITS,IE.MON ; implicit
|
||||
mov #-IE.ITS, space
|
||||
|
||||
space: .word IE.ITS ; the only simple relocation
|
||||
.word -IE.ITS ; all others are complex relocations
|
||||
.word ^C<IE.ITS>
|
||||
.word IE.ITS + IE.MON
|
||||
.word IE.ITS - IE.MON
|
||||
.word IE.ITS * IE.MON
|
||||
.word IE.ITS / IE.MON
|
||||
.word IE.ITS & IE.MON
|
||||
.word IE.ITS ! IE.MON
|
||||
26
crossassemblers/macro11/tests/test-complex-reloc.objd.ok
Normal file
26
crossassemblers/macro11/tests/test-complex-reloc.objd.ok
Normal file
@@ -0,0 +1,26 @@
|
||||
GSD:
|
||||
GLOBAL IE.ITS=0 REF ABS flags=100
|
||||
GLOBAL IE.MON=0 REF ABS flags=100
|
||||
MODNAME .MAIN.=0 flags=0
|
||||
PSECT =30 CON RW REL LCL I flags=40
|
||||
PSECT . ABS.=0 OVR RW ABS GBL I flags=104
|
||||
XFER . ABS.=1 flags=10
|
||||
ENDGSD
|
||||
RLD
|
||||
Location counter definition +0
|
||||
TEXT ADDR=0 LEN=30
|
||||
000000: 012767 000000 000000 000000 ........
|
||||
000010: 000000 000000 000000 000000 ........
|
||||
000020: 000000 000000 000000 000000 ........
|
||||
RLD
|
||||
Complex 2=IE.ITS neg store
|
||||
Global 6=IE.ITS
|
||||
Complex 10=IE.ITS neg store
|
||||
Complex 12=IE.ITS ^C store
|
||||
Complex 14=IE.ITS IE.MON + store
|
||||
Complex 16=IE.ITS IE.MON - store
|
||||
Complex 20=IE.ITS IE.MON * store
|
||||
Complex 22=IE.ITS IE.MON / store
|
||||
Complex 24=IE.ITS IE.MON & store
|
||||
Complex 26=IE.ITS IE.MON ! store
|
||||
ENDMOD
|
||||
67
crossassemblers/macro11/tests/test-endm.lst.ok
Normal file
67
crossassemblers/macro11/tests/test-endm.lst.ok
Normal file
@@ -0,0 +1,67 @@
|
||||
1 ;;;;;
|
||||
2 ;
|
||||
3 ; Test nested macros and name on .ENDM
|
||||
4 ;
|
||||
5
|
||||
6 .macro M1
|
||||
7 .word 1
|
||||
8 .endm M1 ; ok
|
||||
9
|
||||
10 000000 M1
|
||||
1 000000 000001 .word 1
|
||||
11
|
||||
12 .macro M2
|
||||
13 .word 2
|
||||
14 .macro M3
|
||||
15 .word 3
|
||||
16 .endm M3 ; ok
|
||||
17 .endm M2 ; ok
|
||||
18
|
||||
19 000002 M2
|
||||
1 000002 000002 .word 2
|
||||
2 .macro M3
|
||||
3 .word 3
|
||||
4 .endm M3 ; ok
|
||||
20 000004 M3
|
||||
1 000004 000003 .word 3
|
||||
21
|
||||
22 .macro M4
|
||||
23 .word 4
|
||||
24 .macro M4
|
||||
25 .endm M4 ; ok
|
||||
26 .endm M4 ; ok
|
||||
27
|
||||
28 000006 M4
|
||||
1 000006 000004 .word 4
|
||||
2 .macro M4
|
||||
3 .endm M4 ; ok
|
||||
29 000010 M4 ; should be empty now
|
||||
30
|
||||
31 .macro M5
|
||||
32 .word 5
|
||||
33 .macro M5
|
||||
34 .endm notM5 ; wrong; detected when M5 is expanded
|
||||
35 .endm M5 ; ok
|
||||
36
|
||||
37 000010 M5
|
||||
1 000010 000005 .word 5
|
||||
2 .macro M5
|
||||
test-endm.mac:37->M5:3: ***ERROR .ENDM 'NOTM5' does not match .MACRO 'M5'
|
||||
3 .endm notM5 ; wrong; detected when M5 is expanded
|
||||
38 000012 M5
|
||||
39
|
||||
40 .macro M6
|
||||
test-endm.mac:41: ***ERROR .ENDM 'NOTM6' does not match .MACRO 'M6'
|
||||
41 .endm notM6 ; wrong
|
||||
41
|
||||
|
||||
|
||||
Symbol table
|
||||
|
||||
. ******R 001
|
||||
|
||||
|
||||
Program sections:
|
||||
|
||||
. ABS. 000000 000 (RW,I,GBL,ABS,OVR,NOSAV)
|
||||
000012 001 (RW,I,LCL,REL,CON,NOSAV)
|
||||
41
crossassemblers/macro11/tests/test-endm.mac
Normal file
41
crossassemblers/macro11/tests/test-endm.mac
Normal file
@@ -0,0 +1,41 @@
|
||||
;;;;;
|
||||
;
|
||||
; Test nested macros and name on .ENDM
|
||||
;
|
||||
|
||||
.macro M1
|
||||
.word 1
|
||||
.endm M1 ; ok
|
||||
|
||||
M1
|
||||
|
||||
.macro M2
|
||||
.word 2
|
||||
.macro M3
|
||||
.word 3
|
||||
.endm M3 ; ok
|
||||
.endm M2 ; ok
|
||||
|
||||
M2
|
||||
M3
|
||||
|
||||
.macro M4
|
||||
.word 4
|
||||
.macro M4
|
||||
.endm M4 ; ok
|
||||
.endm M4 ; ok
|
||||
|
||||
M4
|
||||
M4 ; should be empty now
|
||||
|
||||
.macro M5
|
||||
.word 5
|
||||
.macro M5
|
||||
.endm notM5 ; wrong; detected when M5 is expanded
|
||||
.endm M5 ; ok
|
||||
|
||||
M5
|
||||
M5
|
||||
|
||||
.macro M6
|
||||
.endm notM6 ; wrong
|
||||
26
crossassemblers/macro11/tests/test-impword.lst.ok
Normal file
26
crossassemblers/macro11/tests/test-impword.lst.ok
Normal file
@@ -0,0 +1,26 @@
|
||||
1 ;;;;;
|
||||
2 ;
|
||||
3 ; Test the implied .word construction
|
||||
4 ;
|
||||
5
|
||||
6 000000 000003 start: 3
|
||||
7 000002 000000' start
|
||||
8 ; The following could be a macro which by accident is not defined
|
||||
9 ; which takes arguments that don't parse as expressions.
|
||||
test-impword.mac:10: ***ERROR Invalid expression in .WORD
|
||||
10 000004 000000G macro 8-BIT,1,2,3
|
||||
11 ; The following can by accident be parsed as an expression.
|
||||
12 000006 000000G 150007 000001 macro 7-BIT,1,2,3
|
||||
000014 000002 000003
|
||||
12
|
||||
|
||||
|
||||
Symbol table
|
||||
|
||||
. ******R 001 MACRO =****** GX START 000000R 001
|
||||
|
||||
|
||||
Program sections:
|
||||
|
||||
. ABS. 000000 000 (RW,I,GBL,ABS,OVR,NOSAV)
|
||||
000020 001 (RW,I,LCL,REL,CON,NOSAV)
|
||||
12
crossassemblers/macro11/tests/test-impword.mac
Normal file
12
crossassemblers/macro11/tests/test-impword.mac
Normal file
@@ -0,0 +1,12 @@
|
||||
;;;;;
|
||||
;
|
||||
; Test the implied .word construction
|
||||
;
|
||||
|
||||
start: 3
|
||||
start
|
||||
; The following could be a macro which by accident is not defined
|
||||
; which takes arguments that don't parse as expressions.
|
||||
macro 8-BIT,1,2,3
|
||||
; The following can by accident be parsed as an expression.
|
||||
macro 7-BIT,1,2,3
|
||||
62
crossassemblers/macro11/tests/test-include.lst.ok
Normal file
62
crossassemblers/macro11/tests/test-include.lst.ok
Normal file
@@ -0,0 +1,62 @@
|
||||
1 ;;;;;
|
||||
2 ;
|
||||
3 ; Test some delimiters for the .INCLUDE directive
|
||||
4 ;
|
||||
5
|
||||
6 .include "incl.mac"
|
||||
1 ;;;;;
|
||||
2 ;
|
||||
3 ; file to be included
|
||||
4
|
||||
5 000000 000001 .word 1 ; to show it is included
|
||||
5
|
||||
7 .include /incl.mac/
|
||||
1 ;;;;;
|
||||
2 ;
|
||||
3 ; file to be included
|
||||
4
|
||||
5 000002 000001 .word 1 ; to show it is included
|
||||
5
|
||||
8 .include \incl.mac\
|
||||
1 ;;;;;
|
||||
2 ;
|
||||
3 ; file to be included
|
||||
4
|
||||
5 000004 000001 .word 1 ; to show it is included
|
||||
5
|
||||
9 .include ?incl.mac?
|
||||
1 ;;;;;
|
||||
2 ;
|
||||
3 ; file to be included
|
||||
4
|
||||
5 000006 000001 .word 1 ; to show it is included
|
||||
5
|
||||
10 .include >incl.mac>
|
||||
1 ;;;;;
|
||||
2 ;
|
||||
3 ; file to be included
|
||||
4
|
||||
5 000010 000001 .word 1 ; to show it is included
|
||||
5
|
||||
11
|
||||
12 ; these are errors: (in MACRO V05.05, some terminate the assembler)
|
||||
13
|
||||
test-include.mac:14: ***ERROR Bad .INCLUDE file name
|
||||
14 .include <incl.mac>
|
||||
test-include.mac:15: ***ERROR Bad .INCLUDE file name
|
||||
15 .include <incl.mac<
|
||||
16 .include =incl.mac= ; looks like assignment
|
||||
test-include.mac:17: ***ERROR Invalid expression
|
||||
17 000012 000000G 000000 .include :incl.mac: ; looks like a label
|
||||
17
|
||||
|
||||
|
||||
Symbol table
|
||||
|
||||
. ******R 001 .INCLU 000012R 001 INCL.M=****** GX
|
||||
|
||||
|
||||
Program sections:
|
||||
|
||||
. ABS. 000000 000 (RW,I,GBL,ABS,OVR,NOSAV)
|
||||
000016 001 (RW,I,LCL,REL,CON,NOSAV)
|
||||
17
crossassemblers/macro11/tests/test-include.mac
Normal file
17
crossassemblers/macro11/tests/test-include.mac
Normal file
@@ -0,0 +1,17 @@
|
||||
;;;;;
|
||||
;
|
||||
; Test some delimiters for the .INCLUDE directive
|
||||
;
|
||||
|
||||
.include "incl.mac"
|
||||
.include /incl.mac/
|
||||
.include \incl.mac\
|
||||
.include ?incl.mac?
|
||||
.include >incl.mac>
|
||||
|
||||
; these are errors: (in MACRO V05.05, some terminate the assembler)
|
||||
|
||||
.include <incl.mac>
|
||||
.include <incl.mac<
|
||||
.include =incl.mac= ; looks like assignment
|
||||
.include :incl.mac: ; looks like a label
|
||||
49
crossassemblers/macro11/tests/test-jmp.lst.ok
Normal file
49
crossassemblers/macro11/tests/test-jmp.lst.ok
Normal file
@@ -0,0 +1,49 @@
|
||||
1 ;;;;;
|
||||
2 ;
|
||||
3 ; Tests the addressing modes for JMP.
|
||||
4 ; JMP Rx is not allowed, all other modes are.
|
||||
5 ;
|
||||
6
|
||||
7 000000 000167 000104 start: jmp label ; rel(pc) jumps to label
|
||||
8 000004 000177 000100 jmp @label ; @rel(pc) does something else!
|
||||
9 000010 000127 000110' jmp #label ; (pc)+ does something else!
|
||||
10 000014 000137 000110' jmp @#label ; @(pc)+ jumps to label
|
||||
11
|
||||
test-jmp.mac:12: ***ERROR JMP Rn is illegal
|
||||
12 000020 000101 jmp r1 ; must fail
|
||||
13 000022 000112 jmp (r2)
|
||||
14 000024 000121 jmp (r1)+
|
||||
15 000026 000131 jmp @(r1)+
|
||||
16 000030 000141 jmp -(r1)
|
||||
17 000032 000151 jmp @-(r1)
|
||||
18 000034 000161 001234 jmp 1234(r1)
|
||||
19 000040 000171 001234 jmp @1234(r1)
|
||||
20
|
||||
21 000044 004067 000040 secnd: jsr r0,label ; rel(pc) jumps to label
|
||||
22 000050 004077 000034 jsr r0,@label ; @rel(pc) does something else!
|
||||
23 000054 004027 000110' jsr r0,#label ; (pc)+ does something else!
|
||||
24 000060 004037 000110' jsr r0,@#label ; @(pc)+ jumps to label
|
||||
25
|
||||
test-jmp.mac:26: ***ERROR JSR Rn,Rm is illegal
|
||||
26 000064 004201 jsr r2,r1 ; must fail
|
||||
27 000066 004312 jsr r3,(r2)
|
||||
28 000070 004421 jsr r4,(r1)+
|
||||
29 000072 004531 jsr r5,@(r1)+
|
||||
30 000074 004241 jsr r2,-(r1)
|
||||
31 000076 004351 jsr r3,@-(r1)
|
||||
32 000100 004461 001234 jsr r4,1234(r1)
|
||||
33 000104 004571 001234 jsr r5,@1234(r1)
|
||||
34
|
||||
35 000110 000207 label: rts pc
|
||||
35
|
||||
|
||||
|
||||
Symbol table
|
||||
|
||||
. ******R 001 LABEL 000110R 001 SECND 000044R 001 START 000000R 001
|
||||
|
||||
|
||||
Program sections:
|
||||
|
||||
. ABS. 000000 000 (RW,I,GBL,ABS,OVR,NOSAV)
|
||||
000112 001 (RW,I,LCL,REL,CON,NOSAV)
|
||||
35
crossassemblers/macro11/tests/test-jmp.mac
Normal file
35
crossassemblers/macro11/tests/test-jmp.mac
Normal file
@@ -0,0 +1,35 @@
|
||||
;;;;;
|
||||
;
|
||||
; Tests the addressing modes for JMP.
|
||||
; JMP Rx is not allowed, all other modes are.
|
||||
;
|
||||
|
||||
start: jmp label ; rel(pc) jumps to label
|
||||
jmp @label ; @rel(pc) does something else!
|
||||
jmp #label ; (pc)+ does something else!
|
||||
jmp @#label ; @(pc)+ jumps to label
|
||||
|
||||
jmp r1 ; must fail
|
||||
jmp (r2)
|
||||
jmp (r1)+
|
||||
jmp @(r1)+
|
||||
jmp -(r1)
|
||||
jmp @-(r1)
|
||||
jmp 1234(r1)
|
||||
jmp @1234(r1)
|
||||
|
||||
secnd: jsr r0,label ; rel(pc) jumps to label
|
||||
jsr r0,@label ; @rel(pc) does something else!
|
||||
jsr r0,#label ; (pc)+ does something else!
|
||||
jsr r0,@#label ; @(pc)+ jumps to label
|
||||
|
||||
jsr r2,r1 ; must fail
|
||||
jsr r3,(r2)
|
||||
jsr r4,(r1)+
|
||||
jsr r5,@(r1)+
|
||||
jsr r2,-(r1)
|
||||
jsr r3,@-(r1)
|
||||
jsr r4,1234(r1)
|
||||
jsr r5,@1234(r1)
|
||||
|
||||
label: rts pc
|
||||
48
crossassemblers/macro11/tests/test-locals.lst.ok
Normal file
48
crossassemblers/macro11/tests/test-locals.lst.ok
Normal file
@@ -0,0 +1,48 @@
|
||||
1 ;;;;;
|
||||
2 ;
|
||||
3 ; Test long local labels
|
||||
4 ;
|
||||
5
|
||||
6 000000 001400 lab1: beq 1$
|
||||
7 000002 001376 1$: bne lab1
|
||||
8
|
||||
9 ; -- new scope
|
||||
10
|
||||
11 000004 001400 lab2a: beq 12345$
|
||||
12 000006 001376 12345$: bne lab2a
|
||||
13
|
||||
14 ; -- new scope
|
||||
15
|
||||
16 000010 001400 lab2b: beq 12345$
|
||||
17 000012 001376 12345$: bne lab2b
|
||||
18
|
||||
19 ; -- new scope
|
||||
20
|
||||
21 000014 001400 lab3: beq 1$
|
||||
22 000016 001000 1$: bne 2$
|
||||
23 000020 001400 2$: beq 3$
|
||||
24 000022 001400 3$: beq 4$
|
||||
25 000024 001773 4$: beq lab3
|
||||
26
|
||||
27 ; -- new scope
|
||||
28
|
||||
29 000026 001400 lab4: beq 1$
|
||||
30 000030 001000 1$: bne 2$
|
||||
31 000032 001400 2$: beq 3$
|
||||
32 000034 001400 3$: beq 4$
|
||||
33 000036 001773 4$: beq lab4
|
||||
33
|
||||
|
||||
|
||||
Symbol table
|
||||
|
||||
. ******R 001 12345$1 000006R L 001 3$3 000022R L 001 LAB1 000000R 001 LAB4 000026R 001
|
||||
1$0 000002R L 001 12345$2 000012R L 001 3$4 000034R L 001 LAB2A 000004R 001
|
||||
1$3 000016R L 001 2$3 000020R L 001 4$3 000024R L 001 LAB2B 000010R 001
|
||||
1$4 000030R L 001 2$4 000032R L 001 4$4 000036R L 001 LAB3 000014R 001
|
||||
|
||||
|
||||
Program sections:
|
||||
|
||||
. ABS. 000000 000 (RW,I,GBL,ABS,OVR,NOSAV)
|
||||
000040 001 (RW,I,LCL,REL,CON,NOSAV)
|
||||
33
crossassemblers/macro11/tests/test-locals.mac
Normal file
33
crossassemblers/macro11/tests/test-locals.mac
Normal file
@@ -0,0 +1,33 @@
|
||||
;;;;;
|
||||
;
|
||||
; Test long local labels
|
||||
;
|
||||
|
||||
lab1: beq 1$
|
||||
1$: bne lab1
|
||||
|
||||
; -- new scope
|
||||
|
||||
lab2a: beq 12345$
|
||||
12345$: bne lab2a
|
||||
|
||||
; -- new scope
|
||||
|
||||
lab2b: beq 12345$
|
||||
12345$: bne lab2b
|
||||
|
||||
; -- new scope
|
||||
|
||||
lab3: beq 1$
|
||||
1$: bne 2$
|
||||
2$: beq 3$
|
||||
3$: beq 4$
|
||||
4$: beq lab3
|
||||
|
||||
; -- new scope
|
||||
|
||||
lab4: beq 1$
|
||||
1$: bne 2$
|
||||
2$: beq 3$
|
||||
3$: beq 4$
|
||||
4$: beq lab4
|
||||
36
crossassemblers/macro11/tests/test-macro-comma.lst.ok
Normal file
36
crossassemblers/macro11/tests/test-macro-comma.lst.ok
Normal file
@@ -0,0 +1,36 @@
|
||||
1 .macro tstarg a1,a2,a3,a4
|
||||
2 .narg label
|
||||
3 .endm
|
||||
4
|
||||
5 000000 start: tstarg ; 0 args
|
||||
1 000000 .narg label
|
||||
6 000000 tstarg 123 ; 1 arg
|
||||
1 000001 .narg label
|
||||
7 000000 tstarg 1, ; 2 args
|
||||
1 000002 .narg label
|
||||
8 000000 tstarg ,2 ; 2 args
|
||||
1 000002 .narg label
|
||||
9 000000 tstarg , ; 2 args
|
||||
1 000002 .narg label
|
||||
10 000000 tstarg ,, ; 3 args
|
||||
1 000003 .narg label
|
||||
11 000000 tstarg 1,, ; 3 args
|
||||
1 000003 .narg label
|
||||
12 000000 tstarg ,,3 ; 3 args
|
||||
1 000003 .narg label
|
||||
13 000000 tstarg 1,,3 ; 3 args
|
||||
1 000003 .narg label
|
||||
14 000000 tstarg 1,2,3 ; 3 args
|
||||
1 000003 .narg label
|
||||
14
|
||||
|
||||
|
||||
Symbol table
|
||||
|
||||
. ******R 001 LABEL =000003 START 000000R 001
|
||||
|
||||
|
||||
Program sections:
|
||||
|
||||
. ABS. 000000 000 (RW,I,GBL,ABS,OVR,NOSAV)
|
||||
000000 001 (RW,I,LCL,REL,CON,NOSAV)
|
||||
14
crossassemblers/macro11/tests/test-macro-comma.mac
Normal file
14
crossassemblers/macro11/tests/test-macro-comma.mac
Normal file
@@ -0,0 +1,14 @@
|
||||
.macro tstarg a1,a2,a3,a4
|
||||
.narg label
|
||||
.endm
|
||||
|
||||
start: tstarg ; 0 args
|
||||
tstarg 123 ; 1 arg
|
||||
tstarg 1, ; 2 args
|
||||
tstarg ,2 ; 2 args
|
||||
tstarg , ; 2 args
|
||||
tstarg ,, ; 3 args
|
||||
tstarg 1,, ; 3 args
|
||||
tstarg ,,3 ; 3 args
|
||||
tstarg 1,,3 ; 3 args
|
||||
tstarg 1,2,3 ; 3 args
|
||||
72
crossassemblers/macro11/tests/test-prec.lst.ok
Normal file
72
crossassemblers/macro11/tests/test-prec.lst.ok
Normal file
@@ -0,0 +1,72 @@
|
||||
1 ;;;;;
|
||||
2 ;
|
||||
3 ; Test operator precedencce
|
||||
4 ; or rather the lack thereof
|
||||
5 ;
|
||||
6 000000 000006 .word 1 + 2 + 3 ; 6
|
||||
7 000002 000011 .word 1 + 2 * 3 ; 3*3 = 11
|
||||
8 000004 000004 .word 1 & 2 ! 4 ; 0 ! 4 = 4
|
||||
9 000006 000000 .word 1 ! 2 & 4 ; 3 & 4 = 0
|
||||
10 000010 000003 .word 1 ! 2 & 7 ; 3 & 7 = 3
|
||||
11 000012 000005 .word 1+1 ! 2+3 ; 2!2+3 = 2+3 = 5
|
||||
12
|
||||
13 ;;;;;
|
||||
14 ;
|
||||
15 ; Test all operators at least once
|
||||
16 ;
|
||||
17 000014 000007 .word 3 + 4 ; 000007
|
||||
18 000016 000001 .word 4 - 3 ; 000001
|
||||
19 000020 000014 .word 3 * 4 ; 000014
|
||||
20 000022 000003 .word 12. / 4 ; 000003
|
||||
21 000024 000121 .word 123 & 771 ; 000121
|
||||
22 000026 123323 .word 123121 ! 322 ; 123323
|
||||
23
|
||||
24 000030 177401 .word - 377 ; 177401
|
||||
25 000032 000377 .word + 377 ; 000377
|
||||
26
|
||||
27 000034 177400 .word ^C 377 ; 177400
|
||||
28 000036 177400 .word ^c 377 ; 177400
|
||||
29 000040 052525 .word ^B 0101010101010101 ; 052525
|
||||
30 000042 125252 .word ^b 1010101010101010 ; 125252
|
||||
31 000044 000144 .word ^d 100 ; 000144
|
||||
32 000046 000144 .word 100. ; 000144
|
||||
33 000050 000400 .word ^x 100 ; 000400 hexadecimal is an extension
|
||||
34 000052 070254 .word ^rRAD ; 070254 up to 3 characters; no leading spaces
|
||||
35 000054 003100 .word ^rA ; 003100 up to 3 characters
|
||||
36 000056 000050 .word ^r A ; 000050 up to 3 characters
|
||||
37 000060 000001 .word ^r A ; 000001 up to 3 characters
|
||||
38 000062 000051 .word ^r AA ; 000051
|
||||
39 000064 003101 .word ^rA A ; 003101
|
||||
40 000066 003150 .word ^rAA ; 003150
|
||||
41 000070 003151 .word ^r^/AAA/ ; bracketed strings are an extension
|
||||
42 000072 070254 .word ^r<RAD> ; bracketed strings are an extension
|
||||
43 000074 000054 .word ^r< AD> ; bracketed strings are an extension
|
||||
44 000076 000004 .word ^r< D> ; bracketed strings are an extension
|
||||
45 000100 070204 .word ^r<R D> ; bracketed strings are an extension
|
||||
46 000102 070250 .word ^r<RA > ; bracketed strings are an extension
|
||||
47 000104 157614 .word ^R50. ; 157614 there is no whitespace in between.
|
||||
48 000106 040140 .word ^f 1.5 ; 040140
|
||||
49
|
||||
50 ;;;;;
|
||||
51 ;
|
||||
52 ; Test bracketing
|
||||
53 ;
|
||||
54 000110 000007 .word 1 + < 2 * 3 > ; 1 + 6 = 7
|
||||
55 000112 000007 .word 1 + ^! 2 * 3 ! ; 1 + 6 = 7
|
||||
56 000114 000007 .word 1 + ^/ 2 * 3 / ; 1 + 6 = 7
|
||||
57 000116 000007 .word 1 + ^$ 2 * 3 $ ; 1 + 6 = 7
|
||||
test-prec.mac:58: ***ERROR Invalid expression
|
||||
58 000120 000003 000000 000000G .word 1 + ^* 2 * 3 * ; Invalid expression
|
||||
000126 000000G
|
||||
58
|
||||
|
||||
|
||||
Symbol table
|
||||
|
||||
. ******R 001 EXPRES=****** GX INVALI=****** GX
|
||||
|
||||
|
||||
Program sections:
|
||||
|
||||
. ABS. 000000 000 (RW,I,GBL,ABS,OVR,NOSAV)
|
||||
000130 001 (RW,I,LCL,REL,CON,NOSAV)
|
||||
58
crossassemblers/macro11/tests/test-prec.mac
Normal file
58
crossassemblers/macro11/tests/test-prec.mac
Normal file
@@ -0,0 +1,58 @@
|
||||
;;;;;
|
||||
;
|
||||
; Test operator precedencce
|
||||
; or rather the lack thereof
|
||||
;
|
||||
.word 1 + 2 + 3 ; 6
|
||||
.word 1 + 2 * 3 ; 3*3 = 11
|
||||
.word 1 & 2 ! 4 ; 0 ! 4 = 4
|
||||
.word 1 ! 2 & 4 ; 3 & 4 = 0
|
||||
.word 1 ! 2 & 7 ; 3 & 7 = 3
|
||||
.word 1+1 ! 2+3 ; 2!2+3 = 2+3 = 5
|
||||
|
||||
;;;;;
|
||||
;
|
||||
; Test all operators at least once
|
||||
;
|
||||
.word 3 + 4 ; 000007
|
||||
.word 4 - 3 ; 000001
|
||||
.word 3 * 4 ; 000014
|
||||
.word 12. / 4 ; 000003
|
||||
.word 123 & 771 ; 000121
|
||||
.word 123121 ! 322 ; 123323
|
||||
|
||||
.word - 377 ; 177401
|
||||
.word + 377 ; 000377
|
||||
|
||||
.word ^C 377 ; 177400
|
||||
.word ^c 377 ; 177400
|
||||
.word ^B 0101010101010101 ; 052525
|
||||
.word ^b 1010101010101010 ; 125252
|
||||
.word ^d 100 ; 000144
|
||||
.word 100. ; 000144
|
||||
.word ^x 100 ; 000400 hexadecimal is an extension
|
||||
.word ^rRAD ; 070254 up to 3 characters; no leading spaces
|
||||
.word ^rA ; 003100 up to 3 characters
|
||||
.word ^r A ; 000050 up to 3 characters
|
||||
.word ^r A ; 000001 up to 3 characters
|
||||
.word ^r AA ; 000051
|
||||
.word ^rA A ; 003101
|
||||
.word ^rAA ; 003150
|
||||
.word ^r^/AAA/ ; bracketed strings are an extension
|
||||
.word ^r<RAD> ; bracketed strings are an extension
|
||||
.word ^r< AD> ; bracketed strings are an extension
|
||||
.word ^r< D> ; bracketed strings are an extension
|
||||
.word ^r<R D> ; bracketed strings are an extension
|
||||
.word ^r<RA > ; bracketed strings are an extension
|
||||
.word ^R50. ; 157614 there is no whitespace in between.
|
||||
.word ^f 1.5 ; 040140
|
||||
|
||||
;;;;;
|
||||
;
|
||||
; Test bracketing
|
||||
;
|
||||
.word 1 + < 2 * 3 > ; 1 + 6 = 7
|
||||
.word 1 + ^! 2 * 3 ! ; 1 + 6 = 7
|
||||
.word 1 + ^/ 2 * 3 / ; 1 + 6 = 7
|
||||
.word 1 + ^$ 2 * 3 $ ; 1 + 6 = 7
|
||||
.word 1 + ^* 2 * 3 * ; Invalid expression
|
||||
12
crossassemblers/macro11/tests/test-psect.mac
Normal file
12
crossassemblers/macro11/tests/test-psect.mac
Normal file
@@ -0,0 +1,12 @@
|
||||
;;;;;
|
||||
;
|
||||
; Contrary to what the manual says, flags in .PSECT directives
|
||||
; are merged. They do not need to be identical every time.
|
||||
;
|
||||
|
||||
.psect $pdata
|
||||
.iif P1, .psect $pdata ,ro,d,lcl,rel,con
|
||||
.psect $PDATA ,D
|
||||
|
||||
; and ends up with
|
||||
; $PDATA 000000 002 (RO,D,LCL,REL,CON)
|
||||
47
crossassemblers/macro11/tests/test-rad50.lst.ok
Normal file
47
crossassemblers/macro11/tests/test-rad50.lst.ok
Normal file
@@ -0,0 +1,47 @@
|
||||
1 ;;;;;
|
||||
2 ;
|
||||
3 ; Test .rad50 directive
|
||||
4 ;
|
||||
5 ;
|
||||
6 ; 0 space
|
||||
7 ; 01-32 A-Z
|
||||
8 ; 33 $
|
||||
9 ; 34 .
|
||||
10 ; 35 (undefined)
|
||||
11 ; 36-47 0-9
|
||||
12 ;
|
||||
13 ; radix-50 value: ((C1 * 50) + C2) * 50) + C3 ; everything octal of course
|
||||
14 ; example: ABC => ((1*50)+2)*50+3 = 3223
|
||||
15
|
||||
16 000000 003223 .rad50 /ABC/ ; Packs ABC into one word
|
||||
17 000002 003223 .rad50 ^ABC^ ; Packs ABC into one word
|
||||
18 000004 003220 .rad50 /AB/ ; Packs AB (SPACE) into one word
|
||||
19 000006 003223 014400 .rad50 /ABCD/ ; Packs ABC into first word and
|
||||
20 ; D (SPACE) (SPACE) into second word.
|
||||
21 000012 003223 014716 .rad50 /ABCDEF/ ; Packs ABC into first word, DEF into
|
||||
22 ; second word.
|
||||
23 000016 003255 .rad50 /AB/<35> ; stores 3255 in one word
|
||||
test-rad50.mac:24: ***ERROR invalid character '?'
|
||||
test-rad50.mac:24: ***ERROR invalid character '!'
|
||||
test-rad50.mac:24: ***ERROR invalid character '='
|
||||
24 000020 000000 .rad50 /?!=/ ; invalid characters
|
||||
test-rad50.mac:25: ***ERROR invalid character value 50
|
||||
test-rad50.mac:25: ***ERROR invalid character value 37777777777
|
||||
25 000022 000000 .rad50 <0><50><-1> ; invalid characters
|
||||
26 000001 CHR1=1
|
||||
27 000002 CHR2=2
|
||||
28 000003 CHR3=3
|
||||
29 000024 003223 .RAD50 <1><2><3> ; Equivalent to .RAD50 /ABC/
|
||||
30 000026 003223 .RAD50 <CHR1><CHR2><CHR3> ; Equivalent to .RAD50 /ABC/
|
||||
30
|
||||
|
||||
|
||||
Symbol table
|
||||
|
||||
. ******R 001 CHR1 =000001 CHR2 =000002 CHR3 =000003
|
||||
|
||||
|
||||
Program sections:
|
||||
|
||||
. ABS. 000000 000 (RW,I,GBL,ABS,OVR,NOSAV)
|
||||
000030 001 (RW,I,LCL,REL,CON,NOSAV)
|
||||
30
crossassemblers/macro11/tests/test-rad50.mac
Normal file
30
crossassemblers/macro11/tests/test-rad50.mac
Normal file
@@ -0,0 +1,30 @@
|
||||
;;;;;
|
||||
;
|
||||
; Test .rad50 directive
|
||||
;
|
||||
;
|
||||
; 0 space
|
||||
; 01-32 A-Z
|
||||
; 33 $
|
||||
; 34 .
|
||||
; 35 (undefined)
|
||||
; 36-47 0-9
|
||||
;
|
||||
; radix-50 value: ((C1 * 50) + C2) * 50) + C3 ; everything octal of course
|
||||
; example: ABC => ((1*50)+2)*50+3 = 3223
|
||||
|
||||
.rad50 /ABC/ ; Packs ABC into one word
|
||||
.rad50 ^ABC^ ; Packs ABC into one word
|
||||
.rad50 /AB/ ; Packs AB (SPACE) into one word
|
||||
.rad50 /ABCD/ ; Packs ABC into first word and
|
||||
; D (SPACE) (SPACE) into second word.
|
||||
.rad50 /ABCDEF/ ; Packs ABC into first word, DEF into
|
||||
; second word.
|
||||
.rad50 /AB/<35> ; stores 3255 in one word
|
||||
.rad50 /?!=/ ; invalid characters
|
||||
.rad50 <0><50><-1> ; invalid characters
|
||||
CHR1=1
|
||||
CHR2=2
|
||||
CHR3=3
|
||||
.RAD50 <1><2><3> ; Equivalent to .RAD50 /ABC/
|
||||
.RAD50 <CHR1><CHR2><CHR3> ; Equivalent to .RAD50 /ABC/
|
||||
14
crossassemblers/macro11/tests/test-undef.lst.ok
Normal file
14
crossassemblers/macro11/tests/test-undef.lst.ok
Normal file
@@ -0,0 +1,14 @@
|
||||
test-undef.mac:1: ***ERROR MACRO .TTYOU not found
|
||||
1 .MCALL .TTYOUT
|
||||
1
|
||||
|
||||
|
||||
Symbol table
|
||||
|
||||
. ******R 001
|
||||
|
||||
|
||||
Program sections:
|
||||
|
||||
. ABS. 000000 000 (RW,I,GBL,ABS,OVR,NOSAV)
|
||||
000000 001 (RW,I,LCL,REL,CON,NOSAV)
|
||||
1
crossassemblers/macro11/tests/test-undef.mac
Normal file
1
crossassemblers/macro11/tests/test-undef.mac
Normal file
@@ -0,0 +1 @@
|
||||
.MCALL .TTYOUT
|
||||
24
crossassemblers/macro11/tests/test-word-comma.lst.ok
Normal file
24
crossassemblers/macro11/tests/test-word-comma.lst.ok
Normal file
@@ -0,0 +1,24 @@
|
||||
1
|
||||
2 000000 000123 start: .word 123 ; 1 word
|
||||
3 000002 000000 .word ; 1 word
|
||||
4 000004 000001 000000 .word 1, ; 2 words
|
||||
5 000010 000000 000002 .word ,2 ; 2 words
|
||||
6 000014 000000 000000 .word , ; 2 words
|
||||
7 000020 000000 000000 000000 .word ,, ; 3 words
|
||||
8 000026 000001 000000 000000 .word 1,, ; 3 words
|
||||
9 000034 000000 000000 000003 .word ,,3 ; 3 words
|
||||
10 000042 000001 000000 000003 .word 1,,3 ; 3 words
|
||||
11 000050 000001 000002 000003 .word 1,2,3 ; 3 words
|
||||
12
|
||||
12
|
||||
|
||||
|
||||
Symbol table
|
||||
|
||||
. ******R 001 START 000000R 001
|
||||
|
||||
|
||||
Program sections:
|
||||
|
||||
. ABS. 000000 000 (RW,I,GBL,ABS,OVR,NOSAV)
|
||||
000056 001 (RW,I,LCL,REL,CON,NOSAV)
|
||||
12
crossassemblers/macro11/tests/test-word-comma.mac
Normal file
12
crossassemblers/macro11/tests/test-word-comma.mac
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
start: .word 123 ; 1 word
|
||||
.word ; 1 word
|
||||
.word 1, ; 2 words
|
||||
.word ,2 ; 2 words
|
||||
.word , ; 2 words
|
||||
.word ,, ; 3 words
|
||||
.word 1,, ; 3 words
|
||||
.word ,,3 ; 3 words
|
||||
.word 1,,3 ; 3 words
|
||||
.word 1,2,3 ; 3 words
|
||||
|
||||
100
crossassemblers/macro11/tools/checker.pl
Executable file
100
crossassemblers/macro11/tools/checker.pl
Executable file
@@ -0,0 +1,100 @@
|
||||
#!/usr/pkg/bin/perl
|
||||
#
|
||||
# Checker script - checks if a bunch of macro11 object files have
|
||||
# undefined symbols left over.
|
||||
#
|
||||
# Uses the dumpobj tool to parse the object files.
|
||||
#
|
||||
use strict;
|
||||
#use Data::Dumper;
|
||||
|
||||
my %symtab;
|
||||
|
||||
# Symbols are stored in the symbol table.
|
||||
# They have 2 fields:
|
||||
# - a list of definitions (hopefully 1 entry long)
|
||||
# - a list of references
|
||||
|
||||
sub read_object_file {
|
||||
my $fn = shift;
|
||||
|
||||
if ($fn =~ /\.def$/i) {
|
||||
open OBJ, "<", $fn;
|
||||
} else {
|
||||
open OBJ, "dumpobj '".$fn."' |";
|
||||
}
|
||||
|
||||
my $gsd = 0;
|
||||
my $line = <OBJ>;
|
||||
|
||||
while (defined $line) {
|
||||
# print $line;
|
||||
if ($line =~ /^GSD:/) {
|
||||
$gsd = 1;
|
||||
# print "gsd = 1\n";
|
||||
} elsif ($line =~ /^ENDGSD/) {
|
||||
$gsd = 0;
|
||||
# print "gsd = 0\n";
|
||||
} elsif ($gsd) {
|
||||
#print $line;
|
||||
# GLOBAL AT$CDT=0 REF ABS flags=100
|
||||
if ($line =~ /GLOBAL ([A-Z0-9.\$]*)=[0-9]* (.*)/) {
|
||||
my $symbol = $1;
|
||||
my $flags = $2;
|
||||
|
||||
#print "flags: $flags\n";
|
||||
my $key = 'refs';
|
||||
if ($flags =~ /\bDEF\b/) {
|
||||
$key = 'defs';
|
||||
}
|
||||
|
||||
if (!defined $symtab{$symbol}) {
|
||||
$symtab{$symbol} = {
|
||||
'defs' => [],
|
||||
'refs' => []
|
||||
};
|
||||
}
|
||||
|
||||
push @{$symtab{$symbol}->{$key}}, $fn;
|
||||
}
|
||||
}
|
||||
$line = <OBJ>;
|
||||
}
|
||||
|
||||
close OBJ;
|
||||
}
|
||||
|
||||
# Read all object files
|
||||
|
||||
foreach my $fn (@ARGV) {
|
||||
read_object_file($fn);
|
||||
|
||||
# print Dumper(\%symtab);
|
||||
}
|
||||
|
||||
# Check which symbols have no definition
|
||||
|
||||
print "Symbols with no definition:\n";
|
||||
my $undefs = 0;
|
||||
|
||||
foreach my $key (sort keys %symtab) {
|
||||
#print $key, " : ", Dumper($entry);
|
||||
my $entry = %symtab{$key};
|
||||
|
||||
my @defs = @{$entry->{defs}};
|
||||
#print (@defs), "\n";
|
||||
#print scalar(@defs), "\n";
|
||||
|
||||
if (scalar(@defs) == 0) {
|
||||
$undefs++;
|
||||
print $key, ":";
|
||||
for my $ref (@{$entry->{refs}}) {
|
||||
print " ", $ref;
|
||||
}
|
||||
print "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ($undefs == 0) {
|
||||
print "(none)\n";
|
||||
}
|
||||
34
crossassemblers/macro11/tools/varrec.c
Normal file
34
crossassemblers/macro11/tools/varrec.c
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* A little tool to convert files with variable records to byte streams.
|
||||
*
|
||||
* Each record consist of 2 bytes of length (little endian) followed by
|
||||
* that number of data bytes.
|
||||
*
|
||||
* If the length is odd, there is a padding byte. This byte does not have
|
||||
* to be 0.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
while (!feof(stdin)) {
|
||||
int count, savecount;
|
||||
unsigned char ch;
|
||||
|
||||
ch = getchar();
|
||||
count = ch;
|
||||
ch = getchar();
|
||||
count += ch << 8;
|
||||
|
||||
savecount = count;
|
||||
|
||||
while (count-- > 0) {
|
||||
ch = getchar();
|
||||
putchar(ch);
|
||||
}
|
||||
|
||||
if (savecount & 1) {
|
||||
getchar();
|
||||
}
|
||||
}
|
||||
}
|
||||
311
crossassemblers/macro11/util.c
Normal file
311
crossassemblers/macro11/util.c
Normal file
@@ -0,0 +1,311 @@
|
||||
#define UTIL__C
|
||||
|
||||
|
||||
/* Some generally useful routines */
|
||||
/* The majority of the non-portable code is in here. */
|
||||
|
||||
/*
|
||||
|
||||
Copyright (c) 2001, Richard Krehbiel
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
o Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
o Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
o Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "util.h" /* own defintions */
|
||||
|
||||
#ifdef WIN32
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#define stat _stat
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
static void my_searchenv1(
|
||||
char *name,
|
||||
char *envname,
|
||||
char *hitfile,
|
||||
int hitlen);
|
||||
|
||||
static void my_searchenv2(
|
||||
char *name,
|
||||
char *envname,
|
||||
char *hitfile,
|
||||
int hitlen);
|
||||
|
||||
/* Sure, the library typically provides some kind of
|
||||
ultoa or _ultoa function. But since it's merely typical
|
||||
and not standard, and since the function is so simple,
|
||||
I'll write my own.
|
||||
|
||||
It's significant feature is that it'll produce representations in
|
||||
any number base from 2 to 36.
|
||||
*/
|
||||
|
||||
char *my_ultoa(
|
||||
unsigned long val,
|
||||
char *buf,
|
||||
unsigned int base)
|
||||
{
|
||||
static char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
char *strt = buf,
|
||||
*end;
|
||||
|
||||
do {
|
||||
*buf++ = digits[val % base];
|
||||
val /= base;
|
||||
} while (val != 0);
|
||||
|
||||
*buf = 0; /* delimit */
|
||||
end = buf + 1;
|
||||
|
||||
/* Now reverse the bytes */
|
||||
|
||||
while (buf > strt) {
|
||||
char temp;
|
||||
|
||||
temp = *--buf;
|
||||
*buf = *strt;
|
||||
*strt++ = temp;
|
||||
}
|
||||
|
||||
return end;
|
||||
}
|
||||
|
||||
/* Ditto my_ultoa. This actually emits
|
||||
a signed representation in other number bases. */
|
||||
|
||||
char *my_ltoa(
|
||||
long val,
|
||||
char *buf,
|
||||
unsigned int base)
|
||||
{
|
||||
unsigned long uval;
|
||||
|
||||
if (val < 0)
|
||||
uval = -val, *buf++ = '-';
|
||||
else
|
||||
uval = val;
|
||||
|
||||
return my_ultoa(uval, buf, base);
|
||||
}
|
||||
|
||||
/*
|
||||
_searchenv is a function provided by the MSVC library that finds
|
||||
files which may be anywhere along a path which appears in an
|
||||
environment variable. I duplicate that function for portability.
|
||||
Note also that mine avoids destination buffer overruns.
|
||||
|
||||
Added functionality to lowercase the file name and to remove the
|
||||
device name and directory.
|
||||
*/
|
||||
|
||||
void my_searchenv(
|
||||
char *name,
|
||||
char *envname,
|
||||
char *hitfile,
|
||||
int hitlen)
|
||||
{
|
||||
my_searchenv1(name, envname, hitfile, hitlen);
|
||||
if (*hitfile) {
|
||||
return;
|
||||
}
|
||||
|
||||
char *copy = memcheck(strdup(name));
|
||||
downcase(copy);
|
||||
my_searchenv1(copy, envname, hitfile, hitlen);
|
||||
free(copy);
|
||||
}
|
||||
|
||||
static void my_searchenv1(
|
||||
char *name,
|
||||
char *envname,
|
||||
char *hitfile,
|
||||
int hitlen)
|
||||
{
|
||||
my_searchenv2(name, envname, hitfile, hitlen);
|
||||
if (*hitfile) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse DEV:[DIR]NAME
|
||||
* while re-trying the search after DEV: and after [DIR].
|
||||
*
|
||||
* Let's not be too critical about the characters we allow in those.
|
||||
*/
|
||||
char *p = name;
|
||||
char c;
|
||||
|
||||
while ((c = *p++)) {
|
||||
if (c == ':') {
|
||||
my_searchenv2(p, envname, hitfile, hitlen);
|
||||
if (*hitfile) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (c == '[') {
|
||||
char *enddir = strchr(p, ']');
|
||||
if (enddir == NULL) {
|
||||
return; /* weird syntax */
|
||||
}
|
||||
p = enddir + 1;
|
||||
my_searchenv2(p, envname, hitfile, hitlen);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void my_searchenv2(
|
||||
char *name,
|
||||
char *envname,
|
||||
char *hitfile,
|
||||
int hitlen)
|
||||
{
|
||||
char *env;
|
||||
char *envcopy;
|
||||
char *envcopy2;
|
||||
char *cp;
|
||||
char *last;
|
||||
|
||||
*hitfile = 0; /* Default failure indication */
|
||||
|
||||
/* Note: If the given name is absolute, then don't search the
|
||||
path, but use it as is. */
|
||||
|
||||
if (
|
||||
#ifdef WIN32
|
||||
strchr(name, ':') != NULL || /* Contain a drive spec? */
|
||||
name[0] == '\\' || /* Start with absolute ref? */
|
||||
#endif
|
||||
name[0] == '/') { /* Start with absolute ref? */
|
||||
strncpy(hitfile, name, hitlen); /* Copy to target */
|
||||
return;
|
||||
}
|
||||
|
||||
env = getenv(envname);
|
||||
if (env == NULL) { /* If not defined, search in */
|
||||
env = "."; /* current directory */
|
||||
}
|
||||
|
||||
envcopy = strdup(env); /* strtok destroys its text
|
||||
argument. I don't want the return
|
||||
value from getenv destroyed. */
|
||||
|
||||
envcopy2 = envcopy;
|
||||
while ((cp = strtok_r(envcopy2, PATHSEP, &last)) != NULL) {
|
||||
struct stat info;
|
||||
char *concat = malloc(strlen(cp) + strlen(name) + 2);
|
||||
|
||||
if (concat == NULL) {
|
||||
free(envcopy);
|
||||
return;
|
||||
}
|
||||
strcpy(concat, cp);
|
||||
if (concat[strlen(concat) - 1] != '/')
|
||||
strcat(concat, "/");
|
||||
strcat(concat, name);
|
||||
if (!stat(concat, &info)) {
|
||||
/* Copy the file name to hitfile. Assure that it's really
|
||||
zero-delimited. */
|
||||
strncpy(hitfile, concat, hitlen - 1);
|
||||
hitfile[hitlen - 1] = 0;
|
||||
free(envcopy);
|
||||
return;
|
||||
}
|
||||
envcopy2 = NULL;
|
||||
}
|
||||
|
||||
/* If I fall out of that loop, then hitfile indicates no match,
|
||||
and return. */
|
||||
free(envcopy);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* memcheck - crash out if a pointer (returned from malloc) is NULL. */
|
||||
|
||||
void *memcheck(
|
||||
void *ptr)
|
||||
{
|
||||
if (ptr == NULL) {
|
||||
fprintf(stderr, "Out of memory.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* upcase turns a string to upper case */
|
||||
|
||||
void upcase(
|
||||
char *str)
|
||||
{
|
||||
while (*str) {
|
||||
*str = toupper((unsigned char)*str);
|
||||
str++;
|
||||
}
|
||||
}
|
||||
|
||||
/* downcase turns a string to lower case */
|
||||
|
||||
void downcase(
|
||||
char *str)
|
||||
{
|
||||
while (*str) {
|
||||
*str = tolower((unsigned char)*str);
|
||||
str++;
|
||||
}
|
||||
}
|
||||
|
||||
/* padto adds blanks to the end of a string until it's the given
|
||||
length. */
|
||||
|
||||
void padto(
|
||||
char *str,
|
||||
int to)
|
||||
{
|
||||
int needspace = to - strlen(str);
|
||||
|
||||
str += strlen(str);
|
||||
while (needspace > 0)
|
||||
*str++ = ' ', needspace--;
|
||||
*str = 0;
|
||||
}
|
||||
93
crossassemblers/macro11/util.h
Normal file
93
crossassemblers/macro11/util.h
Normal file
@@ -0,0 +1,93 @@
|
||||
#ifndef UTIL__H
|
||||
#define UTIL__H
|
||||
|
||||
/*
|
||||
|
||||
Copyright (c) 2001, Richard Krehbiel
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
o Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
o Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
o Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "stream2.h"
|
||||
|
||||
char *my_ultoa(
|
||||
unsigned long val,
|
||||
char *buf,
|
||||
unsigned int base);
|
||||
char *my_ltoa(
|
||||
long val,
|
||||
char *buf,
|
||||
unsigned int base);
|
||||
void my_searchenv(
|
||||
char *name,
|
||||
char *envname,
|
||||
char *hitfile,
|
||||
int hitlen);
|
||||
|
||||
/* Cover a few platform-dependencies */
|
||||
|
||||
#ifdef WIN32
|
||||
typedef unsigned __int64 ulong64;
|
||||
|
||||
#define strdup _strdup
|
||||
#define putenv _putenv
|
||||
#define PATHSEP ";"
|
||||
#else
|
||||
typedef unsigned long long ulong64;
|
||||
|
||||
#define PATHSEP ":"
|
||||
#endif
|
||||
|
||||
|
||||
#define FALSE 0 /* Everybody needs FALSE and TRUE */
|
||||
#define TRUE 1
|
||||
|
||||
|
||||
/* EOL says whether a char* is pointing at the end of a line */
|
||||
#define EOL(c) (!(c) || (c) == '\n' || (c) == ';')
|
||||
|
||||
#define SIZEOF_MEMBER(s, m) (sizeof((s *)0)->m)
|
||||
|
||||
void upcase(
|
||||
char *str);
|
||||
|
||||
void downcase(
|
||||
char *str);
|
||||
|
||||
void padto(
|
||||
char *str,
|
||||
int to);
|
||||
|
||||
void *memcheck(
|
||||
void *ptr);
|
||||
|
||||
|
||||
#endif /* UTIL__H */
|
||||
Reference in New Issue
Block a user