~ubuntu-branches/ubuntu/utopic/simh/utopic

« back to all changes in this revision

Viewing changes to TOOLS/crossassemblers/macro1.c

  • Committer: Bazaar Package Importer
  • Author(s): Vince Mulhollon
  • Date: 2004-04-20 20:01:26 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040420200126-ehsuleda8xcgi51h
Tags: 3.2.0-1
New upstream 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id: macro1.c,v 1.74 2003/10/23 23:29:17 phil Exp $
 
3
 *
 
4
 * TODO:
 
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?
 
8
 *
 
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??
 
15
 *
 
16
 * macro addressing: labels defined during macro are local use only????
 
17
 *      spacewar expects this??? (is it wrong?)
 
18
 *
 
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
 
25
 *
 
26
 * other;
 
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 ','?
 
33
 */
 
34
 
 
35
/*
 
36
 * Program:  MACRO1
 
37
 * File:     macro1.c
 
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>
 
42
 *
 
43
 * Purpose:  A 2 pass PDP-1 assembler
 
44
 *
 
45
 * NAME
 
46
 *    macro1 - a PDP-1 assembler.
 
47
 *
 
48
 * SYNOPSIS:
 
49
 *    macro1 [ -d -p -m -r -s -x ] inputfile inputfile...
 
50
 *
 
51
 * DESCRIPTION
 
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)
 
68
 *
 
69
 * OPTIONS
 
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
 
73
 *          START in it.)
 
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)
 
77
 *    -S file
 
78
 *         Read a symbol tape back in
 
79
 *
 
80
 * DIAGNOSTICS
 
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
 
83
 *
 
84
 *       <filename>:<line>:<col> : error:  <message> at Loc = <loc>
 
85
 *
 
86
 *    An example error message is:
 
87
 *
 
88
 *       bintst.7:17:9 : error:  undefined symbol "UNDEF" at Loc = 07616
 
89
 *
 
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:
 
94
 *
 
95
 *          17 07616 3000          DAC     UNDEF
 
96
 *       UD undefined                      ^
 
97
 *          18 07617 1777          TAD  I  DUMMY
 
98
 *
 
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:
 
102
 *
 
103
 *       #REDEF   04567
 
104
 *        SWITCH  07612
 
105
 *       ?UNDEF   00000
 
106
 *
 
107
 *    Refer to the code for the diagnostic messages generated.
 
108
 *
 
109
 * REFERENCES:
 
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>
 
113
 *
 
114
 * COPYRIGHT NOTICE:
 
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
 
120
 *    new version.
 
121
 *
 
122
 *
 
123
 * Amendments Record:
 
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
 
140
 */
 
141
 
 
142
 
 
143
#include <ctype.h>
 
144
#include <stdio.h>
 
145
#include <stdlib.h>
 
146
#include <string.h>
 
147
 
 
148
#define LINELEN              96
 
149
#define LIST_LINES_PER_PAGE  60         /* Includes 3 line page header. */
 
150
#define NAMELEN             128
 
151
#define SYMBOL_COLUMNS        5
 
152
#define SYMLEN                7
 
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. */
 
158
 
 
159
#define MAX_LITERALS       1000
 
160
#define MAX_CONSTANTS        10         /* max number of "constants" blocks  */
 
161
 
 
162
#define XREF_COLUMNS          8
 
163
 
 
164
#define ADDRESS_FIELD  0007777
 
165
#define INDIRECT_BIT   0010000
 
166
#define OP_CODE        0760000
 
167
 
 
168
#define CONCISE_LC 072
 
169
#define CONCISE_UC 074
 
170
 
 
171
/* Macro to get the number of elements in an array. */
 
172
#define DIM(a) (sizeof(a)/sizeof(a[0]))
 
173
 
 
174
#define ISBLANK(c) ((c==' ') || (c=='\f'))
 
175
#define ISEND(c)   ((c=='\0')|| (c=='\n') || (c == '\t'))
 
176
#define ISDONE(c)  ((c=='/') || ISEND(c))
 
177
 
 
178
#define ISOVERBAR(c) (c == '\\' || c == '~')
 
179
 
 
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 */
 
183
/* tested. */
 
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)
 
192
 
 
193
typedef unsigned char BOOL;
 
194
typedef unsigned char BYTE;
 
195
typedef          int  WORD32;
 
196
 
 
197
#ifndef FALSE
 
198
  #define FALSE 0
 
199
  #define TRUE (!FALSE)
 
200
#endif
 
201
 
 
202
/* Line listing styles.  Used to control listing of lines. */
 
203
enum linestyle_t
 
204
{
 
205
  LINE, LINE_VAL, LINE_LOC_VAL, LOC_VAL, LINE_LOC
 
206
};
 
207
typedef enum linestyle_t LINESTYLE_T;
 
208
 
 
209
/* Symbol Types. */
 
210
/* Note that the names that have FIX as the suffix contain the FIXED bit */
 
211
/* included in the value. */
 
212
enum symtyp
 
213
{
 
214
  UNDEFINED = 0000,
 
215
  DEFINED   = 0001,
 
216
  FIXED     = 0002,
 
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
 
225
};
 
226
typedef enum symtyp SYMTYP;
 
227
 
 
228
enum pseudo_t {
 
229
    DECIMAL,
 
230
    DEFINE,
 
231
    FLEX,
 
232
    CONSTANTS,
 
233
    OCTAL,
 
234
    REPEAT,
 
235
    START,
 
236
    CHAR,
 
237
    VARIABLES,
 
238
    TEXT,
 
239
    NOINPUT,
 
240
    EXPUNGE
 
241
};
 
242
typedef enum pseudo_t PSEUDO_T;
 
243
 
 
244
struct sym_t
 
245
{
 
246
  SYMTYP  type;
 
247
  char    name[SYMLEN];
 
248
  WORD32  val;
 
249
  WORD32  xref_index;
 
250
  WORD32  xref_count;
 
251
};
 
252
typedef struct sym_t SYM_T;
 
253
 
 
254
struct emsg_t
 
255
{
 
256
  char  *list;
 
257
  char  *file;
 
258
};
 
259
typedef struct emsg_t EMSG_T;
 
260
 
 
261
struct errsave_t
 
262
{
 
263
  char   *mesg;
 
264
  WORD32  col;
 
265
};
 
266
typedef struct errsave_t ERRSAVE_T;
 
267
 
 
268
/*----------------------------------------------------------------------------*/
 
269
 
 
270
/* Function Prototypes */
 
271
 
 
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 );
 
279
SYM_T   eval( void );
 
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 );
 
286
BOOL    isLexSymbol();
 
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 );
 
291
void    next(int);
 
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);
 
310
void    eob(void);
 
311
void    dump_symbols(void);
 
312
 
 
313
/*----------------------------------------------------------------------------*/
 
314
 
 
315
/* Table of pseudo-ops (directives) which are used to setup the symbol */
 
316
/* table on startup */
 
317
SYM_T pseudos[] =
 
318
{
 
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. */
 
332
};
 
333
 
 
334
/* Symbol Table */
 
335
/* The table is put in lexical order on startup, so symbols can be */
 
336
/* inserted as desired into the initial table. */
 
337
#define DIO 0320000
 
338
#define JMP 0600000
 
339
SYM_T permanent_symbols[] =
 
340
{
 
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 },*/
 
405
 
 
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 },
 
417
  /* IOT's */
 
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 */
 
434
 
 
435
/* Global variables */
 
436
SYM_T *symtab;                          /* Symbol Table */
 
437
int    symbol_top;                      /* Number of entries in symbol table. */
 
438
 
 
439
#define LOADERBASE 07751
 
440
 
 
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)
 
447
 
 
448
WORD32 loader[] = {
 
449
    0730002,                            /* in,  rpb */
 
450
    0320000+LOADER_A,                   /*      dio a */
 
451
    0100000+LOADER_A,                   /*      xct a */
 
452
    0320000+LOADER_CK,                  /*      dio ck */
 
453
    0730002,                            /*      rpb */
 
454
    0320000+LOADER_EN1,                 /*      dio en1 */
 
455
    0730002,                            /* b,   rpb */
 
456
    0000000,                            /* a,   xx */
 
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 */
 
465
    0730002,                            /*      rpb */
 
466
    0320000+LOADER_CK,                  /*      dio ck */
 
467
    0520000+LOADER_CK,                  /*      sas ck */
 
468
    0760400,                            /*      hlt */
 
469
    0600000+LOADER_IN                   /*      jmp in */
 
470
                                        /* ck,  0 */
 
471
                                        /* en1, 0 */
 
472
};
 
473
 
 
474
#define LOADERBUFSIZE 0100              /* <=0100, power of 2*/
 
475
#define LOADERBUFMASK (LOADERBUFSIZE-1) /* for block alignment */
 
476
 
 
477
WORD32 loaderbuf[LOADERBUFSIZE];
 
478
WORD32 loaderbufcount;
 
479
WORD32 loaderbufstart;
 
480
 
 
481
/*----------------------------------------------------------------------------*/
 
482
 
 
483
WORD32 *xreftab;                        /* Start of the concordance table. */
 
484
 
 
485
ERRSAVE_T error_list[20];
 
486
int     save_error_count;
 
487
 
 
488
char   s_detected[] = "detected";
 
489
char   s_error[]    = "error";
 
490
char   s_errors[]   = "errors";
 
491
char   s_no[]       = "No";
 
492
char   s_page[]     = "Page";
 
493
char   s_symtable[] = "Symbol Table";
 
494
char   s_xref[]     = "Cross Reference";
 
495
 
 
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" };
 
555
 
 
556
/*----------------------------------------------------------------------------*/
 
557
 
 
558
FILE   *errorfile;
 
559
FILE   *infile;
 
560
FILE   *listfile;
 
561
FILE   *listsave;
 
562
FILE   *objectfile;
 
563
FILE   *objectsave;
 
564
 
 
565
char    filename[NAMELEN];
 
566
char    listpathname[NAMELEN];
 
567
char    sympathname[NAMELEN];
 
568
char    objectpathname[NAMELEN];
 
569
char   *pathname;
 
570
char    permpathname[NAMELEN];
 
571
 
 
572
WORD32  mac_count;                      /* Total macros defined. */
 
573
 
 
574
/*
 
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"
 
579
 */
 
580
struct macdef {
 
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];
 
585
 
 
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 */
 
593
 
 
594
int     nrepeats;                       /* count of nested repeats */
 
595
 
 
596
int     list_lineno;
 
597
int     list_pageno;
 
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. */
 
604
WORD32  listedsave;
 
605
 
 
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 */
 
619
 
 
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 */
 
623
 
 
624
int     noinput;                        /* don't punch loader */
 
625
 
 
626
int     nvars;                          /* number of variables */
 
627
WORD32  vars_addr;                      /* address of "variables" */
 
628
WORD32  vars_end;                       /* end of "variables" */
 
629
 
 
630
/* pass 2 only; */
 
631
int     nlit;                           /* number of literals in litter[] */
 
632
WORD32  litter[MAX_LITERALS];           /* literals */
 
633
 
 
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 */
 
645
BOOL    xref;
 
646
 
 
647
SYM_T   sym_undefined = { UNDEFINED, "", 0 };/* Symbol Table Terminator */
 
648
 
 
649
/* initial data from SIMH v3.0 pdp1_stddev.c (different encoding of UC/LC) */
 
650
#define UC 0100                         /* Upper case */
 
651
#define LC 0200
 
652
#define CHARBITS 077
 
653
#define BC LC|UC                        /* both case bits */
 
654
#define BAD 014                         /* unused concise code */
 
655
 
 
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
 
673
};
 
674
 
 
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 };
 
685
 
 
686
/* used at startup & for expunge */
 
687
void
 
