Import J Hoppe's 20090427 release from http://retrocmp.com/tools/macro-11-on-windows

This commit is contained in:
Sergey Svishchev
2013-02-15 23:50:38 +04:00
parent 3b8e141917
commit 6a2afc3fa7
34 changed files with 8705 additions and 7735 deletions

26
CHANGES
View File

@@ -1,3 +1,29 @@
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

6
TODO
View File

@@ -1,3 +1,9 @@
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

1500
assemble.c Normal file

File diff suppressed because it is too large Load Diff

17
assemble.h Normal file
View File

@@ -0,0 +1,17 @@
#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);
#endif

748
assemble_aux.c Normal file
View File

@@ -0,0 +1,748 @@
/*
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:
{
SYMBOL *sym;
if (!(value->data.symbol->flags & SYMBOLFLAG_LOCAL)) { /* Unless it's a
local symbol, */
sym = add_sym(value->data.symbol->label, 0, SYMBOLFLAG_GLOBAL, &absolute_section, &implicit_st);
}
}
break;
case EX_LIT:
case EX_SYM:
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.
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)
{
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)
{
if (size == 2 && (DOT & 1)) {
report(stack->top, ".WORD on odd boundary\n");
store_word(stack->top, tr, 1, 0); /* Align it */
}
do {
EX_TREE *value = parse_expr(cp, 0);
store_value(stack, tr, size, value);
cp = skipdelim(value->cp);
free_tree(value);
} while (cp = skipdelim(cp), !EOL(*cp));
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)
return; /* Nothing 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 it's 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 *sym;
unsigned offset;
if (!express_sym_offset(xfer_address, &sym, &offset)) {
report(NULL, "Illegal program transfer address\n");
} else {
gsd_xfer(&gsd, sym->section->label, sym->value + offset);
}
}
gsd_flush(&gsd);
gsd_end(&gsd);
}

91
assemble_aux.h Normal file
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

96
assemble_globals.c Normal file
View File

@@ -0,0 +1,96 @@
#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 last_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 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[32]; /* 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
}; /* the section containing the registers */
SECTION pseudo_section = {
"", SECTION_PSEUDO, 0, 0
}; /* the section containing the
pseudo-operations */
SECTION instruction_section = {
". ABS.", SECTION_INSTRUCTION, 0, 0
}; /* the section containing instructions */
SECTION macro_section = {
"", SECTION_SYSTEM, 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 */

84
assemble_globals.h Normal file
View File

@@ -0,0 +1,84 @@
#ifndef ASSEMBLE_GLOBALS__H
#define ASSEMBLE_GLOBALS__H
#include "mlb.h"
#include "symbols.h"
#include "extree.h"
//#include "stream2.h"
//#include "object.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;
#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 last_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 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[32]; /* 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

1026
dumpobj.c

File diff suppressed because it is too large Load Diff

701
extree.c Normal file
View File

@@ -0,0 +1,701 @@
#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. */
static void print_tree(
FILE *printfile,
EX_TREE *tp,
int depth)
{
SYMBOL *sym;
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);
case EX_LIT:
case EX_SYM:
free(tp);
break;
case EX_COM:
case EX_NEG:
free_tree(tp->data.child.left);
free(tp);
break;
case EX_ERR:
if (tp->data.child.left)
free_tree(tp->data.child.left);
free(tp);
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);
free(tp);
break;
}
}
/* 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;
}
#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 = new_ex_tree();
res->type = EX_SYM;
res->data.symbol = tp->data.symbol;
res->cp = tp->cp;
break;
}
case EX_LIT:
res = new_ex_tree();
*res = *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_NEG;
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_SYM || tp->type == EX_TEMP_SYM) {
/* 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 = ex_err(tp->data.child.left, tp->cp);
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_tree();
res->type = EX_ADD;
res->data.child.left = left;
res->data.child.right = 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_tree();
res->type = EX_SUB;
res->data.child.left = left;
res->data.child.right = 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_tree();
res->type = EX_MUL;
res->data.child.left = left;
res->data.child.right = 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_tree();
res->type = EX_DIV;
res->data.child.left = left;
res->data.child.right = 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_tree();
res->type = EX_AND;
res->data.child.left = left;
res->data.child.right = 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_tree();
res->type = EX_OR;
res->data.child.left = left;
res->data.child.right = right;
}
break;
}
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;
}

66
extree.h Normal file
View File

@@ -0,0 +1,66 @@
#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 *evaluate(
EX_TREE *tp,
int undef);
#endif

172
listing.c Normal file
View File

@@ -0,0 +1,172 @@
#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;
/* do_list returns TRUE if listing is enabled. */
static int dolist(
void)
{
int ok = lstfile != NULL && 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", SIZEOF_MEMBER(LSTFORMAT, flag), "", 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)
{
int len = strlen(binline);
size_t col1 = offsetof(LSTFORMAT, source);
size_t col2 = offsetof(LSTFORMAT, pc);
if (strlen(binline) >= col1) {
int offset = offsetof(LSTFORMAT, pc);
list_flush();
listline[0] = 0;
binline[0] = 0;
sprintf(binline, "%*s %6.6o", offsetof(LSTFORMAT, pc), "", addr);
padto(binline, offsetof(LSTFORMAT, words));
} else if (strlen(binline) <= col2) {
sprintf(binline, "%*s%*d %6.6o", SIZEOF_MEMBER(LSTFORMAT, flag), "",
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", SIZEOF_MEMBER(LSTFORMAT, flag), "",
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);
}
}
/* reports errors */
void report(
STREAM *str,
char *fmt,
...)
{
va_list ap;
char *name = "**";
int line = 0;
if (!pass)
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);
}
}

