1
0
mirror of https://github.com/aap/pdp6.git synced 2026-01-13 15:27:46 +00:00
aap.pdp6/tools/as6.c
2019-12-05 00:31:20 +01:00

2411 lines
46 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <ctype.h>
#include <stdarg.h>
#include "pdp6common.h"
#include "pdp6bin.h"
#include "args.h"
// TODO: A,,B
#define nil NULL
enum
{
FW = 0777777777777
};
enum
{
MAXSYM = 4000,
MAXLINE = 256,
MAXOPND = 20
};
enum Toktype
{
Unused = 0,
Symbol,
Word,
/* These must be kept as a block for expression parsing */
Plus,
Minus,
Star,
Slash,
Exclam,
Amper,
Shift,
Radix10,
Radix8,
Radix2,
Eol,
/* char classes */
Letter,
Digit,
Ignore,
};
enum Symtype
{
Undef = 000,
Local = 001, /* defined, Intern may modify this */
Intern = 002, /* exported */
Extern = 004, /* defined in other module */
Def = 010,
Hide = 020, /* not visible to debugger */
Label = 040, /* to forbid redefinition */
Operator = 0100, /* primary instruction and opdef */
IoOperator, /* io instruction */
Pseudo
/* Macro etc... */
};
typedef struct Value Value;
struct Value
{
word val;
int rel; /* 0 = absolute, else relative */
};
typedef struct Additive Additive;
struct Additive
{
int l;
Value v;
Additive *next;
};
typedef struct Sym Sym;
struct Sym
{
word name; /* sixbit */
int type; /* Symtype */
union {
Value v;
void (*f)(void);
};
Additive *add;
};
typedef struct Token Token;
struct Token
{
int type;
union {
word w;
Sym *s;
};
};
/* Expressions */
enum Xtype
{
Xval, Xsym, Xunop, Xbiop
};
/* This holds an expression AST */
typedef struct Expr Expr;
struct Expr
{
int type; /* Xtype */
Value v; /* Xval */
Sym *s; /* Xsym */
int op; /* Xunop (unary), Xbiop (binary) */
Expr *l, *r;
};
typedef struct Litword Litword;
struct Litword
{
Value v;
Litword *next;
};
int ctab[] = {
Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused,
Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused,
Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused,
Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused,
Ignore, Exclam, '"', Unused, Letter, Letter, Amper, '\'',
'(', ')', Star, Plus, ',', Minus, Letter, Slash,
Digit, Digit, Digit, Digit, Digit, Digit, Digit, Digit,
Digit, Digit, Unused, ';', '<', Unused, '>', Unused,
Unused, Letter, Letter, Letter, Letter, Letter, Letter, Letter,
Letter, Letter, Letter, Letter, Letter, Letter, Letter, Letter,
Letter, Letter, Letter, Letter, Letter, Letter, Letter, Letter,
Letter, Letter, Letter, '[', Unused, ']', '^', Shift,
Unused, Letter, Letter, Letter, Letter, Letter, Letter, Letter,
Letter, Letter, Letter, Letter, Letter, Letter, Letter, Letter,
Letter, Letter, Letter, Letter, Letter, Letter, Letter, Letter,
Letter, Letter, Letter, Unused, Unused, Unused, Unused, Unused,
};
char *argv0;
char *filename;
char **files;
int nfiles;
FILE *infp, *tmpfp, *relfp, *lstfp;
char progtitle[MAXLINE];
char progsubtitle[MAXLINE];
int hadstart;
Value start;
char line[MAXLINE];
char curline[MAXLINE]; /* unmodified line for listing */
char *lp; /* pointer to input */
char *ops[MAXOPND]; /* tokenized operands */
int numops;
int lineno;
int pass2;
int error;
Sym symtab[MAXSYM];
Sym *dot;
Value absdot, reldot; /* saved values of dot */
int radix = 8;
Token peekt;
Value littabs[9]; /* memory locations of literal tables */
int nlit; /* current literal table */
int litlevel; /* literal nesting level; 0 = not inside literal */
Litword *curlit; /* currently active literal */
Litword *litlist; /* list of literals seen */
/*
* for REL output
*/
word item[01000000];
hword itemp;
hword itemtype, itemsz;
hword relocp;
word blockreloc;
int blocksz;
void statement(void);
/* Helpers */
void
err(int n, char *fmt, ...)
{
if(n == 0 && pass2)
return;
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "%s:%d: ", filename, lineno);
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
va_end(ap);
error |= n;
}
void
panic(char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
va_end(ap);
exit(1);
}
FILE*
mustopen(const char *name, const char *mode)
{
FILE *f;
if(f = fopen(name, mode), f == nil)
panic("couldn't open file: %s", name);
return f;
}
/* Append to literal and return position in list */
int
addw(Litword **list, Litword *lw)
{
int n;
Litword **p;
n = 0;
for(p = list; *p; p = &(*p)->next)
n++;
*p = lw;
return n;
}
/* Add literal */
/* TODO: don't add duplicates */
Value
addlit(Litword *l)
{
Value loc;
loc = littabs[nlit];
loc.val += addw(&litlist, l);
return loc;
}
/* Output/listing */
void
writeout(void)
{
hword i;
for(i = 0; i < itemp-1; i++){
writew(item[i], relfp);
// printf("\t\tDUMP: %06o %06o\n", left(item[i]), right(item[i]));
}
//printf("\n");
}
/* Start a REL block */
void
startblock(void)
{
if(blocksz){
blockreloc <<= 2*(18-blocksz);
item[relocp] = blockreloc;
relocp = itemp++;
blockreloc = 0;
blocksz = 0;
}
}
/* Put a relocated word into REL block */
void
putword(word w, int reloc)
{
item[itemp++] = w;
blockreloc = blockreloc<<2 | reloc;
blocksz++;
itemsz++;
if(blocksz == 18)
startblock();
}
/* Start a REL item and write out the last one */
void
startitem(hword it)
{
startblock();
if(itemsz){
item[0] = fw(itemtype, itemsz);
writeout();
}
itemtype = it;
itemsz = 0;
itemp = 1;
relocp = itemp++;
}
int lastline; /* last line number printed in listing */
void
listline(void)
{
if(lastline != lineno)
fprintf(lstfp, "%05d\t%s\n", lineno, curline);
else
fprintf(lstfp, "\n");
lastline = lineno;
}
word relbreak, absbreak;
Value lastdot;
/* Emit a relocated word at dot and advance dot */
void
putv(word w, int rel)
{
Litword *lw;
if(litlevel){
lw = malloc(sizeof(Litword));
lw->v = (Value){ w, rel };
lw->next = nil;
addw(&curlit, lw);
return;
}
if(pass2){
fprintf(lstfp, "%06o%c\t%06o%c%06o%c\t",
right(dot->v.val), dot->v.rel ? '\'' : ' ',
left(w), rel & 2 ? '\'' : ' ',
right(w), rel & 1 ? '\'' : ' ');
listline();
if(dot->v.rel != lastdot.rel ||
dot->v.val != lastdot.val+1){
startitem(Code);
putword(dot->v.val, dot->v.rel);
}
putword(w, rel);
}else{
// printf("\t%06o%c\t%06o%c%06o%c\n",
// right(dot->v.val), dot->v.rel ? '\'' : ' ',
// left(w), rel & 2 ? '\'' : ' ',
// right(w), rel & 1 ? '\'' : ' ');
}
lastdot = dot->v;
dot->v.val++;
if(dot->v.rel){
if(dot->v.val > relbreak)
relbreak = dot->v.val;
}else{
if(dot->v.val > absbreak)
absbreak = dot->v.val;
}
}
/* Input */
char*
getln(void)
{
int c;
char *s;
static char filen[MAXLINE];
if(pass2)
for(;;){
/* if no words were produced,
* list the original line here */
if(lastline == lineno-1){
fprintf(lstfp, "\t%14s\t", "");
listline();
}
c = getc(tmpfp);
if(c == 1){ /* filename */
s = filen;
while(c = getc(tmpfp), c)
*s++ = c;
*s = '\0';
filename = filen;
fprintf(lstfp, "\n\t%s\n\n", filename);
lineno = 0;
lastline = 0;
}else if(c == 2){ /* line */
s = line;
while(c = getc(tmpfp), c)
*s++ = c;
*s = '\0';
lineno++;
strcpy(curline, line);
return line;
}else if(c == 3) /* EOF */
return nil;
}
s = line;
lineno++;
while(c = getc(infp), c != EOF){
if(c == 037){ /* line continuation */
lineno++;
getc(infp);
continue;
}
if(c == '\n')
break;
if(s < &line[MAXLINE])
*s++ = c & 0177; /* force 7 bit */
}
if(s >= &line[MAXLINE])
err(0, "warning: line too long");
if(c == EOF)
return nil;
*s = '\0';
putc(2, tmpfp);
fputs(line, tmpfp);
putc(0, tmpfp);
return line;
}
void
skipwhite(void)
{
while(isspace(*lp))
lp++;
}
/* Symbols */
/* Just find symbol, or return nil.
* TODO: improve linear search... */
Sym*
findsym(word name)
{
Sym *s;
for(s = symtab; s < &symtab[MAXSYM]; s++)
if(s->name == name)
return s;
return nil;
}
/* Get symbol, add to table if not present */
Sym*
getsym(word name)
{
Sym *s;
s = findsym(name);
if(s == nil){
for(s = symtab; s < &symtab[MAXSYM]; s++)
if(s->name == 0)
goto found;
panic("symbol table full");
found:
s->name = name;
s->type = Undef;
s->v = (Value){ 0, 0 };
}
return s;
}
void
updateext(Sym *s, Value *v, int l)
{
Additive *a;
if(!pass2 || s == nil)
return;
if(l){
a = malloc(sizeof(Additive));
a->l = 1;
a->v = dot->v;
a->next = s->add;
s->add = a;
}else{
if(v->val == 0 && v->rel == 0){
/* add to request chain */
*v = s->v;
s->v = dot->v;
}else{
a = malloc(sizeof(Additive));
a->l = 0;
a->v = dot->v;
a->next = s->add;
s->add = a;
}
}
}
/* Token parsing */
/* shift uint64 by any amount */
uint64_t
shift(uint64_t i, int sh)
{
int left;
left = sh < 0;
if(left) sh = -sh;
if(sh > 64)
return 0;
else{
if(left)
return i << sh;
else
return i >> sh;
}
}
/* combined shift of two 36 bit words */
void
shiftc(word *a, word *b, int sh)
{
word aa, bb;
aa = shift(*a, sh) & FW;
bb = shift(*b, sh) & FW;
if(sh < 0){
*a = aa | shift(*b, sh+36) & FW;
*b = bb;
}else{
*b = bb | shift(*a, sh-36) & FW;
*a = aa;
}
}
/* get the integer and fractional parts of a double */
void
splitd(double d, word *integ, word *fract)
{
int s;
word e;
uint64_t m;
decompdbl(d, &s, &e, &m);
*integ = shift(m, 52 + 1023-e) & FW;
*fract = shift(m, 16 + 1023-e) & FW;
}
/* parse a potential number, fall back to symbol, advance line pointer */
Token
symnum(void)
{
Token t;
int neg, exp;
word n;
double f, e;
word fract, integ;
int isnum;
char *symp, symbuf[7];
int fixed;
int sgn;
int sh;
n = 0;
f = 0.0;
isnum = 0;
fixed = 0;
fract = 0;
if(lp[0] == '^' && lp[1] == 'F'){
fixed = 1;
lp += 2;
}
while(isdigit(*lp)){
n = n*radix + *lp-'0';
f = f*10.0 + *lp-'0';
isnum = 1;
lp++;
}
/* ignore leading digits if it is a symbol */
symp = lp;
/* try to parse a fractional number */
if(*lp == '.'){
lp++;
e = 1.0/10.0;
while(isdigit(*lp)){
f += (*lp-'0')*e;
e /= 10.0;
isnum = 1;
lp++;
}
if(isnum){
if(*lp == 'e' || *lp == 'E'){
lp++;
neg = 0;
if(*lp == '+')
lp++;
else if(*lp == '-'){
neg = 1;
lp++;
}
exp = 0;
while(isdigit(*lp)){
exp = exp*10 + *lp-'0';
lp++;
}
while(exp--)
if(neg)
f /= 10.0;
else
f *= 10.0;
}
splitd(f, &integ, &fract);
n = fixed ? integ : dtopdp(f);
}
}
/* bit shift */
if(isnum && *lp == 'B'){
/* TODO: actually a numeric expression */
lp++;
sh = 0;
sgn = 1;
if(*lp == '-'){
sgn = -1;
lp++;
}else if(*lp == '+')
lp++;
while(isdigit(*lp)){
sh = sh*10 + *lp-'0';
lp++;
}
sh *= sgn;
shiftc(&n, &fract, sh-35);
}
/* A number would end here, so it's a symbol */
if(!isnum || *lp && !isspace(*lp) && israd50(*lp)){
lp = symp;
symp = symbuf;
while(*lp && !isspace(*lp) && israd50(*lp)){
if(symp < &symbuf[6])
*symp++ = *lp;
lp++;
}
*symp = '\0';
t.type = Symbol;
t.s = getsym(sixbit(symbuf));
}else{
t.type = Word;
t.w = n;
}
return t;
}
word
character(char delim, int sz)
{
int mask;
word w;
char c;
w = 0;
mask = (1<<sz) - 1;
while(c = *lp++, c != delim){
if(c == '\\')
c = *lp++;
if(sz == 6)
c = ascii2sixbit(c);
if(c < 0)
continue;
c &= mask;
w = (w<<sz) | c;
}
if(sz == 7)
w &= 0377777777777;
return w;
}
Token
token(void)
{
Token t;
if(peekt.type != Unused){
t = peekt;
peekt.type = Unused;
return t;
}
skipwhite();
while(*lp)
switch(ctab[*lp]){
case Letter:
case Digit:
return symnum();
case '"':
lp++;
t.type = Word;
t.w = character('"', 7);
return t;
case '\'':
lp++;
t.type = Word;
t.w = character('\'', 6);
return t;
case ';':
while(*lp)
lp++;
t.type = Eol;
return t;
case '^':
lp++;
if(*lp == 'D')
t.type = Radix10;
else if(*lp == 'O')
t.type = Radix8;
else if(*lp == 'B')
t.type = Radix2;
else if(*lp == 'F'){
lp--;
return symnum();
}else{
err(1, "error: unknown Radix ^%c\n", *lp);
t.type = Radix8;
}
lp++;
return t;
case Unused:
err(0, "warning: unknown char %c", *lp);
/* fallthrough */
case Ignore:
lp++;
break;
default:
t.type = ctab[*lp++];
return t;
}
t.type = Eol;
return t;
}
/* Expressions */
Expr*
newexpr(int type)
{
Expr *e;
e = malloc(sizeof(Expr));
memset(e, 0, sizeof(Expr));
e->type = type;
return e;
}
void
freeexpr(Expr *e)
{
if(e->type >= Xunop)
freeexpr(e->r);
if(e->type == Xbiop)
freeexpr(e->l);
free(e);
}
int
isop(int op)
{
static int prectab[] = {
0, 0, /* Plus, Minus */
1, 1, /* Star, Slash */
2, 2, /* Exclam, Amper */
3, /* Shift */
};
if(op >= Plus && op <= Shift)
return prectab[op-Plus];
return -1;
}
/* Evaluate an expression AST, also record an additive external symbol.
* If pass is 1 or 2, the expression must be defined in pass 1 or 2 resp. */
Value
eval(Expr *e, Sym **ext, int pass)
{
int shft;
Value v, v2;
Sym *ex1, *ex2;
char name[8];
switch(e->type){
case Xval:
return e->v;
case Xsym:
if(!pass2 && pass == 1 && (e->s->type & Def) == 0 ||
pass2 && pass == 2 && e->s->type & Extern){
unsixbit(e->s->name, name);
err(1, "error: symbol %s must be defined", name);
return (Value){ 0, 0 };
}
if(e->s->type & Extern){
*ext = e->s;
return (Value){ 0, 0 };
}
return e->s->v;
case Xunop:
if(e->op == Minus){
v = eval(e->r, ext, pass);
if(*ext)
err(1, "error: Invalid use of external");
v.val = negw(v.val);
return v;
}
panic("expression operator");
case Xbiop:
ex1 = nil;
ex2 = nil;
v = eval(e->l, &ex1, pass);
v2 = eval(e->r, &ex2, pass);
if(ex1 == nil)
*ext = ex2;
else if(ex2 == nil)
*ext = ex1;
else
err(1, "error: Invalid use of external");
shft = v2.val;
if(isneg(v2.val))
shft = -negw(v2.val);
switch(e->op){
case Shift:
if(shft < 0)
v.val >>= -shft;
else
v.val <<= shft;
break;
case Exclam:
v.val |= v2.val;
break;
case Amper:
v.val &= v2.val;
break;
case Star:
v.val *= v2.val;
break;
case Slash:
v.val /= v2.val;
break;
case Plus:
v.val += v2.val;
break;
case Minus:
v.val -= v2.val;
if(v.rel == v2.rel)
v.rel = 0;
goto ret;
default:
panic("expression operator");
}
v.rel += v2.rel;
if(v.rel > 1){
err(1, "error: invalid expression type");
return (Value){ 0, 0 };
}
ret:
v.val &= 0777777777777;
return v;
}
panic("Doesn't happen\n");
}
/* Build an expression AST */
Expr*
parseexpr(int i)
{
Expr *e, *e2;
Token t;
Sym *s;
int oldradix;
Litword *litsav;
t = token();
if(t.type == Eol || t.type == ','){
peekt = t;
e = newexpr(Xval);
e->v = (Value){ 0, 0 };
return e;
}
/* unary and atoms */
if(i == 4){
if(t.type == Word){
e = newexpr(Xval);
e->v.val = t.w;
e->v.rel = 0;
}else if(t.type == Symbol){
e = newexpr(Xsym);
e->s = t.s;
}else if(t.type == Minus){
e = newexpr(Xunop);
e->op = Minus;
e->r = parseexpr(i);
}else if(t.type == Radix10 || t.type == Radix8 || t.type == Radix2){
oldradix = radix;
if(t.type == Radix10)
radix = 10;
else if(t.type == Radix8)
radix = 8;
else if(t.type == Radix2)
radix = 2;
e = parseexpr(i);
radix = oldradix;
}else if(t.type == '<'){
e = parseexpr(0);
t = token();
if(t.type != '>'){
err(1, "error: '>' expected");
peekt = t;
}
}else if(t.type == '['){
litlevel++;
litsav = curlit;
curlit = nil;
// TODO: more than one line
statement();
t = token();
if(t.type != ']'){
err(1, "error: ']' expected");
peekt = t;
}
e = newexpr(Xval);
e->v = addlit(curlit);
curlit = litsav;
litlevel--;
}else{
err(1, "error: expression syntax %o", t.type);
return nil;
}
return e;
}
/* n-ary expressions */
if(t.type == Word || t.type == Symbol ||
t.type == Minus || t.type == '<' || t.type == '[' ||
t.type == Radix10 || t.type == Radix8 || t.type == Radix2 ){
peekt = t;
e = parseexpr(i+1);
}else{
err(1, "error: expression syntax %o", t.type);
return nil;
}
for(t = token(); isop(t.type) == i; t = token()){
e2 = newexpr(Xbiop);
e2->op = t.type;
e2->l = e;
e2->r = parseexpr(i+1);
e = e2;
}
peekt = t;
return e;
}
void
printexpr(Expr *e)
{
char name[8];
char *opnames[] = {
"+", "-", "*", "/", "!", "&", "_", "^D", "^O", "^B"
};
if(e->type == Xval)
printf("%lo %d", e->v.val, e->v.rel);
else if(e->type == Xsym){
unsixbit(e->s->name, name);
printf("%s", name);
}else if(e->type == Xunop){
printf("(%s ", opnames[e->op - Plus]);
printexpr(e->r);
printf(")");
}else if(e->type == Xbiop){
printf("(");
printexpr(e->l);
printf(" %s ", opnames[e->op - Plus]);
printexpr(e->r);
printf(")");
}
}
/* Parse and evaluate an expression */
Value
expr(int pass, Sym **s)
{
/* - 5
* ^D ^O ^B ^L 4
* B _ 3
* logical ! & 2
* mul/div * / 1
* add/sub + - 0
* <>
*/
Expr *e;
Sym *ext;
Value v;
ext = nil;
e = parseexpr(0);
v = eval(e, &ext, pass);
if(s)
*s = ext;
freeexpr(e);
return v;
}
/* Statements */
/* split operands separated by ',' starting at lp; remove whitespace */
void
splitop(void)
{
int nparn;
numops = 0;
skipwhite();
if(*lp == ';' || *lp == '\0')
return;
/* this routine is terrible, null everything
* we don't care about and drag along pointers
* to the beginnig of operands */
ops[numops++] = lp;
for(; *lp && *lp != ';'; lp++){
if(isspace(*lp))
*lp = '\0';
else if(*lp == ','){
*lp = '\0';
ops[numops++] = lp;
if(numops >= MAXOPND){
err(0, "warning: operand overflow");
return;
}
}else if(*lp == '('){
/* read parenthesized operands as one */
if(*ops[numops-1] == '\0')
ops[numops-1] = lp;
lp++;
nparn = 1;
for(; *lp && *lp != ';' && nparn != 0; lp++)
if(*lp == '(')
nparn++;
else if(*lp == ')')
nparn--;
lp--;
}else if(*lp == '['){
/* same as above */
if(*ops[numops-1] == '\0')
ops[numops-1] = lp;
lp++;
nparn = 1;
for(; *lp && *lp != ';' && nparn != 0; lp++)
if(*lp == '[')
nparn++;
else if(*lp == ']')
nparn--;
lp--;
}else{
if(*ops[numops-1] == '\0')
ops[numops-1] = lp;
}
}
*lp = '\0';
}
/* parse an effective address of the form @Y(X) */
Value
ea(void)
{
word w;
Token t;
Sym *ext;
Value x, y;
w = 0;
if(*lp == '@'){
lp++;
w = 0000020000000;
}
ext = nil;
y = expr(0, &ext);
updateext(ext, &y, 0);
if(left(y.val))
err(0, "warning: address truncated");
w |= right(y.val);
t = token();
if(t.type == '('){
/* TODO: this is probably a statement */
x = expr(2, nil);
if(t = token(), t.type != ')'){
err(1, "error: ')' expected");
peekt = t;
}
if(x.rel)
err(0, "warning: index relocation ignored");
w |= fw(right(x.val) & 017, left(x.val));
}else
peekt = t;
return (Value){ w, y.rel };
}
/* Primary and IO instruction statement */
void
opline(word w, int io)
{
char *acp, *ep;
Sym *ext;
Value ac, x, y;
Token t;
int i;
splitop();
/*
* OP AC,
* OP ,E
* OP E
* E: @Y(X)
*/
switch(numops){
case 0:
acp = "";
ep = "";
break;
case 1:
acp = "";
ep = ops[0];
break;
default:
err(0, "warning: too many operands: %d", numops);
case 2:
acp = ops[0];
ep = ops[1];
}
lp = acp;
peekt.type = Unused;
ac = expr(2, nil);
i = 0;
lp = ep;
peekt.type = Unused;
if(*lp == '@'){
lp++;
i = 1;
}
t = token();
peekt = t;
if(peekt.type != '('){
ext = nil;
y = expr(0, &ext);
updateext(ext, &y, 0);
}else
y = (Value){ 0, 0 };
x = (Value){ 0, 0 };
t = token();
if(t.type == '('){
/* TODO: this is probably a statement */
x = expr(2, nil);
t = token();
if(t.type != ')')
err(1, "error: ')' expected");
x.val = fw(right(x.val), left(x.val));
}
/* TODO: is this correct or should we mask out some stuff? */
if(io){
w += (ac.val&0774) << 24;
}else
w += (ac.val&017) << 23;
if(ac.rel)
err(0, "warning: AC relocation ignored");
if(i)
w |= 0000020000000;
w = fw(left(w), right(w)+right(y.val));
/* TODO: really warn about this? */
// if(left(y.val))
// err(0, "warning: address too large");
w = fw(left(w)+left(x.val), right(w)+right(x.val));
if(x.rel)
err(0, "warning: X relocation ignored");
putv(w, y.rel);
}
/*
* Pseudo Ops
*/
void
internOp(void)
{
Sym *s;
int i;
if(pass2)
return;
splitop();
for(i = 0; i < numops; i++){
s = getsym(sixbit(ops[i]));
if(s->type >= Operator || s->type & Extern)
err(0, "warning: can't INTERN symbol %s", ops[i]);
else
s->type |= Intern;
}
}
void
externOp(void)
{
Sym *s;
int i;
if(pass2)
return;
splitop();
for(i = 0; i < numops; i++){
s = getsym(sixbit(ops[i]));
if(s->type >= Operator || s->type & Intern)
err(0, "warning: can't EXTERN symbol %s", ops[i]);
else
s->type |= Extern;
}
}
void
title(void)
{
skipwhite();
strncpy(progtitle, lp, MAXLINE);
}
void
subttl(void)
{
skipwhite();
strncpy(progsubtitle, lp, MAXLINE);
}
void
radixOp(void)
{
int r;
Value v;
skipwhite();
if(*lp == '\0' || *lp == ';')
return;
r = radix;
radix = 10;
v = expr(1, nil);
radix = r;
if(v.val < 2 || v.val > 10)
err(1, "error: invalid radix %d", v.val);
else
radix = v.val;
}
void
endOp(void)
{
skipwhite();
start = expr(2, nil);
hadstart = 1;
}
void
litOp(void)
{
Litword *l, *next;
if(litlist)
littabs[nlit] = dot->v;
for(l = litlist; l; l = next){
next = l->next;
// printf("L: %012lo %d\n", l->v.val, l->v.rel);
putv(l->v.val, l->v.rel);
free(l);
}
if(litlist)
nlit++;
litlist = nil;
}
void
expOp(void)
{
Value v;
Token t;
Sym *ext;
do{
ext = nil;
v = expr(0, &ext);
updateext(ext, &v, 0);
putv(v.val, v.rel);
}while(t = token(), t.type == ',');
}
void
decOp(void)
{
int r;
r = radix;
radix = 10;
expOp();
radix = r;
}
void
octOp(void)
{
int r;
r = radix;
radix = 8;
expOp();
radix = r;
}
void
byteOp(void)
{
Token t;
word b, w;
int sz;
int mask;
int r;
int pos;
w = 0;
pos = 36;
sz = 6;
mask = 077;
for(;;){
/* byte size change */
if(t = token(), t.type == '('){
r = radix;
radix = 10;
sz = expr(0, nil).val;
if(t = token(), t.type != ')'){
err(1, "error: ')' expected");
peekt = t;
}
radix = r;
mask = (1<<sz) - 1;
}else
peekt = t;
/* byte */
b = expr(2, nil).val & mask;
pos -= sz;
if(pos < 0){
putv(w, 0);
w = 0;
pos = 36 - sz;
}
w |= b << pos;
t = token();
if(t.type == '(')
peekt = t;
else if(t.type != ',')
break;
}
putv(w, 0);
}
void
xwd(void)
{
Token t;
Value l, r;
Sym *exl, *exr;
exl = nil;
exr = nil;
l = (Value){ 0, 0 };
r = (Value){ 0, 0 };
l = expr(0, &exl);
updateext(exl, &l, 1);
if(t = token(), t.type == ','){
r = expr(0, &exr);
updateext(exr, &r, 0);
}else
err(0, "warning: right operand missing");
putv(fw(right(l.val), right(r.val)), (l.rel<<1) | r.rel);
}
void
iowd(void)
{
Token t;
Value l, r;
Sym *exl, *exr;
exl = nil;
exr = nil;
l = (Value){ 0, 0 };
r = (Value){ 0, 0 };
l = expr(2, &exl);
if(t = token(), t.type == ','){
r = expr(0, &exr);
updateext(exr, &r, 0);
}else
err(0, "warning: right operand missing");
putv(fw(right(-l.val), right(r.val-1)), (l.rel<<1) | r.rel);
}
void
pointOp(void)
{
Value v;
Token t;
word sz, pos;
int r;
peekt.type = Unused;
r = radix;
radix = 10;
sz = expr(2, nil).val & 077;
radix = r;
if(t = token(), t.type != ','){
peekt = t;
err(2, "error: ',' expected");
}
v = ea();
pos = 044;
if(t = token(), t.type == ','){
r = radix;
radix = 10;
pos = expr(2, nil).val & 077;
radix = r;
}else
peekt = t;
v.val |= sz<<24 | pos<<30;
putv(v.val, v.rel);
}
int asciiz;
void
ascii(void)
{
char delim;
word w;
int i;
skipwhite();
delim = *lp++;
if(delim == ';' || delim == '\0'){
putv(0, 0);
return;
}
w = 0;
i = 0;
for(; *lp != delim; lp++){
/* This is a hack since LF is not part of the line
* but we have to output it in multiline strings */
if(*lp == '\0')
*lp = '\n';
w = (w<<7) | *lp;
if(++i == 5){
w <<= 1;
putv(w, 0);
i = 0;
w = 0;
}
/* load the next line when we recognized EOL earlier */
if(*lp == '\n'){
lp = getln();
if(lp == nil){
err(1, "error: unexpected EOF");
break;
}
lp--;
}
}
if(asciiz){
i++;
w <<= 7;
}
w <<= 36-i*7;
if(w || asciiz)
putv(w, 0);
}
void
asciz(void)
{
asciiz = 1;
ascii();
asciiz = 0;
}
void
sixbitOp(void)
{
char delim;
char c;
word w;
int i;
skipwhite();
delim = *lp++;
if(delim == ';' || delim == '\0'){
putv(0, 0);
return;
}
w = 0;
i = 0;
for(; *lp && *lp != delim; lp++){
c = ascii2sixbit(*lp);
if(c < 0){
err(0, "warning: ignoring non-SIXBIT char %c", *lp);
continue;
}
w = (w<<6) | c;
if(++i == 6){
putv(w, 0);
i = 0;
w = 0;
}
}
if(*lp != delim)
err(1, "error: '%c' expected", delim);
w <<= 36-i*6;
if(w)
putv(w, 0);
}
void
blockOp(void)
{
Value v;
skipwhite();
v = expr(1, nil);
if(v.rel)
err(1, "error: non-absolute block size");
else
dot->v.val += v.val;
}
void
locOp(void)
{
skipwhite();
if(dot->v.rel) reldot = dot->v;
else absdot = dot->v;
if(*lp && *lp != ';'){
dot->v = expr(1, nil);
dot->v.val &= 0777777;
dot->v.rel = 0;
}else
dot->v = absdot;
}
void
relocOp(void)
{
skipwhite();
if(dot->v.rel) reldot = dot->v;
else absdot = dot->v;
if(*lp && *lp != ';'){
dot->v = expr(1, nil);
dot->v.val &= 0777777;
dot->v.rel = 1;
}else
dot->v = reldot;
}
void
statement(void)
{
Token t;
Value val;
int type;
Sym *s, *ext;
char name[8];
while(t = token(), t.type != Eol)
switch(t.type){
case Symbol:
s = t.s;
unsixbit(s->name, name);
if(*lp == ':'){
/* label:
* : label
* :! label hide
* :: label internal
* ::! label internal hide
*/
lp++;
type = Label | Local | Def;
if(*lp == ':'){
lp++;
type |= Intern;
}
if(*lp == '!'){
lp++;
type |= Hide;
}
if(!pass2){
if(s->type & Def){
err(1, "error: redefinition of %s", name);
return;
}
s->type = (s->type&(Intern|Extern|Hide)) | type;
s->v = dot->v;
}
}else if(*lp == '='){
/* assignment:
* = assign
* == assign hide
* =: assign internal
* ==: assign internal hide
*/
lp++;
type = Local | Def;
if(*lp == '='){
lp++;
type |= Hide;
}
if(*lp == ':'){
lp++;
type |= Intern;
}
val = expr(1, nil);
if(!pass2){
if(s->type & Label){
err(1, "error: redefinition of %s", name);
return;
}
s->type = (s->type&(Intern|Extern|Hide)) | type;
s->v = val;
}
}else if(s->type == Operator){
unsixbit(s->name, name);
opline(s->v.val, 0);
return;
}else if(s->type == IoOperator){
unsixbit(s->name, name);
opline(s->v.val, 1);
return;
}else if(s->type == Pseudo){
s->f();
return;
}else{
err(1, "error: unknown operator %s", name);
return;
}
break;
case ',':
return;
case Word:
case Radix10: case Radix8: case Radix2:
case Minus:
peekt = t;
ext = nil;
val = expr(0, &ext);
updateext(ext, &val, 0);
putv(val.val, val.rel);
break;
case ']':
peekt = t;
return;
default:
err(0, "unknown token %c(%o)", t.type, t.type);
}
}
void
assemble(void)
{
while(lp = getln()){
peekt.type = Unused;
statement();
}
}
void
resetdot(void)
{
dot = getsym(sixbit("."));
dot->type = Local | Def | Hide;
absdot = (Value){ 0, 0 };
reldot = (Value){ 0, 1 };
dot->v = reldot;
lastdot = dot->v;
/* invalidate lastdot */
lastdot.val = 0777777777777;
}
void
checkundef(int glob)
{
char name[8];
Sym *s;
for(s = symtab; s < &symtab[MAXSYM]; s++)
if(s->name &&
s->type != Operator && s->type != IoOperator && s->type != Pseudo){
unsixbit(s->name, name);
if(s->type == Undef){
// if(glob)
// s->type |= Extern;
// else
err(1, "undefined symbol: %s\n", name);
}
}
}
int
symcmp(const void *a, const void *b)
{
char s1[8], s2[8];
unsixbit((*(Sym**)a)->name, s1);
unsixbit((*(Sym**)b)->name, s2);
return strcmp(s1, s2);
}
void
writesymtab(void)
{
hword l, r;
char name[8];
Sym *s;
Sym *sortlist[MAXSYM];
Additive *add;
word rad;
int i, nsym;
int type;
nsym = 0;
for(s = symtab; s < &symtab[MAXSYM]; s++){
if(s->name == 0 || s == dot ||
s->type == Operator || s->type == IoOperator || s->type == Pseudo)
continue;
sortlist[nsym++] = s;
}
qsort(sortlist, nsym, sizeof(Sym*), symcmp);
startitem(Symbols);
fprintf(lstfp, "\nSYMBOL TABLE\n\n");
for(i = 0; i < nsym; i++){
s = sortlist[i];
if(s->type & Extern &&
s->v.val == 0 && s->v.rel == 0)
continue;
type = 0;
if(s->type & Intern)
type = SymGlobal;
else if(s->type & Local)
type = SymLocal;
if(s->type & Hide)
type |= 040;
if(s->type & Extern)
type = SymUndef;
unsixbit(s->name, name);
l = left(s->v.val);
r = right(s->v.val);
fprintf(lstfp, "%s%6s", name, "");
if(l)
fprintf(lstfp, "%06o", l);
else
fprintf(lstfp, "%6s", "");
fprintf(lstfp, "%06o%c ", r, s->v.rel ? '\'' : ' ');
if(s->type & Extern)
fprintf(lstfp, "EXT");
if(s->type & Intern)
fprintf(lstfp, "INT");
fprintf(lstfp, "\n");
rad = rad50(type, name);
putword(rad, 0);
putword(fw(0, right(s->v.val)), s->v.rel);
//printf("%s %3o: %012lo %o\n", name, s->type, s->v.val, s->v.rel);
for(add = s->add; add; add = add->next){
//printf(" %c %06o\n", "rl"[add->l], right(add->v.val));
putword(rad, 0);
putword(fw(0400000 | (add->l ? 0200000 : 0), right(add->v.val)),
add->v.rel);
}
}
}
/* Basic program flow */
void
cleanup(void)
{
remove("a.tmp");
}
void
usage(void)
{
panic("usage: %s", argv0);
}
void initsymtab(void);
int
main(int argc, char *argv[])
{
int i;
char *outfile;
char *lstfile;
outfile = "a.rel";
lstfile = "/dev/null";
ARGBEGIN{
case 'o':
outfile = EARGF(usage());
break;
case 'l':
lstfile = EARGF(usage());
break;
default:
usage();
break;
}ARGEND;
nfiles = argc;
files = argv;
tmpfp = mustopen("a.tmp", "w");
atexit(cleanup);
initsymtab();
resetdot();
pass2 = 0;
if(argc){
for(i = 0; i < argc; i++){
filename = argv[i];
infp = mustopen(filename, "r");
putc(1, tmpfp);
fputs(filename, tmpfp);
putc(0, tmpfp);
lineno = 0;
assemble();
fclose(infp);
}
}else{
filename = "stdin";
infp = stdin;
putc(1, tmpfp);
fputs(filename, tmpfp);
putc(0, tmpfp);
lineno = 0;
assemble();
}
litOp();
putc(3, tmpfp);
fclose(tmpfp);
checkundef(1);
if(error & 1)
panic("Error\n*****");
lstfp = mustopen(lstfile, "w");
relfp = mustopen(outfile, "w");
tmpfp = mustopen("a.tmp", "r");
resetdot();
nlit = 0;
pass2 = 1;
radix = 8;
// printf("\n PASS2\n\n");
startitem(Name);
putword(rad50(0, progtitle), 0);
assemble();
litOp();
writesymtab();
if(hadstart){
startitem(Start);
putword(right(start.val), start.rel);
}
startitem(End);
putword(right(relbreak), 1);
putword(right(absbreak), 0);
startitem(Nothing);
fclose(tmpfp);
fclose(relfp);
fclose(lstfp);
return 0;
}
typedef struct Op Op;
struct Op
{
const char *name;
int type;
word val;
};
typedef struct Ps Ps;
struct Ps
{
const char *name;
void (*f)(void);
};
extern Op oplist[];
extern Ps pslist[];
void
initsymtab(void)
{
Op *op;
Ps *ps;
Sym *s;
for(op = oplist; op->name[0]; op++){
s = getsym(sixbit(op->name));
s->type = op->type;
s->v.val = op->val;
s->v.rel = 0;
}
for(ps = pslist; ps->name[0]; ps++){
s = getsym(sixbit(ps->name));
s->type = Pseudo;
s->f = ps->f;
}
}
Ps pslist[] = {
{ "INTERN", internOp },
{ "EXTERN", externOp },
{ "TITLE", title },
{ "SUBTTL", subttl },
{ "RADIX", radixOp },
{ "END", endOp },
{ "LIT", litOp },
{ "EXP", expOp },
{ "DEC", decOp },
{ "OCT", octOp },
{ "BYTE", byteOp },
{ "XWD", xwd },
{ "IOWD", iowd },
{ "POINT", pointOp },
{ "ASCII", ascii },
{ "ASCIZ", asciz },
{ "SIXBIT", sixbitOp },
{ "BLOCK", blockOp },
{ "LOC", locOp },
{ "RELOC", relocOp },
/*
RADIX50 SQUOZE
INTEGER
ARRAY
ENTRY
OPDEF
*/
{ "", nil }
};
Op oplist[] = {
{ "Z", Operator, 0 },
{ "UUO1", Operator, 0001000000000 },
{ "UUO2", Operator, 0002000000000 },
{ "FSC", Operator, 0132000000000 },
{ "IBP", Operator, 0133000000000 },
{ "ILDB", Operator, 0134000000000 },
{ "LDB", Operator, 0135000000000 },
{ "IDPB", Operator, 0136000000000 },
{ "DPB", Operator, 0137000000000 },
{ "FAD", Operator, 0140000000000 },
{ "FADL", Operator, 0141000000000 },
{ "FADM", Operator, 0142000000000 },
{ "FADB", Operator, 0143000000000 },
{ "FADR", Operator, 0144000000000 },
{ "FADRL", Operator, 0145000000000 },
{ "FADRM", Operator, 0146000000000 },
{ "FADRB", Operator, 0147000000000 },
{ "FSB", Operator, 0150000000000 },
{ "FSBL", Operator, 0151000000000 },
{ "FSBM", Operator, 0152000000000 },
{ "FSBB", Operator, 0153000000000 },
{ "FSBR", Operator, 0154000000000 },
{ "FSBRL", Operator, 0155000000000 },
{ "FSBRM", Operator, 0156000000000 },
{ "FSBRB", Operator, 0157000000000 },
{ "FMP", Operator, 0160000000000 },
{ "FMPL", Operator, 0161000000000 },
{ "FMPM", Operator, 0162000000000 },
{ "FMPB", Operator, 0163000000000 },
{ "FMPR", Operator, 0164000000000 },
{ "FMPRL", Operator, 0165000000000 },
{ "FMPRM", Operator, 0166000000000 },
{ "FMPRB", Operator, 0167000000000 },
{ "FDV", Operator, 0170000000000 },
{ "FDVL", Operator, 0171000000000 },
{ "FDVM", Operator, 0172000000000 },
{ "FDVB", Operator, 0173000000000 },
{ "FDVR", Operator, 0174000000000 },
{ "FDVRL", Operator, 0175000000000 },
{ "FDVRM", Operator, 0176000000000 },
{ "FDVRB", Operator, 0177000000000 },
{ "MOVE", Operator, 0200000000000 },
{ "MOVEI", Operator, 0201000000000 },
{ "MOVEM", Operator, 0202000000000 },
{ "MOVES", Operator, 0203000000000 },
{ "MOVS", Operator, 0204000000000 },
{ "MOVSI", Operator, 0205000000000 },
{ "MOVSM", Operator, 0206000000000 },
{ "MOVSS", Operator, 0207000000000 },
{ "MOVN", Operator, 0210000000000 },
{ "MOVNI", Operator, 0211000000000 },
{ "MOVNM", Operator, 0212000000000 },
{ "MOVNS", Operator, 0213000000000 },
{ "MOVM", Operator, 0214000000000 },
{ "MOVMI", Operator, 0215000000000 },
{ "MOVMM", Operator, 0216000000000 },
{ "MOVMS", Operator, 0217000000000 },
{ "IMUL", Operator, 0220000000000 },
{ "IMULI", Operator, 0221000000000 },
{ "IMULM", Operator, 0222000000000 },
{ "IMULB", Operator, 0223000000000 },
{ "MUL", Operator, 0224000000000 },
{ "MULI", Operator, 0225000000000 },
{ "MULM", Operator, 0226000000000 },
{ "MULB", Operator, 0227000000000 },
{ "IDIV", Operator, 0230000000000 },
{ "IDIVI", Operator, 0231000000000 },
{ "IDIVM", Operator, 0232000000000 },
{ "IDIVB", Operator, 0233000000000 },
{ "DIV", Operator, 0234000000000 },
{ "DIVI", Operator, 0235000000000 },
{ "DIVM", Operator, 0236000000000 },
{ "DIVB", Operator, 0237000000000 },
{ "ASH", Operator, 0240000000000 },
{ "ROT", Operator, 0241000000000 },
{ "LSH", Operator, 0242000000000 },
{ "ASHC", Operator, 0244000000000 },
{ "ROTC", Operator, 0245000000000 },
{ "LSHC", Operator, 0246000000000 },
{ "EXCH", Operator, 0250000000000 },
{ "BLT", Operator, 0251000000000 },
{ "AOBJP", Operator, 0252000000000 },
{ "AOBJN", Operator, 0253000000000 },
{ "JRST", Operator, 0254000000000 },
{ "JFCL", Operator, 0255000000000 },
{ "XCT", Operator, 0256000000000 },
{ "PUSHJ", Operator, 0260000000000 },
{ "PUSH", Operator, 0261000000000 },
{ "POP", Operator, 0262000000000 },
{ "POPJ", Operator, 0263000000000 },
{ "JSR", Operator, 0264000000000 },
{ "JSP", Operator, 0265000000000 },
{ "JSA", Operator, 0266000000000 },
{ "JRA", Operator, 0267000000000 },
{ "ADD", Operator, 0270000000000 },
{ "ADDI", Operator, 0271000000000 },
{ "ADDM", Operator, 0272000000000 },
{ "ADDB", Operator, 0273000000000 },
{ "SUB", Operator, 0274000000000 },
{ "SUBI", Operator, 0275000000000 },
{ "SUBM", Operator, 0276000000000 },
{ "SUBB", Operator, 0277000000000 },
{ "CAI", Operator, 0300000000000 },
{ "CAIL", Operator, 0301000000000 },
{ "CAIE", Operator, 0302000000000 },
{ "CAILE", Operator, 0303000000000 },
{ "CAIA", Operator, 0304000000000 },
{ "CAIGE", Operator, 0305000000000 },
{ "CAIN", Operator, 0306000000000 },
{ "CAIG", Operator, 0307000000000 },
{ "CAM", Operator, 0310000000000 },
{ "CAML", Operator, 0311000000000 },
{ "CAME", Operator, 0312000000000 },
{ "CAMLE", Operator, 0313000000000 },
{ "CAMA", Operator, 0314000000000 },
{ "CAMGE", Operator, 0315000000000 },
{ "CAMN", Operator, 0316000000000 },
{ "CAMG", Operator, 0317000000000 },
{ "JUMP", Operator, 0320000000000 },
{ "JUMPL", Operator, 0321000000000 },
{ "JUMPE", Operator, 0322000000000 },
{ "JUMPLE",Operator, 0323000000000 },
{ "JUMPA", Operator, 0324000000000 },
{ "JUMPGE",Operator, 0325000000000 },
{ "JUMPN", Operator, 0326000000000 },
{ "JUMPG", Operator, 0327000000000 },
{ "SKIP", Operator, 0330000000000 },
{ "SKIPL", Operator, 0331000000000 },
{ "SKIPE", Operator, 0332000000000 },
{ "SKIPLE",Operator, 0333000000000 },
{ "SKIPA", Operator, 0334000000000 },
{ "SKIPGE",Operator, 0335000000000 },
{ "SKIPN", Operator, 0336000000000 },
{ "SKIPG", Operator, 0337000000000 },
{ "AOJ", Operator, 0340000000000 },
{ "AOJL", Operator, 0341000000000 },
{ "AOJE", Operator, 0342000000000 },
{ "AOJLE", Operator, 0343000000000 },
{ "AOJA", Operator, 0344000000000 },
{ "AOJGE", Operator, 0345000000000 },
{ "AOJN", Operator, 0346000000000 },
{ "AOJG", Operator, 0347000000000 },
{ "AOS", Operator, 0350000000000 },
{ "AOSL", Operator, 0351000000000 },
{ "AOSE", Operator, 0352000000000 },
{ "AOSLE", Operator, 0353000000000 },
{ "AOSA", Operator, 0354000000000 },
{ "AOSGE", Operator, 0355000000000 },
{ "AOSN", Operator, 0356000000000 },
{ "AOSG", Operator, 0357000000000 },
{ "SOJ", Operator, 0360000000000 },
{ "SOJL", Operator, 0361000000000 },
{ "SOJE", Operator, 0362000000000 },
{ "SOJLE", Operator, 0363000000000 },
{ "SOJA", Operator, 0364000000000 },
{ "SOJGE", Operator, 0365000000000 },
{ "SOJN", Operator, 0366000000000 },
{ "SOJG", Operator, 0367000000000 },
{ "SOS", Operator, 0370000000000 },
{ "SOSL", Operator, 0371000000000 },
{ "SOSE", Operator, 0372000000000 },
{ "SOSLE", Operator, 0373000000000 },
{ "SOSA", Operator, 0374000000000 },
{ "SOSGE", Operator, 0375000000000 },
{ "SOSN", Operator, 0376000000000 },
{ "SOSG", Operator, 0377000000000 },
{ "SETZ", Operator, 0400000000000 },
{ "SETZI", Operator, 0401000000000 },
{ "SETZM", Operator, 0402000000000 },
{ "SETZB", Operator, 0403000000000 },
{ "AND", Operator, 0404000000000 },
{ "ANDI", Operator, 0405000000000 },
{ "ANDM", Operator, 0406000000000 },
{ "ANDB", Operator, 0407000000000 },
{ "ANDCA", Operator, 0410000000000 },
{ "ANDCAI",Operator, 0411000000000 },
{ "ANDCAM",Operator, 0412000000000 },
{ "ANDCAB",Operator, 0413000000000 },
{ "SETM", Operator, 0414000000000 },
{ "SETMI", Operator, 0415000000000 },
{ "SETMM", Operator, 0416000000000 },
{ "SETMB", Operator, 0417000000000 },
{ "ANDCM", Operator, 0420000000000 },
{ "ANDCMI",Operator, 0421000000000 },
{ "ANDCMM",Operator, 0422000000000 },
{ "ANDCMB",Operator, 0423000000000 },
{ "SETA", Operator, 0424000000000 },
{ "SETAI", Operator, 0425000000000 },
{ "SETAM", Operator, 0426000000000 },
{ "SETAB", Operator, 0427000000000 },
{ "XOR", Operator, 0430000000000 },
{ "XORI", Operator, 0431000000000 },
{ "XORM", Operator, 0432000000000 },
{ "XORB", Operator, 0433000000000 },
{ "IOR", Operator, 0434000000000 },
{ "IORI", Operator, 0435000000000 },
{ "IORM", Operator, 0436000000000 },
{ "IORB", Operator, 0437000000000 },
{ "ANDCB", Operator, 0440000000000 },
{ "ANDCBI",Operator, 0441000000000 },
{ "ANDCBM",Operator, 0442000000000 },
{ "ANDCBB",Operator, 0443000000000 },
{ "EQV", Operator, 0444000000000 },
{ "EQVI", Operator, 0445000000000 },
{ "EQVM", Operator, 0446000000000 },
{ "EQVB", Operator, 0447000000000 },
{ "SETCA", Operator, 0450000000000 },
{ "SETCAI",Operator, 0451000000000 },
{ "SETCAM",Operator, 0452000000000 },
{ "SETCAB",Operator, 0453000000000 },
{ "ORCA", Operator, 0454000000000 },
{ "ORCAI", Operator, 0455000000000 },
{ "ORCAM", Operator, 0456000000000 },
{ "ORCAB", Operator, 0457000000000 },
{ "SETCM", Operator, 0460000000000 },
{ "SETCMI",Operator, 0461000000000 },
{ "SETCMM",Operator, 0462000000000 },
{ "SETCMB",Operator, 0463000000000 },
{ "ORCM", Operator, 0464000000000 },
{ "ORCMI", Operator, 0465000000000 },
{ "ORCMM", Operator, 0466000000000 },
{ "ORCMB", Operator, 0467000000000 },
{ "ORCB", Operator, 0470000000000 },
{ "ORCBI", Operator, 0471000000000 },
{ "ORCBM", Operator, 0472000000000 },
{ "ORCBB", Operator, 0473000000000 },
{ "SETO", Operator, 0474000000000 },
{ "SETOI", Operator, 0475000000000 },
{ "SETOM", Operator, 0476000000000 },
{ "SETOB", Operator, 0477000000000 },
{ "HLL", Operator, 0500000000000 },
{ "HLLI", Operator, 0501000000000 },
{ "HLLM", Operator, 0502000000000 },
{ "HLLS", Operator, 0503000000000 },
{ "HRL", Operator, 0504000000000 },
{ "HRLI", Operator, 0505000000000 },
{ "HRLM", Operator, 0506000000000 },
{ "HRLS", Operator, 0507000000000 },
{ "HLLZ", Operator, 0510000000000 },
{ "HLLZI", Operator, 0511000000000 },
{ "HLLZM", Operator, 0512000000000 },
{ "HLLZS", Operator, 0513000000000 },
{ "HRLZ", Operator, 0514000000000 },
{ "HRLZI", Operator, 0515000000000 },
{ "HRLZM", Operator, 0516000000000 },
{ "HRLZS", Operator, 0517000000000 },
{ "HLLO", Operator, 0520000000000 },
{ "HLLOI", Operator, 0521000000000 },
{ "HLLOM", Operator, 0522000000000 },
{ "HLLOS", Operator, 0523000000000 },
{ "HRLO", Operator, 0524000000000 },
{ "HRLOI", Operator, 0525000000000 },
{ "HRLOM", Operator, 0526000000000 },
{ "HRLOS", Operator, 0527000000000 },
{ "HLLE", Operator, 0530000000000 },
{ "HLLEI", Operator, 0531000000000 },
{ "HLLEM", Operator, 0532000000000 },
{ "HLLES", Operator, 0533000000000 },
{ "HRLE", Operator, 0534000000000 },
{ "HRLEI", Operator, 0535000000000 },
{ "HRLEM", Operator, 0536000000000 },
{ "HRLES", Operator, 0537000000000 },
{ "HRR", Operator, 0540000000000 },
{ "HRRI", Operator, 0541000000000 },
{ "HRRM", Operator, 0542000000000 },
{ "HRRS", Operator, 0543000000000 },
{ "HLR", Operator, 0544000000000 },
{ "HLRI", Operator, 0545000000000 },
{ "HLRM", Operator, 0546000000000 },
{ "HLRS", Operator, 0547000000000 },
{ "HRRZ", Operator, 0550000000000 },
{ "HRRZI", Operator, 0551000000000 },
{ "HRRZM", Operator, 0552000000000 },
{ "HRRZS", Operator, 0553000000000 },
{ "HLRZ", Operator, 0554000000000 },
{ "HLRZI", Operator, 0555000000000 },
{ "HLRZM", Operator, 0556000000000 },
{ "HLRZS", Operator, 0557000000000 },
{ "HRRO", Operator, 0560000000000 },
{ "HRROI", Operator, 0561000000000 },
{ "HRROM", Operator, 0562000000000 },
{ "HRROS", Operator, 0563000000000 },
{ "HLRO", Operator, 0564000000000 },
{ "HLROI", Operator, 0565000000000 },
{ "HLROM", Operator, 0566000000000 },
{ "HLROS", Operator, 0567000000000 },
{ "HRRE", Operator, 0570000000000 },
{ "HRREI", Operator, 0571000000000 },
{ "HRREM", Operator, 0572000000000 },
{ "HRRES", Operator, 0573000000000 },
{ "HLRE", Operator, 0574000000000 },
{ "HLREI", Operator, 0575000000000 },
{ "HLREM", Operator, 0576000000000 },
{ "HLRES", Operator, 0577000000000 },
{ "TRN", Operator, 0600000000000 },
{ "TLN", Operator, 0601000000000 },
{ "TRNE", Operator, 0602000000000 },
{ "TLNE", Operator, 0603000000000 },
{ "TRNA", Operator, 0604000000000 },
{ "TLNA", Operator, 0605000000000 },
{ "TRNN", Operator, 0606000000000 },
{ "TLNN", Operator, 0607000000000 },
{ "TDN", Operator, 0610000000000 },
{ "TSN", Operator, 0611000000000 },
{ "TDNE", Operator, 0612000000000 },
{ "TSNE", Operator, 0613000000000 },
{ "TDNA", Operator, 0614000000000 },
{ "TSNA", Operator, 0615000000000 },
{ "TDNN", Operator, 0616000000000 },
{ "TSNN", Operator, 0617000000000 },
{ "TRZ", Operator, 0620000000000 },
{ "TLZ", Operator, 0621000000000 },
{ "TRZE", Operator, 0622000000000 },
{ "TLZE", Operator, 0623000000000 },
{ "TRZA", Operator, 0624000000000 },
{ "TLZA", Operator, 0625000000000 },
{ "TRZN", Operator, 0626000000000 },
{ "TLZN", Operator, 0627000000000 },
{ "TDZ", Operator, 0630000000000 },
{ "TSZ", Operator, 0631000000000 },
{ "TDZE", Operator, 0632000000000 },
{ "TSZE", Operator, 0633000000000 },
{ "TDZA", Operator, 0634000000000 },
{ "TSZA", Operator, 0635000000000 },
{ "TDZN", Operator, 0636000000000 },
{ "TSZN", Operator, 0637000000000 },
{ "TRC", Operator, 0640000000000 },
{ "TLC", Operator, 0641000000000 },
{ "TRCE", Operator, 0642000000000 },
{ "TLCE", Operator, 0643000000000 },
{ "TRCA", Operator, 0644000000000 },
{ "TLCA", Operator, 0645000000000 },
{ "TRCN", Operator, 0646000000000 },
{ "TLCN", Operator, 0647000000000 },
{ "TDC", Operator, 0650000000000 },
{ "TSC", Operator, 0651000000000 },
{ "TDCE", Operator, 0652000000000 },
{ "TSCE", Operator, 0653000000000 },
{ "TDCA", Operator, 0654000000000 },
{ "TSCA", Operator, 0655000000000 },
{ "TDCN", Operator, 0656000000000 },
{ "TSCN", Operator, 0657000000000 },
{ "TRO", Operator, 0660000000000 },
{ "TLO", Operator, 0661000000000 },
{ "TROE", Operator, 0662000000000 },
{ "TLOE", Operator, 0663000000000 },
{ "TROA", Operator, 0664000000000 },
{ "TLOA", Operator, 0665000000000 },
{ "TRON", Operator, 0666000000000 },
{ "TLON", Operator, 0667000000000 },
{ "TDO", Operator, 0670000000000 },
{ "TSO", Operator, 0671000000000 },
{ "TDOE", Operator, 0672000000000 },
{ "TSOE", Operator, 0673000000000 },
{ "TDOA", Operator, 0674000000000 },
{ "TSOA", Operator, 0675000000000 },
{ "TDON", Operator, 0676000000000 },
{ "TSON", Operator, 0677000000000 },
{ "BLKI", IoOperator, 0700000000000 },
{ "BLKO", IoOperator, 0700100000000 },
{ "DATAI", IoOperator, 0700040000000 },
{ "DATAO", IoOperator, 0700140000000 },
{ "CONO", IoOperator, 0700200000000 },
{ "CONI", IoOperator, 0700240000000 },
{ "CONSZ", IoOperator, 0700300000000 },
{ "CONSO", IoOperator, 0700340000000 },
{ "JEN", Operator, 0254500000000 }, /* JRST 12, */
{ "HALT", Operator, 0254200000000 }, /* JRST 4, */
{ "JRSTF", Operator, 0254100000000 }, /* JRST 2, */
{ "JOV", Operator, 0255400000000 }, /* JFCL 10, */
{ "JCRY0", Operator, 0255200000000 }, /* JFCL 4, */
{ "JCRY1", Operator, 0255100000000 }, /* JFCL 2, */
{ "JCRY", Operator, 0255300000000 }, /* JFCL 6, */
{ "JPC", Operator, 0255040000000 }, /* JFCL 1, */
{ "RSW", IoOperator, 0700040000000 },
{ "", 0, 0 }
};