688
init_symtab(void) {
 
689
    /* Place end marker in symbol table. */
 
690
    symtab[0] = sym_undefined;
 
691
    symbol_top = 0;
 
692
}
 
693
 
 
694
/*  Function:  main */
 
695
/*  Synopsis:  Starting point.  Controls order of assembly. */
 
696
int
 
697
main( int argc, char *argv[] )
 
698
{
 
699
    int     ix;
 
700
    int     space;
 
701
 
 
702
    save_argc = argc;
 
703
    save_argv = argv;
 
704
 
 
705
    /* Set the default values for global symbols. */
 
706
    print_permanent_symbols = FALSE;
 
707
    nomac_exp = TRUE;
 
708
    rim_mode = FALSE;                   /* default to loader tapes */
 
709
    sym_dump = FALSE;
 
710
    noinput = FALSE;
 
711
 
 
712
    symtab_print = FALSE;
 
713
    xref = FALSE;
 
714
    pathname = NULL;
 
715
 
 
716
    /* init symbol table before processing arguments, so we can
 
717
     * load symbol punch tapes on the fly
 
718
     */
 
719
 
 
720
    /*
 
721
     * Setup the error file in case symbol table overflows while
 
722
     * installing the permanent symbols.
 
723
     */
 
724
    errorfile = stderr;
 
725
    pass = 0;                           /* required for symbol table init */
 
726
    symtab = (SYM_T *) malloc( sizeof( SYM_T ) * SYMBOL_TABLE_SIZE );
 
727
 
 
728
    if( symtab == NULL ) {
 
729
        fprintf( stderr, "Could not allocate memory for symbol table.\n");
 
730
        exit( -1 );
 
731
    }
 
732
 
 
733
    init_symtab();
 
734
 
 
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 );
 
738
 
 
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 );
 
745
 
 
746
    /* Get the options and pathnames */
 
747
    getArgs( argc, argv );
 
748
 
 
749
    /* Do pass one of the assembly */
 
750
    pass = 1;
 
751
    onePass();
 
752
    errors_pass_1 = errors;
 
753
 
 
754
    /* Set up for pass two */
 
755
    objectfile = fopen( objectpathname, "wb" );
 
756
    objectsave = objectfile;
 
757
 
 
758
    listfile = fopen( listpathname, "w" );
 
759
    listsave = listfile;
 
760
 
 
761
    /* XXX punch title into tape! */
 
762
    punchLeader( 0 );
 
763
    if (!rim_mode) {
 
764
        punchLoader();
 
765
        punchLeader(5);
 
766
    }
 
767
 
 
768
    if (nlit > 0)
 
769
        constants();                    /* implied "constants"? */
 
770
 
 
771
    /* Do pass two of the assembly */
 
772
    errors = 0;
 
773
    save_error_count = 0;
 
774
 
 
775
    if( xref ) {
 
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. */
 
781
        }
 
782
        /* Allocate & clear the necessary space. */
 
783
        xreftab = (WORD32 *) calloc( space, sizeof( WORD32 ));
 
784
    }
 
785
    pass = 2;
 
786
    onePass();
 
787
 
 
788
    objectfile = objectsave;
 
789
 
 
790
    /* Works great for trailer. */
 
791
    punchLeader( 1 );
 
792
 
 
793
    /* undo effects of NOLIST for any following output to listing file. */
 
794
    listfile = listsave;
 
795
 
 
796
    /* Display value of error counter. */
 
797
    if( errors == 0 ) {
 
798
        fprintf( listfile, "\n      %s %s %s\n", s_no, s_errors, s_detected );
 
799
    }
 
800
    else {
 
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 ));
 
805
    }
 
806
 
 
807
    if( symtab_print )
 
808
        printSymbolTable();
 
809
 
 
810
    if( print_permanent_symbols )
 
811
        printPermanentSymbolTable();
 
812
 
 
813
    if( xref )
 
814
        printCrossReference();
 
815
 
 
816
    fclose( objectfile );
 
817
    fclose( listfile );
 
818
    if( errors == 0 && errors_pass_1 == 0 ) {
 
819
        /* after closing objectfile -- we reuse the FILE *!! */
 
820
        if (sym_dump)
 
821
            dump_symbols();
 
822
    }
 
823
    else
 
824
        remove( objectpathname );
 
825
 
 
826
    return( errors != 0 );
 
827
} /* main() */
 
828
 
 
829
/* read a word from a binary punch file */
 
830
WORD32
 
831
getw(FILE *f)
 
832
{
 
833
    int i, c;
 
834
    WORD32 w;
 
835
 
 
836
    w = 0;
 
837
    for (i = 0; i < 3;) {
 
838
        c = getc(f);
 
839
        if (c == -1)
 
840
            return -1;
 
841
        if (c & 0200) {                 /* ignore if ch8 not punched */
 
842
            w <<= 6;
 
843
            w |= c & 077;
 
844
            i++;
 
845
        }
 
846
    }
 
847
    return w;
 
848
}
 
849
 
 
850
/*
 
851
 * "permute zone bits" like MACRO does for proper sorting
 
852
 * (see routine "per" in MACRO) -- it's what DDT expects
 
853
 *
 
854
 * it's it's own inverse!
 
855
 */
 
856
 
 
857
WORD32
 
858
permute(WORD32 name)
 
859
{
 
860
    WORD32 temp;
 
861
 
 
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 */
 
866
    return name;
 
867
}
 
868
 
 
869
/* add a symbol from a "symbol punch" tape */
 
870
void
 
871
addsym(WORD32 sym, WORD32 val)
 
872
{
 
873
    char name[4];
 
874
 
 
875
    sym = permute(sym);
 
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];
 
879
    name[3] = '\0';
 
880
    defineSymbol( name, val, LABEL, 0);
 
881
}
 
882
 
 
883
void
 
884
read_symbols(char *fname)
 
885
{
 
886
    FILE *f;
 
887
 
 
888
    f = fopen(fname, "rb");
 
889
    if (!f) {
 
890
        perror(fname);
 
891
        exit(1);
 
892
    }
 
893
 
 
894
    /* skip loader */
 
895
    for (;;) {
 
896
        WORD32 w;
 
897
 
 
898
        w = getw(f);
 
899
        if (w == -1)
 
900
            goto err;                   /* XXX complain? */
 
901
        if ((w & OP_CODE) == JMP)
 
902
            break;
 
903
        if ((w & OP_CODE) != DIO)
 
904
            goto err;                   /* XXX complain? */
 
905
        w = getw(f);
 
906
        if (w == -1)
 
907
            goto err;                   /* XXX complain? */
 
908
    }
 
909
 
 
910
 
 
911
    /* XXX should push block reader down into a co-routine */
 
912
    for (;;) {
 
913
        WORD32 start, end, sum;
 
914
 
 
915
        start = getw(f);
 
916
        if ((start & OP_CODE) == JMP) {
 
917
            fclose(f);
 
918
            return;
 
919
        }
 
920
 
 
921
        if (start == -1 || (start & OP_CODE) != DIO)
 
922
            goto err;
 
923
 
 
924
        end = getw(f);
 
925
        if (end == -1 || (end & OP_CODE) != DIO)
 
926
            goto err;                   /* XXX complain? */
 
927
 
 
928
        sum = start + end;
 
929
        while (start < end) {
 
930
            WORD32 sym, val;
 
931
            sym = getw(f);
 
932
            if (sym == -1)
 
933
                goto err;
 
934
            sum += sym;
 
935
            start++;
 
936
            /* XXX handle block boundaries? */
 
937
            if (start >= end)
 
938
                goto err;
 
939
            val = getw(f);
 
940
            if (val == -1)
 
941
                goto err;
 
942
            /*printf("%06o %06o\n", sym, val);*/
 
943
            addsym(sym, val);
 
944
            sum += val;
 
945
            start++;
 
946
        }
 
947
        start = getw(f);                /* eat checksum XXX verify? */
 
948
        if (start == -1)
 
949
            goto err;
 
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 */
 
954
                sum++;
 
955
        }
 
956
        if (start != sum)
 
957
            goto err;
 
958
    }
 
959
err:
 
960
    fprintf(stderr, "error reading symbol file %s\n", fname);
 
961
    exit(1);
 
962
}
 
963
 
 
964
/*  Function:  getArgs */
 
965
/*  Synopsis:  Parse command line, set flags accordingly and setup input and */
 
966
/*             output files. */
 
967
void getArgs( int argc, char *argv[] )
 
968
{
 
969
  WORD32  len;
 
970
  WORD32  ix, jx;
 
971
 
 
972
  /* Set the defaults */
 
973
  infile = NULL;
 
974
  listfile = NULL;
 
975
  listsave = NULL;
 
976
  objectfile = NULL;
 
977
  objectsave = NULL;
 
978
 
 
979
  for( ix = 1; ix < argc; )
 
980
  {
 
981
    if( argv[ix][0] == '-' )
 
982
    {
 
983
      char *switches = argv[ix++];
 
984
      for( jx = 1; switches[jx] != 0; jx++ )
 
985
      {
 
986
        switch( switches[jx] )
 
987
        {
 
988
        case 'd':
 
989
          symtab_print = TRUE;
 
990
          break;
 
991
 
 
992
        case 'r':
 
993
          rim_mode = TRUE;              /* punch pure rim-mode tapes */
 
994
          break;
 
995
 
 
996
        case 's':
 
997
          sym_dump = TRUE;
 
998
          break;
 
999
 
 
1000
        case 'm':
 
1001
          nomac_exp = FALSE;
 
1002
          break;
 
1003
 
 
1004
        case 'p':
 
1005
          print_permanent_symbols = TRUE;
 
1006
          break;
 
1007
 
 
1008
        case 'x':
 
1009
          xref = TRUE;
 
1010
          break;
 
1011
 
 
1012
        case 'S':
 
1013
          if (ix <= argc)
 
1014
              read_symbols(argv[ix++]);
 
1015
          break;
 
1016
 
 
1017
        default:
 
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" );
 
1026
          fflush( stderr );
 
1027
          exit( -1 );
 
1028
        } /* end switch */
 
1029
      } /* end for */
 
1030
    }
 
1031
    else
 
1032
    {
 
1033
      filix_start = ix;
 
1034
      pathname = argv[ix];
 
1035
      break;
 
1036
    }
 
1037
  } /* end for */
 
1038
 
 
1039
  if( pathname == NULL )
 
1040
  {
 
1041
    fprintf( stderr, "%s:  no input file specified\n", argv[0] );
 
1042
    exit( -1 );
 
1043
  }
 
1044
 
 
1045
  len = strlen( pathname );
 
1046
  if( len > NAMELEN - 5 )
 
1047
  {
 
1048
    fprintf( stderr, "%s: pathname \"%s\" too long\n", argv[0], pathname );
 
1049
    exit( -1 );
 
1050
  }
 
1051
 
 
1052
  /* Now make the pathnames */
 
1053
  /* Find last '.', if it exists. */
 
1054
  jx = len - 1;
 
1055
  while( pathname[jx] != '.'  && pathname[jx] != '/'
 
1056
      && pathname[jx] != '\\' && jx >= 0 )
 
1057
  {
 
1058
    jx--;
 
1059
  }
 
1060
 
 
1061
  switch( pathname[jx] )
 
1062
  {
 
1063
  case '.':
 
1064
    break;
 
1065
 
 
1066
  case '/':
 
1067
  case '\\':
 
1068
    jx = len;
 
1069
    break;
 
1070
 
 
1071
  default:
 
1072
    break;
 
1073
  }
 
1074
 
 
1075
  /* Add the pathname extensions. */
 
1076
  strncpy( objectpathname, pathname, jx );
 
1077
  objectpathname[jx] = '\0';
 
1078
  strcat( objectpathname, ".rim");
 
1079
 
 
1080
  strncpy( listpathname, pathname, jx );
 
1081
  listpathname[jx] = '\0';
 
1082
  strcat( listpathname, ".lst" );
 
1083
 
 
1084
  strncpy( permpathname, pathname, jx );
 
1085
  permpathname[jx] = '\0';
 
1086
  strcat( permpathname, ".prm" );
 
1087
 
 
1088
  strncpy( sympathname, pathname, jx );
 
1089
  sympathname[jx] = '\0';
 
1090
  strcat( sympathname, ".sym" );
 
1091
 
 
1092
  /* Extract the filename from the path. */
 
1093
  if( isalpha( pathname[0] ) && pathname[1] == ':' && pathname[2] != '\\' )
 
1094
      pathname[1] = '\\';               /* MS-DOS style pathname */
 
1095
 
 
1096
  jx = len - 1;
 
1097
  while( pathname[jx] != '/' && pathname[jx] != '\\' && jx >= 0 )
 
1098
      jx--;
 
1099
  strcpy( filename, &pathname[jx + 1] );
 
1100
} /* getArgs() */
 