65
listing.h Normal file
View File

@@ -0,0 +1,65 @@
#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 char *listline; /* Source lines */
extern FILE *lstfile;
#endif
void list_word(
STREAM *str,
unsigned addr,
unsigned value,
int size,
char *flags);
void list_value(
STREAM *str,
unsigned word);
void list_source(
STREAM *str,
char *cp);
void list_flush(
void);
void report(
STREAM *str,
char *fmt,
...);
#endif

6453
macro11.c

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,10 @@
#ifndef MACRO11_H
#define MACRO11_H
#define VERSIONSTR "0.3 (April 21, 2009)"
//#define VERSIONSTR "0.2 July 15, 2001"
/*
Copyright (c) 2001, Richard Krehbiel
All rights reserved.
@@ -34,6 +38,5 @@ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/
extern void *memcheck(void *p);
#endif

550
macros.c Normal file
View File

@@ -0,0 +1,550 @@
#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,
ARG *args)
{
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;
/* Count the args and save their number */
for (mstr->nargs = 0; args; args = args->next, mstr->nargs++) ;
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 not closed\n");
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 */
/* close the body early if it matches the definition */
if (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)
nest = 0; /* End of macro body. */
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();
if (arg->locsym = (*cp == '?')) /* 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(*in)) {
label = get_symbol(in, &next, NULL);
if (label) {
if (arg = find_arg(args, label)) {
/* An apostrophy 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_arg - 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. */
void eval_arg(
STREAM *refstr,
ARG *arg)
{
/* Check for value substitution */
if (arg->value[0] == '\\') {
EX_TREE *value = parse_expr(arg->value + 1, 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->value);
arg->value = memcheck(strdup(temp));
}
}
/* 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;
args = NULL;
arg = NULL;
/* Parse the arguments */
while (!EOL(*cp)) {
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(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(cp, &nextcp);
}
arg->next = args;
args = arg;
eval_arg(refstr, arg); /* Check for expression evaluation */
cp = skipdelim(nextcp);
}
/* Now go back and fill in defaults */ {
int locsym;
if (last_lsb != lsb)
locsym = last_locsym = 32768;
else
locsym = last_locsym;
last_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, args);
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. */
static 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);
printf("\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);
}

71
macros.h Normal file
View File

@@ -0,0 +1,71 @@
#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);
void eval_arg(
STREAM *refstr,
ARG *arg);
BUFFER *subst_args(
BUFFER *text,
ARG *args);
#endif

View File

@@ -1,6 +1,9 @@
CFLAGS = -O -g
MACRO11_SRCS = macro11.c mlb.c object.c stream2.c util.c rad50.c
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.c object.c stream2.c util.c rad50.c
MACRO11_OBJS = $(MACRO11_SRCS:.c=.o)
@@ -30,7 +33,7 @@ clean:
macro11.o: macro11.c macro11.h rad50.h object.h stream2.h \
mlb.h util.h
mlb.o: mlb.c rad50.h stream2.h mlb.h macro11.h util.h
object.o: object.c rad50.h object.h
object.o: object.c rad50.h object.h
stream2.o: stream2.c macro11.h stream2.h
util.o: util.c util.h
rad50.o: rad50.c rad50.h

369
mlb.c
View File

