2
* $Id: macro1.c,v 1.74 2003/10/23 23:29:17 phil Exp $
5
* have flex() use nextfiodec()?? (what if legal in repeat???)
6
* "flex<SP><SP><SP>x" should give right justified result???
7
* squawk if nextfiodec called in a repeat w/ a delim?
9
* forbid variables/constants in macros
10
* forbid text in repeat??
11
* forbid start in repeat or macro
12
* use same error TLA's as MACRO???
13
* IPA error for overbar on LHS of =
14
* variables returns value??
16
* macro addressing: labels defined during macro are local use only????
17
* spacewar expects this??? (is it wrong?)
19
* self-feeding lines: \n legal anywhere \t is
20
* read next token into "token" buffer -- avoid saving "line"?
21
* remove crocks from "define"
22
* list title (first line of file) should not be parsed as source?
23
* incorrect listing for bare "start"
24
* list only 4 digits for address column
27
* note variables in symbol dump, xref?
28
* no "permenant" symbols; flush -p? rename .ini?
29
* keep seperate macro/pseudo table?
30
* verify bad input(?) detected
31
* implement dimension pseudo?
32
* remove crocks for '/' and ','?
38
* Author: Gary A. Messenbrink <gary@netcom.com> (macro8)
39
* MACRO7 modifications: Bob Supnik <bob.supnik@ljo.dec.com>
40
* MACRO1 modifications: Bob Supnik <bob.supnik@ljo.dec.com>
41
* slashed to be more like real MACRO like by Phil Budne <phil@ultimate.com>
43
* Purpose: A 2 pass PDP-1 assembler
46
* macro1 - a PDP-1 assembler.
49
* macro1 [ -d -p -m -r -s -x ] inputfile inputfile...
52
* This is a cross-assembler to for PDP-1 assembly language programs.
53
* It will produce an output file in rim format only.
54
* A listing file is always produced and with an optional symbol table
55
* and/or a symbol cross-reference (concordance). The permanent symbol
56
* table can be output in a form that may be read back in so a customized
57
* permanent symbol table can be produced. Any detected errors are output
58
* to a separate file giving the filename in which they were detected
59
* along with the line number, column number and error message as well as
60
* marking the error in the listing file.
61
* The following file name extensions are used:
62
* .mac source code (input)
63
* .lst assembly listing (output)
64
* .rim assembly output in DEC's rim format (output)
65
* .prm permanent symbol table in form suitable for reading after
66
* the EXPUNGE pseudo-op.
67
* .sym "symbol punch" tape (for DDT, or reloading into macro)
70
* -d Dump the symbol table at end of assembly
71
* -p Generate a file with the permanent symbols in it.
72
* (To get the current symbol table, assemble a file than has only
74
* -x Generate a cross-reference (concordance) of user symbols.
75
* -r Output a tape using only RIM format (else output block loader)
76
* -s Output a symbol dump tape (loader + loader blocks)
78
* Read a symbol tape back in
81
* Assembler error diagnostics are output to an error file and inserted
82
* in the listing file. Each line in the error file has the form
84
* <filename>:<line>:<col> : error: <message> at Loc = <loc>
86
* An example error message is:
88
* bintst.7:17:9 : error: undefined symbol "UNDEF" at Loc = 07616
90
* The error diagnostics put in the listing start with a two character
91
* error code (if appropriate) and a short message. A carat '^' is
92
* placed under the item in error if appropriate.
93
* An example error message is:
95
* 17 07616 3000 DAC UNDEF
97
* 18 07617 1777 TAD I DUMMY
99
* Undefined symbols are marked in the symbol table listing by prepending
100
* a '?' to the symbol. Redefined symbols are marked in the symbol table
101
* listing by prepending a '#' to the symbol. Examples are:
107
* Refer to the code for the diagnostic messages generated.
110
* This assembler is based on the pal assember by:
111
* Douglas Jones <jones@cs.uiowa.edu> and
112
* Rich Coon <coon@convexw.convex.com>
115
* This is free software. There is no fee for using it. You may make
116
* any changes that you wish and also give it away. If you can make
117
* a commercial product out of it, fine, but do not put any limits on
118
* the purchaser's right to do the same. If you improve it or fix any
119
* bugs, it would be nice if you told me and offered me a copy of the
124
* Version Date by Comments
125
* ------- ------- --- ---------------------------------------------------
126
* v1.0 12Apr96 GAM Original
127
* v1.1 18Nov96 GAM Permanent symbol table initialization error.
128
* v1.2 20Nov96 GAM Added BINPUNch and RIMPUNch pseudo-operators.
129
* v1.3 24Nov96 GAM Added DUBL pseudo-op (24 bit integer constants).
130
* v1.4 29Nov96 GAM Fixed bug in checksum generation.
131
* v2.1 08Dec96 GAM Added concordance processing (cross reference).
132
* v2.2 10Dec96 GAM Added FLTG psuedo-op (floating point constants).
133
* v2.3 2Feb97 GAM Fixed paging problem in cross reference output.
134
* v3.0 14Feb97 RMS MACRO8X features.
135
* 8Mar97 RMS MACRO7 released w/ sim8swre
136
* 13Mar97 RMS MACRO1 released w/ lispswre
137
* 28Nov01 RMS MACRO1 released w/ simtools
138
* 5Mar03 DP MACRO1 released w/ ddt1
139
* 2003 PLB major reworking, assembles MACRO, DDT
149
#define LIST_LINES_PER_PAGE 60 /* Includes 3 line page header. */
151
#define SYMBOL_COLUMNS 5
153
/*#define SYMSIG 4 /* EXP: significant chars in a symbol */
154
#define SYMBOL_TABLE_SIZE 8192
155
#define MAC_MAX_ARGS 20
156
#define MAC_MAX_LENGTH 8192
157
#define MAC_TABLE_LENGTH 1024 /* Must be <= 4096. */
159
#define MAX_LITERALS 1000
160
#define MAX_CONSTANTS 10 /* max number of "constants" blocks */
162
#define XREF_COLUMNS 8
164
#define ADDRESS_FIELD 0007777
165
#define INDIRECT_BIT 0010000
166
#define OP_CODE 0760000
168
#define CONCISE_LC 072
169
#define CONCISE_UC 074
171
/* Macro to get the number of elements in an array. */
172
#define DIM(a) (sizeof(a)/sizeof(a[0]))
174
#define ISBLANK(c) ((c==' ') || (c=='\f'))
175
#define ISEND(c) ((c=='\0')|| (c=='\n') || (c == '\t'))
176
#define ISDONE(c) ((c=='/') || ISEND(c))
178
#define ISOVERBAR(c) (c == '\\' || c == '~')
180
/* Macros for testing symbol attributes. Each macro evaluates to non-zero */
181
/* (true) if the stated condtion is met. */
182
/* Use these to test attributes. The proper bits are extracted and then */
184
#define M_DEFINED(s) (((s) & DEFINED) == DEFINED)
185
#define M_DUPLICATE(s) (((s) & DUPLICATE) == DUPLICATE)
186
#define M_FIXED(s) (((s) & FIXED) == FIXED)
187
#define M_LABEL(s) (((s) & LABEL) == LABEL)
188
#define M_PSEUDO(s) (((s) & PSEUDO) == PSEUDO)
189
#define M_EPSEUDO(s) (((s) & EPSEUDO) == EPSEUDO)
190
#define M_MACRO(s) (((s) & MACRO) == MACRO)
191
#define M_NOTRDEF(s) (((s) & NOTRDEF) != 0)
193
typedef unsigned char BOOL;
194
typedef unsigned char BYTE;
199
#define TRUE (!FALSE)
202
/* Line listing styles. Used to control listing of lines. */
205
LINE, LINE_VAL, LINE_LOC_VAL, LOC_VAL, LINE_LOC
207
typedef enum linestyle_t LINESTYLE_T;
210
/* Note that the names that have FIX as the suffix contain the FIXED bit */
211
/* included in the value. */
217
LABEL = 0010 | DEFINED,
218
REDEFINED = 0020 | DEFINED,
219
DUPLICATE = 0040 | DEFINED,
220
PSEUDO = 0100 | FIXED | DEFINED,
221
EPSEUDO = 0200 | FIXED | DEFINED,
222
MACRO = 0400 | DEFINED,
223
DEFFIX = DEFINED | FIXED,
224
NOTRDEF = (MACRO | PSEUDO | LABEL | FIXED) & ~DEFINED
226
typedef enum symtyp SYMTYP;
242
typedef enum pseudo_t PSEUDO_T;
252
typedef struct sym_t SYM_T;
259
typedef struct emsg_t EMSG_T;
266
typedef struct errsave_t ERRSAVE_T;
268
/*----------------------------------------------------------------------------*/
270
/* Function Prototypes */
272
int binarySearch( char *name, int start, int symbol_count );
273
int compareSymbols( const void *a, const void *b );
274
SYM_T *defineLexeme( WORD32 start, WORD32 term, WORD32 val, SYMTYP type );
275
SYM_T *defineSymbol( char *name, WORD32 val, SYMTYP type, WORD32 start);
276
void errorLexeme( EMSG_T *mesg, WORD32 col );
277
void errorMessage( EMSG_T *mesg, WORD32 col );
278
void errorSymbol( EMSG_T *mesg, char *name, WORD32 col );
280
SYM_T *evalSymbol( void );
281
void getArgs( int argc, char *argv[] );
282
SYM_T getExpr( void );
283
WORD32 getExprs( void );
284
WORD32 incrementClc( void );
285
WORD32 literal( WORD32 value );
287
char *lexemeToName( char *name, WORD32 from, WORD32 term );
288
void listLine( void );
289
SYM_T *lookup( char *name, int type );
290
void moveToEndOfLine( void );
292
void onePass( void );
293
void printCrossReference( void );
294
void printErrorMessages( void );
295
void printLine(char *line, WORD32 loc, WORD32 val, LINESTYLE_T linestyle);
296
void printPageBreak( void );
297
void printPermanentSymbolTable( void );
298
void printSymbolTable( void );
299
BOOL pseudo( PSEUDO_T val );
300
void punchLocObject( WORD32 loc, WORD32 val );
301
void punchOutObject( WORD32 loc, WORD32 val );
302
void punchLeader( WORD32 count );
303
void punchLoader( void );
304
void flushLoader( void );
305
void readLine( void );
306
void saveError( char *mesg, WORD32 cc );
307
void topOfForm( char *title, char *sub_title );
308
void constants(void);
309
void variables(void);
311
void dump_symbols(void);
313
/*----------------------------------------------------------------------------*/
315
/* Table of pseudo-ops (directives) which are used to setup the symbol */
316
/* table on startup */
319
{ PSEUDO, "consta", CONSTANTS },
320
{ PSEUDO, "define", DEFINE }, /* Define macro. */
321
{ PSEUDO, "repeat", REPEAT },
322
{ PSEUDO, "start", START }, /* Set starting address. */
323
{ PSEUDO, "variab", VARIABLES },
324
{ PSEUDO, "text", TEXT },
325
{ PSEUDO, "noinpu", NOINPUT },
326
{ PSEUDO, "expung", EXPUNGE },
327
/* the following can appear in expressions: */
328
{ EPSEUDO, "charac", CHAR },
329
{ EPSEUDO, "decima", DECIMAL }, /* base 10. */
330
{ EPSEUDO, "flexo", FLEX },
331
{ EPSEUDO, "octal", OCTAL }, /* Read literal constants in base 8. */
335
/* The table is put in lexical order on startup, so symbols can be */
336
/* inserted as desired into the initial table. */
339
SYM_T permanent_symbols[] =
341
/* Memory Reference Instructions */
342
{ DEFFIX, "and", 0020000 },
343
{ DEFFIX, "ior", 0040000 },
344
{ DEFFIX, "xor", 0060000 },
345
{ DEFFIX, "xct", 0100000 },
346
{ DEFFIX, "lac", 0200000 },
347
{ DEFFIX, "lio", 0220000 },
348
{ DEFFIX, "dac", 0240000 },
349
{ DEFFIX, "dap", 0260000 },
350
{ DEFFIX, "dip", 0300000 },
351
{ DEFFIX, "dio", 0320000 },
352
{ DEFFIX, "dzm", 0340000 },
353
{ DEFFIX, "add", 0400000 },
354
{ DEFFIX, "sub", 0420000 },
355
{ DEFFIX, "idx", 0440000 },
356
{ DEFFIX, "isp", 0460000 },
357
{ DEFFIX, "sad", 0500000 },
358
{ DEFFIX, "sas", 0520000 },
359
{ DEFFIX, "mul", 0540000 },
360
{ DEFFIX, "mus", 0540000 }, /* for spacewar */
361
{ DEFFIX, "div", 0560000 },
362
{ DEFFIX, "dis", 0560000 }, /* for spacewar */
363
{ DEFFIX, "jmp", 0600000 },
364
{ DEFFIX, "jsp", 0620000 },
365
{ DEFFIX, "skip", 0640000 }, /* for spacewar */
366
{ DEFFIX, "cal", 0160000 },
367
{ DEFFIX, "jda", 0170000 },
368
{ DEFFIX, "i", 0010000 },
369
{ DEFFIX, "skp", 0640000 },
370
{ DEFFIX, "law", 0700000 },
371
{ DEFFIX, "iot", 0720000 },
372
{ DEFFIX, "opr", 0760000 },
373
{ DEFFIX, "nop", 0760000 },
374
/* Shift Instructions */
375
{ DEFFIX, "ral", 0661000 },
376
{ DEFFIX, "ril", 0662000 },
377
{ DEFFIX, "rcl", 0663000 },
378
{ DEFFIX, "sal", 0665000 },
379
{ DEFFIX, "sil", 0666000 },
380
{ DEFFIX, "scl", 0667000 },
381
{ DEFFIX, "rar", 0671000 },
382
{ DEFFIX, "rir", 0672000 },
383
{ DEFFIX, "rcr", 0673000 },
384
{ DEFFIX, "sar", 0675000 },
385
{ DEFFIX, "sir", 0676000 },
386
{ DEFFIX, "scr", 0677000 },
387
{ DEFFIX, "1s", 0000001 },
388
{ DEFFIX, "2s", 0000003 },
389
{ DEFFIX, "3s", 0000007 },
390
{ DEFFIX, "4s", 0000017 },
391
{ DEFFIX, "5s", 0000037 },
392
{ DEFFIX, "6s", 0000077 },
393
{ DEFFIX, "7s", 0000177 },
394
{ DEFFIX, "8s", 0000377 },
395
{ DEFFIX, "9s", 0000777 },
396
/* Skip Microinstructions */
397
{ DEFFIX, "sza", 0640100 },
398
{ DEFFIX, "spa", 0640200 },
399
{ DEFFIX, "sma", 0640400 },
400
{ DEFFIX, "szo", 0641000 },
401
{ DEFFIX, "spi", 0642000 },
402
{ DEFFIX, "szs", 0640000 },
403
{ DEFFIX, "szf", 0640000 },
404
/*{ DEFFIX, "clo", 0651600 },*/
406
/* Operate Microinstructions */
407
{ DEFFIX, "clf", 0760000 },
408
{ DEFFIX, "stf", 0760010 },
409
{ DEFFIX, "cla", 0760200 },
410
/*{ DEFFIX, "lap", 0760300 },*/
411
{ DEFFIX, "hlt", 0760400 },
412
{ DEFFIX, "xx", 0760400 },
413
{ DEFFIX, "cma", 0761000 },
414
{ DEFFIX, "clc", 0761200 },
415
{ DEFFIX, "lat", 0762200 },
416
{ DEFFIX, "cli", 0764000 },
418
/*{ DEFFIX, "ioh", 0730000 },*/
419
{ DEFFIX, "rpa", 0730001 },
420
{ DEFFIX, "rpb", 0730002 },
421
{ DEFFIX, "rrb", 0720030 },
422
{ DEFFIX, "ppa", 0730005 },
423
{ DEFFIX, "ppb", 0730006 },
424
{ DEFFIX, "tyo", 0730003 },
425
{ DEFFIX, "tyi", 0720004 },
426
{ DEFFIX, "dpy", 0730007 }, /* for spacewar, munching squares! */
427
{ DEFFIX, "lsm", 0720054 },
428
{ DEFFIX, "esm", 0720055 },
429
{ DEFFIX, "cbs", 0720056 },
430
{ DEFFIX, "lem", 0720074 },
431
{ DEFFIX, "eem", 0724074 },
432
{ DEFFIX, "cks", 0720033 },
433
}; /* End-of-Symbols for Permanent Symbol Table */
435
/* Global variables */
436
SYM_T *symtab; /* Symbol Table */
437
int symbol_top; /* Number of entries in symbol table. */
439
#define LOADERBASE 07751
441
/* make it relocatable (DDT expects it at 7751) */
442
#define LOADER_IN LOADERBASE
443
#define LOADER_B (LOADERBASE+06)
444
#define LOADER_A (LOADERBASE+07)
445
#define LOADER_CK (LOADERBASE+025)
446
#define LOADER_EN1 (LOADERBASE+026)
449
0730002, /* in, rpb */
450
0320000+LOADER_A, /* dio a */
451
0100000+LOADER_A, /* xct a */
452
0320000+LOADER_CK, /* dio ck */
454
0320000+LOADER_EN1, /* dio en1 */
455
0730002, /* b, rpb */
457
0210000+LOADER_A, /* lac i a */
458
0400000+LOADER_CK, /* add ck */
459
0240000+LOADER_CK, /* dac ck */
460
0440000+LOADER_A, /* idx a */
461
0520000+LOADER_EN1, /* sas en1 */
462
0600000+LOADER_B, /* jmp b */
463
0200000+LOADER_CK, /* lac ck */
464
0400000+LOADER_EN1, /* add en1 */
466
0320000+LOADER_CK, /* dio ck */
467
0520000+LOADER_CK, /* sas ck */
469
0600000+LOADER_IN /* jmp in */
474
#define LOADERBUFSIZE 0100 /* <=0100, power of 2*/
475
#define LOADERBUFMASK (LOADERBUFSIZE-1) /* for block alignment */
477
WORD32 loaderbuf[LOADERBUFSIZE];
478
WORD32 loaderbufcount;
479
WORD32 loaderbufstart;
481
/*----------------------------------------------------------------------------*/
483
WORD32 *xreftab; /* Start of the concordance table. */
485
ERRSAVE_T error_list[20];
486
int save_error_count;
488
char s_detected[] = "detected";
489
char s_error[] = "error";
490
char s_errors[] = "errors";
492
char s_page[] = "Page";
493
char s_symtable[] = "Symbol Table";
494
char s_xref[] = "Cross Reference";
496
/* Assembler diagnostic messages. */
497
/* Some attempt has been made to keep continuity with the PAL-III and */
498
/* MACRO-8 diagnostic messages. If a diagnostic indicator, (e.g., IC) */
499
/* exists, then the indicator is put in the listing as the first two */
500
/* characters of the diagnostic message. The PAL-III indicators where used */
501
/* when there was a choice between using MACRO-8 and PAL-III indicators. */
502
/* The character pairs and their meanings are: */
503
/* DT Duplicate Tag (symbol) */
504
/* IC Illegal Character */
505
/* ID Illegal Redefinition of a symbol. An attempt was made to give */
506
/* a symbol a new value not via =. */
507
/* IE Illegal Equals An equal sign was used in the wrong context, */
508
/* (e.g., A+B=C, or TAD A+=B) */
509
/* II Illegal Indirect An off page reference was made, but a literal */
510
/* could not be generated because the indirect bit was already set. */
511
/* IR Illegal Reference (address is not on current page or page zero) */
512
/* PE Current, Non-Zero Page Exceeded (literal table flowed into code) */
513
/* RD ReDefintion of a symbol */
514
/* ST Symbol Table full */
515
/* UA Undefined Address (undefined symbol) */
516
/* VR Value Required */
517
/* ZE Zero Page Exceeded (see above, or out of space) */
518
EMSG_T duplicate_label = { "DT duplicate", "duplicate label" };
519
EMSG_T illegal_blank = { "IC illegal blank", "illegal blank" };
520
EMSG_T illegal_character = { "IC illegal char", "illegal character" };
521
EMSG_T illegal_expression = { "IC in expression", "illegal expression" };
522
EMSG_T label_syntax = { "IC label syntax", "label syntax" };
523
EMSG_T not_a_number = { "IC numeric syntax", "numeric syntax of" };
524
EMSG_T number_not_radix = { "IC radix", "number not in current radix"};
525
EMSG_T symbol_syntax = { "IC symbol syntax", "symbol syntax" };
526
EMSG_T illegal_equals = { "IE illegal =", "illegal equals" };
527
EMSG_T illegal_indirect = { "II off page", "illegal indirect" };
528
EMSG_T illegal_reference = { "IR off page", "illegal reference" };
529
EMSG_T undefined_symbol = { "UD undefined", "undefined symbol" };
530
EMSG_T misplaced_symbol = { "misplaced symbol", "misplaced symbol" };
531
EMSG_T redefined_symbol = { "RD redefined", "redefined symbol" };
532
EMSG_T value_required = { "VR value required", "value required" };
533
EMSG_T literal_gen_off = { "lit generation off",
534
"literal generation disabled" };
535
EMSG_T literal_overflow = { "PE page exceeded",
536
"current page literal capacity exceeded" };
537
EMSG_T zblock_too_small = { "expr too small", "ZBLOCK value too small" };
538
EMSG_T zblock_too_large = { "expr too large", "ZBLOCK value too large" };
539
EMSG_T no_pseudo_op = { "not implemented", "Unimplemented pseudo-op" };
540
EMSG_T illegal_vfd_value = { "width out of range",
541
"VFD field width not in range" };
542
EMSG_T no_literal_value = { "no value", "No literal value" };
543
EMSG_T text_string = { "no delimiter",
544
"Text string delimiters not matched" };
545
EMSG_T lt_expected = { "'<' expected", "'<' expected" };
546
EMSG_T symbol_table_full = { "ST Symbol Tbl full", "Symbol table full" };
547
EMSG_T no_macro_name = { "no macro name", "No name following DEFINE" };
548
EMSG_T bad_dummy_arg = { "bad dummy arg",
549
"Bad dummy argument following DEFINE" };
550
EMSG_T macro_too_long = { "macro too long", "Macro too long" };
551
EMSG_T no_virtual_memory = { "out of memory",
552
"Insufficient memory for macro" };
553
EMSG_T macro_table_full = { "Macro Table full", "Macro table full" };
554
EMSG_T define_in_repeat = { "define in a repeat", "Define in a repeat" };
556
/*----------------------------------------------------------------------------*/
565
char filename[NAMELEN];
566
char listpathname[NAMELEN];
567
char sympathname[NAMELEN];
568
char objectpathname[NAMELEN];
570
char permpathname[NAMELEN];
572
WORD32 mac_count; /* Total macros defined. */
575
* malloced macro bodies, indexed by sym->val dummies are evaluated at
576
* invocation time, and value saved in "args"; if recursive macros are
577
* desired (without conditionals, how would you escape?), keep a name
578
* list here and move symbols to "macinv"
581
int nargs; /* number of args */
582
SYM_T args[MAC_MAX_ARGS+1]; /* symbol for each and one for "r" */
583
char body[1]; /* malloc'ed accordingly */
584
} *mac_defs[MAC_TABLE_LENGTH];
586
struct macinv { /* current macro invocation */
587
char mac_line[LINELEN]; /* Saved macro invocation line. */
588
WORD32 mac_cc; /* Saved cc after macro invocation. */
589
char *mac_ptr; /* Pointer to macro body, NULL if no macro. */
590
struct macdef *defn; /* pointer to definition for dummies */
591
struct macinv *prev; /* previous invocation in stack */
592
} *curmacro; /* macro stack */
594
int nrepeats; /* count of nested repeats */
598
char list_title[LINELEN];
599
BOOL list_title_set; /* Set if TITLE pseudo-op used. */
600
char line[LINELEN]; /* Input line. */
601
int lineno; /* Current line number. */
602
int page_lineno; /* print line number on current page. */
603
WORD32 listed; /* Listed flag. */
606
WORD32 cc; /* Column Counter (char position in line). */
607
WORD32 clc; /* Location counter */
608
BOOL end_of_input; /* End of all input files. */
609
int errors; /* Number of errors found so far. */
610
BOOL error_in_line; /* TRUE if error on current line. */
611
int errors_pass_1; /* Number of errors on pass 1. */
612
int filix_curr; /* Index in argv to current input file. */
613
int filix_start; /* Start of input files in argv. */
614
int lexstartprev; /* Where previous lexeme started. */
615
int lextermprev; /* Where previous lexeme ended. */
616
int lexstart; /* Index of current lexeme on line. */
617
int lexterm; /* Index of character after current lexeme. */
618
int overbar; /* next saw an overbar in last token */
620
int nconst; /* number of "constants" blocks */
621
int lit_count[MAX_CONSTANTS]; /* # of lits in each block in pass 1 */
622
WORD32 lit_loc[MAX_CONSTANTS]; /* Base of literal blocks */
624
int noinput; /* don't punch loader */
626
int nvars; /* number of variables */
627
WORD32 vars_addr; /* address of "variables" */
628
WORD32 vars_end; /* end of "variables" */
631
int nlit; /* number of literals in litter[] */
632
WORD32 litter[MAX_LITERALS]; /* literals */
634
WORD32 maxcc; /* Current line length. */
635
BOOL nomac_exp; /* No macro expansion */
636
WORD32 pass; /* Number of current pass. */
637
BOOL print_permanent_symbols;
638
WORD32 radix; /* Default number radix. */
639
BOOL rim_mode; /* RIM mode output. */
640
BOOL sym_dump; /* punch symbol tape */
641
int save_argc; /* Saved argc. */
642
char **save_argv; /* Saved *argv[]. */
643
WORD32 start_addr; /* Saved start address. */
644
BOOL symtab_print; /* Print symbol table flag */
647
SYM_T sym_undefined = { UNDEFINED, "", 0 };/* Symbol Table Terminator */
649
/* initial data from SIMH v3.0 pdp1_stddev.c (different encoding of UC/LC) */
650
#define UC 0100 /* Upper case */
653
#define BC LC|UC /* both case bits */
654
#define BAD 014 /* unused concise code */
656
unsigned char ascii_to_fiodec[128] = {
657
BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
658
BC|075, BC|036, BAD, BAD, BAD, BC|077, BAD, BAD,
659
BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
660
BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
661
BC|000, UC|005, UC|001, UC|004, BAD, BAD, UC|006, UC|002,
662
LC|057, LC|055, UC|073, UC|054, LC|033, LC|054, LC|073, LC|021,
663
LC|020, LC|001, LC|002, LC|003, LC|004, LC|005, LC|006, LC|007,
664
LC|010, LC|011, BAD, BAD, UC|007, UC|033, UC|010, UC|021,
665
LC|040, UC|061, UC|062, UC|063, UC|064, UC|065, UC|066, UC|067,
666
UC|070, UC|071, UC|041, UC|042, UC|043, UC|044, UC|045, UC|046,
667
UC|047, UC|050, UC|051, UC|022, UC|023, UC|024, UC|025, UC|026,
668
UC|027, UC|030, UC|031, UC|057, LC|056, UC|055, UC|011, UC|040,
669
UC|020, LC|061, LC|062, LC|063, LC|064, LC|065, LC|066, LC|067,
670
LC|070, LC|071, LC|041, LC|042, LC|043, LC|044, LC|045, LC|046,
671
LC|047, LC|050, LC|051, LC|022, LC|023, LC|024, LC|025, LC|026,
672
LC|027, LC|030, LC|031, BAD, UC|056, BAD, UC|003, BC|075
675
/* for symbol punch tape conversion only!! */
676
char fiodec_to_ascii[64] = {
677
0, '1', '2', '3', '4', '5', '6', '7',
678
'8', '9', 0, 0, 0, 0, 0, 0,
679
'0', 0, 's', 't', 'u', 'v', 'w', 'x',
680
'y', 'z', 0, 0, 0, 0, 0, 0,
681
0, 'j', 'k', 'l', 'm', 'n', 'o', 'p',
682
'q', 'r', 0, 0, 0, 0, 0, 0,
683
0, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
684
'h', 'i', 0, 0, 0, 0, 0, 0 };
686
/* used at startup & for expunge */
689
/* Place end marker in symbol table. */
690
symtab[0] = sym_undefined;
695
/* Synopsis: Starting point. Controls order of assembly. */
697
main( int argc, char *argv[] )
705
/* Set the default values for global symbols. */
706
print_permanent_symbols = FALSE;
708
rim_mode = FALSE; /* default to loader tapes */
712
symtab_print = FALSE;
716
/* init symbol table before processing arguments, so we can
717
* load symbol punch tapes on the fly
721
* Setup the error file in case symbol table overflows while
722
* installing the permanent symbols.
725
pass = 0; /* required for symbol table init */
726
symtab = (SYM_T *) malloc( sizeof( SYM_T ) * SYMBOL_TABLE_SIZE );
728
if( symtab == NULL ) {
729
fprintf( stderr, "Could not allocate memory for symbol table.\n");
735
/* Enter the pseudo-ops into the symbol table */
736
for( ix = 0; ix < DIM( pseudos ); ix++ )
737
defineSymbol( pseudos[ix].name, pseudos[ix].val, pseudos[ix].type, 0 );
739
/* Enter the predefined symbols into the table. */
740
/* Also make them part of the permanent symbol table. */
741
for( ix = 0; ix < DIM( permanent_symbols ); ix++ )
742
defineSymbol( permanent_symbols[ix].name,
743
permanent_symbols[ix].val,
744
permanent_symbols[ix].type, 0 );
746
/* Get the options and pathnames */
747
getArgs( argc, argv );
749
/* Do pass one of the assembly */
752
errors_pass_1 = errors;
754
/* Set up for pass two */
755
objectfile = fopen( objectpathname, "wb" );
756
objectsave = objectfile;
758
listfile = fopen( listpathname, "w" );
761
/* XXX punch title into tape! */
769
constants(); /* implied "constants"? */
771
/* Do pass two of the assembly */
773
save_error_count = 0;
776
/* Get the amount of space that will be required for the concordance */
777
for( space = 0, ix = 0; ix < symbol_top; ix++ ) {
778
symtab[ix].xref_index = space; /* Index into concordance table. */
779
space += symtab[ix].xref_count + 1;
780
symtab[ix].xref_count = 0; /* Clear the count for pass 2. */
782
/* Allocate & clear the necessary space. */
783
xreftab = (WORD32 *) calloc( space, sizeof( WORD32 ));
788
objectfile = objectsave;
790
/* Works great for trailer. */
793
/* undo effects of NOLIST for any following output to listing file. */
796
/* Display value of error counter. */
798
fprintf( listfile, "\n %s %s %s\n", s_no, s_errors, s_detected );
801
fprintf( errorfile, "\n %d %s %s\n", errors, s_detected,
802
( errors == 1 ? s_error : s_errors ));
803
fprintf( listfile, "\n %d %s %s\n", errors, s_detected,
804
( errors == 1 ? s_error : s_errors ));
810
if( print_permanent_symbols )
811
printPermanentSymbolTable();
814
printCrossReference();
816
fclose( objectfile );
818
if( errors == 0 && errors_pass_1 == 0 ) {
819
/* after closing objectfile -- we reuse the FILE *!! */
824
remove( objectpathname );
826
return( errors != 0 );
829
/* read a word from a binary punch file */
837
for (i = 0; i < 3;) {
841
if (c & 0200) { /* ignore if ch8 not punched */
851
* "permute zone bits" like MACRO does for proper sorting
852
* (see routine "per" in MACRO) -- it's what DDT expects
854
* it's it's own inverse!
862
temp = name & 0202020; /* get zone bits */
863
temp = ((temp << 1) & 0777777) | ((temp >> 17) & 1); /* rotate left */
864
name ^= temp; /* flip zone bits */
865
name ^= 0400000; /* toggle sign */
869
/* add a symbol from a "symbol punch" tape */
871
addsym(WORD32 sym, WORD32 val)
876
name[0] = fiodec_to_ascii[(sym >>12) & 077];
877
name[1] = fiodec_to_ascii[(sym >> 6) & 077];
878
name[2] = fiodec_to_ascii[sym & 077];
880
defineSymbol( name, val, LABEL, 0);
884
read_symbols(char *fname)
888
f = fopen(fname, "rb");
900
goto err; /* XXX complain? */
901
if ((w & OP_CODE) == JMP)
903
if ((w & OP_CODE) != DIO)
904
goto err; /* XXX complain? */
907
goto err; /* XXX complain? */
911
/* XXX should push block reader down into a co-routine */
913
WORD32 start, end, sum;
916
if ((start & OP_CODE) == JMP) {
921
if (start == -1 || (start & OP_CODE) != DIO)
925
if (end == -1 || (end & OP_CODE) != DIO)
926
goto err; /* XXX complain? */
929
while (start < end) {
936
/* XXX handle block boundaries? */
942
/*printf("%06o %06o\n", sym, val);*/
947
start = getw(f); /* eat checksum XXX verify? */
950
/* roll over all the overflows at once */
951
if (sum & ~0777777) {
952
sum = (sum & 0777777) + (sum >> 18);
953
if (sum & 01000000) /* one more time */
960
fprintf(stderr, "error reading symbol file %s\n", fname);
964
/* Function: getArgs */
965
/* Synopsis: Parse command line, set flags accordingly and setup input and */
967
void getArgs( int argc, char *argv[] )
972
/* Set the defaults */
979
for( ix = 1; ix < argc; )
981
if( argv[ix][0] == '-' )
983
char *switches = argv[ix++];
984
for( jx = 1; switches[jx] != 0; jx++ )
986
switch( switches[jx] )
993
rim_mode = TRUE; /* punch pure rim-mode tapes */
1005
print_permanent_symbols = TRUE;
1014
read_symbols(argv[ix++]);
1018
fprintf( stderr, "%s: unknown flag: %s\n", argv[0], argv[ix] );
1019
fprintf( stderr, " -d -- dump symbol table\n" );
1020
fprintf( stderr, " -m -- output macro expansions\n" );
1021
fprintf( stderr, " -p -- output permanent symbols to file\n" );
1022
fprintf( stderr, " -r -- output RIM format file\n" );
1023
fprintf( stderr, " -s -- output symbol punch tape to file\n" );
1024
fprintf( stderr, " -S file -- read symbol punch tape\n" );
1025
fprintf( stderr, " -x -- output cross reference to file\n" );
1034
pathname = argv[ix];
1039
if( pathname == NULL )
1041
fprintf( stderr, "%s: no input file specified\n", argv[0] );
1045
len = strlen( pathname );
1046
if( len > NAMELEN - 5 )
1048
fprintf( stderr, "%s: pathname \"%s\" too long\n", argv[0], pathname );
1052
/* Now make the pathnames */
1053
/* Find last '.', if it exists. */
1055
while( pathname[jx] != '.' && pathname[jx] != '/'
1056
&& pathname[jx] != '\\' && jx >= 0 )
1061
switch( pathname[jx] )
1075
/* Add the pathname extensions. */
1076
strncpy( objectpathname, pathname, jx );
1077
objectpathname[jx] = '\0';
1078
strcat( objectpathname, ".rim");
1080
strncpy( listpathname, pathname, jx );
1081
listpathname[jx] = '\0';
1082
strcat( listpathname, ".lst" );
1084
strncpy( permpathname, pathname, jx );
1085
permpathname[jx] = '\0';
1086
strcat( permpathname, ".prm" );
1088
strncpy( sympathname, pathname, jx );
1089
sympathname[jx] = '\0';
1090
strcat( sympathname, ".sym" );
1092
/* Extract the filename from the path. */
1093
if( isalpha( pathname[0] ) && pathname[1] == ':' && pathname[2] != '\\' )
1094
pathname[1] = '\\'; /* MS-DOS style pathname */
1097
while( pathname[jx] != '/' && pathname[jx] != '\\' && jx >= 0 )
1099
strcpy( filename, &pathname[jx + 1] );
1104
invokeMacro(int index)
1110
mdp = mac_defs[index];
1111
if (mdp == NULL || mdp->body[0] == '\0')
1114
/* Find arguments. */
1115
while (ISBLANK(line[lexstart]))
1118
mip = calloc(1, sizeof(struct macinv));
1120
fprintf(stderr, "could not allocate memory for macro invocation\n");
1125
/* evaluate args, saving values in SYM_T entries in defn.
1126
* (cannot have recursive macros)
1128
mdp->args[0].val = clc; /* r is location at start */
1129
for( jx = 1; !ISDONE(line[lexstart]) && jx <= MAC_MAX_ARGS; ) {
1133
if (ISDONE(line[lexstart]))
1136
if (line[lexstart] == ',')
1139
while( ISBLANK( line[lexstart] ))
1142
if (ISDONE(line[lexstart]))
1147
/* ignore excess values silently? */
1148
if (jx <= mdp->nargs)
1149
mdp->args[jx].val = val;
1153
/* XXX complain if too few actuals? -- nah */
1154
while (jx <= mdp->nargs)
1155
mdp->args[jx++].val = 0;
1157
strcpy(mip->mac_line, line); /* save line */
1158
mip->mac_cc = cc; /* save position in line */
1159
mip->mac_ptr = mdp->body;
1160
mip->prev = curmacro; /* push the old entry */
1161
curmacro = mip; /* step up to the plate! */
1165
/* process input; used by onePass and repeat */
1168
if (!list_title_set) {
1171
/* assert(sizeof(title) >= sizeof(line)); */
1172
strcpy(list_title, line);
1174
if ((cp = strchr(list_title, '\n')))
1177
if (list_title[0]) {
1178
list_title_set = TRUE;
1179
fprintf(stderr, "%s - pass %d\n", list_title, pass );
1180
/* XXX punch title into tape banner (until an '@' seen) */
1193
if( ISEND( line[lexstart] )) {
1194
if (line[lexstart] != '\t')
1198
if (line[lexstart] == '/') /* comment? */
1201
/* look ahead for 'exp/' */
1202
/* skip until whitespace or terminator */
1203
for( jx = lexstart; jx < maxcc; jx++ )
1204
if( ISBLANK(line[jx]) || ISDONE(line[jx]))
1206
if( line[jx] == '/') { /* EXP/ set location */
1209
newclc = getExprs();
1211
/* Do not change Current Location Counter if an error occurred. */
1212
if( !error_in_line )
1215
printLine( line, newclc, 0, LINE_LOC );
1217
next(0); /* discard slash */
1221
switch( line[lexterm] ) {
1223
if( isLexSymbol()) {
1228
/* Use lookup so symbol will not be counted as reference. */
1229
sym = lookup(lexemeToName(name, lexstart, lexterm), UNDEFINED);
1232
/* relative during macro expansion!! */
1233
val = clc - curmacro->defn->args[0].val;
1238
if( M_DEFINED( sym->type )) {
1239
if( sym->val != val && pass == 2 )
1240
errorSymbol( &duplicate_label, sym->name, lexstart );
1241
sym->type |= DUPLICATE; /* XXX never used! */
1243
/* Must call define on pass 2 to generate concordance. */
1244
defineLexeme( lexstart, lexterm, val, LABEL );
1246
else if (isdigit(line[lexstart])) { /* constant, */
1250
for( i = lexstart; i < lexterm; i++ ) {
1251
if( isdigit( line[i] )) {
1253
digit = line[i] - '0';
1254
if( digit >= radix ) {
1255
errorLexeme( &number_not_radix, i );
1259
val = val * radix + digit;
1262
errorLexeme( ¬_a_number, lexstart );
1268
if( clc != val && pass == 2 )
1269
errorLexeme( &duplicate_label, lexstart); /* XXX */
1273
errorLexeme( &label_syntax, lexstart );
1274
next(0); /* skip comma */
1278
if( isLexSymbol()) {
1279
WORD32 start, term, val;
1283
next(0); /* skip symbol */
1284
next(0); /* skip trailing = */
1286
defineLexeme( start, term, val, DEFINED );
1287
printLine( line, 0, val, LINE_VAL );
1290
errorLexeme( &symbol_syntax, lexstartprev );
1291
next(0); /* skip symbol */
1292
next(0); /* skip trailing = */
1293
getExprs(); /* skip expression */
1296
} /* switch on terminator */
1298
if( isLexSymbol()) {
1304
if( M_MACRO(sym->type)) {
1305
if (!invokeMacro(val))
1306
next(0); /* bad defn? or body is empty! */
1308
} /* macro invocation */
1309
else if( M_PSEUDO(sym->type)) { /* NO EPSEUDOs */
1310
pseudo( (PSEUDO_T)val & 0777777 );
1313
} /* macro, or non-char pseudo */
1316
if (evalue.type != PSEUDO) { /* not a bare pseudo-op? */
1317
if (line[lexstart] == ',') { /* EXP, */
1318
if(evalue.val != clc && pass == 2 )
1319
errorLexeme( &duplicate_label, lexstart); /* XXX */
1321
else if (line[lexstart] == '/') { /* EXP/ */
1323
printLine( line, clc, 0, LINE_LOC );
1327
punchOutObject( clc, evalue.val & 0777777); /* punch it! */
1334
/* Function: onePass */
1335
/* Synopsis: Do one assembly pass. */
1339
clc = 4; /* Default location is 4 */
1340
start_addr = 0; /* No starting address. */
1341
nconst = 0; /* No constant blocks seen */
1342
nvars = 0; /* No variables seen */
1344
while (curmacro) { /* pop macro stack */
1347
mp = curmacro->prev;
1352
for( ix = 0; ix < mac_count; ix++) {
1354
free( mac_defs[ix] );
1355
mac_defs[ix] = NULL;
1357
mac_count = 0; /* No macros defined. */
1363
list_title_set = FALSE;
1364
page_lineno = LIST_LINES_PER_PAGE; /* Force top of page for new titles. */
1365
radix = 8; /* Initial radix is octal (base 8). */
1367
/* Now open the first input file. */
1368
end_of_input = FALSE;
1369
filix_curr = filix_start; /* Initialize pointer to input files. */
1370
if(( infile = fopen( save_argv[filix_curr], "r" )) == NULL ) {
1371
fprintf( stderr, "%s: cannot open \"%s\"\n", save_argv[0],
1372
save_argv[filix_curr] );
1388
/* Function: getExprs */
1389
/* Synopsys: gutted like a fish */
1395
if (sym.type == PSEUDO)
1396
errorMessage( &value_required, lexstart ); /* XXX wrong pointer? */
1398
return sym.val & 0777777;
1408
/* Here we assume the current lexeme is the operator separating the */
1409
/* previous operator from the next, if any. */
1414
* falling out of switch breaks loop and returns from routine
1415
* so if you want to keep going, you must "continue"!!
1418
switch( line[lexstart] ) {
1423
next(1); /* skip operator */
1424
if (space && ISEND(line[lexstart])) /* tollerate a trailing space */
1426
sym.val += eval().val; /* XXX look at type? */
1428
if( sym.val >= 01000000 )
1429
sym.val = ( sym.val + 1 ) & 0777777;
1432
case '-': /* subtract */
1433
next(1); /* skip over the operator */
1434
sym.val += eval().val ^ 0777777; /* XXX look at type? */
1436
if( sym.val >= 01000000 )
1437
sym.val = ( sym.val + 1 ) & 0777777;
1440
case '*': /* multiply */
1441
next(1); /* skip over the operator */
1442
sym.val *= eval().val;
1444
if( sym.val >= 01000000 )
1445
sym.val = ( sym.val + 1 ) & 0777777;
1449
case '%': /* divide !??? */
1451
* neither '%' nor the divide symbol appear in FIO-DEC,
1452
* does any known program use such an operator?
1453
* Easily confused for "MOD", which is how C uses '%'!
1456
sym.val /= eval().val;
1462
next(1); /* skip over the operator */
1463
sym.val &= eval().val;
1468
next(1); /* skip over the operator */
1469
sym.val |= eval().val;
1481
errorMessage( &illegal_equals, lexstart );
1487
if (!ISEND(line[lexstart])) {
1488
errorMessage( &illegal_expression, lexstart );
1494
break; /* break loop!! */
1500
* return fio-dec code for next char
1501
* embeds shifts as needed
1504
nextfiodec(int *ccase, int delim)
1513
/* XXX MUST NOT BE IN A REPEAT!! */
1514
readLine(); /* danger will robinson! */
1529
if (delim != -1 && c == delim) {
1531
cc++; /* eat delim */
1535
return CONCISE_LC; /* shift down first */
1538
if (c > 0177) { /* non-ascii */
1539
errorMessage( &illegal_character, cc );
1540
c = 0; /* space?! */
1543
c = ascii_to_fiodec[c&0177];
1545
errorMessage( &illegal_character, cc );
1546
c = 0; /* space?! */
1549
if (!(c & *ccase)) { /* char not in current case? */
1550
*ccase ^= BC; /* switch case */
1552
return CONCISE_LC; /* shift down */
1554
return CONCISE_UC; /* shift up */
1557
return c & CHARBITS;
1562
* Synopsis: Handle data for "flexo" pseudo
1563
* handle upper case by doing shifts
1572
if (line[lexstart] == ' ') /* always? */
1575
/* original version appears to take next 3 characters,
1576
* REGARDLESS of what they are (tab, newline, space?)!
1579
ccase = LC; /* current case */
1580
for (shift = 12; shift >= 0; shift -= 6) {
1582
if( lexstart >= maxcc )
1586
if (c == '\t' || c == '\n') {
1589
c = CONCISE_LC; /* shift down first */
1592
if (c > 0177) { /* non-ascii */
1593
errorMessage( &illegal_character, lexstart );
1597
c = ascii_to_fiodec[c&0177];
1599
errorMessage( &illegal_character, lexstart );
1603
if (!(c & ccase)) { /* char not in current case? */
1604
ccase ^= BC; /* switch case */
1606
c = CONCISE_LC; /* shift down */
1608
c = CONCISE_UC; /* shift up */
1613
w |= (c & CHARBITS) << shift;
1615
/* error to get here w/ case == UC? nah. shift down could be next */
1621
* Synopsis: Handle data for "char" pseudo
1626
unsigned char c, pos;
1629
return 0; /* XXX error? */
1631
if (pos != 'l' && pos != 'm' && pos != 'r') {
1632
errorMessage( &illegal_character, lexstart );
1637
return 0; /* XXX error? */
1641
errorMessage( &illegal_character, lexstart );
1645
c = ascii_to_fiodec[c];
1647
errorMessage( &illegal_character, lexstart );
1651
if (!(c & LC)) { /* upper case only char? */
1652
c = CONCISE_UC; /* take a shift up */
1653
cc--; /* and leave char for next luser */
1658
case 'l': return c << 12;
1659
case 'm': return c << 6;
1662
/* should not happen */
1666
/* Function: eval */
1667
/* Synopsis: Get the value of the current lexeme, and advance.*/
1676
sym_eval.type = DEFINED;
1677
sym_eval.name[0] = '\0';
1678
sym_eval.val = sym_eval.xref_index = sym_eval.xref_count = 0;
1682
if( isLexSymbol()) {
1684
if(!M_DEFINED( sym->type )) {
1686
errorSymbol( &undefined_symbol, sym->name, lexstart );
1690
else if( M_PSEUDO(sym->type) || M_EPSEUDO(sym->type)) {
1694
sym_eval.type = PSEUDO;
1695
sym_eval.val = 0; /* has zero as a value! */
1699
sym_eval.type = PSEUDO;
1700
sym_eval.val = 0; /* has zero as a value */
1703
next(1); /* skip keyword */
1704
sym_eval.val = flex();
1707
next(1); /* skip keyword */
1708
sym_eval.val = getChar();
1711
errorSymbol( &value_required, sym->name, lexstart );
1712
sym_eval.type = sym->type;
1719
else if( M_MACRO( sym->type ))
1723
errorSymbol( &misplaced_symbol, sym->name, lexstart );
1725
sym_eval.type = sym->type;
1736
else if( isdigit( line[lexstart] )) {
1739
while( from < lexterm ) {
1740
if( isdigit( line[from] )) {
1741
digit = line[from++] - '0';
1742
if( digit >= radix ) {
1743
errorLexeme( &number_not_radix, from - 1 );
1747
val = val * radix + digit;
1750
errorLexeme( ¬_a_number, lexstart );
1760
switch( line[lexstart] ) {
1761
case '.': /* Value of Current Location Counter */
1765
case '(': /* Generate literal */
1766
next(1); /* Skip paren */
1767
val = getExprs(); /* recurse */
1768
if( line[lexstart] == ')' )
1769
next(1); /* Skip end paren */
1770
sym_eval.val = literal(val);
1772
case '[': /* parens!! */
1774
sym_eval.val = getExprs(); /* mutual recursion */
1775
if( line[lexstart] == ']' )
1776
next(1); /* Skip close bracket */
1778
errorMessage( &illegal_character, lexstart );
1781
switch( line[lexstart] ) {
1783
errorMessage( &illegal_equals, lexstart );
1787
errorMessage( &illegal_character, lexstart );
1789
} /* error switch */
1790
val = 0; /* On error, set value to zero. */
1791
next(1); /* Go past illegal character. */
1792
} /* switch on first char */
1793
} /* not symbol or number */
1802
switch (line[lexstart]) {
1803
case '-': /* unary - */
1805
sym = eval2(); /* skip op */
1808
case '+': /* unary + */
1809
next(1); /* skip op */
1817
/* Function: incrementClc */
1818
/* Synopsis: Set the next assembly location. Test for collision with */
1819
/* the literal tables. */
1820
WORD32 incrementClc()
1822
clc = (( clc + 1 ) & ADDRESS_FIELD );
1824
} /* incrementClc */
1827
/* Function: readLine */
1828
/* Synopsis: Get next line of input. Print previous line if needed. */
1834
char inpline[LINELEN];
1836
/* XXX panic if nrepeats > 0 (if self-feeding, do the backup here?) */
1838
listLine(); /* List previous line if needed. */
1839
error_in_line = FALSE; /* No error in line. */
1841
if(curmacro && *curmacro->mac_ptr == '\0') { /* end of macro? */
1844
listed = TRUE; /* Already listed. */
1846
/* Restore invoking line. */
1847
strcpy(line, curmacro->mac_line);
1848
cc = lexstartprev = curmacro->mac_cc; /* Restore cc. */
1849
maxcc = strlen( line ); /* Restore maxcc. */
1851
mp = curmacro->prev; /* pop stack */
1856
} /* end of macro */
1858
cc = 0; /* Initialize column counter. */
1860
if( curmacro ) { /* Inside macro? */
1866
mc = *curmacro->mac_ptr++; /* Next character. */
1867
/* watch for overflow? how could it?? */
1869
} while( !ISEND( mc )); /* note: terminates on tab?! */
1873
} /* inside macro */
1875
lineno++; /* Count lines read. */
1876
listed = FALSE; /* Mark as not listed. */
1878
if(( fgets( inpline, LINELEN - 1, infile )) == NULL ) {
1879
filix_curr++; /* Advance to next file. */
1880
if( filix_curr < save_argc ) { /* More files? */
1882
if(( infile = fopen( save_argv[filix_curr], "r" )) == NULL ) {
1883
fprintf( stderr, "%s: cannot open \"%s\"\n", save_argv[0],
1884
save_argv[filix_curr] );
1887
list_title_set = FALSE;
1891
end_of_input = TRUE;
1892
} /* fgets failed */
1895
for( ix = 0, iy = 0; inpline[ix] != '\0'; ix++ ) {
1896
if( inpline[ix] == '\f' ) {
1897
if( !ffseen && list_title_set ) topOfForm( list_title, NULL );
1901
line[iy++] = inpline[ix];
1905
/* If the line is terminated by CR-LF, remove, the CR. */
1906
if( line[iy - 2] == '\r' ) {
1908
line[iy - 1] = line[iy - 0];
1911
maxcc = iy; /* Save the current line length. */
1915
/* Function: listLine */
1916
/* Synopsis: Output a line to the listing file. */
1918
/* generate a line of listing if not already done! */
1920
if( listfile != NULL && listed == FALSE )
1922
printLine( line, 0, 0, LINE );
1927
/* Function: printPageBreak */
1928
/* Synopsis: Output a Top of Form and listing header if new page necessary. */
1929
void printPageBreak()
1931
if( page_lineno >= LIST_LINES_PER_PAGE )
1932
/* ( list_lineno % LIST_LINES_PER_PAGE ) == 0 ) */
1934
topOfForm( list_title, NULL );
1936
} /* printPageBreak */
1939
/* Function: printLine */
1940
/* Synopsis: Output a line to the listing file with new page if necessary. */
1941
void printLine( char *line, WORD32 loc, WORD32 val, LINESTYLE_T linestyle )
1943
if( listfile == NULL )
1945
save_error_count = 0;
1957
fprintf( listfile, "%5d ", lineno );
1958
fputs( line, listfile );
1965
fprintf( listfile, "%5d %6.6o ", lineno, val );
1966
fputs( line, listfile );
1971
fprintf( listfile, " %6.6o\n", val );
1978
fprintf( listfile, "%5d %5.5o ", lineno, loc );
1979
fputs( line, listfile );
1984
fprintf( listfile, " %5.5o\n", loc );
1991
fprintf( listfile, "%5d %5.5o %6.6o ", lineno, loc, val );
1992
fputs( line, listfile );
1997
fprintf( listfile, " %5.5o %6.6o\n", loc, val );
2002
fprintf( listfile, " %5.5o %6.6o\n", loc, val );
2005
printErrorMessages();
2009
/* Function: printErrorMessages */
2010
/* Synopsis: Output any error messages from the current list of errors. */
2011
void printErrorMessages()
2016
if( listfile != NULL )
2018
/* If any errors, display them now. */
2019
for( iy = 0; iy < save_error_count; iy++ )
2022
fprintf( listfile, "%-18.18s ", error_list[iy].mesg );
2023
if( error_list[iy].col >= 0 )
2025
for( ix = 0; ix < error_list[iy].col; ix++ )
2027
if( line[ix] == '\t' )
2029
putc( '\t', listfile );
2033
putc( ' ', listfile );
2036
fputs( "^", listfile );
2040
fputs( "\n", listfile );
2043
save_error_count = 0;
2044
} /* printErrorMessages */
2047
/* Function: punchObject */
2048
/* Synopsis: Put one character to object file */
2049
void punchObject( WORD32 val )
2052
if( objectfile != NULL )
2053
fputc( val, objectfile );
2056
/* Function: punchTriplet */
2057
/* Synopsis: Output 18b word as three 6b characters with ho bit set. */
2058
void punchTriplet( WORD32 val )
2060
punchObject((( val >> 12) & 077) | 0200 );
2061
punchObject((( val >> 6 ) & 077) | 0200 );
2062
punchObject(( val & 077) | 0200 );
2063
} /* punchTriplet */
2067
/* in case no "start" in file (an error?) */
2070
/* Function: punchLeader */
2071
/* Synopsis: Generate 2 feet of leader on object file, as per DEC */
2072
/* documentation. Paper tape has 10 punches per inch. */
2073
void punchLeader( WORD32 count )
2077
/* If value is zero, set to the default of 2 feet of leader. */
2078
count = ( count == 0 ) ? 240 : count;
2080
if( objectfile != NULL )
2082
for( ix = 0; ix < count; ix++ )
2084
fputc( 0, objectfile );
2089
/* Function: punchOutObject */
2090
/* Synopsis: Output the current line and then then punch value to the */
2092
void punchOutObject( WORD32 loc, WORD32 val )
2094
printLine( line, loc, val, LINE_LOC_VAL );
2095
punchLocObject( loc, val );
2096
} /* punchOutObject */
2099
/* Function: punchLocObjectRIM */
2100
/* Synopsis: Output the word in RIM mode */
2101
void punchLocObjectRIM( WORD32 loc, WORD32 val )
2103
punchTriplet( DIO | loc );
2104
punchTriplet( val );
2105
} /* punchLocObject */
2107
/* punch loader in RIM mode */
2115
for (i = 0; i < DIM(loader); i++)
2116
punchLocObjectRIM(LOADERBASE+i, loader[i]);
2117
punchTriplet( JMP | LOADERBASE );
2121
* flush out loader buffer; output a block:
2127
#define PW(X) { WORD32 x = X; sum += x; punchTriplet(x); }
2133
if (loaderbufcount == 0)
2137
PW( DIO | loaderbufstart );
2138
PW( DIO | loaderbufstart + loaderbufcount );
2139
for (i = 0; i < loaderbufcount; i++)
2142
/* roll over all the overflows at once */
2144
sum = (sum & 0777777) + (sum >> 18);
2145
if (sum & 01000000) /* one more time */
2153
void punchLocObject( WORD32 loc, WORD32 val )
2156
if ((loc & LOADERBUFMASK) == 0 || /* full/force alignment */
2157
loaderbufcount > 0 &&
2158
loc != loaderbufstart + loaderbufcount) /* disjoint */
2160
if (loaderbufcount == 0)
2161
loaderbufstart = loc;
2162
loaderbuf[loaderbufcount++] = val;
2165
punchLocObjectRIM( loc, val );
2168
/* Function: literal */
2169
/* Synopsis: Add a value to the literal pool */
2171
literal( WORD32 value )
2175
if (nconst >= MAX_CONSTANTS) {
2176
fprintf(stderr, "too many 'constants'; increase MAX_CONSTANTS\n");
2181
if (++lit_count[nconst] == MAX_LITERALS) {
2182
fprintf(stderr, "too many literals; increase MAX_LITERALS\n");
2185
return lit_count[nconst];
2190
* pool constants; makes for a shorter tape
2191
* (but "middle" constants blocks can't shrink)
2193
for (i = 0; i < nlit; i++)
2194
if (litter[i] == value)
2195
return lit_loc[nconst] + i;
2199
if (nlit == MAX_LITERALS) {
2200
fprintf(stderr, "too many literals; increase MAX_LITERALS\n");
2204
/* not found, save it */
2205
litter[nlit] = value;
2207
/* use base for this block, determined on pass1 */
2208
return lit_loc[nconst] + nlit++;
2212
/* Function: printSymbolTable */
2213
/* Synopsis: Output the symbol table. */
2214
/* XXX now prints FIXED symbols too */
2215
void printSymbolTable()
2223
for (ix = 0, sym = symtab; ix < symbol_top; ix++, sym++) {
2224
if (M_FIXED(sym->type) || M_PSEUDO(sym->type) ||
2225
M_MACRO(sym->type) || M_EPSEUDO(sym->type))
2228
if (symbol_lines == 0) {
2229
topOfForm( list_title, s_symtable );
2230
symbol_lines = LIST_LINES_PER_PAGE;
2233
switch( sym->type & ( DEFINED | REDEFINED )) {
2246
fprintf( listfile, "%c%-6.6s %6.6o\n", mark, sym->name, sym->val );
2249
} /* printSymbolTable */
2252
/* Function: printPermanentSymbolTable */
2253
/* Synopsis: Output the permanent symbol table to a file suitable for */
2254
/* being input after the EXPUNGE pseudo-op. */
2255
void printPermanentSymbolTable()
2260
if(( permfile = fopen( permpathname, "w" )) == NULL )
2265
fprintf( permfile, "/ PERMANENT SYMBOL TABLE\n/\n" );
2266
fprintf( permfile, " expunge\n/\n" );
2268
for( ix = 0; ix < symbol_top; ix++ )
2270
int type = symtab[ix].type;
2271
if( M_FIXED(type) && !M_PSEUDO(type) && !M_EPSEUDO(type) )
2272
fprintf( permfile, "\t%s=%o\n",
2273
symtab[ix].name, symtab[ix].val );
2276
} /* printPermanentSymbolTable */
2279
/* Function: printCrossReference */
2280
/* Synopsis: Output a cross reference (concordance) for the file being */
2282
void printCrossReference()
2291
/* Force top of form for first page. */
2292
page_lineno = LIST_LINES_PER_PAGE;
2296
for( ix = 0, sym = symtab; ix < symbol_top; ix++, sym++ ) {
2297
if (M_FIXED(sym->type) && xreftab[sym->xref_index] == 0)
2301
if( page_lineno >= LIST_LINES_PER_PAGE )
2302
topOfForm( list_title, s_xref );
2304
fprintf( listfile, "%5d", list_lineno );
2306
/* Get reference count & index into concordance table for this symbol */
2307
xc_refcount = sym->xref_count;
2308
xc_index = sym->xref_index;
2309
/* Determine how to label symbol on concordance. */
2310
/* XXX flag variables? */
2311
switch( sym->type & ( DEFINED | REDEFINED )) {
2313
fprintf( listfile, " U ");
2317
fprintf( listfile, " M %5d ", xreftab[xc_index] );
2321
fprintf( listfile, " A %5d ", xreftab[xc_index] );
2324
fprintf( listfile, "%-6.6s ", sym->name );
2326
/* Output the references, 8 numbers per line after symbol name. */
2327
for( xc_cols = 0, xc = 1; xc < xc_refcount + 1; xc++, xc_cols++ ) {
2328
if( xc_cols >= XREF_COLUMNS ) {
2331
if( page_lineno >= LIST_LINES_PER_PAGE )
2332
topOfForm( list_title, s_xref);
2334
fprintf( listfile, "\n%5d%-19s", list_lineno, " " );
2336
fprintf( listfile, " %5d", xreftab[xc_index + xc] );
2338
fprintf( listfile, "\n" );
2340
} /* printCrossReference */
2343
/* Function: topOfForm */
2344
/* Synopsis: Prints title and sub-title on top of next page of listing. */
2345
void topOfForm( char *title, char *sub_title )
2350
strcpy( temp, s_page );
2351
sprintf( temp, "%s %d", s_page, list_pageno );
2356
/* Output a top of form if not the first page of the listing. */
2357
if( list_pageno > 1 )
2358
fprintf( listfile, "\f" );
2360
fprintf( listfile, "\n %-63s %10s\n", title, temp );
2362
/* Reset the current page line counter. */
2364
if( sub_title != NULL )
2366
fprintf( listfile, "%80s\n", sub_title );
2371
fprintf( listfile, "\n" );
2374
fprintf( listfile, "\n" );
2379
/* Function: lexemeToName */
2380
/* Synopsis: Convert the current lexeme into a string. */
2381
char *lexemeToName( char *name, WORD32 from, WORD32 term )
2386
while( from < term && to < SYMLEN-1) {
2387
char c = line[from++];
2395
} /* lexemeToName */
2397
/* Function: defineLexeme */
2398
/* Synopsis: Put lexeme into symbol table with a value. */
2399
SYM_T *defineLexeme( WORD32 start, /* start of lexeme being defined. */
2400
WORD32 term, /* end+1 of lexeme being defined. */
2401
WORD32 val, /* value of lexeme being defined. */
2402
SYMTYP type ) /* how symbol is being defined. */
2406
lexemeToName( name, start, term);
2407
return( defineSymbol( name, val, type, start ));
2408
} /* defineLexeme */
2411
/* Function: defineSymbol */
2412
/* Synopsis: Define a symbol in the symbol table, enter symbol name if not */
2413
/* not already in table. */
2414
SYM_T *defineSymbol( char *name, WORD32 val, SYMTYP type, WORD32 start )
2419
if( strlen( name ) < 1 )
2421
return( &sym_undefined ); /* Protect against non-existent names. */
2423
sym = lookup( name, type );
2424
xref_count = 0; /* Set concordance for normal defintion. */
2426
if( M_DEFINED( sym->type ) && sym->val != val && M_NOTRDEF( sym -> type ))
2430
errorSymbol( &redefined_symbol, sym->name, start );
2431
type = type | REDEFINED;
2432
sym->xref_count++; /* Referenced symbol, count it. */
2433
xref_count = sym->xref_count;
2434
/* moved inside "if pass2" -plb 10/2/03 allow redefinition
2435
* of predefined symbols during pass1
2441
if( pass == 2 && xref )
2443
/* Put the definition line number in the concordance table. */
2444
/* Defined symbols are not counted as references. */
2445
if (sym->xref_index >= 0) { /* beware macro dummies */
2446
xreftab[sym->xref_index] = lineno;
2447
/* Put the line number in the concordance table. */
2448
xreftab[sym->xref_index + xref_count] = lineno;
2452
/* Now set the value and the type. */
2453
sym->val = val & 0777777;
2456
} /* defineSymbol */
2459
/* Function: lookup */
2460
/* Synopsis: Find a symbol in table. If not in table, enter symbol in */
2461
/* table as undefined. Return address of symbol in table. */
2462
SYM_T *lookup( char *name, int type )
2464
int ix; /* Insertion index */
2465
int lx; /* Left index */
2466
int rx; /* Right index */
2467
SYM_T *best; /* best match */
2470
/* YIKES! Search dummies (and "R") before anything else!! */
2471
if (curmacro && curmacro->defn) {
2472
struct macdef *mdp = curmacro->defn;
2475
for (i = 0, sym = mdp->args; i <= mdp->nargs; i++, sym++)
2476
if (strcmp(name, sym->name) == 0)
2481
rx = symbol_top - 1;
2484
int mx = (lx + rx) / 2; /* Find center of search area. */
2489
compare = strcmp(name, sym->name);
2492
else if (compare > 0)
2495
if (overbar && !M_DEFINED(sym->type) && pass == 2) {
2496
sym->type = DEFINED;
2497
sym->val = vars_addr++;
2500
return sym; /* return exact match */
2503
/* save best non-exact match; MACRO returns last defined n-x match! */
2504
if ((M_PSEUDO(sym->type)||M_EPSEUDO(sym->type)||M_MACRO(sym->type)) &&
2505
strncmp(name, sym->name, 3) == 0)
2509
/* return best match (pseudo or macro) if any for lookups (not defns) */
2510
if (best && type == UNDEFINED)
2513
/* Must put symbol in table if index is negative. */
2514
ix = lx; /* insertion point */
2515
if( symbol_top + 1 >= SYMBOL_TABLE_SIZE ) {
2516
errorSymbol( &symbol_table_full, name, lexstart );
2520
for( rx = symbol_top; rx >= ix; rx-- )
2521
symtab[rx + 1] = symtab[rx];
2525
/* Enter the symbol as UNDEFINED with a value of zero. */
2527
strcpy( sym->name, name );
2528
sym->type = UNDEFINED;
2530
sym->xref_count = 0;
2531
if( xref && pass == 2 && sym->xref_index >= 0)
2532
xreftab[sym->xref_index] = 0;
2540
/* Function: compareSymbols */
2541
/* Synopsis: Used to presort the symbol table when starting assembler. */
2542
int compareSymbols( const void *a, const void *b )
2544
return( strcmp( ((SYM_T *) a)->name, ((SYM_T *) b)->name ));
2545
} /* compareSymbols */
2547
/* Function: evalSymbol */
2548
/* Synopsis: Get the pointer for the symbol table entry if exists. */
2549
/* If symbol doesn't exist, return a pointer to the undefined sym */
2555
sym = lookup( lexemeToName( name, lexstart, lexterm ), UNDEFINED);
2557
sym->xref_count++; /* Count the number of references to symbol. */
2559
if( xref && pass == 2 && sym->xref_index >= 0)
2561
/* Put the line number in the concordance table. */
2562
xreftab[sym->xref_index + sym->xref_count] = lineno;
2569
/* Function: moveToEndOfLine */
2570
/* Synopsis: Move the parser input to the end of the current input line. */
2571
void moveToEndOfLine()
2573
while( !ISEND( line[cc] )) cc++; /* XXX wrong! will stop on a tab! */
2576
lexstartprev = lexstart;
2577
} /* moveToEndOfLine */
2579
/* frame the next token in "line" with lexstart and lexterm indicies */
2584
/* Save start column of previous lexeme for diagnostic messages. */
2585
lexstartprev = lexstart;
2586
lextermprev = lexterm;
2594
if (op) /* looking for operators? */
2595
cc--; /* return one */
2601
if( isalnum(c) || ISOVERBAR(c)) {
2608
} while (isalnum(c) || ISOVERBAR(c));
2610
else if(!ISDONE(c) || c == '\t') /* not end of line, or comment */
2611
cc++; /* advance past all punctuation */
2619
/* XXX alpha within first 4? 3?? */
2620
for( ix = lexstart; ix < lexterm; ix++ )
2621
if(isalpha(line[ix]))
2622
return TRUE; /* any position will do! */
2627
* from macro manual (F-36BP), p.18;
2629
* "A macro-instruction definition consists of four parts;
2630
* the pseudo-instruction _define_, the _macro instruction name_
2631
* amd _dummy symbol list,_ the _body_, and the pseudo-instruction
2632
* _terminate_. Each part is followed by at least one tabulation or
2635
* and in the next paragraph;
2637
* "The name is terminated by a _space_ or by a _tab_ or _cr_
2638
* if there is no dummy symbol list."
2640
* This accepts tabs and/or a newline after define
2641
* (but will accept a space), and only accepts spaces
2642
* between macro and dummy names.
2647
int lexstartsave; /* point to macro name */
2648
int index; /* point to error char */
2649
int error; /* error boolean */
2654
char termin[SYMLEN];
2655
char args[MAC_MAX_ARGS][SYMLEN]; /* macro & arg names */
2656
char body[MAC_MAX_LENGTH + 1];
2661
/* we can call readLine, so throw up hands now */
2662
errorLexeme( &define_in_repeat, lexstartprev );
2666
while (line[lexstart] == ' ' || line[lexstart] == '\t')
2669
/* not a tab or space */
2670
if (ISEND(line[lexstart])) { /* newline or EOS? */
2671
/* crock; next token should invisibly skip over line boundaries? */
2674
while (line[lexstart] == ' ' || line[lexstart] == '\t')
2678
/* XXX pick up macro name out here */
2683
lexstartsave = lexstart;
2684
while (!ISDONE(line[lexstart]) && count < MAC_MAX_ARGS) {
2685
if (!isalnum(line[lexstart]) && index == 0)
2686
index = lexstart; /* error pointer */
2687
lexemeToName( args[count++], lexstart, lexterm );
2688
/* XXX error if NOT a comma (& not first dummy) ? */
2689
if (line[lexterm] == ',')
2690
next(0); /* eat the comma */
2692
if (line[lexstart] == ' ')
2695
if( count == 0 ) { /* No macro name. */
2696
errorMessage( &no_macro_name, lexstartsave );
2699
else if( index ) { /* Bad argument name. */
2700
errorMessage( &bad_dummy_arg, index );
2703
else if( mac_count >= MAC_TABLE_LENGTH ) {
2704
errorMessage( ¯o_table_full, lexstartsave );
2708
value = mac_count++; /* sym value is index into mac */
2709
defineSymbol( args[0], value, MACRO, lexstartsave );
2712
for( length = 0;; ) {
2717
while (line[lexstart] == ' ' || line[lexstart] == '\t')
2720
lexemeToName( termin, lexstart, lexterm ); /* just look at line? */
2721
if (strncmp( termin, "term", 4 ) == 0)
2725
int ll = strlen(line);
2726
int allblank = FALSE;
2728
/* don't save blank lines! */
2729
for( i = 0; i < ll && allblank; i++ )
2730
if(!ISBLANK(line[i]))
2733
if (allblank) /* nothing but air? */
2734
continue; /* skip it! */
2736
if ((length + ll + 1) >= MAC_MAX_LENGTH ) {
2737
errorMessage (¯o_too_long, lexstart );
2742
strcpy(body+length, line);
2749
mdp = calloc(1, sizeof(struct macdef) + length);
2751
fprintf(stderr, "error allocating memory for macro definition\n");
2754
mac_defs[value] = mdp;
2756
strncpy(mdp->body, body, length);
2757
mdp->body[length] = '\0';
2758
mdp->nargs = count - 1;
2762
* symbol slot 0 reserved for "r" symbol
2763
* move SYM_T entries to macinv to allow recursion
2766
sym->type = DEFINED;
2767
strcpy(sym->name, "R");
2769
sym->xref_index = -1; /* ??? allow xref? */
2772
for (i = 1; i <= mdp->nargs; i++, sym++) {
2773
sym->type = DEFINED;
2774
strcpy(sym->name, args[i]);
2776
sym->xref_index = -1; /* don't xref!! */
2780
/* VARIABLES pseudo-op */
2783
/* XXX error if "variables" already seen (in this pass) */
2784
/* XXX error if different address on pass 2 */
2786
printLine( line, clc, 0, LINE_LOC );
2788
vars_end = clc = (clc + nvars) & ADDRESS_FIELD;
2790
printLine( line, clc, 0, LINE_LOC);
2793
/* TEXT pseudo-op */
2801
/* XXX error in repeat!! */
2804
/* XXX EOL before delim found!!! */
2805
fprintf(stderr, "FIX ME!\n");
2809
} while (delim == ' '); /* others? NL */
2814
int c = nextfiodec(&ccase, delim);
2817
w |= c << ((2-count)*6);
2819
punchOutObject(clc, w); /* punch it! */
2825
punchOutObject(clc, w); /* punch remainder */
2830
/* CONSTANTS pseudo-op */
2835
/* XXX illegal inside macro (curmacro != NULL) */
2838
lit_loc[nconst] = clc;
2840
/* just use addition?! */
2841
for (i = 0; i < lit_count[nconst]; i++)
2849
/* XXX complain if clc != lit_base[nconst]? */
2851
for (i = 0; i < lit_count[nconst]; i++) {
2853
punchOutObject( clc, litter[i] & 0777777); /* punch it! */
2858
nlit = 0; /* litter[] now empty */
2862
/* process pseudo-ops
2863
* return FALSE if line scan should end (no longer used)
2865
BOOL pseudo( PSEUDO_T val )
2870
switch( (PSEUDO_T) val ) {
2872
next(0); /* Skip symbol */
2877
next(0); /* Skip symbol */
2882
next(0); /* Skip symbol */
2888
next(0); /* Skip symbol */
2890
/* NOTE!! constant followed by SPACE picked up as expression!! */
2891
count = getExprs() & ADDRESS_FIELD;
2892
/* XXX error if sign bit set? */
2894
/* allow comma, but do not require */
2895
if( line[lexstart] == ',')
2899
repeatstart = lexstart; /* save line start */
2900
while (count-- > 0) {
2901
cc = repeatstart; /* reset input pointer */
2902
processLine(); /* recurse! */
2911
next(0); /* Skip symbol */
2912
/* XXX illegal in macro or repeat */
2914
if (!ISDONE(line[lexstart])) {
2915
if (line[lexstart] == ' ')
2917
start_addr = getExprs() & ADDRESS_FIELD;
2919
printLine( line, 0, start_addr, LINE_VAL );
2920
/* MACRO punches 4" of leader */
2921
punchTriplet(JMP | start_addr);
2922
/* MACRO punches 24" of leader? */
2925
* handle multiple tapes concatenated into one file!!
2926
* have command line option?? treat "start" as EOF??
2928
list_title_set = FALSE;
2932
/* NOTE!! no next()! */
2937
next(0); /* Skip symbol */
2942
next(0); /* Skip symbol */
2949
} /* end switch for pseudo-ops */
2950
return TRUE; /* keep scanning */
2954
/* Function: errorLexeme */
2955
/* Synopsis: Display an error message using the current lexical element. */
2956
void errorLexeme( EMSG_T *mesg, WORD32 col )
2960
errorSymbol( mesg, lexemeToName( name, lexstart, lexterm ), col );
2964
/* Function: errorSymbol */
2965
/* Synopsis: Display an error message with a given string. */
2966
void errorSymbol( EMSG_T *mesg, char *name, WORD32 col )
2973
s = ( name == NULL ) ? "" : name ;
2975
sprintf( linecol, ":%d:%d", lineno, col + 1 );
2976
fprintf( errorfile, "%s%-9s : error: %s \"%s\" at Loc = %5.5o\n",
2977
filename, linecol, mesg->file, s, clc );
2978
saveError( mesg->list, col );
2980
error_in_line = TRUE;
2984
/* Function: errorMessage */
2985
/* Synopsis: Display an error message without a name argument. */
2986
void errorMessage( EMSG_T *mesg, WORD32 col )
2993
sprintf( linecol, ":%d:%d", lineno, col + 1 );
2994
fprintf( errorfile, "%s%-9s : error: %s at Loc = %5.5o\n",
2995
filename, linecol, mesg->file, clc );
2996
saveError( mesg->list, col );
2998
error_in_line = TRUE;
2999
} /* errorMessage */
3001
/* Function: saveError */
3002
/* Synopsis: Save the current error in a list so it may displayed after the */
3003
/* the current line is printed. */
3004
void saveError( char *mesg, WORD32 col )
3006
if( save_error_count < DIM( error_list ))
3008
error_list[save_error_count].mesg = mesg;
3009
error_list[save_error_count].col = col;
3012
error_in_line = TRUE;
3015
printErrorMessages();
3018
/* create a "symbol punch" for DDT */
3019
/* MUST be called after object file closed; we reuse the FILE*! */
3022
dump_symbols(void) {
3026
objectfile = fopen( sympathname, "wb" );
3028
perror(sympathname);
3036
/* XXX fudge addr -- get count, and subtract 2N from 07750? */
3039
for( ix = 0; ix < symbol_top; ix++ ) {
3043
type = symtab[ix].type;
3044
if (M_FIXED(type) || M_PSEUDO(type) || M_MACRO(type))
3048
for (i = 0; i < 3; i++) {
3051
c = symtab[ix].name[i];
3052
/* XXX leave on NUL? */
3054
c = ascii_to_fiodec[tolower(c) & 0177];
3055
/* XXX check for BAD entries? */
3057
/* XXX OR in val<<(3-i)*6?? */
3059
name |= c & CHARBITS;
3061
punchLocObject(addr++, permute(name));
3062
punchLocObject(addr++, symtab[ix].val);
3065
punchTriplet( JMP ); /* ??? */