1101
 
 
1102
 
 
1103
int
 
1104
invokeMacro(int index)
 
1105
{
 
1106
    struct macinv *mip;
 
1107
    struct macdef *mdp;
 
1108
    int jx;
 
1109
 
 
1110
    mdp = mac_defs[index];
 
1111
    if (mdp == NULL || mdp->body[0] == '\0')
 
1112
        return 0;
 
1113
 
 
1114
    /* Find arguments. */
 
1115
    while (ISBLANK(line[lexstart]))
 
1116
        next(0);
 
1117
 
 
1118
    mip = calloc(1, sizeof(struct macinv));
 
1119
    if (!mip) {
 
1120
        fprintf(stderr, "could not allocate memory for macro invocation\n");
 
1121
        exit(1);
 
1122
    }
 
1123
    mip->defn = mdp;
 
1124
 
 
1125
    /* evaluate args, saving values in SYM_T entries in defn.
 
1126
     * (cannot have recursive macros)
 
1127
     */
 
1128
    mdp->args[0].val = clc;             /* r is location at start */
 
1129
    for( jx = 1; !ISDONE(line[lexstart]) && jx <= MAC_MAX_ARGS; ) {
 
1130
        WORD32 val;
 
1131
 
 
1132
        next(0);
 
1133
        if (ISDONE(line[lexstart]))
 
1134
            break;
 
1135
 
 
1136
        if (line[lexstart] == ',')
 
1137
            next(0);
 
1138
 
 
1139
        while( ISBLANK( line[lexstart] ))
 
1140
            next(0);
 
1141
 
 
1142
        if (ISDONE(line[lexstart]))
 
1143
            break;
 
1144
 
 
1145
        val = getExprs();
 
1146
 
 
1147
        /* ignore excess values silently? */
 
1148
        if (jx <= mdp->nargs)
 
1149
            mdp->args[jx].val = val;
 
1150
        jx++;
 
1151
    } /* end for */
 
1152
 
 
1153
    /* XXX complain if too few actuals? -- nah */
 
1154
    while (jx <= mdp->nargs)
 
1155
        mdp->args[jx++].val = 0;
 
1156
 
 
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! */
 
1162
    return 1;
 
1163
}
 
1164
 
 
1165
/* process input; used by onePass and repeat */
 
1166
void
 
1167
processLine() {
 
1168
    if (!list_title_set) {
 
1169
        char *cp;
 
1170
 
 
1171
        /* assert(sizeof(title) >= sizeof(line)); */
 
1172
        strcpy(list_title, line);
 
1173
 
 
1174
        if ((cp = strchr(list_title, '\n')))
 
1175
            *cp = '\0';
 
1176
 
 
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) */
 
1181
        }
 
1182
        return;
 
1183
    }
 
1184
 
 
1185
    for (;;) {
 
1186
        int jx;
 
1187
        SYM_T evalue;
 
1188
 
 
1189
        next(0);
 
1190
        if( end_of_input )
 
1191
            return;
 
1192
 
 
1193
        if( ISEND( line[lexstart] )) {
 
1194
            if (line[lexstart] != '\t')
 
1195
                return;
 
1196
            continue;
 
1197
        }
 
1198
        if (line[lexstart] == '/')      /* comment? */
 
1199
            return;                     /* done */
 
1200
 
 
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]))
 
1205
                break;
 
1206
        if( line[jx] == '/') {          /* EXP/ set location */
 
1207
            WORD32  newclc;
 
1208
 
 
1209
            newclc = getExprs();
 
1210
 
 
1211
            /* Do not change Current Location Counter if an error occurred. */
 
1212
            if( !error_in_line )
 
1213
                clc = newclc;
 
1214
 
 
1215
            printLine( line, newclc, 0, LINE_LOC );
 
1216
            cc = jx + 1;
 
1217
            next(0);                    /* discard slash */
 
1218
            continue;
 
1219
        }
 
1220
 
 
1221
        switch( line[lexterm] ) {
 
1222
        case ',':
 
1223
            if( isLexSymbol()) {
 
1224
                WORD32 val;
 
1225
                SYM_T *sym;
 
1226
                char name[SYMLEN];
 
1227
 
 
1228
                /* Use lookup so symbol will not be counted as reference. */
 
1229
                sym = lookup(lexemeToName(name, lexstart, lexterm), UNDEFINED);
 
1230
 
 
1231
                if (curmacro) {
 
1232
                    /* relative during macro expansion!! */
 
1233
                    val = clc - curmacro->defn->args[0].val;
 
1234
                }
 
1235
                else
 
1236
                    val = clc;
 
1237
 
 
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! */
 
1242
                }
 
1243
                /* Must call define on pass 2 to generate concordance. */
 
1244
                defineLexeme( lexstart, lexterm, val, LABEL );
 
1245
            }
 
1246
            else if (isdigit(line[lexstart])) { /* constant, */
 
1247
                int i;
 
1248
                WORD32 val = 0;
 
1249
 
 
1250
                for( i = lexstart; i < lexterm; i++ ) {
 
1251
                    if( isdigit( line[i] )) {
 
1252
                        int digit;
 
1253
                        digit = line[i] - '0';
 
1254
                        if( digit >= radix ) {
 
1255
                            errorLexeme( &number_not_radix, i );
 
1256
                            val = 0;
 
1257
                            break;
 
1258
                        }
 
1259
                        val = val * radix + digit;
 
1260
                    }
 
1261
                    else {
 
1262
                        errorLexeme( &not_a_number, lexstart );
 
1263
                        val = 0;
 
1264
                        break;
 
1265
                    }
 
1266
                }
 
1267
                if (i == lexterm) {
 
1268
                    if( clc != val && pass == 2 )
 
1269
                        errorLexeme( &duplicate_label, lexstart); /* XXX */
 
1270
                }
 
1271
            }
 
1272
            else
 
1273
                errorLexeme( &label_syntax, lexstart );
 
1274
            next(0);                    /* skip comma */
 
1275
            continue;
 
1276
 
 
1277
        case '=':
 
1278
            if( isLexSymbol()) {
 
1279
                WORD32 start, term, val;
 
1280
 
 
1281
                start = lexstart;
 
1282
                term = lexterm;
 
1283
                next(0);                /* skip symbol */
 
1284
                next(0);                /* skip trailing = */
 
1285
                val = getExprs();
 
1286
                defineLexeme( start, term, val, DEFINED );
 
1287
                printLine( line, 0, val, LINE_VAL );
 
1288
            }
 
1289
            else {
 
1290
                errorLexeme( &symbol_syntax, lexstartprev );
 
1291
                next(0);                /* skip symbol */
 
1292
                next(0);                /* skip trailing = */
 
1293
                getExprs();             /* skip expression */
 
1294
            }
 
1295
            continue;
 
1296
        } /* switch on terminator */
 
1297
 
 
1298
        if( isLexSymbol()) {
 
1299
            SYM_T  *sym;
 
1300
            WORD32  val;
 
1301
 
 
1302
            sym = evalSymbol();
 
1303
            val = sym->val;
 
1304
            if( M_MACRO(sym->type)) {
 
1305
                if (!invokeMacro(val))
 
1306
                    next(0);            /* bad defn? or body is empty! */
 
1307
                continue;
 
1308
            } /* macro invocation */
 
1309
            else if( M_PSEUDO(sym->type)) {     /* NO EPSEUDOs */
 
1310
                pseudo( (PSEUDO_T)val & 0777777 );
 
1311
                continue;
 
1312
            } /* pseudo */
 
1313
        } /* macro, or non-char pseudo */
 
1314
 
 
1315
        evalue = getExpr();
 
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 */
 
1320
            }
 
1321
            else if (line[lexstart] == '/') {   /* EXP/ */
 
1322
                clc = evalue.val;
 
1323
                printLine( line, clc, 0, LINE_LOC );
 
1324
                next(0);
 
1325
            }
 
1326
            else {
 
1327
                punchOutObject( clc, evalue.val & 0777777); /* punch it! */
 
1328
                incrementClc();
 
1329
            }
 
1330
        }
 
1331
    } /* forever */
 
1332
}
 
1333
 
 
1334
/*  Function:  onePass */
 
1335
/*  Synopsis:  Do one assembly pass. */
 
1336
void onePass() {
 
1337
    int     ix;
 
1338
 
 
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 */
 
1343
 
 
1344
    while (curmacro) {                  /* pop macro stack */
 
1345
        struct macinv *mp;
 
1346
 
 
1347
        mp = curmacro->prev;
 
1348
        free(curmacro);
 
1349
        curmacro = mp;
 
1350
    }
 
1351
 
 
1352
    for( ix = 0; ix < mac_count; ix++) {
 
1353
        if (mac_defs[ix])
 
1354
            free( mac_defs[ix] );
 
1355
        mac_defs[ix] = NULL;
 
1356
    }
 
1357
    mac_count = 0;                      /* No macros defined. */
 
1358
 
 
1359
    listed = TRUE;
 
1360
    lineno = 0;
 
1361
    list_pageno = 0;
 
1362
    list_lineno = 0;
 
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). */
 
1366
 
 
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] );
 
1373
        exit( -1 );
 
1374
    }
 
1375
 
 
1376
    for (;;) {
 
1377
        readLine();
 
1378
        if (end_of_input) {
 
1379
            eob();
 
1380
            fclose( infile );
 
1381
            return;
 
1382
        }
 
1383
        processLine();
 
1384
    } /* forever */
 
1385
} /* onePass */
 
1386
 
 
1387
 
 
1388
/*  Function:  getExprs */
 
1389
/*  Synopsys:  gutted like a fish */
 
1390
WORD32 getExprs()
 
1391
{
 
1392
    SYM_T sym;
 
1393
 
 
1394
    sym = getExpr();
 
1395
    if (sym.type == PSEUDO)
 
1396
        errorMessage( &value_required, lexstart ); /* XXX wrong pointer? */
 
1397
 
 
1398
    return sym.val & 0777777;
 
1399
} /* getExprs */
 
1400
 
 
1401
 
 
1402
SYM_T getExpr()
 