@@ -57,237 +57,227 @@ DAMAGE.
#define BYTEPOS(rec) ((WORD((rec)+4) & 32767) * 512 + (WORD((rec)+6) & 511))
extern FILE *lstfile;
extern FILE *lstfile;
/* 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)
static int compare_position(
const void *arg1,
const void *arg2)
{
const char *c1 = arg1, *c2 = arg2;
const char *c1 = arg1,
*c2 = arg2;
if(BYTEPOS(c1) < BYTEPOS(c2))
return -1;
if(BYTEPOS(c1) > BYTEPOS(c2))
return 1;
return 0;
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)
static void trim(
char *buf)
{
char *cp = buf + strlen(buf);
while(--cp >= buf && *cp == ' ')
*cp = 0;
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_open(
char *name)
{
MLB *mlb = memcheck(malloc(sizeof(MLB)));
char *buff;
unsigned entsize;
unsigned nr_entries;
unsigned start_block;
int i;
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;
}
mlb->directory = NULL;
buff = memcheck(malloc(044)); /* Size of MLB library header */
mlb->fp = fopen(name, "rb");
if (mlb->fp == NULL) {
mlb_close(mlb);
return NULL;
}
if(fread(buff, 1, 044, mlb->fp) < 044)
{
mlb_close(mlb);
free(buff);
return NULL;
}
buff = memcheck(malloc(044)); /* Size of MLB library header */
if(WORD(buff) != 01001) /* Is this really a macro library? */
{
mlb_close(mlb); /* Nope. */
return NULL;
}
if (fread(buff, 1, 044, mlb->fp) < 044) {
mlb_close(mlb);
free(buff);
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 */
if (WORD(buff) != 01001) { /* Is this really a macro library? */
mlb_close(mlb); /* Nope. */
return NULL;
}
free(buff); /* Done with that header. */
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 */
/* 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;
}
free(buff); /* Done with that header. */
/* Shift occupied directory entries to the front of the array
before sorting */
/* 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 */
{
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 */
}
}
/* Read the disk directory */
if (fread(buff, entsize, nr_entries, mlb->fp) < nr_entries) {
mlb_close(mlb); /* Sorry, read error. */
free(buff);
return NULL;
}
/* Now i contains the actual number of entries. */
/* Shift occupied directory entries to the front of the array
before sorting */
{
int j;
mlb->nentries = i;
for (i = 0, j = nr_entries; i < j; i++) {
char *ent1,
*ent2;
/* Sort the array by file position */
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 */
}
}
qsort(buff, i, entsize, compare_position);
/* Now i contains the actual number of entries. */
/* Now, allocate my in-memory directory */
mlb->directory = memcheck(malloc(sizeof(MLBENT) * mlb->nentries));
memset(mlb->directory, 0, sizeof(MLBENT) * mlb->nentries);
mlb->nentries = i;
/* Build in-memory directory */
for(j = 0; j < i; j++)
{
char radname[16];
char *ent;
/* Sort the array by file position */
ent = buff + (j * entsize);
qsort(buff, i, entsize, compare_position);
unrad50(WORD(ent), radname);
unrad50(WORD(ent+2), radname+3);
radname[6] = 0;
/* Now, allocate my in-memory directory */
mlb->directory = memcheck(malloc(sizeof(MLBENT) * mlb->nentries));
memset(mlb->directory, 0, sizeof(MLBENT) * mlb->nentries);
trim(radname);
/* Build in-memory directory */
for (j = 0; j < i; j++) {
char radname[16];
char *ent;
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);
}
}
ent = buff + (j * entsize);
free(buff);
unrad50(WORD(ent), radname);
unrad50(WORD(ent + 2), radname + 3);
radname[6] = 0;
}
trim(radname);
/* Done. Return the struct that represents the opened MLB. */
return mlb;
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)
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);
if (mlb) {
int i;
free(mlb);
}
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)
BUFFER *mlb_entry(
MLB *mlb,
char *name)
{
int i;
MLBENT *ent;
BUFFER *buf;
char *bp;
int c;
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;
}
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;
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;
/* 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);
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 */
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, bp - buf->buffer);
/* Now resize that buffer to the length actually read. */
buffer_resize(buf, (int) (bp - buf->buffer));
return buf;
return buf;
}
/* mlb_extract - walk thru a macro library and store it's contents
@@ -300,20 +290,21 @@ BUFFER *mlb_entry(MLB *mlb, char *name)
in the file system from thence forward.
*/
void mlb_extract(MLB *mlb)
void mlb_extract(
MLB *mlb)
{
int i;
FILE *fp;
BUFFER *buf;
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);
}
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);
}
}

31
mlb.h
View File

