Add 'crossassemblers/macro11/' from commit '2a14ffe2519589011ffc4050d5d4fd6591fb4c3c'

git-subtree-dir: crossassemblers/macro11
git-subtree-mainline: fc2c8875ca
git-subtree-split: 2a14ffe251

command was: git subtree add --prefix=crossassemblers/macro11 git://github.com/Rhialto/macro11.git master
This commit is contained in:
Olaf Seibert
2016-02-21 10:58:33 +01:00
75 changed files with 13395 additions and 0 deletions

45
crossassemblers/macro11/.indent.pro vendored Executable file
View 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

View 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.

View 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.

View 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 $@.$$$$

View 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.

View 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.

File diff suppressed because it is too large Load Diff

View 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

View 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, &current_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, &current_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);
}

View 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

View 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 */

View 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

View 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;
}

View 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

View 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;
}

View 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

View 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);
}
}

View 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

View 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;
}

View 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

View 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>
{{{
}}}
###############################################################################

View 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

View 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 = &macro_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, &macro_st);
if (mac) {
/* Remove from the symbol table... */
remove_sym(&mac->sym, &macro_st);
free_macro(mac);
}
mac = new_macro(label);
add_table(&mac->sym, &macro_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, &macro_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, &macro_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(&macro_st, &iter); mac != NULL; mac = (MACRO *) next_sym(&macro_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 = &macro_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);
}

View 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

View 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

View 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);
}
}
}

View 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);
}
}

View 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 */

File diff suppressed because it is too large Load Diff

View 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 */

View 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;
}

View 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

View 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;
}

View 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 */

View 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;
}

View 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

View 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;
}

View 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 */

View 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, &register_section, &system_st);
reg_sym[1] = add_sym("R1", 1, 0, &register_section, &system_st);
reg_sym[2] = add_sym("R2", 2, 0, &register_section, &system_st);
reg_sym[3] = add_sym("R3", 3, 0, &register_section, &system_st);
reg_sym[4] = add_sym("R4", 4, 0, &register_section, &system_st);
reg_sym[5] = add_sym("R5", 5, 0, &register_section, &system_st);
reg_sym[6] = add_sym("SP", 6, 0, &register_section, &system_st);
reg_sym[7] = add_sym("PC", 7, 0, &register_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, &section_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");
}

View 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

View 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

View File

@@ -0,0 +1,5 @@
;;;;;
;
; file to be included
.word 1 ; to show it is included

View 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)

View 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 ^...^.

View 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)

View 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

View 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)

View 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.

View 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

View 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

View 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)

View 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

View 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)

View 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

View 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)

View 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

View 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)

View 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

View 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)

View 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

View 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)

View 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

View 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)

View 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

View 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)

View 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)

View 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/

View 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)

View File

@@ -0,0 +1 @@
.MCALL .TTYOUT

View 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)

View 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

View 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";
}

View 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();
}
}
}

View 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;
}

View 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 */