1403
{
 
1404
    SYM_T sym;
 
1405
 
 
1406
    sym = eval();
 
1407
 
 
1408
    /* Here we assume the current lexeme is the operator separating the */
 
1409
    /* previous operator from the next, if any. */
 
1410
 
 
1411
    for (;;) {
 
1412
        int space;
 
1413
        /*
 
1414
         * falling out of switch breaks loop and returns from routine
 
1415
         * so if you want to keep going, you must "continue"!!
 
1416
         */
 
1417
        space = FALSE;
 
1418
        switch( line[lexstart] ) {
 
1419
        case ' ':
 
1420
            space = TRUE;
 
1421
            /* fall */
 
1422
        case '+':                       /* add */
 
1423
            next(1);                    /* skip operator */
 
1424
            if (space && ISEND(line[lexstart])) /* tollerate a trailing space */
 
1425
                return sym;
 
1426
            sym.val += eval().val;      /* XXX look at type? */
 
1427
            sym.type = DEFINED;
 
1428
            if( sym.val >= 01000000 )
 
1429
                sym.val = ( sym.val + 1 ) & 0777777;
 
1430
            continue;
 
1431
 
 
1432
        case '-':                       /* subtract */
 
1433
            next(1);                    /* skip over the operator */
 
1434
            sym.val += eval().val ^ 0777777; /* XXX look at type? */
 
1435
            sym.type = DEFINED;
 
1436
            if( sym.val >= 01000000 )
 
1437
                sym.val = ( sym.val + 1 ) & 0777777;
 
1438
            continue;
 
1439
 
 
1440
        case '*':                       /* multiply */
 
1441
            next(1);                    /* skip over the operator */
 
1442
            sym.val *= eval().val;
 
1443
            sym.type = DEFINED;
 
1444
            if( sym.val >= 01000000 )
 
1445
                sym.val = ( sym.val + 1 ) & 0777777;
 
1446
            continue;
 
1447
 
 
1448
#if 0
 
1449
        case '%':                       /* divide !??? */
 
1450
            /*
 
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 '%'!
 
1454
             */
 
1455
            next(1);
 
1456
            sym.val /= eval().val;
 
1457
            sym.type = DEFINED;
 
1458
            continue;
 
1459
#endif
 
1460
 
 
1461
        case '&':                       /* and */
 
1462
            next(1);                    /* skip over the operator */
 
1463
            sym.val &= eval().val;
 
1464
            sym.type = DEFINED;
 
1465
            continue;
 
1466
 
 
1467
        case '!':                       /* or */
 
1468
            next(1);                    /* skip over the operator */
 
1469
            sym.val |= eval().val;
 
1470
            sym.type = DEFINED;
 
1471
            continue;
 
1472
 
 
1473
        case '/':
 
1474
        case ')':
 
1475
        case ']':
 
1476
        case ':':
 
1477
        case ',':
 
1478
            break;
 
1479
 
 
1480
        case '=':
 
1481
            errorMessage( &illegal_equals, lexstart );
 
1482
            moveToEndOfLine();
 
1483
            sym.val = 0;
 
1484
            break;
 
1485
 
 
1486
        default:
 
1487
            if (!ISEND(line[lexstart])) {
 
1488
                errorMessage( &illegal_expression, lexstart );
 
1489
                moveToEndOfLine();
 
1490
                sym.val = 0;
 
1491
                break;
 
1492
            }
 
1493
        } /* switch */
 
1494
        break;                          /* break loop!! */
 
1495
    } /* "forever" */
 
1496
    return( sym );
 
1497
} /* getExpr */
 
1498
 
 
1499
/*
 
1500
 * return fio-dec code for next char
 
1501
 * embeds shifts as needed
 
1502
 */
 
1503
int
 
1504
nextfiodec(int *ccase, int delim)
 
1505
{
 
1506
    unsigned char c;
 
1507
 
 
1508
    for (;;) {
 
1509
        if (cc >= maxcc) {
 
1510
            if (delim == -1)
 
1511
                return -1;
 
1512
 
 
1513
            /* XXX MUST NOT BE IN A REPEAT!! */
 
1514
            readLine();                 /* danger will robinson! */
 
1515
            if (end_of_input)
 
1516
                return -1;
 
1517
        }
 
1518
        c = line[cc];
 
1519
        switch (c) {
 
1520
        case '\n':
 
1521
            c = '\r';
 
1522
            break;
 
1523
        case '\r':
 
1524
            continue;
 
1525
        }
 
1526
        break;
 
1527
    }
 
1528
 
 
1529
    if (delim != -1 && c == delim) {
 
1530
        if (*ccase == LC) {
 
1531
            cc++;                       /* eat delim */
 
1532
            return -1;
 
1533
        }
 
1534
        *ccase = LC;
 
1535
        return CONCISE_LC;              /* shift down first */
 
1536
    }
 
1537
 
 
1538
    if (c > 0177) {                     /* non-ascii */
 
1539
        errorMessage( &illegal_character, cc );
 
1540
        c = 0;                          /* space?! */
 
1541
    }
 
1542
 
 
1543
    c = ascii_to_fiodec[c&0177];
 
1544
    if (c == BAD) {
 
1545
        errorMessage( &illegal_character, cc );
 
1546
        c = 0;                          /* space?! */
 
1547
    }
 
1548
 
 
1549
    if (!(c & *ccase)) {                /* char not in current case? */
 
1550
        *ccase ^= BC;                   /* switch case */
 
1551
        if (*ccase == LC)
 
1552
            return CONCISE_LC;          /* shift down */
 
1553
        else
 
1554
            return CONCISE_UC;          /* shift up */
 
1555
    }
 
1556
    cc++;
 
1557
    return c & CHARBITS;
 
1558
}
 
1559
 
 
1560
/*
 
1561
 * Function: flex
 
1562
 * Synopsis: Handle data for "flexo" pseudo
 
1563
 * handle upper case by doing shifts
 
1564
 */
 
1565
 
 
1566
WORD32 flex()
 
1567
{
 
1568
    WORD32 w;
 
1569
    int shift;
 
1570
    int ccase;
 
1571
 
 
1572
    if (line[lexstart] == ' ')          /* always? */
 
1573
        next(0);
 
1574
 
 
1575
    /* original version appears to take next 3 characters,
 
1576
     * REGARDLESS of what they are (tab, newline, space?)!
 
1577
     */
 
1578
    w = 0;
 
1579
    ccase = LC;                         /* current case */
 
1580
    for (shift = 12; shift >= 0; shift -= 6) {
 
1581
        unsigned char c;
 
1582
        if( lexstart >= maxcc )
 
1583
            break;
 
1584
 
 
1585
        c = line[lexstart];
 
1586
        if (c == '\t' || c == '\n') {
 
1587
            if (ccase == LC)
 
1588
                break;
 
1589
            c = CONCISE_LC;                     /* shift down first */
 
1590
        }
 
1591
        else {
 
1592
            if (c > 0177) {             /* non-ascii */
 
1593
                errorMessage( &illegal_character, lexstart );
 
1594
                c = 0;
 
1595
            }
 
1596
 
 
1597
            c = ascii_to_fiodec[c&0177];
 
1598
            if (c == BAD) {
 
1599
                errorMessage( &illegal_character, lexstart );
 
1600
                c = 0;
 
1601
            }
 
1602
 
 
1603
            if (!(c & ccase)) {         /* char not in current case? */
 
1604
                ccase ^= BC;            /* switch case */
 
1605
                if (ccase == LC)
 
1606
                    c = CONCISE_LC;     /* shift down */
 
1607
                else
 
1608
                    c = CONCISE_UC;     /* shift up */
 
1609
            }
 
1610
            else
 
1611
                lexstart++;
 
1612
        }
 
1613
        w |= (c & CHARBITS) << shift;
 
1614
    }
 
1615
    /* error to get here w/ case == UC? nah. shift down could be next */
 
1616
    return w;
 
1617
} /* flex */
 
1618
 
 
1619
/*
 
1620
 * Function: getChar
 
1621
 * Synopsis: Handle data for "char" pseudo
 
1622
 */
 
1623
 
 
1624
WORD32 getChar()
 
1625
{
 
1626
    unsigned char c, pos;
 
1627
 
 
1628
    if( cc >= maxcc )
 
1629
        return 0;                       /* XXX error? */
 
1630
    pos = line[cc++];
 
1631
    if (pos != 'l' && pos != 'm' && pos != 'r') {
 
1632
        errorMessage( &illegal_character, lexstart );
 
1633
        return 0;
 
1634
    }
 
1635
 
 
1636
    if( cc >= maxcc )
 
1637
        return 0;                       /* XXX error? */
 
1638
 
 
1639
    c = line[cc++];
 
1640
    if (c > 0177) {
 
1641
        errorMessage( &illegal_character, lexstart );
 
1642
        c = 0;
 
1643
    }
 
1644
 
 
1645
    c = ascii_to_fiodec[c];
 
1646
    if (c == BAD) {
 
1647
        errorMessage( &illegal_character, lexstart );
 
1648
        c = 0;
 
1649
    }
 
1650
 
 
1651
    if (!(c & LC)) {                    /* upper case only char? */
 
1652
        c = CONCISE_UC;                 /* take a shift up */
 
1653
        cc--;                           /* and leave char for next luser */
 
1654
    }
 
1655
 
 
1656
    c &= CHARBITS;
 
1657
    switch (pos) {
 
1658
    case 'l': return c << 12;
 
1659
    case 'm': return c << 6;
 
1660
    case 'r': return c;
 
1661
    }
 
1662
    /* should not happen */
 
1663
    return 0;
 
1664
} /* flex */
 
1665
 
 
1666
/*  Function:  eval */
 
1667
/*  Synopsis:  Get the value of the current lexeme, and advance.*/
 
1668
SYM_T eval2()
 
1669
{
 
1670
  WORD32  digit;
 
1671
  WORD32  from;
 
1672
  SYM_T  *sym;
 
1673
  WORD32  val;
 
1674
  SYM_T   sym_eval;
 
1675
 
 
1676
  sym_eval.type = DEFINED;
 
1677
  sym_eval.name[0] = '\0';
 
1678
  sym_eval.val = sym_eval.xref_index = sym_eval.xref_count = 0;
 
1679
 
 
1680
  val = 0;
 
1681
 
 
1682
  if( isLexSymbol()) {
 
1683
    sym = evalSymbol();
 
1684
    if(!M_DEFINED( sym->type )) {
 
1685
      if( pass == 2 )
 
1686
        errorSymbol( &undefined_symbol, sym->name, lexstart );
 
1687
      next(1);
 
1688
      return( *sym );
 
1689
    }
 
1690
    else if( M_PSEUDO(sym->type) || M_EPSEUDO(sym->type)) {
 
1691
      switch (sym->val) {
 
1692
      case DECIMAL:
 
1693
        radix = 10;
 
1694
        sym_eval.type = PSEUDO;
 
1695
        sym_eval.val = 0;               /* has zero as a value! */
 
1696
        break;
 
1697
      case OCTAL:
 
1698
        radix = 8;
 
1699
        sym_eval.type = PSEUDO;
 
1700
        sym_eval.val = 0;               /* has zero as a value */
 
1701
        break;
 
1702
      case FLEX:
 
1703
        next(1);                        /* skip keyword */
 
1704
        sym_eval.val = flex();
 
1705
        break;
 
1706
      case CHAR:
 
1707
        next(1);                        /* skip keyword */
 
1708
        sym_eval.val = getChar();
 
1709
        break;
 
1710
      default:
 
1711
        errorSymbol( &value_required, sym->name, lexstart );
 
1712
        sym_eval.type = sym->type;
 
1713
        sym_eval.val = 0;
 
1714
        break;
 
1715
      }
 
1716
      next(1);
 
1717
      return( sym_eval );
 
1718
    }
 
1719
    else if( M_MACRO( sym->type ))
 
1720
    {
 
1721
      if( pass == 2 )
 
1722
      {
 
1723
        errorSymbol( &misplaced_symbol, sym->name, lexstart );
 
1724
      }
 
1725
      sym_eval.type = sym->type;
 
1726
      sym_eval.val = 0;
 
1727
      next(1);
 
1728
      return( sym_eval );
 
1729
    }
 
1730
    else
 
1731
    {
 
1732
      next(1);
 
1733
      return( *sym );
 
1734
    }
 
1735
  } /* symbol */
 
1736
  else if( isdigit( line[lexstart] )) {
 
1737
    from = lexstart;
 
1738
    val = 0;
 
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 );
 
1744
                val = 0;
 
1745
                break;
 
1746
            }
 