@@ -40,23 +40,26 @@ DAMAGE.
/* Routines to open and read entries from a macro library */
typedef struct mlbent
{
char *label;
unsigned long position;
int length;
typedef struct mlbent {
char *label;
unsigned long position;
int length;
} MLBENT;
typedef struct mlb
{
FILE *fp;
MLBENT *directory;
int nentries;
typedef struct mlb {
FILE *fp;
MLBENT *directory;
int nentries;
} MLB;
extern MLB *mlb_open(char *name);
extern BUFFER *mlb_entry(MLB *mlb, char *name);
extern void mlb_close(MLB *mlb);
extern void mlb_extract(MLB *mlb);
extern MLB *mlb_open(
char *name);
extern BUFFER *mlb_entry(
MLB *mlb,
char *name);
extern void mlb_close(
MLB *mlb);
extern void mlb_extract(
MLB *mlb);
#endif /* MLB_H */

942
object.c

File diff suppressed because it is too large Load Diff

380
object.h
View File

@@ -38,71 +38,73 @@ DAMAGE.
*/
#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 */
#include <stdio.h>
#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 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 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 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 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 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 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 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 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 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_BYTE 0200 /* RLD modifies a byte, else a word */
#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. */
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_NOP 00 /* NOP - used for padding */
#define CPLX_ADD 01
#define CPLX_SUB 02
#define CPLX_MUL 03
@@ -112,99 +114,197 @@ DAMAGE.
#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 */
#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 */
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);
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 */
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);
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;
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);
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);
int write_endmod(
FILE *fp);
#endif /* OBJECT_J */

856
parse.c Normal file
View File

