#include #include #include #include #include #include #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<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<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; // 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 } };