1747
            val = val * radix + digit;
 
1748
        }
 
1749
        else {
 
1750
            errorLexeme( &not_a_number, lexstart );
 
1751
            val = 0;
 
1752
            break;
 
1753
        }
 
1754
    }
 
1755
    next(1);
 
1756
    sym_eval.val = val;
 
1757
    return( sym_eval );
 
1758
  } /* digit */
 
1759
  else {
 
1760
    switch( line[lexstart] ) {
 
1761
    case '.':                           /* Value of Current Location Counter */
 
1762
        val = clc;
 
1763
        next(1);
 
1764
        break;
 
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);
 
1771
        return sym_eval;
 
1772
    case '[':                           /* parens!! */
 
1773
        next(1);
 
1774
        sym_eval.val = getExprs();      /* mutual recursion */
 
1775
        if( line[lexstart] == ']' )
 
1776
            next(1);                    /* Skip close bracket */
 
1777
        else
 
1778
            errorMessage( &illegal_character, lexstart );
 
1779
        return sym_eval;
 
1780
    default:
 
1781
        switch( line[lexstart] ) {
 
1782
        case '=':
 
1783
            errorMessage( &illegal_equals, lexstart );
 
1784
            moveToEndOfLine();
 
1785
            break;
 
1786
        default:
 
1787
            errorMessage( &illegal_character, lexstart );
 
1788
            break;
 
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 */
 
1794
  sym_eval.val = val;
 
1795
  return( sym_eval );
 
1796
} /* eval2 */
 
1797
 
 
1798
 
 
1799
SYM_T eval() {
 
1800
    SYM_T sym;
 
1801
 
 
1802
    switch (line[lexstart]) {
 
1803
    case '-':                           /* unary - */
 
1804
        next(1);
 
1805
        sym = eval2();                  /* skip op */
 
1806
        sym.val ^= 0777777;
 
1807
        break;
 
1808
    case '+':                           /* unary + */
 
1809
        next(1);                        /* skip op */
 
1810
        /* fall */
 
1811
    default:
 
1812
        sym = eval2();
 
1813
    }
 
1814
    return sym;
 
1815
}
 
1816
 
 
1817
/*  Function:  incrementClc */
 
1818
/*  Synopsis:  Set the next assembly location.  Test for collision with */
 
1819
/*             the literal tables. */
 
1820
WORD32 incrementClc()
 
1821
{
 
1822
  clc = (( clc + 1 ) & ADDRESS_FIELD );
 
1823
  return( clc );
 
1824
} /* incrementClc */
 
1825
 
 
1826
 
 
1827
/*  Function:  readLine */
 
1828
/*  Synopsis:  Get next line of input.  Print previous line if needed. */
 
1829
void readLine()
 
1830
{
 
1831
    BOOL    ffseen;
 
1832
    WORD32  ix;
 
1833
    WORD32  iy;
 
1834
    char    inpline[LINELEN];
 
1835
 
 
1836
    /* XXX panic if nrepeats > 0 (if self-feeding, do the backup here?) */
 
1837
 
 
1838
    listLine();                         /* List previous line if needed. */
 
1839
    error_in_line = FALSE;              /* No error in line. */
 
1840
 
 
1841
    if(curmacro && *curmacro->mac_ptr == '\0') { /* end of macro? */
 
1842
        struct macinv *mp;
 
1843
 
 
1844
        listed = TRUE;                  /* Already listed. */
 
1845
 
 
1846
        /* Restore invoking line. */
 
1847
        strcpy(line, curmacro->mac_line);
 
1848
        cc = lexstartprev = curmacro->mac_cc; /* Restore cc. */
 
1849
        maxcc = strlen( line );         /* Restore maxcc. */
 
1850
 
 
1851
        mp = curmacro->prev;            /* pop stack */
 
1852
        free(curmacro);
 
1853
        curmacro = mp;
 
1854
 
 
1855
        return;
 
1856
    } /* end of macro */
 
1857
 
 
1858
    cc = 0;                             /* Initialize column counter. */
 
1859
    lexstartprev = 0;
 
1860
    if( curmacro ) {                    /* Inside macro? */
 
1861
        char mc;
 
1862
 
 
1863
        maxcc = 0;
 
1864
        do {
 
1865
 
 
1866
            mc = *curmacro->mac_ptr++;  /* Next character. */
 
1867
            /* watch for overflow? how could it?? */
 
1868
            line[maxcc++] = mc;
 
1869
        } while( !ISEND( mc ));         /* note: terminates on tab?! */
 
1870
        line[maxcc] = '\0';
 
1871
        listed = nomac_exp;
 
1872
        return;
 
1873
    } /* inside macro */
 
1874
 
 
1875
    lineno++;                           /* Count lines read. */
 
1876
    listed = FALSE;                     /* Mark as not listed. */
 
1877
 READ_LINE:
 
1878
    if(( fgets( inpline, LINELEN - 1, infile )) == NULL ) {
 
1879
        filix_curr++;                   /* Advance to next file. */
 
1880
        if( filix_curr < save_argc ) {  /* More files? */
 
1881
            fclose( infile );
 
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] );
 
1885
                exit( -1 );
 
1886
            }
 
1887
            list_title_set = FALSE;
 
1888
            goto READ_LINE;
 
1889
        }
 
1890
        else
 
1891
            end_of_input = TRUE;
 
1892
    } /* fgets failed */
 
1893
 
 
1894
    ffseen = FALSE;
 
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 );
 
1898
            ffseen = TRUE;
 
1899
        }
 
1900
        else
 
1901
            line[iy++] = inpline[ix];
 
1902
    }
 
1903
    line[iy] = '\0';
 
1904
 
 
1905
    /* If the line is terminated by CR-LF, remove, the CR. */
 
1906
    if( line[iy - 2] == '\r' ) {
 
1907
        iy--;
 
1908
        line[iy - 1] = line[iy - 0];
 
1909
        line[iy] = '\0';
 
1910
    }
 
1911
    maxcc = iy;                         /* Save the current line length. */
 
1912
} /* readLine */
 
1913
 
 
1914
 
 
1915
/*  Function:  listLine */
 
1916
/*  Synopsis:  Output a line to the listing file. */
 
1917
void listLine()
 
1918
/* generate a line of listing if not already done! */
 
1919
{
 
1920
  if( listfile != NULL && listed == FALSE )
 
1921
  {
 
1922
    printLine( line, 0, 0, LINE );
 
1923
  }
 
1924
} /* listLine */
 
1925
 
 
1926
 
 
1927
/*  Function:  printPageBreak */
 
1928
/*  Synopsis:  Output a Top of Form and listing header if new page necessary. */
 
1929
void printPageBreak()
 
1930
{
 
1931
  if( page_lineno >= LIST_LINES_PER_PAGE )
 
1932
         /*  ( list_lineno % LIST_LINES_PER_PAGE ) == 0 ) */
 
1933
  {
 
1934
    topOfForm( list_title, NULL );
 
1935
  }
 
1936
} /* printPageBreak */
 
1937
 
 
1938
 
 
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 )
 
1942
{
 
1943
  if( listfile == NULL )
 
1944
  {
 
1945
    save_error_count = 0;
 
1946
    return;
 
1947
  }
 
1948
 
 
1949
  printPageBreak();
 
1950
 
 
1951
  list_lineno++;
 
1952
  page_lineno++;
 
1953
  switch( linestyle )
 
1954
  {
 
1955
  default:
 
1956
  case LINE:
 
1957
    fprintf( listfile, "%5d                   ", lineno );
 
1958
    fputs( line, listfile );
 
1959
    listed = TRUE;
 
1960
    break;
 
1961
 
 
1962
  case LINE_VAL:
 
1963
    if( !listed )
 
1964
    {
 
1965
      fprintf( listfile, "%5d       %6.6o      ", lineno, val );
 
1966
      fputs( line, listfile );
 
1967
      listed = TRUE;
 
1968
    }
 
1969
    else
 
1970
    {
 
1971
      fprintf( listfile, "            %6.6o\n", val );
 
1972
    }
 
1973
    break;
 
1974
 
 
1975
  case LINE_LOC:
 
1976
    if( !listed )
 
1977
    {
 
1978
      fprintf( listfile, "%5d %5.5o             ", lineno, loc );
 
1979
      fputs( line, listfile );
 
1980
      listed = TRUE;
 
1981
    }
 
1982
    else
 
1983
    {
 
1984
      fprintf( listfile, "      %5.5o\n", loc );
 
1985
    }
 
1986
    break;
 
1987
 
 
1988
  case LINE_LOC_VAL:
 
1989
    if( !listed )
 
1990
    {
 
1991
      fprintf( listfile, "%5d %5.5o %6.6o      ", lineno, loc, val );
 
1992
      fputs( line, listfile );
 
1993
      listed = TRUE;
 
1994
    }
 
1995
    else
 
1996
    {
 
1997
      fprintf( listfile, "      %5.5o %6.6o\n", loc, val );
 
1998
    }
 
1999
    break;
 
2000
 
 
2001
  case LOC_VAL:
 
2002
    fprintf( listfile, "      %5.5o %6.6o\n", loc, val );
 
2003
    break;
 
2004
  }
 
2005
  printErrorMessages();
 
2006
} /* printLine */
 
2007
 
 
2008
 
 
2009
/*  Function:  printErrorMessages */
 
2010
/*  Synopsis:  Output any error messages from the current list of errors. */
 
2011
void printErrorMessages()
 
2012
{
 
2013
  WORD32  ix;
 
2014
  WORD32  iy;
 
2015
 
 
2016
  if( listfile != NULL )
 
2017
  {
 
2018
    /* If any errors, display them now. */
 
2019
    for( iy = 0; iy < save_error_count; iy++ )
 
2020
    {
 
2021
      printPageBreak();
 
2022
      fprintf( listfile, "%-18.18s      ", error_list[iy].mesg );
 
2023
      if( error_list[iy].col >= 0 )
 
2024
      {
 
2025
        for( ix = 0; ix < error_list[iy].col; ix++ )
 
2026
        {
 
2027
          if( line[ix] == '\t' )
 
2028
          {
 
2029
            putc( '\t', listfile );
 
2030
          }
 
2031
          else
 
2032
          {
 
2033
            putc( ' ', listfile );
 
2034
          }
 
2035
        }
 
2036
        fputs( "^", listfile );
 
2037
        list_lineno++;
 
2038
        page_lineno++;
 
2039
      }
 
2040
      fputs( "\n", listfile );
 
2041
    }
 
2042
  }
 
2043
  save_error_count = 0;
 
2044
} /* printErrorMessages */
 
2045
 
 
2046
 
 
2047
/*  Function:  punchObject */
 
2048
/*  Synopsis:  Put one character to object file */
 
2049
void punchObject( WORD32 val )
 
2050
{
 
2051
  val &= 0377;
 
2052
  if( objectfile != NULL )
 
2053
      fputc( val, objectfile );
 
2054
} /* punchObject */
 
2055
 
 
2056
/*  Function:  punchTriplet */
 
2057
/*  Synopsis:  Output 18b word as three 6b characters with ho bit set. */
 
2058
void punchTriplet( WORD32 val )
 
2059
{
 
2060
  punchObject((( val >> 12) & 077) | 0200 );
 
2061
  punchObject((( val >> 6 ) & 077) | 0200 );
 
2062
  punchObject(( val & 077) | 0200 );
 
2063
} /* punchTriplet */
 