@@ -0,0 +1,856 @@
#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 "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;
}
/* 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;
}
/* 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 exp; /* 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. */
exp = sexp + 128; /* Make excess-128 mode */
exp &= 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 */
exp--;
}
}
flt[0] = (unsigned) (sign | (exp << 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_tree();
tp->type = EX_ADD;
tp->data.child.left = leftp;
tp->data.child.right = 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_tree();
tp->type = EX_SUB;
tp->data.child.left = leftp;
tp->data.child.right = 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_tree();
tp->type = EX_MUL;
tp->data.child.left = leftp;
tp->data.child.right = 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_tree();
tp->type = EX_DIV;
tp->data.child.left = leftp;
tp->data.child.right = rightp;
tp->cp = rightp->cp;
leftp = tp;
break;
case '!':
if (depth >= OR_PREC)
return leftp;
rightp = parse_binary(cp + 1, term, 2);
tp = new_ex_tree();
tp->type = EX_OR;
tp->data.child.left = leftp;
tp->data.child.right = 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_tree();
tp->type = EX_AND;
tp->data.child.left = leftp;
tp->data.child.right = 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(*cp))
return NULL;
digits = 0;
if (isdigit(*cp))
digits = 2; /* Think about digit count */
for (symcp = cp + 1; issym(*symcp); symcp++) {
if (!isdigit(*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, "%d$%d", strtol(symcp, NULL, 10), lsb);
free(symcp);
symcp = newsym;
if (islocal)
*islocal = SYMBOLFLAG_LOCAL;
} else {
free(symcp);
return NULL;
}
}
} else {
/* disallow local label format */
if (isdigit(*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;
nest = 1;
while (nest) {
int sublen;
sublen = strcspn(cp + len, endstr);
if (cp[len + sublen] == '<')
nest++;
else
nest--;
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(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':
/* An enhancement! ^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;
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(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_tree();
tp->type = EX_LIT;
tp->data.lit = *cp & 0xff;
tp->cp = ++cp;
return tp;
}
if (*cp == '\"') {
/* "xx ASCII character pair */
cp++;
tp = new_ex_tree();
tp->type = EX_LIT;
tp->data.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(*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(*endcp); endcp++) ;
if (*endcp == '.')
rad = 10;
value = strtoul(cp, &endcp, rad);
if (*endcp == '.')
endcp++;
tp = new_ex_tree();
tp->type = EX_LIT;
tp->data.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;
}

54
parse.h Normal file
View File

@@ -0,0 +1,54 @@
#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);
SYMBOL *get_op(
char *cp,
char **endp);
char *getstring(
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);
int parse_float(
char *cp,
char **endp,
int size,
unsigned *flt);
int brackrange(
char *cp,
int *start,
int *length,
char **endp);
#endif

105
rad50.c
View File

@@ -37,81 +37,84 @@ DAMAGE.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "rad50.h"
static char radtbl[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$. 0123456789";
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 rad50(
char *cp,
char **endp)
{
unsigned long acc = 0;
char *rp;
unsigned long acc = 0;
char *rp;
if(endp)
*endp = cp;
if (endp)
*endp = cp;
if(!*cp) /* Got to check for end-of-string
manually, because strchr will call
it a hit. :-/ */
return acc;
if (!*cp) /* Got to check for end-of-string manually, because strchr will call it a hit. :-/ */
return acc;
rp = strchr(radtbl, toupper(*cp));
if(rp == NULL) /* Not a RAD50 character */
return acc;
acc = (rp - radtbl) * 03100; /* Convert */
cp++;
rp = strchr(radtbl, toupper(*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... */
/* Now, do the same thing two more times... */
if(endp)
*endp = cp;
if(!*cp)
return acc;
rp = strchr(radtbl, toupper(*cp));
if(rp == NULL)
return acc;
acc += (rp - radtbl) * 050;
if (endp)
*endp = cp;
if (!*cp)
return acc;
rp = strchr(radtbl, toupper(*cp));
if (rp == NULL)
return acc;
acc += ((int) (rp - radtbl)) * 050;
cp++;
if(endp)
*endp = cp;
if(!*cp)
return acc;
rp = strchr(radtbl, toupper(*cp));
if(rp == NULL)
return acc;
acc += (rp - radtbl);
cp++;
if (endp)
*endp = cp;
if (!*cp)
return acc;
rp = strchr(radtbl, toupper(*cp));
if (rp == NULL)
return acc;
acc += (int) (rp - radtbl);
cp++;
if(endp)
*endp = cp;
cp++;
if (endp)
*endp = cp;
return acc; /* Done. */
return acc; /* Done. */
}
/* rad50x2 - converts from 0 to 6 characters into two words of RAD50. */
void rad50x2(char *cp, unsigned *rp)
void rad50x2(
char *cp,
unsigned *rp)
{
*rp++ = rad50(cp, &cp);
*rp = 0;
if(*cp)
*rp = rad50(cp, &cp);
*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)
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] = ' ';
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] = ' ';
}

12
rad50.h
View File

@@ -34,10 +34,16 @@ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/
extern unsigned rad50(char *cp, char **endp);
extern unsigned rad50(
char *cp,
char **endp);
extern void rad50x2(char *cp, unsigned *rp);
extern void rad50x2(
char *cp,
unsigned *rp);
extern void unrad50(unsigned word, char *cp);
extern void unrad50(
unsigned word,
char *cp);
#endif /* RAD50_H */

371
rept_irpc.c Normal file
View File

@@ -0,0 +1,371 @@
#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(cp, &cp);
cp = skipdelim(cp);
istr->offset = (int) (cp - istr->items);
eval_arg(str, arg);
buf = subst_args(istr->body, arg);
free(arg->value);
free(arg);
buffer_stream_set_buffer(&istr->bstr, buf);
buffer_free(buf);
}
}
/* irp_stream_delete - also pops the conditional stack */
void irp_stream_delete(
STREAM *str)
{
IRP_STREAM *istr = (IRP_STREAM *) str;
pop_cond(istr->savecond); /* complete unterminated
conditionals */
buffer_free(istr->body);
free(istr->items);
free(istr->label);
buffer_stream_delete(str);
}
STREAM_VTBL irp_stream_vtbl = {
irp_stream_delete, irp_stream_gets, buffer_stream_rewind
};
/* expand_irp is called when a .IRP is encountered in the input. */
STREAM *expand_irp(
STACK *stack,
char *cp)
{
char *label,
*items;
BUFFER *gb;
int levelmod = 0;
IRP_STREAM *str;
label = get_symbol(cp, &cp, NULL);
if (!label) {
report(stack->top, "Illegal .IRP syntax\n");
return NULL;
}
cp = skipdelim(cp);
items = getstring(cp, &cp);
if (!items) {
report(stack->top, "Illegal .IRP syntax\n");
free(label);
return NULL;
}
gb = new_buffer();
levelmod = 0;
if (!list_md) {
list_level--;
levelmod++;
}
read_body(stack, gb, NULL, FALSE);
list_level += levelmod;
str = memcheck(malloc(sizeof(IRP_STREAM))); {
char *name = memcheck(malloc(strlen(stack->top->name) + 32));
sprintf(name, "%s:%d->.IRP", stack->top->name, stack->top->line);
buffer_stream_construct(&str->bstr, NULL, name);
free(name);
}
str->bstr.stream.vtbl = &irp_stream_vtbl;
str->body = gb;
str->items = items;
str->offset = 0;
str->label = label;
str->savecond = last_cond;
return &str->bstr.stream;
}
/* *** implement IRPC_STREAM */
typedef struct irpc_stream {
BUFFER_STREAM bstr;
char *label; /* The substitution label */
char *items; /* The substitution items (in source code
format) */
int offset; /* Current offset in "items" */
BUFFER *body; /* Original body */
int savecond; /* conditional stack at invocation */
} IRPC_STREAM;
/* irpc_stream_gets - same comments apply as with irp_stream_gets, but
the substitution is character-by-character */
char *irpc_stream_gets(
STREAM *str)
{
IRPC_STREAM *istr = (IRPC_STREAM *) str;
char *cp;
BUFFER *buf;
ARG *arg;
for (;;) {
if ((cp = buffer_stream_gets(str)) != NULL)
return cp;
cp = istr->items + istr->offset;
if (!*cp)
return NULL; /* No more items. EOF. */
arg = new_arg();
arg->next = NULL;
arg->locsym = 0;
arg->label = istr->label;
arg->value = memcheck(malloc(2));
arg->value[0] = *cp++;
arg->value[1] = 0;
istr->offset = (int) (cp - istr->items);
buf = subst_args(istr->body, arg);
free(arg->value);
free(arg);
buffer_stream_set_buffer(&istr->bstr, buf);
buffer_free(buf);
}
}
/* irpc_stream_delete - also pops contidionals */
void irpc_stream_delete(
STREAM *str)
{
IRPC_STREAM *istr = (IRPC_STREAM *) str;
pop_cond(istr->savecond); /* complete unterminated
conditionals */
buffer_free(istr->body);
free(istr->items);
free(istr->label);
buffer_stream_delete(str);
}
STREAM_VTBL irpc_stream_vtbl = {
irpc_stream_delete, irpc_stream_gets, buffer_stream_rewind
};
/* expand_irpc - called when .IRPC is encountered in the input */
STREAM *expand_irpc(
STACK *stack,
char *cp)
{
char *label,
*items;
BUFFER *gb;
int levelmod = 0;
IRPC_STREAM *str;
label = get_symbol(cp, &cp, NULL);
if (!label) {
report(stack->top, "Illegal .IRPC syntax\n");
return NULL;
}
cp = skipdelim(cp);
items = getstring(cp, &cp);
if (!items) {
report(stack->top, "Illegal .IRPC syntax\n");
free(label);
return NULL;
}
gb = new_buffer();
levelmod = 0;
if (!list_md) {
list_level--;
levelmod++;
}
read_body(stack, gb, NULL, FALSE);
list_level += levelmod;
str = memcheck(malloc(sizeof(IRPC_STREAM))); {
char *name = memcheck(malloc(strlen(stack->top->name) + 32));
sprintf(name, "%s:%d->.IRPC", stack->top->name, stack->top->line);
buffer_stream_construct(&str->bstr, NULL, name);
free(name);
}
str->bstr.stream.vtbl = &irpc_stream_vtbl;
str->body = gb;
str->items = items;
str->offset = 0;
str->label = label;
str->savecond = last_cond;
return &str->bstr.stream;
}

26
rept_irpc.h Normal file
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

387
stream2.c
View File

@@ -42,7 +42,7 @@ DAMAGE.
#include <ctype.h>
#include <stdarg.h>
#include "macro11.h"
#include "util.h"
#include "stream2.h"
@@ -50,331 +50,362 @@ DAMAGE.
/* new_buffer allocates a new buffer */
BUFFER *new_buffer(void)
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 *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)
void buffer_resize(
BUFFER *buff,
int size)
{
buff->size = size;
buff->length = 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));
}
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)
BUFFER *buffer_clone(
BUFFER *from)
{
if(from)
from->use++;
return 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)
void buffer_free(
BUFFER *buf)
{
if(buf)
{
if(--(buf->use) == 0)
{
free(buf->buffer);
free(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)
void buffer_appendn(
BUFFER *buf,
char *str,
int len)
{
int needed = buf->length + len + 1;
int needed = buf->length + len + 1;
if(needed >= buf->size)
{
buf->size = needed + GROWBUF_INCR;
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));
}
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;
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)
void buffer_append_line(
BUFFER *buf,
char *str)
{
char *nl;
if((nl = strchr(str, '\n')) != NULL)
buffer_appendn(buf, str, nl - str + 1);
else
buffer_appendn(buf, str, strlen(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)
void stream_construct(
STREAM *str,
char *name)
{
str->line = 0;
str->name = memcheck(strdup(name));
str->next = NULL;
str->vtbl = NULL;
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)
void stream_delete(
STREAM *str)
{
free(str->name);
free(str);
free(str->name);
free(str);
}
/* *** class BUFFER_STREAM implementation */
/* STREAM::gets for a buffer stream */
char *buffer_stream_gets(STREAM *str)
char *buffer_stream_gets(
STREAM *str)
{
char *nl;
char *cp;
BUFFER_STREAM *bstr = (BUFFER_STREAM *)str;
BUFFER *buf = bstr->buffer;
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;
if (buf == NULL)
return NULL; /* No buffer */
cp = buf->buffer + bstr->offset;
if (bstr->offset >= buf->length)
return NULL;
/* Find the next line in preparation for the next call */
cp = buf->buffer + bstr->offset;
nl = memchr(cp, '\n', buf->length - bstr->offset);
/* Find the next line in preparation for the next call */
if(nl)
nl++;
nl = memchr(cp, '\n', buf->length - bstr->offset);
bstr->offset = nl - buf->buffer;
str->line++;
if (nl)
nl++;
return cp;
bstr->offset = (int) (nl - buf->buffer);
str->line++;
return cp;
}
/* STREAM::close for a buffer stream */
void buffer_stream_delete(STREAM *str)
void buffer_stream_delete(
STREAM *str)
{
BUFFER_STREAM *bstr = (BUFFER_STREAM *)str;
buffer_free(bstr->buffer);
stream_delete(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)
void buffer_stream_rewind(
STREAM *str)
{
BUFFER_STREAM *bstr = (BUFFER_STREAM *)str;
bstr->offset = 0;
str->line = 0;
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 };
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)
void buffer_stream_construct(
BUFFER_STREAM * bstr,
BUFFER *buf,
char *name)
{
bstr->stream.vtbl = &buffer_stream_vtbl;
bstr->stream.name = memcheck(strdup(name));
bstr->stream.vtbl = &buffer_stream_vtbl;
bstr->buffer = buffer_clone(buf);
bstr->offset = 0;
bstr->stream.line = 0;
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)
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;
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)
STREAM *new_buffer_stream(
BUFFER *buf,
char *name)
{
BUFFER_STREAM *bstr = memcheck(malloc(sizeof(BUFFER_STREAM)));
BUFFER_STREAM *bstr = memcheck(malloc(sizeof(BUFFER_STREAM)));
buffer_stream_construct(bstr, buf, name);
return &bstr->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)
static char *file_gets(
STREAM *str)
{
int i, c;
FILE_STREAM *fstr = (FILE_STREAM *)str;
int i,
c;
FILE_STREAM *fstr = (FILE_STREAM *) str;
if(fstr->fp == NULL)
return NULL;
if (fstr->fp == NULL)
return NULL;
if(feof(fstr->fp))
return NULL;
if (feof(fstr->fp))
return NULL;
/* Read single characters, end of line when '\n' or '\f' hit */
/* 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;
}
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;
fstr->buffer[i++] = '\n'; /* Silently transform formfeeds
into newlines */
fstr->buffer[i] = 0;
if(c == '\n')
fstr->stream.line++; /* Count a line */
if (c == '\n')
fstr->stream.line++; /* Count a line */
return fstr->buffer;
return fstr->buffer;
}
/* Implement STREAM::destroy for a file stream */
void file_destroy(STREAM *str)
void file_destroy(
STREAM *str)
{
FILE_STREAM *fstr = (FILE_STREAM *)str;
fclose(fstr->fp);
free(fstr->buffer);
stream_delete(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)
void file_rewind(
STREAM *str)
{
FILE_STREAM *fstr = (FILE_STREAM *)str;
rewind(fstr->fp);
str->line = 0;
FILE_STREAM *fstr = (FILE_STREAM *) str;
rewind(fstr->fp);
str->line = 0;
}
static STREAM_VTBL file_stream_vtbl = { file_destroy, file_gets,
file_rewind };
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)
STREAM *new_file_stream(
char *filename)
{
FILE *fp;
FILE_STREAM *str;
FILE *fp;
FILE_STREAM *str;
fp = fopen(filename, "r");
if(fp == NULL)
return NULL;
fp = fopen(filename, "r");
if (fp == NULL)
return NULL;
str = memcheck(malloc(sizeof(FILE_STREAM)));
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;
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;
return &str->stream;
}
/* STACK functions */
/* stack_init prepares a stack */
void stack_init(STACK *stack)
void stack_init(
STACK *stack)
{
stack->top = NULL; /* Too simple */
stack->top = NULL; /* Too simple */
}
/* stack_pop removes and deletes the topmost STRAM on the stack */
void stack_pop(STACK *stack)
void stack_pop(
STACK *stack)
{
STREAM *top = stack->top;
STREAM *next = top->next;
STREAM *top = stack->top;
STREAM *next = top->next;
top->vtbl->delete(top);
stack->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)
void stack_push(
STACK *stack,
STREAM *str)
{
str->next = stack->top;
stack->top = 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 *stack_gets(
STACK *stack)
{
char *line;
char *line;
if(stack->top == NULL)
return NULL;
if (stack->top == NULL)
return NULL;
while((line = stack->top->vtbl->gets(stack->top)) == NULL)
{
stack_pop(stack);
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;
return line;
}

125
stream2.h
View File

@@ -35,76 +35,103 @@ 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
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
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
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
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
#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
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
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);
#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);
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);
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);
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);
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 */