2064
 
 
2065
void
 
2066
eob() {
 
2067
    /* in case no "start" in file (an error?) */
 
2068
}
 
2069
 
 
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 )
 
2074
{
 
2075
  WORD32  ix;
 
2076
 
 
2077
  /* If value is zero, set to the default of 2 feet of leader. */
 
2078
  count = ( count == 0 ) ? 240 : count;
 
2079
 
 
2080
  if( objectfile != NULL )
 
2081
  {
 
2082
    for( ix = 0; ix < count; ix++ )
 
2083
    {
 
2084
      fputc( 0, objectfile );
 
2085
    }
 
2086
  }
 
2087
} /* punchLeader */
 
2088
 
 
2089
/*  Function:  punchOutObject */
 
2090
/*  Synopsis:  Output the current line and then then punch value to the */
 
2091
/*             object file. */
 
2092
void punchOutObject( WORD32 loc, WORD32 val )
 
2093
{
 
2094
  printLine( line, loc, val, LINE_LOC_VAL );
 
2095
  punchLocObject( loc, val );
 
2096
} /* punchOutObject */
 
2097
 
 
2098
 
 
2099
/*  Function:  punchLocObjectRIM */
 
2100
/*  Synopsis:  Output the word in RIM mode */
 
2101
void punchLocObjectRIM( WORD32 loc, WORD32 val )
 
2102
{
 
2103
    punchTriplet( DIO | loc );
 
2104
    punchTriplet( val );
 
2105
} /* punchLocObject */
 
2106
 
 
2107
/* punch loader in RIM mode */
 
2108
void
 
2109
punchLoader() {
 
2110
    int i;
 
2111
 
 
2112
    if (noinput)
 
2113
        return;
 
2114
 
 
2115
    for (i = 0; i < DIM(loader); i++)
 
2116
        punchLocObjectRIM(LOADERBASE+i, loader[i]);
 
2117
    punchTriplet( JMP | LOADERBASE );
 
2118
}
 
2119
 
 
2120
/*
 
2121
 * flush out loader buffer; output a block:
 
2122
 * DIO start
 
2123
 * DIO end+1
 
2124
 * .... data ....
 
2125
 * sum
 
2126
 */
 
2127
#define PW(X) { WORD32 x = X; sum += x; punchTriplet(x); }
 
2128
void
 
2129
flushLoader() {
 
2130
    WORD32 sum;
 
2131
    int i;
 
2132
 
 
2133
    if (loaderbufcount == 0)
 
2134
        return;
 
2135
 
 
2136
    sum = 0;
 
2137
    PW( DIO | loaderbufstart );
 
2138
    PW( DIO | loaderbufstart + loaderbufcount );
 
2139
    for (i = 0; i < loaderbufcount; i++)
 
2140
        PW( loaderbuf[i] );
 
2141
 
 
2142
    /* roll over all the overflows at once */
 
2143
    if (sum & ~0777777)
 
2144
        sum = (sum & 0777777) + (sum >> 18);
 
2145
    if (sum & 01000000)                 /* one more time */
 
2146
        sum++;
 
2147
    PW( sum );
 
2148
 
 
2149
    punchLeader(5);
 
2150
    loaderbufcount = 0;
 
2151
}
 
2152
 
 
2153
void punchLocObject( WORD32 loc, WORD32 val )
 
2154
{
 
2155
    if (!rim_mode) {
 
2156
        if ((loc & LOADERBUFMASK) == 0 || /* full/force alignment */
 
2157
            loaderbufcount > 0 &&
 
2158
            loc != loaderbufstart + loaderbufcount) /* disjoint */
 
2159
            flushLoader();
 
2160
        if (loaderbufcount == 0)
 
2161
            loaderbufstart = loc;
 
2162
        loaderbuf[loaderbufcount++] = val;
 
2163
    }
 
2164
    else
 
2165
        punchLocObjectRIM( loc, val );
 
2166
}
 
2167
 
 
2168
/*  Function:  literal */
 
2169
/*  Synopsis:  Add a value to the literal pool */
 
2170
WORD32
 
2171
literal( WORD32 value )
 
2172
{
 
2173
    int i;
 
2174
 
 
2175
    if (nconst >= MAX_CONSTANTS) {
 
2176
        fprintf(stderr, "too many 'constants'; increase MAX_CONSTANTS\n");
 
2177
        exit(1);
 
2178
    }
 
2179
 
 
2180
    if (pass == 1) {
 
2181
        if (++lit_count[nconst] == MAX_LITERALS) {
 
2182
            fprintf(stderr, "too many literals; increase MAX_LITERALS\n");
 
2183
            exit(1);
 
2184
        }
 
2185
        return lit_count[nconst];
 
2186
    }
 
2187
 
 
2188
#if 1
 
2189
    /*
 
2190
     * pool constants; makes for a shorter tape
 
2191
     * (but "middle" constants blocks can't shrink)
 
2192
     */
 
2193
    for (i = 0; i < nlit; i++)
 
2194
        if (litter[i] == value)
 
2195
            return lit_loc[nconst] + i;
 
2196
#endif
 
2197
 
 
2198
    /* paranoia */
 
2199
    if (nlit == MAX_LITERALS) {
 
2200
        fprintf(stderr, "too many literals; increase MAX_LITERALS\n");
 
2201
        exit(1);
 
2202
    }
 
2203
 
 
2204
    /* not found, save it */
 
2205
    litter[nlit] = value;
 
2206
 
 
2207
    /* use base for this block, determined on pass1 */
 
2208
    return lit_loc[nconst] + nlit++;
 
2209
} /* literal */
 
2210
 
 
2211
 
 
2212
/*  Function:  printSymbolTable */
 
2213
/*  Synopsis:  Output the symbol table. */
 
2214
/* XXX now prints FIXED symbols too */
 
2215
void printSymbolTable()
 
2216
{
 
2217
    int    ix;
 
2218
    int    symbol_lines;
 
2219
    SYM_T *sym;
 
2220
    char mark;
 
2221
 
 
2222
    symbol_lines = 0;
 
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))
 
2226
            continue;
 
2227
 
 
2228
        if (symbol_lines == 0) {
 
2229
            topOfForm( list_title, s_symtable );
 
2230
            symbol_lines = LIST_LINES_PER_PAGE;
 
2231
        }
 
2232
 
 
2233
        switch( sym->type & ( DEFINED | REDEFINED )) {
 
2234
        case UNDEFINED:
 
2235
            mark = '?';
 
2236
            break;
 
2237
 
 
2238
        case REDEFINED:
 
2239
            mark = '#';
 
2240
            break;
 
2241
 
 
2242
        default:
 
2243
            mark = ' ';
 
2244
            break;
 
2245
        }
 
2246
        fprintf( listfile, "%c%-6.6s %6.6o\n", mark, sym->name, sym->val );
 
2247
        symbol_lines--;
 
2248
    }
 
2249
} /* printSymbolTable */
 
2250
 
 
2251
 
 
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()
 
2256
{
 
2257
    int     ix;
 
2258
    FILE   *permfile;
 
2259
 
 
2260
    if(( permfile = fopen( permpathname, "w" )) == NULL )
 
2261
    {
 
2262
        exit( 2 );
 
2263
    }
 
2264
 
 
2265
    fprintf( permfile, "/ PERMANENT SYMBOL TABLE\n/\n" );
 
2266
    fprintf( permfile, "        expunge\n/\n" );
 
2267
 
 
2268
    for( ix = 0; ix < symbol_top; ix++ )
 
2269
    {
 
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 );
 
2274
    }
 
2275
    fclose( permfile );
 
2276
} /* printPermanentSymbolTable */
 
2277
 
 
2278
 
 
2279
/*  Function:  printCrossReference */
 
2280
/*  Synopsis:  Output a cross reference (concordance) for the file being */
 
2281
/*             assembled. */
 
2282
void printCrossReference()
 
2283
{
 
2284
    int    ix;
 
2285
    int    xc;
 
2286
    int    xc_index;
 
2287
    int    xc_refcount;
 
2288
    int    xc_cols;
 
2289
    SYM_T  *sym;
 
2290
 
 
2291
    /* Force top of form for first page. */
 
2292
    page_lineno = LIST_LINES_PER_PAGE;
 
2293
 
 
2294
    list_lineno = 0;
 
2295
 
 
2296
    for( ix = 0, sym = symtab; ix < symbol_top; ix++, sym++ ) {
 
2297
        if (M_FIXED(sym->type) && xreftab[sym->xref_index] == 0)
 
2298
            continue;
 
2299
        list_lineno++;
 
2300
        page_lineno++;
 
2301
        if( page_lineno >= LIST_LINES_PER_PAGE )
 
2302
            topOfForm( list_title, s_xref );
 
2303
 
 
2304
        fprintf( listfile, "%5d", list_lineno );
 
2305
 
 
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 )) {
 
2312
        case UNDEFINED:
 
2313
            fprintf( listfile, " U         ");
 
2314
            break;
 
2315
 
 
2316
        case REDEFINED:
 
2317
            fprintf( listfile, " M  %5d  ", xreftab[xc_index] );
 
2318
            break;
 
2319
 
 
2320
        default:
 
2321
            fprintf( listfile, " A  %5d  ", xreftab[xc_index] );
 
2322
            break;
 
2323
        }
 
2324
        fprintf( listfile, "%-6.6s  ", sym->name );
 
2325
 
 
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 ) {
 
2329
                xc_cols = 0;
 
2330
                page_lineno++;
 
2331
                if( page_lineno >= LIST_LINES_PER_PAGE )
 
2332
                    topOfForm( list_title, s_xref);
 
2333
                list_lineno++;
 
2334
                fprintf( listfile, "\n%5d%-19s", list_lineno, " " );
 
2335
            }
 
2336
            fprintf( listfile, "  %5d", xreftab[xc_index + xc] );
 
2337
        }
 
2338
        fprintf( listfile, "\n" );
 
2339
    } /* for */
 
2340
} /* printCrossReference */
 
2341
 
 
2342
 
 
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 )
 
2346
{
 
2347
    char temp[10];
 
2348
 
 
2349
    list_pageno++;
 
2350
    strcpy( temp, s_page );
 
2351
    sprintf( temp, "%s %d", s_page, list_pageno );
 
2352
 
 
2353
    if (!listfile)
 
2354
        return;
 
2355
 
 
2356
    /* Output a top of form if not the first page of the listing. */
 
2357
    if( list_pageno > 1 )
 
2358
        fprintf( listfile, "\f" );
 
2359
 
 
2360
    fprintf( listfile, "\n      %-63s %10s\n", title, temp );
 
2361
 
 
2362
    /* Reset the current page line counter. */
 
2363
    page_lineno = 1;
 
2364
    if( sub_title != NULL )
 
2365
    {
 
2366
        fprintf( listfile, "%80s\n", sub_title );
 
2367
        page_lineno++;
 
2368
    }
 
2369
    else
 
2370
    {
 
2371
        fprintf( listfile, "\n" );
 
2372
        page_lineno++;
 
2373
    }
 
2374
    fprintf( listfile, "\n" );
 
2375
    page_lineno++;
 
2376
} /* topOfForm */
 
2377
 
 
2378
 
 
2379
/*  Function:  lexemeToName */
 
2380
/*  Synopsis:  Convert the current lexeme into a string. */
 
2381
char *lexemeToName( char *name, WORD32 from, WORD32 term )
 
2382
{
 
2383
    int to;
 
2384
 
 
2385
    to = 0;
 
2386
    while( from < term && to < SYMLEN-1) {
 
2387
        char c = line[from++];
 
2388
        if (ISOVERBAR(c))
 
2389
            continue;
 
2390
        name[to++] = c;
 
2391
    }
 
2392
    name[to] = '\0';
 
2393
 
 
2394
    return( name );
 
2395
} /* lexemeToName */
 