478
symbols.c Normal file
View File

@@ -0,0 +1,478 @@
#define SYMBOLS__C
#include <stdlib.h>
#include <string.h>
#include "symbols.h" /* my own definitions */
#include "util.h"
#include "assemble_globals.h"
#include "listing.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 */
/* 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
//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(".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. */
static 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);
}
}

361
symbols.h Normal file
View File

@@ -0,0 +1,361 @@
#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$) */
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_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);
#endif

211
util.c
View File

@@ -1,3 +1,6 @@
#define UTIL__C
/* Some generally useful routines */
/* The majority of the non-portable code is in here. */
@@ -39,8 +42,9 @@ DAMAGE.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "util.h"
#include "util.h" /* own defintions */
#ifdef WIN32
#include <sys/types.h>
@@ -52,54 +56,60 @@ DAMAGE.
#endif
/* 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.
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.
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)
char *my_ultoa(
unsigned long val,
char *buf,
unsigned int base)
{
static char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char *strt = buf, *end;
static char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char *strt = buf,
*end;
do
{
*buf++ = digits[val % base];
val /= base;
} while(val != 0);
do {
*buf++ = digits[val % base];
val /= base;
} while (val != 0);
*buf = 0; /* delimit */
end = buf+1;
*buf = 0; /* delimit */
end = buf + 1;
/* Now reverse the bytes */
/* Now reverse the bytes */
while(buf > strt)
{
char temp;
temp = *--buf;
*buf = *strt;
*strt++ = temp;
}
while (buf > strt) {
char temp;
return end;
temp = *--buf;
*buf = *strt;
*strt++ = temp;
}
return end;
}
/* Ditto my_ultoa. This actually emits
a signed representation in other number bases. */
a signed representation in other number bases. */
char *my_ltoa(long val, char *buf, unsigned int base)
char *my_ltoa(
long val,
char *buf,
unsigned int base)
{
unsigned long uval;
unsigned long uval;
if(val < 0)
uval = -val, *buf++ = '-';
else
uval = val;
if (val < 0)
uval = -val, *buf++ = '-';
else
uval = val;
return my_ultoa(uval, buf, base);
return my_ultoa(uval, buf, base);
}
/*
@@ -113,60 +123,103 @@ char *my_ltoa(long val, char *buf, unsigned int base)
this function.
*/
void my_searchenv(char *name, char *envname, char *hitfile, int hitlen)
void my_searchenv(
char *name,
char *envname,
char *hitfile,
int hitlen)
{
char *env;
char *envcopy;
char *cp;
char *env;
char *envcopy;
char *cp;
*hitfile = 0; /* Default failure indication */
*hitfile = 0; /* Default failure indication */
/* Note: If the given name is absolute, then don't search the
path, but use it as is. */
/* Note: If the given name is absolute, then don't search the
path, but use it as is. */
if(
if (
#ifdef WIN32
strchr(name, ':') != NULL || /* Contain a drive spec? */
name[0] == '\\' || /* Start with absolute ref? */
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;
}
name[0] == '/') { /* Start with absolute ref? */
strncpy(hitfile, name, hitlen); /* Copy to target */
return;
}
env = getenv(envname);
if(env == NULL)
return; /* Variable not defined, no search. */
env = getenv(envname);
if (env == NULL)
return; /* Variable not defined, no search. */
envcopy = strdup(env); /* strtok destroys it's text
argument. I don't want the return
value from getenv destroyed. */
envcopy = strdup(env); /* strtok destroys it's text
argument. I don't want the return
value from getenv destroyed. */
while((cp = strtok(envcopy, PATHSEP)) != 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;
}
}
while ((cp = strtok(envcopy, PATHSEP)) != NULL) {
struct stat info;
char *concat = malloc(strlen(cp) + strlen(name) + 2);
/* If I fall out of that loop, then hitfile indicates no match,
and return. */
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;
}
}
/* If I fall out of that loop, then hitfile indicates no match,
and return. */
}
/* 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(*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;
}

48
util.h
View File

@@ -1,5 +1,5 @@
#ifndef UTIL_H
#define UTIL_H
#ifndef UTIL__H
#define UTIL__H
/*
@@ -36,21 +36,55 @@ DAMAGE.
*/
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);
#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
#endif /* UTIL_H */
#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 padto(
char *str,
int to);
void *memcheck(
void *ptr);
#endif /* UTIL__H */