2396
 
 
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. */
 
2403
{
 
2404
    char  name[SYMLEN];
 
2405
 
 
2406
    lexemeToName( name, start, term);
 
2407
    return( defineSymbol( name, val, type, start ));
 
2408
} /* defineLexeme */
 
2409
 
 
2410
 
 
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 )
 
2415
{
 
2416
    SYM_T  *sym;
 
2417
    WORD32  xref_count;
 
2418
 
 
2419
    if( strlen( name ) < 1 )
 
2420
    {
 
2421
        return( &sym_undefined );               /* Protect against non-existent names. */
 
2422
    }
 
2423
    sym = lookup( name, type );
 
2424
    xref_count = 0;                     /* Set concordance for normal defintion. */
 
2425
 
 
2426
    if( M_DEFINED( sym->type ) && sym->val != val && M_NOTRDEF( sym -> type ))
 
2427
    {
 
2428
        if( pass == 2 )
 
2429
        {
 
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
 
2436
             */
 
2437
            return ( sym );
 
2438
        }
 
2439
    }
 
2440
 
 
2441
    if( pass == 2 && xref )
 
2442
    {
 
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;
 
2449
        }
 
2450
    }
 
2451
 
 
2452
    /* Now set the value and the type. */
 
2453
    sym->val = val & 0777777;
 
2454
    sym->type = type;
 
2455
    return( sym );
 
2456
} /* defineSymbol */
 
2457
 
 
2458
 
 
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 )
 
2463
{
 
2464
    int ix;                             /* Insertion index */
 
2465
    int lx;                             /* Left index */
 
2466
    int rx;                             /* Right index */
 
2467
    SYM_T *best;                        /* best match */
 
2468
    SYM_T *sym;
 
2469
 
 
2470
    /* YIKES!  Search dummies (and "R") before anything else!! */
 
2471
    if (curmacro && curmacro->defn) {
 
2472
        struct macdef *mdp = curmacro->defn;
 
2473
        int i;
 
2474
 
 
2475
        for (i = 0, sym = mdp->args; i <= mdp->nargs; i++, sym++)
 
2476
            if (strcmp(name, sym->name) == 0)
 
2477
                return sym;
 
2478
    }
 
2479
 
 
2480
    lx = 0;
 
2481
    rx = symbol_top - 1;
 
2482
    best = NULL;
 
2483
    while (lx <= rx) {
 
2484
        int mx = (lx + rx) / 2;         /* Find center of search area. */
 
2485
        int compare;
 
2486
 
 
2487
        sym = symtab + mx;
 
2488
 
 
2489
        compare = strcmp(name, sym->name);
 
2490
        if (compare < 0)
 
2491
            rx = mx - 1;
 
2492
        else if (compare > 0)
 
2493
            lx = mx + 1;
 
2494
        else {                          /* match */
 
2495
            if (overbar && !M_DEFINED(sym->type) && pass == 2) {
 
2496
                sym->type = DEFINED;
 
2497
                sym->val = vars_addr++;
 
2498
                nvars++;
 
2499
            }
 
2500
            return sym;                 /* return exact match */
 
2501
        } /* match */
 
2502
 
 
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)
 
2506
            best = sym;
 
2507
    } /* while */
 
2508
 
 
2509
    /* return best match (pseudo or macro) if any for lookups (not defns) */
 
2510
    if (best && type == UNDEFINED)
 
2511
        return best;
 
2512
 
 
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 );
 
2517
        exit( 1 );
 
2518
    }
 
2519
 
 
2520
    for( rx = symbol_top; rx >= ix; rx-- )
 
2521
        symtab[rx + 1] = symtab[rx];
 
2522
 
 
2523
    symbol_top++;
 
2524
 
 
2525
    /* Enter the symbol as UNDEFINED with a value of zero. */
 
2526
    sym = symtab + ix;
 
2527
    strcpy( sym->name, name );
 
2528
    sym->type = UNDEFINED;
 
2529
    sym->val  = 0;
 
2530
    sym->xref_count = 0;
 
2531
    if( xref && pass == 2 && sym->xref_index >= 0)
 
2532
        xreftab[sym->xref_index] = 0;
 
2533
 
 
2534
    if (overbar)
 
2535
        nvars++;
 
2536
 
 
2537
    return sym;
 
2538
} /* lookup */
 
2539
 
 
2540
/*  Function:  compareSymbols */
 
2541
/*  Synopsis:  Used to presort the symbol table when starting assembler. */
 
2542
int compareSymbols( const void *a, const void *b )
 
2543
{
 
2544
    return( strcmp( ((SYM_T *) a)->name, ((SYM_T *) b)->name ));
 
2545
} /* compareSymbols */
 
2546
 
 
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 */
 
2550
SYM_T *evalSymbol()
 
2551
{
 
2552
    char   name[SYMLEN];
 
2553
    SYM_T *sym;
 
2554
 
 
2555
    sym = lookup( lexemeToName( name, lexstart, lexterm ), UNDEFINED);
 
2556
 
 
2557
    sym->xref_count++;                  /* Count the number of references to symbol. */
 
2558
 
 
2559
    if( xref && pass == 2 && sym->xref_index >= 0)
 
2560
    {
 
2561
        /* Put the line number in the concordance table. */
 
2562
        xreftab[sym->xref_index + sym->xref_count] = lineno;
 
2563
    }
 
2564
 
 
2565
    return( sym );
 
2566
} /* evalSymbol */
 
2567
 
 
2568
 
 
2569
/*  Function:  moveToEndOfLine */
 
2570
/*  Synopsis:  Move the parser input to the end of the current input line. */
 
2571
void moveToEndOfLine()
 
2572
{
 
2573
    while( !ISEND( line[cc] )) cc++;    /* XXX wrong! will stop on a tab! */
 
2574
    lexstart = cc;
 
2575
    lexterm = cc;
 
2576
    lexstartprev = lexstart;
 
2577
} /* moveToEndOfLine */
 
2578
 
 
2579
/* frame the next token in "line" with lexstart and lexterm indicies */
 
2580
void
 
2581
next(int op) {
 
2582
    char c;
 
2583
 
 
2584
    /* Save start column of previous lexeme for diagnostic messages. */
 
2585
    lexstartprev = lexstart;
 
2586
    lextermprev = lexterm;
 
2587
 
 
2588
    c = line[cc];
 
2589
    if (c == ' ') {
 
2590
        /* eat spaces */
 
2591
        do {
 
2592
            c = line[++cc];
 
2593
        } while (c == ' ');
 
2594
        if (op)                         /* looking for operators? */
 
2595
            cc--;                       /* return one */
 
2596
    }
 
2597
 
 
2598
    overbar = 0;
 
2599
    lexstart = cc;
 
2600
    c = line[cc];
 
2601
    if( isalnum(c) || ISOVERBAR(c)) {
 
2602
        if (ISOVERBAR(c))
 
2603
            overbar = 1;
 
2604
        do {
 
2605
            c = line[++cc];
 
2606
            if (ISOVERBAR(c))
 
2607
                overbar = 1;
 
2608
        } while (isalnum(c) || ISOVERBAR(c));
 
2609
    }
 
2610
    else if(!ISDONE(c) || c == '\t')    /* not end of line, or comment */
 
2611
        cc++;                           /* advance past all punctuation */
 
2612
    lexterm = cc;
 
2613
} /* next */
 
2614
 
 
2615
BOOL isLexSymbol()
 
2616
{
 
2617
    int ix;
 
2618
 
 
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! */
 
2623
    return FALSE;
 
2624
} /* isLexSymbol */
 
2625
 
 
2626
/*
 
2627
 * from macro manual (F-36BP), p.18;
 
2628
 *
 
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
 
2633
 * carriage return."
 
2634
 *
 
2635
 * and in the next paragraph;
 
2636
 *
 
2637
 * "The name is terminated by a _space_ or by a _tab_ or _cr_
 
2638
 * if there is no dummy symbol list."
 
2639
 *
 
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.
 
2643
 */
 
2644
 
 
2645
void
 
2646
defineMacro() {
 
2647
    int lexstartsave;                   /* point to macro name */
 
2648
    int index;                          /* point to error char */
 
2649
    int error;                          /* error boolean */
 
2650
    int i;
 
2651
    int count;
 
2652
    WORD32  length;
 
2653
    WORD32  value;
 
2654
    char    termin[SYMLEN];
 
2655
    char    args[MAC_MAX_ARGS][SYMLEN]; /* macro & arg names */
 
2656
    char    body[MAC_MAX_LENGTH + 1];
 
2657
    struct macdef *mdp;
 
2658
    SYM_T *sym;
 
2659
 
 
2660
    if (nrepeats) {
 
2661
        /* we can call readLine, so throw up hands now */
 
2662
        errorLexeme( &define_in_repeat, lexstartprev );
 
2663
        return;
 
2664
    }
 
2665
 
 
2666
    while (line[lexstart] == ' ' || line[lexstart] == '\t')
 
2667
        next(0);
 
2668
 
 
2669
    /* not a tab or space */
 
2670
    if (ISEND(line[lexstart])) {        /* newline or EOS? */
 
2671
        /* crock; next token should invisibly skip over line boundaries? */
 
2672
        readLine();
 
2673
        next(0);
 
2674
        while (line[lexstart] == ' ' || line[lexstart] == '\t')
 
2675
            next(0);
 
2676
    }
 
2677
 
 
2678
    /* XXX pick up macro name out here */
 
2679
 
 
2680
    count = 0;
 
2681
    index = 0;
 
2682
    error = FALSE;
 
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 */
 
2691
        next(0);
 
2692
        if (line[lexstart] == ' ')
 
2693
            next(0);
 
2694
    }
 
2695
    if( count == 0 ) {                  /* No macro name. */
 
2696
        errorMessage( &no_macro_name, lexstartsave );
 
2697
        error = TRUE;
 
2698
    }
 
2699
    else if( index ) {                  /* Bad argument name. */
 
2700
        errorMessage( &bad_dummy_arg, index );
 
2701
        error = TRUE;
 
2702
    }
 
2703
    else if( mac_count >= MAC_TABLE_LENGTH ) {
 
2704
        errorMessage( &macro_table_full, lexstartsave );
 
2705
        error = TRUE;
 
2706
    }
 
2707
    else {
 
2708
        value = mac_count++;            /* sym value is index into mac */
 
2709
        defineSymbol( args[0], value, MACRO, lexstartsave );
 
2710
    }
 
2711
 
 
2712
    for( length = 0;; ) {
 
2713
        readLine();
 
2714
        if (end_of_input)
 
2715
            break;
 
2716
        next(0);
 
2717
        while (line[lexstart] == ' ' || line[lexstart] == '\t')
 
2718
            next(0);
 
2719
 
 
2720
        lexemeToName( termin, lexstart, lexterm ); /* just look at line? */
 
2721
        if (strncmp( termin, "term", 4 ) == 0)
 
2722
            break;
 
2723
 
 
2724
        if (!error) {
 
2725
            int ll = strlen(line);
 
2726
            int allblank = FALSE;
 
2727
 
 
2728
            /* don't save blank lines! */
 
2729
            for( i = 0; i < ll && allblank; i++ )
 
2730
                if(!ISBLANK(line[i]))
 
2731
                    allblank = FALSE;
 
2732
 
 
2733
            if (allblank)                       /* nothing but air? */
 
2734
                continue;                       /* skip it! */
 
2735
 
 
2736
            if ((length + ll + 1) >= MAC_MAX_LENGTH ) {
 
2737
                errorMessage (&macro_too_long, lexstart );
 
2738
                error = TRUE;
 
2739
                continue;
 
2740
            }
 
2741
 
 
2742
            strcpy(body+length, line);
 
2743
            length += ll;
 
2744
        }
 
2745
    } /* for */
 
2746
    if( error )
 
2747
        return;
 
2748
 
 
2749
    mdp = calloc(1, sizeof(struct macdef) + length);
 
2750
    if (mdp == NULL) {
 
2751
        fprintf(stderr, "error allocating memory for macro definition\n");
 
2752
        exit(1);
 
2753
    }
 
2754
    mac_defs[value] = mdp;
 
2755
 
 
2756
    strncpy(mdp->body, body, length);
 
2757
    mdp->body[length] = '\0';
 
2758
    mdp->nargs = count - 1;
 
2759
 
 
2760
    /*
 
2761
     * save dummy names
 
2762
     * symbol slot 0 reserved for "r" symbol
 
2763
     * move SYM_T entries to macinv to allow recursion
 
2764
     */
 
2765
    sym = mdp->args;
 
2766
    sym->type = DEFINED;
 
2767
    strcpy(sym->name, "R");
 
2768
    sym->val = 0;
 
2769
    sym->xref_index = -1;               /* ??? allow xref? */
 
2770
    sym++;
 
2771
 
 
2772
    for (i = 1; i <= mdp->nargs; i++, sym++) {
 
2773
        sym->type = DEFINED;
 
2774
        strcpy(sym->name, args[i]);
 
2775
        sym->val = 0;
 
2776
        sym->xref_index = -1;           /* don't xref!! */
 
2777
    }
 
2778
} /* defineMacro */
 
2779
 
 
2780
/* VARIABLES pseudo-op */
 
2781
void
 
2782
variables() {
 
2783
    /* XXX error if "variables" already seen (in this pass) */
 
2784
    /* XXX error if different address on pass 2 */
 
2785
    if (pass == 2)
 
2786
        printLine( line, clc, 0, LINE_LOC );
 
2787
    vars_addr = clc;
 
2788
    vars_end = clc = (clc + nvars) & ADDRESS_FIELD;
 
2789
    if (pass == 2)
 
2790
        printLine( line, clc, 0, LINE_LOC);
 
2791
}
 
2792
 
 
2793
/* TEXT pseudo-op */
 
2794
void
 
2795
text(void)
 
2796
{
 
2797
    char delim;
 
2798
    WORD32 w;
 
2799
    int count;
 
2800
    int ccase;
 
2801
    /* XXX error in repeat!! */
 
2802
    do {
 
2803
        if (cc == maxcc) {
 
2804
            /* XXX EOL before delim found!!! */
 
2805
            fprintf(stderr, "FIX ME!\n");
 
2806
            return;
 
2807
        }
 
2808
        delim = line[cc++];
 
2809
    } while (delim == ' ');             /* others? NL */
 
2810
 
 
2811
    w = count = 0;
 
2812
    ccase = LC;
 
2813
    for (;;) {
 
2814
        int c = nextfiodec(&ccase, delim);
 
2815
        if (c == -1)
 
2816
            break;
 
2817
        w |= c << ((2-count)*6);
 
2818
        if (++count == 3) {
 
2819
            punchOutObject(clc, w);     /* punch it! */
 
2820
            incrementClc();
 
2821
            count = w = 0;
 
2822
        }
 
2823
    }
 
2824
    if (count > 0) {
 
2825
        punchOutObject(clc, w);         /* punch remainder */
 
2826
        incrementClc();
 
2827
    }
 
2828
}
 
2829
 
 
2830
/* CONSTANTS pseudo-op */
 
2831
void
 
2832
constants(void) {
 
2833
    int i;
 
2834
 
 
2835
    /* XXX illegal inside macro (curmacro != NULL) */
 
2836
 
 
2837
    if (pass == 1) {
 
2838
        lit_loc[nconst] = clc;
 
2839
 
 
2840
        /* just use addition?! */
 
2841
        for (i = 0; i < lit_count[nconst]; i++)
 
2842
            incrementClc();
 
2843
 
 
2844
        nconst++;
 
2845
        return;
 
2846
    }
 
2847
 
 
2848
    /* pass 2: */
 
2849
    /* XXX complain if clc != lit_base[nconst]? */
 
2850
 
 
2851
    for (i = 0; i < lit_count[nconst]; i++) {
 
2852
        if (i < nlit)
 
2853
            punchOutObject( clc, litter[i] & 0777777); /* punch it! */
 
2854
        incrementClc();
 
2855
    }
 
2856
 
 
2857
    nconst++;
 
2858
    nlit = 0;                           /* litter[] now empty */
 
2859
} /* constants */
 
2860
 
 
2861
 
 
2862
/* process pseudo-ops
 
2863
 * return FALSE if line scan should end (no longer used)
 
2864
 */
 
2865
BOOL pseudo( PSEUDO_T val )
 
2866
{
 
2867
    int count;
 
2868
    int repeatstart;
 
2869
 
 
2870
    switch( (PSEUDO_T) val ) {
 
2871
    case CONSTANTS:
 
2872
        next(0);                        /* Skip symbol */
 
2873
        constants();
 
2874
        break;
 
2875
 
 
2876
    case VARIABLES:
 
2877
        next(0);                        /* Skip symbol */
 
2878
        variables();
 
2879
        break;
 
2880
 
 
2881
    case DEFINE:
 
2882
        next(0);                        /* Skip symbol */
 
2883
        defineMacro();
 
2884
        return FALSE;
 
2885
        break;
 
2886
 
 
2887
    case REPEAT:
 
2888
        next(0);                        /* Skip symbol */
 
2889
 
 
2890
        /* NOTE!! constant followed by SPACE picked up as expression!! */
 
2891
        count = getExprs() & ADDRESS_FIELD;
 
2892
        /* XXX error if sign bit set? */
 
2893
 
 
2894
        /* allow comma, but do not require */
 
2895
        if( line[lexstart] == ',')
 
2896
            next(0);
 
2897
 
 
2898
        nrepeats++;
 
2899
        repeatstart = lexstart;         /* save line start */
 
2900
        while (count-- > 0) {
 
2901
            cc = repeatstart;           /* reset input pointer */
 
2902
            processLine();              /* recurse! */
 
2903
        }
 
2904
        cc = maxcc;
 
2905
        nrepeats--;
 
2906
 
 
2907
        return FALSE;
 
2908
        break;
 
2909
 
 
2910
    case START:
 
2911
        next(0);                        /* Skip symbol */
 
2912
        /* XXX illegal in macro or repeat */
 
2913
        flushLoader();
 
2914
        if (!ISDONE(line[lexstart])) {
 
2915
            if (line[lexstart] == ' ')
 
2916
                next(0);
 
2917
            start_addr = getExprs() & ADDRESS_FIELD;
 
2918
            next(0);
 
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? */
 
2923
        }
 
2924
        /*
 
2925
         * handle multiple tapes concatenated into one file!!
 
2926
         * have command line option?? treat "start" as EOF??
 
2927
         */
 
2928
        list_title_set = FALSE;
 
2929
        return FALSE;
 
2930
 
 
2931
    case TEXT:
 
2932
        /* NOTE!! no next()! */
 
2933
        text();
 
2934
        break;
 
2935
 
 
2936
    case NOINPUT:
 
2937
        next(0);                        /* Skip symbol */
 
2938
        noinput = TRUE;
 
2939
        break;
 
2940
 
 
2941
    case EXPUNGE:
 
2942
        next(0);                        /* Skip symbol */
 
2943
        if (pass == 1)
 
2944
            init_symtab();
 
2945
        break;
 
2946
 
 
2947
    default:
 
2948
        break;
 
2949
    } /* end switch for pseudo-ops */
 
2950
    return TRUE;                        /* keep scanning */
 
2951
} /* pseudo */
 
2952
 
 
2953
 
 
2954
/*  Function:  errorLexeme */
 
2955
/*  Synopsis:  Display an error message using the current lexical element. */
 
2956
void errorLexeme( EMSG_T *mesg, WORD32 col )
 
2957
{
 
2958
  char   name[SYMLEN];
 
2959
 
 
2960
  errorSymbol( mesg, lexemeToName( name, lexstart, lexterm ), col );
 
2961
} /* errorLexeme */
 
2962
 
 
2963
 
 
2964
/*  Function:  errorSymbol */
 
2965
/*  Synopsis:  Display an error message with a given string. */
 
2966
void errorSymbol( EMSG_T *mesg, char *name, WORD32 col )
 
2967
{
 
2968
  char   linecol[12];
 
2969
  char  *s;
 
2970
 
 
2971
  if( pass == 2 )
 
2972
  {
 
2973
    s = ( name == NULL ) ? "" : name ;
 
2974
    errors++;
 
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 );
 
2979
  }
 
2980
  error_in_line = TRUE;
 
2981
} /* errorSymbol */
 
2982
 
 
2983
 
 
2984
/*  Function:  errorMessage */
 
2985
/*  Synopsis:  Display an error message without a name argument. */
 
2986
void errorMessage( EMSG_T *mesg, WORD32 col )
 
2987
{
 
2988
  char   linecol[12];
 
2989
 
 
2990
  if( pass == 2 )
 
2991
  {
 
2992
    errors++;
 
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 );
 
2997
  }
 
2998
  error_in_line = TRUE;
 
2999
} /* errorMessage */
 
3000
 
 
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 )
 
3005
{
 
3006
  if( save_error_count < DIM( error_list ))
 
3007
  {
 
3008
    error_list[save_error_count].mesg = mesg;
 
3009
    error_list[save_error_count].col = col;
 
3010
    save_error_count++;
 
3011
  }
 
3012
  error_in_line = TRUE;
 
3013
 
 
3014
  if( listed )
 
3015
    printErrorMessages();
 
3016
} /* saveError */
 
3017
 
 
3018
/* create a "symbol punch" for DDT */
 
3019
/* MUST be called after object file closed; we reuse the FILE*! */
 
3020
 
 
3021
void
 
3022
dump_symbols(void) {
 
3023
    int ix;
 
3024
    WORD32 addr;
 
3025
 
 
3026
    objectfile = fopen( sympathname, "wb" );
 
3027
    if (!objectfile) {
 
3028
        perror(sympathname);
 
3029
        return;
 
3030
    }
 
3031
 
 
3032
    punchLeader(0);
 
3033
    punchLoader();
 
3034
    punchLeader(5);
 
3035
 
 
3036
    /* XXX fudge addr -- get count, and subtract 2N from 07750? */
 
3037
    addr = 05000;
 
3038
 
 
3039
    for( ix = 0; ix < symbol_top; ix++ ) {
 
3040
        int i, type;
 
3041
        WORD32 name;
 
3042
 
 
3043
        type = symtab[ix].type;
 
3044
        if (M_FIXED(type) || M_PSEUDO(type) || M_MACRO(type))
 
3045
            continue;
 
3046
 
 
3047
        name = 0;
 
3048
        for (i = 0; i < 3; i++) {
 
3049
            char c;
 
3050
 
 
3051
            c = symtab[ix].name[i];
 
3052
            /* XXX leave on NUL? */
 
3053
 
 
3054
            c = ascii_to_fiodec[tolower(c) & 0177];
 
3055
            /* XXX check for BAD entries? */
 
3056
 
 
3057
            /* XXX OR in val<<(3-i)*6?? */
 
3058
            name <<= 6;
 
3059
            name |= c & CHARBITS;
 
3060
        }
 
3061
        punchLocObject(addr++, permute(name));
 
3062
        punchLocObject(addr++, symtab[ix].val);
 
3063
    }
 
3064
    flushLoader();
 
3065
    punchTriplet( JMP );                /* ??? */
 
3066
    punchLeader(0);
 
3067
    fclose(objectfile);
 
3068
}