A large commit.
[pdp8.git] / sw / pc / palbart / palbart.c
1 /******************************************************************************/
2 /* */
3 /* Program: PAL (BART version) */
4 /* File: pal.c */
5 /* Author: Gary A. Messenbrink <gary@netcom.com> */
6 /* */
7 /* Purpose: A 2 pass PDP-8 pal-like assembler. */
8 /* */
9 /* PAL(1) */
10 /* */
11 /* NAME */
12 /* pal - a PDP/8 pal-like assembler. */
13 /* */
14 /* SYNOPSIS: */
15 /* pal [ -d -l -p -r -x ] inputfile */
16 /* */
17 /* DESCRIPTION */
18 /* This is a cross-assembler to for PDP/8 assembly language programs. */
19 /* It will produce an output file in bin format, rim format, and using the */
20 /* appropriate pseudo-ops, a combination of rim and bin formats. */
21 /* A listing file is always produced and with an optional symbol table */
22 /* and/or a symbol cross-reference (concordance). The permanent symbol */
23 /* table can be output in a form that may be read back in so a customized */
24 /* permanent symbol table can be produced. Any detected errors are output */
25 /* to a separate file giving the filename in which they were detected */
26 /* along with the line number, column number and error message as well as */
27 /* marking the error in the listing file. */
28 /* The following file name extensions are used: */
29 /* .pal source code (input) */
30 /* .lst assembly listing (output) */
31 /* .bin assembly output in DEC's bin format (output) */
32 /* .rim assembly output in DEC's rim format (output) */
33 /* .err assembly errors detected (if any) (output) */
34 /* .prm permanent symbol table in form suitable for reading after */
35 /* the EXPUNGE pseudo-op. */
36 /* */
37 /* OPTIONS */
38 /* -d Dump the symbol table at end of assembly */
39 /* -l Allow generation of literals (default is no literal generation) */
40 /* -p Generate a file with the permanent symbols in it. */
41 /* (To get the current symbol table, assemble a file than has only */
42 /* a $ in it.) */
43 /* -r Produce output in rim format (default is bin format) */
44 /* -x Generate a cross-reference (concordance) of user symbols. */
45 /* */
46 /* DIAGNOSTICS */
47 /* Assembler error diagnostics are output to an error file and inserted */
48 /* in the listing file. Each line in the error file has the form */
49 /* */
50 /* <filename>(<line>:<col>) : error: <message> at Loc = <loc> */
51 /* */
52 /* An example error message is: */
53 /* */
54 /* bintst.pal(17:9) : error: undefined symbol "UNDEF" at Loc = 07616 */
55 /* */
56 /* The error diagnostics put in the listing start with a two character */
57 /* error code (if appropriate) and a short message. A carat '^' is */
58 /* placed under the item in error if appropriate. */
59 /* An example error message is: */
60 /* */
61 /* 17 07616 3000 DCA UNDEF */
62 /* UD undefined ^ */
63 /* 18 07617 1777 TAD I DUMMY */
64 /* */
65 /* When an indirect is generated, an at character '@' is placed after the */
66 /* the instruction value in the listing as an indicator as follows: */
67 /* */
68 /* 14 03716 1777@ TAD OFFPAG */
69 /* */
70 /* Undefined symbols are marked in the symbol table listing by prepending */
71 /* a '?' to the symbol. Redefined symbols are marked in the symbol table */
72 /* listing by prepending a '#' to the symbol. Examples are: */
73 /* */
74 /* #REDEF 04567 */
75 /* SWITCH 07612 */
76 /* ?UNDEF 00000 */
77 /* */
78 /* Refer to the code for the diagnostic messages generated. */
79 /* */
80 /* BUGS */
81 /* Only a minimal effort has been made to keep the listing format */
82 /* anything like the PAL-8 listing format. */
83 /* The operation of the conditional assembly pseudo-ops may not function */
84 /* exactly as the DEC versions. I did not have any examples of these so */
85 /* the implementation is my interpretation of how they should work. */
86 /* */
87 /* The RIMPUNch and BINPUNch pseudo-ops do not change the binary output */
88 /* file type that was specified on startup. This was intentional and */
89 /* and allows rim formatted data to be output prior to the actual binary */
90 /* formatted data. On UN*X style systems, the same effect can be achieved */
91 /* by using the "cat" command, but on DOS/Windows systems, doing this was */
92 /* a major chore. */
93 /* */
94 /* The floating point input does not generate values exactly as the DEC */
95 /* compiler does. I worked out several examples by hand and believe that */
96 /* this implementation is slightly more accurate. If I am mistaken, */
97 /* let me know and, if possible, a better method of generating the values. */
98 /* */
99 /* BUILD and INSTALLATION */
100 /* This program has been built and successfully executed on: */
101 /* a. Linux (80486 CPU)using gcc */
102 /* b. RS/6000 (AIX 3.2.5) */
103 /* c. Borland C++ version 3.1 (large memory model) */
104 /* d. Borland C++ version 4.52 (large memory model) */
105 /* with no modifications to the source code. */
106 /* */
107 /* On UNIX type systems, store the the program as the pal command */
108 /* and on PC type systems, store it as pal.exe */
109 /* */
110 /* HISTORICAL NOTE: */
111 /* This assembler was written to support the fleet of PDP-8 systems */
112 /* used by the Bay Area Rapid Transit System. As of early 1997, */
113 /* this includes about 40 PDP-8/E systems driving the train destination */
114 /* signs in passenger stations. */
115 /* */
116 /* REFERENCES: */
117 /* This assembler is based on the pal assember by: */
118 /* Douglas Jones <jones@cs.uiowa.edu> and */
119 /* Rich Coon <coon@convexw.convex.com> */
120 /* */
121 /* DISCLAIMER: */
122 /* See the symbol table for the set of pseudo-ops supported. */
123 /* See the code for pseudo-ops that are not standard for PDP/8 assembly. */
124 /* Refer to DEC's "Programming Languages (for the PDP/8)" for complete */
125 /* documentation of pseudo-ops. */
126 /* Refer to DEC's "Introduction to Programming (for the PDP/8)" or a */
127 /* lower level introduction to the assembly language. */
128 /* */
129 /* WARRANTY: */
130 /* If you don't like it the way it works or if it doesn't work, that's */
131 /* tough. You're welcome to fix it yourself. That's what you get for */
132 /* using free software. */
133 /* */
134 /* COPYRIGHT NOTICE: */
135 /* This is free software. There is no fee for using it. You may make */
136 /* any changes that you wish and also give it away. If you can make */
137 /* a commercial product out of it, fine, but do not put any limits on */
138 /* the purchaser's right to do the same. If you improve it or fix any */
139 /* bugs, it would be nice if you told me and offered me a copy of the */
140 /* new version. */
141 /* */
142 /* */
143 /* Amendments Record: */
144 /* Version Date by Comments */
145 /* ------- ------- --- --------------------------------------------------- */
146 /* v1.0 12Apr96 GAM Original */
147 /* v1.1 18Nov96 GAM Permanent symbol table initialization error. */
148 /* v1.2 20Nov96 GAM Added BINPUNch and RIMPUNch pseudo-operators. */
149 /* v1.3 24Nov96 GAM Added DUBL pseudo-op (24 bit integer constants). */
150 /* v1.4 29Nov96 GAM Fixed bug in checksum generation. */
151 /* v2.1 08Dec96 GAM Added concordance processing (cross reference). */
152 /* v2.2 10Dec96 GAM Added FLTG psuedo-op (floating point constants). */
153 /* v2.3 2Feb97 GAM Fixed paging problem in cross reference output. */
154 /* */
155 /******************************************************************************/
156
157 #include <ctype.h>
158 #include <stdio.h>
159 #include <stdlib.h>
160 #include <string.h>
161
162 #define LINELEN 96
163 #define LIST_LINES_PER_PAGE 55 /* Includes 5 line page header. */
164 #define NAMELEN 128
165 #define SYMBOL_COLUMNS 5
166 #define SYMLEN 7
167 #define SYMBOL_TABLE_SIZE 1024
168 #define TITLELEN 63
169 #define XREF_COLUMNS 8
170
171 #define ADDRESS_FIELD 00177
172 #define FIELD_FIELD 070000
173 #define INDIRECT_BIT 00400
174 #define LAST_PAGE_LOC 00177
175 #define OP_CODE 07000
176 #define PAGE_BIT 00200
177
178 #ifdef PAGE_SIZE
179 #undef PAGE_SIZE
180 #endif
181 #define PAGE_SIZE 00200
182
183 #define PAGE_FIELD 07600
184 #define PAGE_ZERO_END 00200
185
186 /* Macro to get the number of elements in an array. */
187 #define DIM(a) (sizeof(a)/sizeof(a[0]))
188
189 /* Macro to get the address plus one of the end of an array. */
190 #define BEYOND(a) ((a) + DIM(A))
191
192 #define is_blank(c) ((c==' ') || (c=='\t') || (c=='\f') || (c=='>'))
193 #define isend(c) ((c=='\0')|| (c=='\n'))
194 #define isdone(c) ((c=='/') || (isend(c)) || (c==';'))
195
196 /* Macros for testing symbol attributes. Each macro evaluates to non-zero */
197 /* (true) if the stated condtion is met. */
198 /* Use these to test attributes. The proper bits are extracted and then */
199 /* tested. */
200 #define M_CONDITIONAL(s) ((s & CONDITION) == CONDITION)
201 #define M_DEFINED(s) ((s & DEFINED) == DEFINED)
202 #define M_DUPLICATE(s) ((s & DUPLICATE) == DUPLICATE)
203 #define M_FIXED(s) ((s & FIXED) == FIXED)
204 #define M_LABEL(s) ((s & LABEL) == LABEL)
205 #define M_MRI(s) ((s & MRI) == MRI)
206 #define M_MRIFIX(s) ((s & MRIFIX) == MRIFIX)
207 #define M_PSEUDO(s) ((s & PSEUDO) == PSEUDO)
208 #define M_REDEFINED(s) ((s & REDEFINED) == REDEFINED)
209 #define M_UNDEFINED(s) (!M_DEFINED(s))
210
211 /* This macro is used to test symbols by the conditional assembly pseudo-ops. */
212 #define M_DEF(s) (M_DEFINED(s))
213 #define M_COND(s) (M_DEFINED(s))
214 #define M_DEFINED_CONDITIONALLY(t) ((M_DEF(t)&&pass==1)||(!M_COND(t)&&pass==2))
215
216 typedef unsigned char BOOL;
217 typedef unsigned char BYTE;
218 typedef short int WORD16;
219 typedef long int WORD32;
220
221 #ifndef FALSE
222 #define FALSE 0
223 #define TRUE (!FALSE)
224 #endif
225
226 /* Line listing styles. Used to control listing of lines. */
227 enum linestyle_t
228 {
229 LINE, LINE_VAL, LINE_LOC_VAL, LOC_VAL
230 };
231 typedef enum linestyle_t LINESTYLE_T;
232
233 /* Symbol Types. */
234 /* Note that the names that have FIX as the suffix contain the FIXED bit */
235 /* included in the value. */
236 /* */
237 /* The CONDITION bit is used when processing the conditional assembly PSEUDO- */
238 /* OPs (e.g., IFDEF). During pass 1 of the assembly, the symbol is either */
239 /* defined or undefined. The condition bit is set when the symbol is defined */
240 /* during pass 1 and reset on pass 2 at the location the symbol was defined */
241 /* during pass 1. When processing conditionals during pass 2, if the symbol */
242 /* is defined and the condition bit is set, the symbol is treated as if it */
243 /* were undefined. This gives consistent behavior of the conditional */
244 /* pseudo-ops during both pass 1 and pass 2. */
245 enum symtyp
246 {
247 UNDEFINED = 0000,
248 DEFINED = 0001,
249 FIXED = 0002,
250 MRI = 0004 | DEFINED,
251 LABEL = 0010 | DEFINED,
252 REDEFINED = 0020 | DEFINED,
253 DUPLICATE = 0040 | DEFINED,
254 PSEUDO = 0100 | FIXED | DEFINED,
255 CONDITION = 0200 | DEFINED,
256 MRIFIX = MRI | FIXED | DEFINED,
257 DEFFIX = DEFINED | FIXED
258 };
259 typedef enum symtyp SYMTYP;
260
261 enum pseudo_t
262 {
263 BANK, BINPUNCH, DECIMAL, DUBL, EJECT, ENPUNCH, EXPUNGE, FIELD,
264 FIXMRI, FIXTAB, FLTG, IFDEF, IFNDEF, IFNZERO, IFZERO, NOPUNCH,
265 OCTAL, PAGE, PAUSE, RELOC, RIMPUNCH, SEGMNT, TEXT, TITLE,
266 XLIST, ZBLOCK
267 };
268 typedef enum pseudo_t PSEUDO_T;
269
270 struct sym_t
271 {
272 SYMTYP type;
273 char name[SYMLEN];
274 WORD16 val;
275 WORD16 xref_index;
276 WORD16 xref_count;
277 };
278 typedef struct sym_t SYM_T;
279
280 struct lpool_t
281 {
282 WORD16 error; /* True if error message has been printed. */
283 WORD16 loc;
284 WORD16 pool[PAGE_SIZE];
285 };
286 typedef struct lpool_t LPOOL_T;
287
288 struct emsg_t
289 {
290 char *list;
291 char *file;
292 };
293 typedef struct emsg_t EMSG_T;
294
295 struct errsave_t
296 {
297 char *mesg;
298 WORD16 col;
299 };
300 typedef struct errsave_t ERRSAVE_T;
301
302 struct fltg_
303 {
304 WORD16 exponent;
305 WORD32 mantissa;
306 };
307 typedef struct fltg_ FLTG_T;
308
309 /*----------------------------------------------------------------------------*/
310
311 /* Function Prototypes */
312
313 int binarySearch( char *name, int start, int symbol_count );
314 int compareSymbols( const void *a, const void *b );
315 void conditionFalse( void );
316 void conditionTrue( void );
317 SYM_T *defineLexeme( WORD16 start, WORD16 term, WORD16 val, SYMTYP type );
318 SYM_T *defineSymbol( char *name, WORD16 val, SYMTYP type, WORD16 start);
319 void endOfBinary( void );
320 void errorLexeme( EMSG_T *mesg, WORD16 col );
321 void errorMessage( EMSG_T *mesg, WORD16 col );
322 void errorSymbol( EMSG_T *mesg, char *name, WORD16 col );
323 SYM_T *eval( void );
324 WORD32 evalDubl( WORD32 initial_value );
325 FLTG_T *evalFltg( void );
326 SYM_T *evalSymbol( void );
327 void getArgs( int argc, char *argv[] );
328 WORD32 getDublExpr( void );
329 WORD32 getDublExprs( void );
330 FLTG_T *getFltgExpr( void );
331 FLTG_T *getFltgExprs( void );
332 SYM_T *getExpr( void );
333 WORD16 getExprs( void );
334 WORD16 incrementClc( void );
335 void inputDubl( void );
336 void inputFltg( void );
337 WORD16 insertLiteral( LPOOL_T *pool, WORD16 value );
338 char *lexemeToName( char *name, WORD16 from, WORD16 term );
339 void listLine( void );
340 SYM_T *lookup( char *name );
341 void moveToEndOfLine( void );
342 void nextLexBlank( void );
343 void nextLexeme( void );
344 void normalizeFltg( FLTG_T *fltg );
345 void onePass( void );
346 void printCrossReference( void );
347 void printErrorMessages( void );
348 void printLine(char *line, WORD16 loc, WORD16 val, LINESTYLE_T linestyle);
349 void printPageBreak( void );
350 void printPermanentSymbolTable( void );
351 void printSymbolTable( void );
352 BOOL pseudoOperators( PSEUDO_T val );
353 void punchChecksum( void );
354 void punchLocObject( WORD16 loc, WORD16 val );
355 void punchLiteralPool( LPOOL_T *p, WORD16 lpool_page );
356 void punchOutObject( WORD16 loc, WORD16 val );
357 void punchLeader( WORD16 count );
358 void punchObject( WORD16 val );
359 void punchOrigin( WORD16 loc );
360 void readLine( void );
361 void saveError( char *mesg, WORD16 cc );
362 BOOL testForLiteralCollision( WORD16 loc );
363 void topOfForm( char *title, char *sub_title );
364
365 /*----------------------------------------------------------------------------*/
366
367 /* Table of pseudo-ops (directives) which are used to setup the symbol */
368 /* table on startup and when the EXPUNGE pseudo-op is executed. */
369 SYM_T pseudo[] =
370 {
371 { PSEUDO, "BANK", BANK }, /* Like field, select some 32K out of 128K*/
372 { PSEUDO, "BINPUN", BINPUNCH }, /* Output in Binary Loader format. */
373 { PSEUDO, "DECIMA", DECIMAL }, /* Read literal constants in base 10. */
374 { PSEUDO, "DUBL", DUBL }, /* Ignored (unsupported). */
375 { PSEUDO, "EJECT", EJECT }, /* Eject a page in the listing. */
376 { PSEUDO, "ENPUNC", ENPUNCH }, /* Turn on object code generation. */
377 { PSEUDO, "EXPUNG", EXPUNGE }, /* Remove all symbols from symbol table. */
378 { PSEUDO, "FIELD", FIELD }, /* Set origin to memory field. */
379 { PSEUDO, "FIXMRI", FIXMRI }, /* Like =, but creates mem ref instruction*/
380 { PSEUDO, "FIXTAB", FIXTAB }, /* Mark current symbols as permanent. */
381 { PSEUDO, "FLTG", FLTG }, /* Ignored (unsupported). */
382 { PSEUDO, "IFDEF", IFDEF }, /* Assemble if symbol is defined. */
383 { PSEUDO, "IFNDEF", IFNDEF }, /* Assemble if symbol is not defined. */
384 { PSEUDO, "IFNZER", IFNZERO }, /* Assemble if symbol value is not 0. */
385 { PSEUDO, "IFZERO", IFZERO }, /* Assemble if symbol value is 0. */
386 { PSEUDO, "NOPUNC", NOPUNCH }, /* Turn off object code generation. */
387 { PSEUDO, "OCTAL", OCTAL }, /* Read literal constants in base 8. */
388 { PSEUDO, "PAGE", PAGE }, /* Set orign to page +1 or page n (0..37).*/
389 { PSEUDO, "PAUSE", PAUSE }, /* Ignored */
390 { PSEUDO, "RELOC", RELOC }, /* Assemble to run at a different address.*/
391 { PSEUDO, "RIMPUN", RIMPUNCH }, /* Output in Read In Mode format. */
392 { PSEUDO, "SEGMNT", SEGMNT }, /* Like page, but with page size=1K words.*/
393 { PSEUDO, "TEXT", TEXT }, /* Pack 6 bit trimmed ASCII into memory. */
394 { PSEUDO, "TITLE", TITLE }, /* Use the text string as a listing title.*/
395 { PSEUDO, "XLIST", XLIST }, /* Toggle listing generation. */
396 { PSEUDO, "ZBLOCK", ZBLOCK } /* Zero a block of memory. */
397 };
398
399 /* Symbol Table */
400 /* The table is put in lexical order on startup, so symbols can be */
401 /* inserted as desired into the initial table. */
402 SYM_T permanent_symbols[] =
403 {
404 /* Memory Reference Instructions */
405 { MRIFIX, "AND", 00000 }, /* LOGICAL AND */
406 { MRIFIX, "TAD", 01000 }, /* TWO'S COMPLEMENT ADD */
407 { MRIFIX, "ISZ", 02000 }, /* INCREMENT AND SKIP IF ZERO */
408 { MRIFIX, "DCA", 03000 }, /* DEPOSIT AND CLEAR ACC */
409 { MRIFIX, "I", 00400 }, /* INDIRECT ADDRESSING */
410 { MRIFIX, "JMP", 05000 }, /* JUMP */
411 { MRIFIX, "JMS", 04000 }, /* JUMP TO SUBROUTINE */
412 { MRIFIX, "Z", 00000 }, /* PAGE ZERO ADDRESS */
413 /* Floating Point Interpreter Instructions */
414 { MRIFIX, "FEXT", 00000 }, /* FLOATING EXIT */
415 { MRIFIX, "FADD", 01000 }, /* FLOATING ADD */
416 { MRIFIX, "FSUB", 02000 }, /* FLOATING SUBTRACT */
417 { MRIFIX, "FMPY", 03000 }, /* FLOATING MULTIPLY */
418 { MRIFIX, "FDIV", 04000 }, /* FLOATING DIVIDE */
419 { MRIFIX, "FGET", 05000 }, /* FLOATING GET */
420 { MRIFIX, "FPUT", 06000 }, /* FLOATING PUT */
421 { FIXED, "FNOR", 07000 }, /* FLOATING NORMALIZE */
422 { FIXED, "FEXT", 00000 }, /* EXIT FROM FLOATING POINT INTERPRETER */
423 { FIXED, "SQUARE", 00001 }, /* SQUARE C(FAC) */
424 { FIXED, "SQROOT", 00002 }, /* TAKE SQUARE ROOT OF C(FAC) */
425 /* Group 1 Operate Microinstrcutions */
426 { FIXED, "NOP", 07000 }, /* NO OPERATION */
427 { FIXED, "IAC", 07001 }, /* INCREMENT AC */
428 { FIXED, "RAL", 07004 }, /* ROTATE AC AND LINK LEFT ONE */
429 { FIXED, "RTL", 07006 }, /* ROTATE AC AND LINK LEFT TWO */
430 { FIXED, "RAR", 07010 }, /* ROTATE AC AND LINK RIGHT ONE */
431 { FIXED, "RTR", 07012 }, /* ROTATE AC AND LINK RIGHT TWO */
432 { FIXED, "CML", 07020 }, /* COMPLEMENT LINK */
433 { FIXED, "CMA", 07040 }, /* COMPLEMEMNT AC */
434 { FIXED, "CLL", 07100 }, /* CLEAR LINK */
435 { FIXED, "CLA", 07200 }, /* CLEAR AC */
436 /* Group 2 Operate Microinstructions */
437 { FIXED, "BSW", 07002 }, /* Swap bytes in AC (PDP/8e) */
438 { FIXED, "HLT", 07402 }, /* HALT THE COMPUTER */
439 { FIXED, "OSR", 07404 }, /* INCLUSIVE OR SR WITH AC */
440 { FIXED, "SKP", 07410 }, /* SKIP UNCONDITIONALLY */
441 { FIXED, "SNL", 07420 }, /* SKIP ON NON-ZERO LINK */
442 { FIXED, "SZL", 07430 }, /* SKIP ON ZERO LINK */
443 { FIXED, "SZA", 07440 }, /* SKIP ON ZERO AC */
444 { FIXED, "SNA", 07450 }, /* SKIP ON NON=ZERO AC */
445 { FIXED, "SMA", 07500 }, /* SKIP MINUS AC */
446 { FIXED, "SPA", 07510 }, /* SKIP ON POSITIVE AC (ZERO IS POSITIVE) */
447 /* Combined Operate Microinstructions */
448 { FIXED, "CIA", 07041 }, /* COMPLEMENT AND INCREMENT AC */
449 { FIXED, "STL", 07120 }, /* SET LINK TO 1 */
450 { FIXED, "GLK", 07204 }, /* GET LINK (PUT LINK IN AC BIT 11) */
451 { FIXED, "STA", 07240 }, /* SET AC TO -1 */
452 { FIXED, "LAS", 07604 }, /* LOAD ACC WITH SR */
453 /* MQ Instructions (PDP/8e) */
454 { FIXED, "MQL", 07421 }, /* Load MQ from AC, then clear AC. */
455 { FIXED, "MQA", 07501 }, /* Inclusive OR MQ with AC */
456 { FIXED, "SWP", 07521 }, /* Swap AC and MQ */
457 { FIXED, "ACL", 07701 }, /* Load MQ into AC */
458 /* Program Interrupt */
459 { FIXED, "IOT", 06000 },
460 { FIXED, "ION", 06001 }, /* TURN INTERRUPT PROCESSOR ON */
461 { FIXED, "IOF", 06002 }, /* TURN INTERRUPT PROCESSOR OFF */
462 /* Program Interrupt, PDP-8/e */
463 { FIXED, "SKON", 06000 }, /* Skip if interrupt on and turn int off. */
464 { FIXED, "SRQ", 06003 }, /* Skip on interrupt request. */
465 { FIXED, "GTF", 06004 }, /* Get interrupt flags. */
466 { FIXED, "RTF", 06005 }, /* Restore interrupt flags. */
467 { FIXED, "SGT", 06006 }, /* Skip on greater than flag. */
468 { FIXED, "CAF", 06007 }, /* Clear all flags. */
469 /* Keyboard/Reader */
470 { FIXED, "KSF", 06031 }, /* SKIP ON KEYBOARD FLAG */
471 { FIXED, "KCC", 06032 }, /* CLEAR KEYBOARD FLAG */
472 { FIXED, "KRS", 06034 }, /* READ KEYBOARD BUFFER (STATIC) */
473 { FIXED, "KRB", 06036 }, /* READ KEYBOARD BUFFER & CLEAR FLAG */
474 /* Teleprinter/Punch */
475 { FIXED, "TSF", 06041 }, /* SKIP ON TELEPRINTER FLAG */
476 { FIXED, "TCF", 06042 }, /* CLEAR TELEPRINTER FLAG */
477 { FIXED, "TPC", 06044 }, /* LOAD TELEPRINTER & PRINT */
478 { FIXED, "TLS", 06046 }, /* LOAD TELPRINTER & CLEAR FLAG */
479 /* High Speed Paper Tape Reader */
480 { FIXED, "RSF", 06011 }, /* SKIP ON READER FLAG */
481 { FIXED, "RRB", 06012 }, /* READ READER BUFFER AND CLEAR FLAG */
482 { FIXED, "RFC", 06014 }, /* READER FETCH CHARACTER */
483 /* PC8-E High Speed Paper Tape Reader & Punch */
484 { FIXED, "RPE", 06010 }, /* Set interrupt enable for reader/punch */
485 { FIXED, "PCE", 06020 }, /* Clear interrupt enable for rdr/punch */
486 { FIXED, "RCC", 06016 }, /* Read reader buffer, clear flags & buf, */
487 /* and fetch character. */
488 /* High Speed Paper Tape Punch */
489 { FIXED, "PSF", 06021 }, /* SKIP ON PUNCH FLAG */
490 { FIXED, "PCF", 06022 }, /* CLEAR ON PUNCH FLAG */
491 { FIXED, "PPC", 06024 }, /* LOAD PUNCH BUFFER AND PUNCH CHARACTER* */
492 { FIXED, "PLS", 06026 }, /* LOAD PUNCH BUFFER AND CLEAR FLAG */
493 /* DECtape Transport Type TU55 and DECtape Control Type TC01 */
494 { FIXED, "DTRA", 06761 }, /* Contents of status register is ORed */
495 /* into AC bits 0-9 */
496 { FIXED, "DTCA", 06762 }, /* Clear status register A, all flags */
497 /* undisturbed */
498 { FIXED, "DTXA", 06764 }, /* Status register A loaded by exclusive */
499 /* OR from AC. If AC bit 10=0, clear */
500 /* error flags; if AC bit 11=0, DECtape */
501 /* control flag is cleared. */
502 { FIXED, "DTLA", 06766 }, /* Combination of DTCA and DTXA */
503 { FIXED, "DTSF", 06771 }, /* Skip if error flag is 1 or if DECtape */
504 /* control flag is 1 */
505 { FIXED, "DTRB", 06772 }, /* Contents of status register B is */
506 /* ORed into AC */
507 { FIXED, "DTLB", 06774 }, /* Memory field portion of status */
508 /* register B loaded from AC bits 6-8 */
509 /* Disk File and Control, Type DF32 */
510 { FIXED, "DCMA", 06601 }, /* CLEAR DISK MEMORY REQUEST AND */
511 /* INTERRUPT FLAGS */
512 { FIXED, "DMAR", 06603 }, /* LOAD DISK FROM AC, CLEAR AC READ */
513 /* INTO CORE, CLEAR INTERRUPT FLAG */
514 { FIXED, "DMAW", 06605 }, /* LOAD DISK FROM AC, WRITE ONTO DISK */
515 /* FROM CORE, CLEAR INTERRUPT FLAG */
516 { FIXED, "DCEA", 06611 }, /* CLEAR DISK EXTENDED ADDRESS AND */
517 { FIXED, "DSAC", 06612 }, /* SKIP IF ADDRESS CONFIRMED FLAG = 1 */
518 /* MEMORY ADDRESS EXTENSION REGISTER */
519 { FIXED, "DEAL", 06615 }, /* CLEAR DISK EXTENDED ADDRESS AND */
520 /* MEMORY ADDRESS EXTENSION REGISTER */
521 /* AND LOAD SAME FROM AC */
522 { FIXED, "DEAC", 06616 }, /* CLEAR AC, LOAD AC FROM DISK EXTENDED */
523 /* ADDRESS REGISTER, SKIP IF ADDRESS */
524 /* CONFIRMED FLAG = 1 */
525 { FIXED, "DFSE", 06621 }, /* SKIP IF PARITY ERROR, DATA REQUEST */
526 /* LATE, OR WRITE LOCK SWITCH FLAG = 0 */
527 /* (NO ERROR) */
528 { FIXED, "DFSC", 06622 }, /* SKIP IF COMPLETION FLAG = 1 (DATA */
529 /* TRANSFER COMPLETE) */
530 { FIXED, "DMAC", 06626 }, /* CLEAR AC, LOAD AC FROM DISK MEMORY */
531 /* ADDRESS REGISTER */
532 /* Disk File and Control, Type RF08 */
533 { FIXED, "DCIM", 06611 },
534 { FIXED, "DIML", 06615 },
535 { FIXED, "DIMA", 06616 },
536 { FIXED, "DISK", 06623 },
537 { FIXED, "DCXA", 06641 },
538 { FIXED, "DXAL", 06643 },
539 { FIXED, "DXAC", 06645 },
540 { FIXED, "DMMT", 06646 },
541 /* Memory Extension Control, Type 183 */
542 { FIXED, "CDF", 06201 }, /* CHANGE DATA FIELD */
543 { FIXED, "CIF", 06202 }, /* CHANGE INSTRUCTION FIELD */
544 { FIXED, "CDI", 06203 }, /* Change data & instrution field. */
545 { FIXED, "RDF", 06214 }, /* READ DATA FIELD */
546 { FIXED, "RIF", 06224 }, /* READ INSTRUCTION FIELD */
547 { FIXED, "RIB", 06234 }, /* READ INTERRUPT BUFFER */
548 { FIXED, "RMF", 06224 }, /* RESTORE MEMORY FIELD */
549 /* Memory Parity, Type MP8/I (MP8/L) */
550 { FIXED, "SMP", 06101 }, /* SKIP IF MEMORY PARITY FLAG = 0 */
551 { FIXED, "CMP", 06104 }, /* CLEAR MEMORY PAIRTY FLAG */
552 /* Memory Parity, Type MP8-E (PDP8/e) */
553 { FIXED, "DPI", 06100 }, /* Disable parity interrupt. */
554 { FIXED, "SNP", 06101 }, /* Skip if no parity error. */
555 { FIXED, "EPI", 06103 }, /* Enable parity interrupt. */
556 { FIXED, "CNP", 06104 }, /* Clear parity error flag. */
557 { FIXED, "CEP", 06106 }, /* Check for even parity. */
558 { FIXED, "SPO", 06107 }, /* Skip on parity option. */
559 /* Data Communications Systems, Type 680I */
560 { FIXED, "TTINCR", 06401 }, /* The content of the line select */
561 /* register is incremented by one. */
562 { FIXED, "TTI", 06402 }, /* The line status word is read and */
563 /* sampled. If the line is active for */
564 /* the fourth time, the line bit is */
565 /* shifted into the character assembly */
566 /* word. If the line bit is active for */
567 /* a number of times less than four, */
568 /* the count is incremented. If the */
569 /* line is not active, the active/inac- */
570 /* tive status of the line is recorded */
571 { FIXED, "TTO", 06404 }, /* The character in the AC is shifted */
572 /* right one position, zeros are shifted */
573 /* into vacated positions, and the orig- */
574 /* inal content of AC11 is transferred */
575 /* out of the computer on the TTY line. */
576 { FIXED, "TTCL", 06411 }, /* The line select register is cleared. */
577 { FIXED, "TTSL", 06412 }, /* The line select register is loaded by */
578 /* an OR transfer from the content of */
579 /* of AC5-11, the the AC is cleared. */
580 { FIXED, "TTRL", 06414 }, /* The content of the line select regis- */
581 /* ter is read into AC5-11 by an OR */
582 /* transfer. */
583 { FIXED, "TTSKP", 06421 }, /* Skip if clock flag is a 1. */
584 { FIXED, "TTXON", 06424 }, /* Clock 1 is enabled to request a prog- */
585 /* ram interrupt and clock 1 flag is */
586 /* cleared. */
587 { FIXED, "TTXOF", 06422 }, /* Clock 1 is disabled from causing a */
588 /* program interrupt and clock 1 flag */
589 /* is cleared. */
590 }; /* End-of-Symbols for Permanent Symbol Table */
591
592 /* Global variables */
593 SYM_T *symtab; /* Symbol Table */
594 int symbol_top; /* Number of entries in symbol table. */
595
596 SYM_T *fixed_symbols; /* Start of the fixed symbol table entries. */
597 int number_of_fixed_symbols;
598
599 /*----------------------------------------------------------------------------*/
600
601 WORD16 *xreftab; /* Start of the concordance table. */
602
603 ERRSAVE_T error_list[20];
604 int save_error_count;
605
606 LPOOL_T pz; /* Storage for page zero constants. */
607 LPOOL_T cp; /* Storage for current page constants. */
608
609 char s_detected[] = "detected";
610 char s_error[] = "error";
611 char s_errors[] = "errors";
612 char s_no[] = "No";
613 char s_page[] = "Page";
614 char s_symtable[] = "Symbol Table";
615 char s_xref[] = "Cross Reference";
616
617 /* Assembler diagnostic messages. */
618 /* Some attempt has been made to keep continuity with the PAL-III and */
619 /* MACRO-8 diagnostic messages. If a diagnostic indicator, (e.g., IC) */
620 /* exists, then the indicator is put in the listing as the first two */
621 /* characters of the diagnostic message. The PAL-III indicators where used */
622 /* when there was a choice between using MACRO-8 and PAL-III indicators. */
623 /* The character pairs and their meanings are: */
624 /* DT Duplicate Tag (symbol) */
625 /* IC Illegal Character */
626 /* ID Illegal Redefinition of a symbol. An attempt was made to give */
627 /* a symbol a new value not via =. */
628 /* IE Illegal Equals An equal sign was used in the wrong context, */
629 /* (e.g., A+B=C, or TAD A+=B) */
630 /* II Illegal Indirect An off page reference was made, but a literal */
631 /* could not be generated because the indirect bit was already set. */
632 /* IR Illegal Reference (address is not on current page or page zero) */
633 /* ND No $ (the program terminator) at end of file. */
634 /* PE Current, Non-Zero Page Exceeded (literal table flowed into code) */
635 /* RD ReDefintion of a symbol */
636 /* ST Symbol Table full */
637 /* UA Undefined Address (undefined symbol) */
638 /* ZE Zero Page Exceeded (see above, or out of space) */
639 EMSG_T duplicate_label = { "DT duplicate", "duplicate label" };
640 EMSG_T illegal_blank = { "IC illegal blank", "illegal blank" };
641 EMSG_T illegal_character = { "IC illegal char", "illegal character" };
642 EMSG_T illegal_expression = { "IC in expression", "illegal expression" };
643 EMSG_T label_syntax = { "IC label syntax", "label syntax" };
644 EMSG_T not_a_number = { "IC numeric syntax", "numeric syntax of" };
645 EMSG_T number_not_radix = { "IC radix", "number not in current radix"};
646 EMSG_T symbol_syntax = { "IC symbol syntax", "symbol syntax" };
647 EMSG_T illegal_equals = { "IE illegal =", "illegal equals" };
648 EMSG_T illegal_indirect = { "II off page", "illegal indirect" };
649 EMSG_T illegal_reference = { "IR off page", "illegal reference" };
650 EMSG_T undefined_symbol = { "UD undefined", "undefined symbol" };
651 EMSG_T redefined_symbol = { "RD redefined", "redefined symbol" };
652 EMSG_T literal_overflow = { "PE page exceeded",
653 "current page literal capacity exceeded" };
654 EMSG_T pz_literal_overflow = { "ZE page exceeded",
655 "page zero capacity exceeded" };
656 EMSG_T dubl_overflow = { "dubl overflow", "DUBL value overflow" };
657 EMSG_T fltg_overflow = { "fltg overflow", "FLTG value overflow" };
658 EMSG_T zblock_too_small = { "expr too small", "ZBLOCK value too small" };
659 EMSG_T zblock_too_large = { "expr too large", "ZBLOCK value too large" };
660 EMSG_T end_of_file = { "ND no $ at EOF", "No $ at End-of-File" };
661 EMSG_T no_pseudo_op = { "not implemented",
662 "not implemented pseudo-op" };
663 EMSG_T illegal_field_value = { "expr out of range",
664 "field value not in range of 0 through 7" };
665 EMSG_T literal_gen_off = { "literals off",
666 "literal generation is off" };
667 EMSG_T no_literal_value = { "no value", "no literal value" };
668 EMSG_T text_string = { "no delimiter",
669 "text string delimiters not matched" };
670 EMSG_T in_rim_mode = { "not OK in rim mode"
671 "FIELD pseudo-op not valid in RIM mode" };
672 EMSG_T lt_expected = { "'<' expected", "'<' expected" };
673 EMSG_T symbol_table_full = { "ST Symbol Tbl Full",
674 "Symbol Table Full" };
675
676 /*----------------------------------------------------------------------------*/
677
678 FILE *errorfile;
679 FILE *infile;
680 FILE *listfile;
681 FILE *listsave;
682 FILE *objectfile;
683 FILE *objectsave;
684
685 char errorpathname[NAMELEN];
686 char filename[NAMELEN];
687 char listpathname[NAMELEN];
688 char objectpathname[NAMELEN];
689 char *pathname;
690 char permpathname[NAMELEN];
691
692 int list_lineno;
693 int list_pageno;
694 char list_title[LINELEN];
695 BOOL list_title_set; /* Set if TITLE pseudo-op used. */
696 char line[LINELEN]; /* Input line. */
697 int lineno; /* Current line number. */
698 int page_lineno; /* print line number on current page. */
699 WORD16 listed; /* Listed flag. */
700 WORD16 listedsave;
701
702 WORD16 cc; /* Column Counter (char position in line). */
703 WORD16 checksum; /* Generated checksum */
704 BOOL binary_data_output; /* Set true when data has been output. */
705 WORD16 clc; /* Location counter */
706 WORD16 cplc; /* Current page literal counter. */
707 char delimiter; /* Character immediately after eval'd term. */
708 int errors; /* Number of errors found so far. */
709 BOOL error_in_line; /* TRUE if error on current line. */
710 int errors_pass_1; /* Number of errors on pass 1. */
711 WORD16 field; /* Current field */
712 WORD16 fieldlc; /* location counter without field portion. */
713 BOOL fltg_input; /* TRUE when doing floating point input. */
714 BOOL indirect_generated; /* TRUE if an off page address generated. */
715 WORD16 lexstartprev; /* Where previous lexeme started. */
716 WORD16 lextermprev; /* Where previous lexeme ended. */
717 WORD16 lexstart; /* Index of current lexeme on line. */
718 WORD16 lexterm; /* Index of character after current lexeme. */
719 BOOL literals_on; /* Generate literals, defaults to none */
720 WORD16 maxcc; /* Current line length. */
721 BOOL overflow; /* Overflow flag for math routines. */
722 WORD16 pass; /* Number of current pass. */
723 BOOL print_permanent_symbols;
724 WORD16 pzlc; /* Page Zero literal counter. */
725 WORD16 radix; /* Default number radix. */
726 WORD16 reloc; /* The relocation distance. */
727 BOOL rim_mode; /* Generate rim format, defaults to bin */
728 BOOL symtab_print; /* Print symbol table flag */
729 BOOL xref;
730
731 FLTG_T fltg_ac; /* Value holder for evalFltg() */
732 SYM_T sym_eval = { DEFINED, "", 0 }; /* Value holder for eval() */
733 SYM_T sym_getexpr = { DEFINED, "", 0 }; /* Value holder for getexpr() */
734 SYM_T sym_undefined = { UNDEFINED, "", 0 };/* Symbol Table Terminator */
735
736
737 /******************************************************************************/
738 /* */
739 /* Function: main */
740 /* */
741 /* Synopsis: Starting point. Controls order of assembly. */
742 /* */
743 /******************************************************************************/
744 int main( int argc, char *argv[] )
745 {
746 int ix;
747 int space;
748
749 /* Set the default values for global symbols. */
750 binary_data_output = FALSE;
751 fltg_input = FALSE;
752 literals_on = FALSE;
753 print_permanent_symbols = FALSE;
754 rim_mode = FALSE;
755 symtab_print = FALSE;
756 xref = FALSE;
757 pathname = NULL;
758
759 /* Get the options and pathnames */
760 getArgs( argc, argv );
761
762 /* Setup the error file in case symbol table overflows while installing the */
763 /* permanent symbols. */
764 errorfile = fopen( errorpathname, "w" );
765 errors = 0;
766 save_error_count = 0;
767 pass = 0; /* This is required for symbol table initialization. */
768 symtab = (SYM_T *) malloc( sizeof( SYM_T ) * SYMBOL_TABLE_SIZE );
769
770 if( symtab == NULL )
771 {
772 fprintf( stderr, "Could not allocate memory for symbol table.\n");
773 exit( -1 );
774 }
775
776 /* Place end marker in symbol table. */
777 symtab[0] = sym_undefined;
778 symbol_top = 0;
779 number_of_fixed_symbols = symbol_top;
780 fixed_symbols = &symtab[symbol_top - 1];
781
782 /* Enter the pseudo-ops into the symbol table */
783 for( ix = 0; ix < DIM( pseudo ); ix++ )
784 {
785 defineSymbol( pseudo[ix].name, pseudo[ix].val, pseudo[ix].type, 0 );
786 }
787
788 /* Enter the predefined symbols into the table. */
789 /* Also make them part of the permanent symbol table. */
790 for( ix = 0; ix < DIM( permanent_symbols ); ix++ )
791 {
792 defineSymbol( permanent_symbols[ix].name,
793 permanent_symbols[ix].val,
794 permanent_symbols[ix].type | DEFFIX , 0 );
795 }
796
797 number_of_fixed_symbols = symbol_top;
798 fixed_symbols = &symtab[symbol_top - 1];
799
800 /* Do pass one of the assembly */
801 checksum = 0;
802 pass = 1;
803 onePass();
804 errors_pass_1 = errors;
805
806 /* Set up for pass two */
807 rewind( infile );
808 errorfile = fopen( errorpathname, "w" );
809 objectfile = fopen( objectpathname, "wb" );
810 objectsave = objectfile;
811
812 listfile = fopen( listpathname, "w" );
813 listsave = NULL;
814
815 punchLeader( 0 );
816 checksum = 0;
817
818 /* Do pass two of the assembly */
819 errors = 0;
820 save_error_count = 0;
821
822 if( xref )
823 {
824 /* Get the amount of space that will be required for the concordance. */
825 for( space = 0, ix = 0; ix < symbol_top; ix++ )
826 {
827 symtab[ix].xref_index = space; /* Index into concordance table. */
828 space += symtab[ix].xref_count + 1;
829 symtab[ix].xref_count = 0; /* Clear the count for pass 2. */
830
831 }
832 /* Allocate the necessary space. */
833 xreftab = (WORD16 *) malloc( sizeof( WORD16 ) * space );
834
835 /* Clear the cross reference space. */
836 for( ix = 0; ix < space; ix++ )
837 {
838 xreftab[ix] = 0;
839 }
840 }
841 pass = 2;
842 onePass();
843
844 /* Undo effects of NOPUNCH for any following checksum */
845 objectfile = objectsave;
846 punchChecksum();
847
848 /* Works great for trailer. */
849 punchLeader( 1 );
850
851 /* undo effects of XLIST for any following output to listing file. */
852 if( listfile == NULL )
853 {
854 listfile = listsave;
855 }
856
857 /* Display value of error counter. */
858 if( errors == 0 )
859 {
860 fprintf( listfile, "\n %s %s %s\n", s_no, s_detected, s_errors );
861 }
862 else
863 {
864 fprintf( errorfile, "\n %d %s %s\n", errors, s_detected,
865 ( errors == 1 ? s_error : s_errors ));
866 fprintf( listfile, "\n %d %s %s\n", errors, s_detected,
867 ( errors == 1 ? s_error : s_errors ));
868 fprintf( stderr, " %d %s %s\n", errors, s_detected,
869 ( errors == 1 ? s_error : s_errors ));
870 }
871
872 if( symtab_print )
873 {
874 printSymbolTable();
875 }
876
877 if( print_permanent_symbols )
878 {
879 printPermanentSymbolTable();
880 }
881
882 if( xref )
883 {
884 printCrossReference();
885 }
886
887 fclose( objectfile );
888 fclose( listfile );
889 fclose( errorfile );
890 if( errors == 0 && errors_pass_1 == 0 )
891 {
892 remove( errorpathname );
893 }
894
895 return( errors != 0 );
896 } /* main() */
897
898 /******************************************************************************/
899 /* */
900 /* Function: getArgs */
901 /* */
902 /* Synopsis: Parse command line, set flags accordingly and setup input and */
903 /* output files. */
904 /* */
905 /******************************************************************************/
906 void getArgs( int argc, char *argv[] )
907 {
908 WORD16 len;
909 WORD16 ix, jx;
910
911 /* Set the defaults */
912 errorfile = NULL;
913 infile = NULL;
914 listfile = NULL;
915 listsave = NULL;
916 objectfile = NULL;
917 objectsave = NULL;
918
919 for( ix = 1; ix < argc; ix++ )
920 {
921 if( argv[ix][0] == '-' )
922 {
923 for( jx = 1; argv[ix][jx] != 0; jx++ )
924 {
925 switch( argv[ix][jx] )
926 {
927 case 'd':
928 symtab_print = TRUE;
929 break;
930
931 case 'r':
932 rim_mode = TRUE;
933 break;
934
935 case 'l':
936 literals_on = TRUE;
937 break;
938
939 case 'p':
940 print_permanent_symbols = TRUE;
941 break;
942
943 case 'x':
944 xref = TRUE;
945 break;
946
947 default:
948 fprintf( stderr, "%s: unknown flag: %s\n", argv[0], argv[ix] );
949 fprintf( stderr, " -d -- dump symbol table\n" );
950 fprintf( stderr, " -l -- generate literals\n" );
951 fprintf( stderr, " -r -- output rim format file\n" );
952 fprintf( stderr, " -p -- output permanent symbols to file\n" );
953 fprintf( stderr, " -x -- output cross reference to file\n" );
954 fflush( stderr );
955 exit( -1 );
956 } /* end switch */
957 } /* end for */
958 }
959 else
960 {
961 if( pathname != NULL )
962 {
963 fprintf( stderr, "%s: too many input files\n", argv[0] );
964 exit( -1 );
965 }
966 pathname = &argv[ix][0];
967 }
968 } /* end for */
969
970 if( pathname == NULL )
971 {
972 fprintf( stderr, "%s: no input file specified\n", argv[0] );
973 exit( -1 );
974 }
975
976 len = strlen( pathname );
977 if( len > NAMELEN - 5 )
978 {
979 fprintf( stderr, "%s: pathname \"%s\" too long\n", argv[0], pathname );
980 exit( -1 );
981 }
982
983 /* Now open the input file. */
984 if(( infile = fopen( pathname, "r" )) == NULL )
985 {
986 fprintf( stderr, "%s: cannot open \"%s\"\n", argv[0], pathname );
987 exit( -1 );
988 }
989
990 /* Now make the pathnames */
991 /* Find last '.', if it exists. */
992 jx = len - 1;
993 while( pathname[jx] != '.' && pathname[jx] != '/'
994 && pathname[jx] != '\\' && jx >= 0 )
995 {
996 jx--;
997 }
998
999 switch( pathname[jx] )
1000 {
1001 case '.':
1002 break;
1003
1004 case '/':
1005 case '\\':
1006 jx = len;
1007 break;
1008
1009 default:
1010 break;
1011 }
1012
1013 /* Add the pathname extensions. */
1014 strncpy( objectpathname, pathname, jx );
1015 objectpathname[jx] = '\0';
1016 strcat( objectpathname, rim_mode ? ".rim" : ".bin" );
1017
1018 strncpy( listpathname, pathname, jx );
1019 listpathname[jx] = '\0';
1020 strcat( listpathname, ".lst" );
1021
1022 strncpy( errorpathname, pathname, jx );
1023 errorpathname[jx] = '\0';
1024 strcat( errorpathname, ".err" );
1025
1026 strncpy( permpathname, pathname, jx );
1027 permpathname[jx] = '\0';
1028 strcat( permpathname, ".prm" );
1029
1030 /* Extract the filename from the path. */
1031 if( isalpha( pathname[0] ) && pathname[1] == ':' && pathname[2] != '\\' )
1032 {
1033 pathname[1] = '\\'; /* MS-DOS style pathname */
1034 }
1035
1036 jx = len - 1;
1037 while( pathname[jx] != '/' && pathname[jx] != '\\' && jx >= 0 )
1038 {
1039 jx--;
1040 }
1041 strcpy( filename, &pathname[jx + 1] );
1042
1043 } /* getArgs() */
1044
1045
1046 /******************************************************************************/
1047 /* */
1048 /* Function: onePass */
1049 /* */
1050 /* Synopsis: Do one assembly pass. */
1051 /* */
1052 /******************************************************************************/
1053 void onePass()
1054 {
1055 char name[SYMLEN];
1056 WORD16 newclc;
1057 BOOL scanning_line;
1058 WORD16 start;
1059 SYM_T *sym;
1060 WORD16 term;
1061 WORD16 val;
1062
1063 clc = 0200; /* Default starting address is 200 octal. */
1064 field = 0;
1065 fieldlc = 0;
1066 reloc = 0;
1067 cp.loc = 00200; /* Points to end of page for [] operands. */
1068 pz.loc = 00200; /* Points to end of page for () operands. */
1069 cp.error = FALSE;
1070 pz.error = FALSE;
1071 listed = TRUE;
1072 lineno = 0;
1073 list_pageno = 0;
1074 list_lineno = 0;
1075 list_title_set = FALSE;
1076 radix = 8; /* Initial radix is octal (base 8). */
1077
1078 while( TRUE )
1079 {
1080 readLine();
1081 nextLexeme();
1082
1083 scanning_line = TRUE;
1084 while( scanning_line )
1085 {
1086 if( isend( line[lexstart] ))
1087 {
1088 scanning_line = FALSE;
1089 }
1090 else
1091 {
1092 switch( line[lexstart] )
1093 {
1094 case '/':
1095 scanning_line = FALSE;
1096 break;
1097
1098 case ';':
1099 nextLexeme();
1100 break;
1101
1102 case '$':
1103 endOfBinary();
1104 return;
1105
1106 case '*':
1107 nextLexeme(); /* Skip '*', (set origin symbol) */
1108 newclc = ((getExpr())->val & 07777 ) | field;
1109 /* Do not change Current Location Counter if an error occurred. */
1110 if( !error_in_line )
1111 {
1112 if(( newclc & 07600 ) != ( clc & 07600 ))
1113 {
1114 /* Current page has changed. */
1115 punchLiteralPool( &cp, clc - 1 );
1116 }
1117 clc = newclc - reloc;
1118 fieldlc = clc & 07777;
1119
1120 if( !rim_mode )
1121 {
1122 /* Not rim mode, put out origin. */
1123 punchOrigin( clc );
1124 }
1125 printLine( line, 0, fieldlc, LINE_VAL );
1126 }
1127 break;
1128
1129 default:
1130 switch( line[lexterm] )
1131 {
1132 case ',':
1133 if( isalpha( line[lexstart] ))
1134 {
1135 /* Use lookup so symbol will not be counted as reference. */
1136 sym = lookup( lexemeToName( name, lexstart, lexterm ));
1137 if( M_DEFINED( sym->type ))
1138 {
1139 if( sym->val != clc && pass == 2 )
1140 {
1141 errorSymbol( &duplicate_label, sym->name, lexstart );
1142 }
1143 sym->type = sym->type | DUPLICATE;
1144 }
1145 /* Must call define on pass 2 to generate concordance. */
1146 defineLexeme( lexstart, lexterm, ( clc+reloc ), LABEL );
1147 }
1148 else
1149 {
1150 errorLexeme( &label_syntax, lexstart );
1151 }
1152 nextLexeme(); /* skip label */
1153 nextLexeme(); /* skip comma */
1154 break;
1155
1156 case '=':
1157 if( isalpha( line[lexstart] ))
1158 {
1159 start = lexstart;
1160 term = lexterm;
1161 delimiter = line[lexterm];
1162 nextLexBlank(); /* skip symbol */
1163 nextLexBlank(); /* skip trailing = */
1164 val = getExprs();
1165 defineLexeme( start, term, val, DEFINED );
1166 printLine( line, 0, val, LINE_VAL );
1167 }
1168 else
1169 {
1170 errorLexeme( &symbol_syntax, lexstartprev );
1171 nextLexeme(); /* skip symbol */
1172 nextLexeme(); /* skip trailing = */
1173 getExprs(); /* skip expression */
1174 }
1175 break;
1176
1177 default:
1178 if( isalpha( line[lexstart] ))
1179 {
1180 sym = evalSymbol();
1181 val = sym->val;
1182 if( M_PSEUDO( sym->type ))
1183 {
1184 nextLexeme(); /* Skip symbol */
1185 scanning_line = pseudoOperators( (PSEUDO_T)val & 07777 );
1186 }
1187 else
1188 {
1189 /* Identifier is not a pseudo-op, interpret as load value */
1190 punchOutObject( clc, getExprs() & 07777 );
1191 incrementClc();
1192 }
1193 }
1194 else
1195 {
1196 /* Identifier is a value, interpret as load value */
1197 punchOutObject( clc, getExprs() & 07777 );
1198 incrementClc();
1199 }
1200 break;
1201 } /* end switch */
1202 break;
1203 } /* end switch */
1204 } /* end if */
1205 } /* end while( scanning_line ) */
1206 } /* end while( TRUE ) */
1207 } /* onePass() */
1208
1209
1210 /******************************************************************************/
1211 /* */
1212 /* Function: getExprs */
1213 /* */
1214 /* Synopsis: Or together a list of blank separated expressions, from the */
1215 /* current lexeme onward. Leave the current lexeme as */
1216 /* the last one in the list. */
1217 /* */
1218 /******************************************************************************/
1219 WORD16 getExprs()
1220 {
1221 SYM_T *symv;
1222 SYM_T *symt;
1223 WORD16 temp;
1224 SYMTYP temp_type;
1225 WORD16 value;
1226 SYMTYP value_type;
1227
1228 symv = getExpr();
1229 value = symv->val;
1230 value_type = symv->type;
1231
1232 while( TRUE )
1233 {
1234 if( isdone( line[lexstart] ))
1235 {
1236 return( value );
1237 }
1238 switch( line[lexstart] )
1239 {
1240 case ')':
1241 case ']':
1242 return( value );
1243
1244 default:
1245 break;
1246 }
1247
1248 /* Interpret space as logical or */
1249 symt = getExpr();
1250 temp = symt->val & 07777;
1251 temp_type = symt->type;
1252
1253 switch( value_type )
1254 {
1255 case MRI:
1256 case MRIFIX:
1257 /* Previous symbol was a Memory Reference Instruction. */
1258 switch( temp_type )
1259 {
1260 case MRI:
1261 case MRIFIX:
1262 /* Current symbol is also a Memory Reference Instruction. */
1263 value |= temp; /* Just OR the MRI instructions. */
1264 break;
1265
1266 default:
1267 /* Now have the address part of the MRI instruction. */
1268 if( temp < 00200 )
1269 {
1270 value |= temp; /* Page zero MRI. */
1271 }
1272 else if( (( fieldlc + reloc ) & 07600 ) <= temp
1273 && temp <= (( fieldlc + reloc ) | 0177 ))
1274 {
1275 value |= ( PAGE_BIT | (temp & ADDRESS_FIELD )); /* Current page MRI */
1276 }
1277 else
1278 {
1279 if(( value & INDIRECT_BIT ) == INDIRECT_BIT )
1280 {
1281 /* Already indirect, can't generate */
1282 errorSymbol( &illegal_indirect, symt->name, lexstartprev );
1283 }
1284 else
1285 {
1286 if( literals_on )
1287 {
1288 /* Now fix off page reference. */
1289 /* Search current page literal pool for needed value. */
1290 /* Set Indirect Current Page */
1291 value |= ( 00600 | insertLiteral( &cp, temp ));
1292 indirect_generated = TRUE;
1293 }
1294 else
1295 {
1296 errorSymbol( &illegal_reference, symt->name, lexstartprev );
1297 value |= ( temp & 0177 );
1298 }
1299 }
1300 }
1301 break;
1302 }
1303 break;
1304
1305 default:
1306 value |= temp; /* Normal 12 bit value. */
1307 break;
1308 }
1309 } /* end while */
1310 } /* getExprs() */
1311
1312
1313 /******************************************************************************/
1314 /* */
1315 /* Function: getExpr */
1316 /* */
1317 /* Synopsis: Get an expression, from the current lexeme onward, leave the */
1318 /* current lexeme as the one after the expression. Expressions */
1319 /* contain terminal symbols (identifiers) separated by operators. */
1320 /* */
1321 /******************************************************************************/
1322 SYM_T *getExpr()
1323 {
1324 delimiter = line[lexterm];
1325
1326 if( line[lexstart] == '-' )
1327 {
1328 nextLexBlank();
1329 sym_getexpr = *(eval());
1330 sym_getexpr.val = ( - sym_getexpr.val );
1331 }
1332 else
1333 {
1334 sym_getexpr = *(eval());
1335 }
1336
1337
1338 if( is_blank( delimiter ))
1339 {
1340 return( &sym_getexpr );
1341 }
1342
1343 /* Here we assume the current lexeme is the operator separating the */
1344 /* previous operator from the next, if any. */
1345 while( TRUE )
1346 {
1347 /* assert line[lexstart] == delimiter */
1348 if( is_blank( delimiter ))
1349 {
1350 return( &sym_getexpr );
1351 }
1352
1353 switch( line[lexstart] )
1354 {
1355 case '+': /* add */
1356 nextLexBlank(); /* skip over the operator */
1357 sym_getexpr.val += (eval())->val;
1358 break;
1359
1360 case '-': /* subtract */
1361 nextLexBlank(); /* skip over the operator */
1362 sym_getexpr.val -= (eval())->val;
1363 break;
1364
1365 case '^': /* multiply */
1366 nextLexBlank(); /* skip over the operator */
1367 sym_getexpr.val *= (eval())->val;
1368 break;
1369
1370 case '%': /* divide */
1371 nextLexBlank(); /* skip over the operator */
1372 sym_getexpr.val /= (eval())->val;
1373 break;
1374
1375 case '&': /* and */
1376 nextLexBlank(); /* skip over the operator */
1377 sym_getexpr.val &= (eval())->val;
1378 break;
1379
1380 case '!': /* or */
1381 nextLexBlank(); /* skip over the operator */
1382 sym_getexpr.val |= (eval())->val;
1383 break;
1384
1385 default:
1386 if( isend( line[lexstart] ))
1387 {
1388 return( &sym_getexpr );
1389 }
1390
1391 switch( line[lexstart] )
1392 {
1393 case '/':
1394 case ';':
1395 case ')':
1396 case ']':
1397 case '<':
1398 break;
1399
1400 case '=':
1401 errorMessage( &illegal_equals, lexstart );
1402 moveToEndOfLine();
1403 sym_getexpr.val = 0;
1404 break;
1405
1406 default:
1407 errorMessage( &illegal_expression, lexstart );
1408 moveToEndOfLine();
1409 sym_getexpr.val = 0;
1410 break;
1411 }
1412 return( &sym_getexpr );
1413 }
1414 } /* end while */
1415 } /* getExpr() */
1416
1417
1418 /******************************************************************************/
1419 /* */
1420 /* Function: eval */
1421 /* */
1422 /* Synopsis: Get the value of the current lexeme, set delimiter and advance.*/
1423 /* */
1424 /******************************************************************************/
1425 SYM_T *eval()
1426 {
1427 WORD16 digit;
1428 WORD16 from;
1429 WORD16 loc;
1430 SYM_T *sym;
1431 WORD16 val;
1432
1433 val = 0;
1434
1435 delimiter = line[lexterm];
1436 if( isalpha( line[lexstart] ))
1437 {
1438 sym = evalSymbol();
1439 if( M_UNDEFINED( sym->type ) && pass == 2 )
1440 {
1441 errorSymbol( &undefined_symbol, sym->name, lexstart );
1442 nextLexeme();
1443 return( sym );
1444 }
1445 else
1446 {
1447 nextLexeme();
1448 return( sym );
1449 }
1450 }
1451 else if( isdigit( line[lexstart] ))
1452 {
1453 from = lexstart;
1454 val = 0;
1455 while( from < lexterm )
1456 {
1457 if( isdigit( line[from] ))
1458 {
1459 digit = (WORD16) line[from++] - (WORD16) '0';
1460 if( digit < radix )
1461 {
1462 val = val * radix + digit;
1463 }
1464 else
1465 {
1466 errorLexeme( &number_not_radix, from - 1 );
1467 val = 0;
1468 from = lexterm;
1469 }
1470 }
1471 else
1472 {
1473 errorLexeme( &not_a_number, lexstart );
1474 val = 0;
1475 from = lexterm;
1476 }
1477 }
1478 nextLexeme();
1479 sym_eval.val = val;
1480 return( &sym_eval );
1481 }
1482 else
1483 {
1484 switch( line[lexstart] )
1485 {
1486 case '"': /* Character literal */
1487 if( cc + 2 < maxcc )
1488 {
1489 val = line[lexstart + 1] | 0200;
1490 delimiter = line[lexstart + 2];
1491 cc = lexstart + 2;
1492 }
1493 else
1494 {
1495 errorMessage( &no_literal_value, lexstart );
1496 }
1497 nextLexeme();
1498 break;
1499
1500 case '.': /* Value of Current Location Counter */
1501 val = clc + reloc;
1502 nextLexeme();
1503 break;
1504
1505 case '[': /* Generate literal on page zero. */
1506 if( !literals_on )
1507 {
1508 errorMessage( &literal_gen_off, lexstart );
1509 }
1510 nextLexBlank(); /* Skip bracket */
1511 val = (getExpr())->val & 07777;
1512 if( line[lexstart] == ']' )
1513 {
1514 nextLexBlank(); /* Skip end bracket */
1515 }
1516 else
1517 {
1518 /* errorMessage( "parens", lexstart ); */
1519 }
1520 sym_eval.val = literals_on ? insertLiteral( &pz, val ) : 0;
1521 return( &sym_eval );
1522
1523 case '(': /* Generate literal on current page. */
1524 if( !literals_on )
1525 {
1526 errorMessage( &literal_gen_off, lexstart );
1527 }
1528
1529 nextLexBlank(); /* Skip paren */
1530 val = getExprs() & 07777;
1531
1532 if( line[lexstart] == ')' )
1533 {
1534 nextLexBlank(); /* Skip end paren */
1535 }
1536 else
1537 {
1538 /* errorMessage( "parens", NULL ); */
1539 }
1540
1541 loc = literals_on ? insertLiteral( &cp, val ) : 0;
1542 sym_eval.val = loc + (( clc + reloc ) & 077600 );
1543 return( &sym_eval );
1544
1545 default:
1546 switch( line[lexstart] )
1547 {
1548 case '=':
1549 errorMessage( &illegal_equals, lexstart );
1550 moveToEndOfLine();
1551 break;
1552
1553 default:
1554 errorMessage( &illegal_character, lexstart );
1555 break;
1556 }
1557 val = 0; /* On error, set value to zero. */
1558 nextLexBlank(); /* Go past illegal character. */
1559 }
1560 }
1561 sym_eval.val = val;
1562 return( &sym_eval );
1563 } /* eval() */
1564
1565
1566 /******************************************************************************/
1567 /* */
1568 /* Function: inputDubl */
1569 /* */
1570 /* Synopsis: Get the value of the current lexeme as a double word. */
1571 /* */
1572 /******************************************************************************/
1573 void inputDubl()
1574 {
1575 WORD32 dublvalue;
1576 BOOL scanning_line;
1577
1578 scanning_line = TRUE;
1579 do
1580 {
1581 while( scanning_line )
1582 {
1583 if( isend( line[lexstart] ))
1584 {
1585 scanning_line = FALSE;
1586 }
1587 else
1588 {
1589 switch( line[lexstart] )
1590 {
1591 case '/':
1592 scanning_line = FALSE;
1593 break;
1594
1595 case ';':
1596 nextLexeme();
1597 break;
1598
1599 case '+':
1600 delimiter = line[lexterm];
1601 nextLexBlank();
1602 case '-':
1603 default:
1604 if( isdigit( line[lexstart] ) || line[lexstart] == '-' )
1605 {
1606 dublvalue = getDublExprs();
1607 punchOutObject( clc, (WORD16)(( dublvalue >> 12 ) & 07777 ));
1608 incrementClc();
1609 punchOutObject( clc, (WORD16)( dublvalue & 07777 ));
1610 incrementClc();
1611 }
1612 else
1613 {
1614 return; /* Non-numeric input, back to assembly. */
1615 }
1616 break;
1617 } /* end switch */
1618 } /* end if */
1619
1620 if( error_in_line )
1621 {
1622 return; /* Error occurred, exit DUBL input mode. */
1623 }
1624 } /* end while( scanning_line ) */
1625 readLine();
1626 nextLexeme();
1627 scanning_line = TRUE;
1628 }
1629 while( TRUE );
1630 } /* inputDubl() */
1631
1632
1633 /******************************************************************************/
1634 /* */
1635 /* Function: getDublExprs */
1636 /* */
1637 /* Synopsis: Get a DUBL expression. */
1638 /* */
1639 /******************************************************************************/
1640 WORD32 getDublExprs()
1641 {
1642 WORD32 dublvalue;
1643
1644 dublvalue = getDublExpr();
1645
1646 while( TRUE )
1647 {
1648 if( isdone( line[lexstart] ))
1649 {
1650 return( dublvalue );
1651 }
1652 else
1653 {
1654 errorMessage( &illegal_expression, lexstart - 1 );
1655 return( 0 );
1656 }
1657 } /* end while */
1658 } /* getDublExprs() */
1659
1660
1661 /******************************************************************************/
1662 /* */
1663 /* Function: getDublExpr */
1664 /* */
1665 /* Synopsis: Get the value of the current lexeme as a double word. The */
1666 /* number is always considered to have a decimal radix. */
1667 /* */
1668 /******************************************************************************/
1669 WORD32 getDublExpr()
1670 {
1671 WORD32 dublvalue;
1672
1673 delimiter = line[lexterm];
1674 if( line[lexstart] == '-' )
1675 {
1676 nextLexBlank();
1677 dublvalue = evalDubl( 0 );
1678 nextLexeme();
1679 /* Test for any value greater than 23 bits in length. */
1680 if( (unsigned long int)dublvalue > 040000000L )
1681 {
1682 errorMessage( &dubl_overflow, lexstart );
1683 dublvalue = 0;
1684 }
1685 dublvalue = -dublvalue;
1686 }
1687 else
1688 {
1689 dublvalue = evalDubl( 0 );
1690 nextLexeme();
1691 /* Test for any value greater than 23 bits in length. */
1692 if( (unsigned long int)dublvalue > 037777777L )
1693 {
1694 errorMessage( &dubl_overflow, lexstart );
1695 dublvalue = 0;
1696 }
1697 }
1698
1699 if( is_blank( delimiter ))
1700 {
1701 return( dublvalue );
1702 }
1703
1704 /* Here we assume the current lexeme is the operator separating the */
1705 /* previous operator from the next, if any. */
1706 while( TRUE )
1707 {
1708 /* assert line[lexstart] == delimiter */
1709 if( is_blank( delimiter ))
1710 {
1711 errorMessage( &illegal_expression, lexstart );
1712 moveToEndOfLine();
1713 dublvalue = 0;
1714 return( dublvalue );
1715 }
1716
1717 switch( line[lexstart] )
1718 {
1719 case '+': /* add */
1720 case '-': /* subtract */
1721 case '^': /* multiply */
1722 case '%': /* divide */
1723 case '&': /* and */
1724 case '!': /* or */
1725 errorMessage( &illegal_expression, lexstart );
1726 moveToEndOfLine();
1727 dublvalue = 0;
1728 break;
1729
1730 default:
1731 if( isend( line[lexstart] ))
1732 {
1733 return( dublvalue );
1734 }
1735
1736 switch( line[lexstart] )
1737 {
1738 case '/':
1739 case ';':
1740 break;
1741
1742 default:
1743 errorMessage( &illegal_expression, lexstart );
1744 moveToEndOfLine();
1745 dublvalue = 0;
1746 break;
1747 }
1748 return( dublvalue );
1749 }
1750 } /* end while */
1751 } /* getDublExpr() */
1752
1753
1754 /******************************************************************************/
1755 /* */
1756 /* Function: evalDubl */
1757 /* */
1758 /* Synopsis: Get the value of the current lexeme as a double word. The */
1759 /* number is always considered to have a decimal radix. */
1760 /* */
1761 /******************************************************************************/
1762 WORD32 evalDubl( WORD32 initial_value )
1763 {
1764 WORD32 digit;
1765 WORD16 from;
1766 WORD32 dublvalue;
1767 WORD32 olddublvalue;
1768
1769 overflow = FALSE;
1770 delimiter = line[lexterm];
1771 from = lexstart;
1772 dublvalue = initial_value;
1773
1774 while( from < lexterm )
1775 {
1776 if( isdigit( line[from] ))
1777 {
1778 olddublvalue = dublvalue;
1779 digit = (WORD32)( line[from++] - '0' );
1780 dublvalue = dublvalue * 10 + digit;
1781 if( dublvalue < olddublvalue )
1782 {
1783 overflow = TRUE;
1784 }
1785 }
1786 else
1787 {
1788 errorLexeme( &not_a_number, from );
1789 dublvalue = 0;
1790 from = lexterm;
1791 }
1792 }
1793 return( dublvalue );
1794 } /* evalDubl() */
1795
1796
1797 /******************************************************************************/
1798 /* */
1799 /* Function: inputFltg */
1800 /* */
1801 /* Synopsis: Get the value of the current lexeme as a Floating Point const. */
1802 /* */
1803 /******************************************************************************/
1804 void inputFltg()
1805 {
1806 FLTG_T *fltg;
1807 BOOL scanning_line;
1808
1809 fltg_input = TRUE; /* Set lexeme scanner for floating point. */
1810 scanning_line = TRUE;
1811 while( TRUE )
1812 {
1813 while( scanning_line )
1814 {
1815 if( isend( line[lexstart] ))
1816 {
1817 scanning_line = FALSE;
1818 }
1819 else
1820 {
1821 switch( line[lexstart] )
1822 {
1823 case '/':
1824 scanning_line = FALSE;
1825 break;
1826
1827 case ';':
1828 nextLexeme();
1829 break;
1830
1831 case '+':
1832 delimiter = line[lexterm];
1833 nextLexBlank();
1834 case '-':
1835 default:
1836 if( isdigit( line[lexstart] ) || line[lexstart] == '-' )
1837 {
1838 fltg = getFltgExprs();
1839 punchOutObject( clc, ( fltg->exponent & 07777 ));
1840 incrementClc();
1841 punchOutObject( clc, (WORD16)(( fltg->mantissa >> 12 ) & 07777 ));
1842 incrementClc();
1843 punchOutObject( clc, (WORD16)( fltg->mantissa & 07777 ));
1844 incrementClc();
1845 }
1846 else
1847 {
1848 fltg_input = FALSE; /* Reset lexeme scanner. */
1849 return; /* Non-numeric input, back to assembly. */
1850 }
1851 break;
1852 } /* end switch */
1853 } /* end if */
1854
1855 if( error_in_line )
1856 {
1857 fltg_input = FALSE; /* Reset lexeme scanner. */
1858 return; /* Error occurred, exit FLTG input mode. */
1859 }
1860 } /* end while( scanning_line ) */
1861 readLine();
1862 nextLexeme();
1863 scanning_line = TRUE;
1864 }
1865 } /* inputFltg() */
1866
1867
1868 /******************************************************************************/
1869 /* */
1870 /* Function: getFltgExprs */
1871 /* */
1872 /* Synopsis: Get a FLTG expression. */
1873 /* */
1874 /******************************************************************************/
1875 FLTG_T *getFltgExprs()
1876 {
1877 FLTG_T *fltg;
1878
1879 fltg = getFltgExpr();
1880
1881 while( TRUE )
1882 {
1883 if( isdone( line[lexstart] ))
1884 {
1885 return( fltg );
1886 }
1887 else
1888 {
1889 errorMessage( &illegal_expression, lexstart - 1 );
1890 return( 0 );
1891 }
1892 } /* end while */
1893 } /* getFltgExprs() */
1894
1895
1896 /******************************************************************************/
1897 /* */
1898 /* Function: getFltgExpr */
1899 /* */
1900 /* Synopsis: Get the value of the current lexeme as a double word. The */
1901 /* number is always considered to have a decimal radix. */
1902 /* */
1903 /******************************************************************************/
1904 FLTG_T *getFltgExpr()
1905 {
1906 FLTG_T *fltg;
1907
1908 delimiter = line[lexterm];
1909 fltg = evalFltg();
1910 /* Test for any value greater than 23 bits in length. */
1911 if( (unsigned long int)fltg->mantissa> 077777777L )
1912 {
1913 errorMessage( &fltg_overflow, lexstart );
1914 }
1915
1916 if( is_blank( delimiter ))
1917 {
1918 return( fltg );
1919 }
1920
1921 /* Here we assume the current lexeme is the operator separating the */
1922 /* previous operator from the next, if any. */
1923 while( TRUE )
1924 {
1925 /* assert line[lexstart] == delimiter */
1926 if( is_blank( delimiter ))
1927 {
1928 errorMessage( &illegal_expression, lexstart );
1929 moveToEndOfLine();
1930 fltg = 0;
1931 return( fltg );
1932 }
1933
1934 switch( line[lexstart] )
1935 {
1936 case '+': /* add */
1937 case '-': /* subtract */
1938 case '^': /* multiply */
1939 case '%': /* divide */
1940 case '&': /* and */
1941 case '!': /* or */
1942 errorMessage( &illegal_expression, lexstart );
1943 moveToEndOfLine();
1944 fltg = NULL;
1945 break;
1946
1947 default:
1948 if( isend( line[lexstart] ))
1949 {
1950 return( fltg );
1951 }
1952
1953 switch( line[lexstart] )
1954 {
1955 case '/':
1956 case ';':
1957 break;
1958
1959 default:
1960 errorMessage( &illegal_expression, lexstart );
1961 moveToEndOfLine();
1962 fltg = NULL;
1963 break;
1964 }
1965 return( fltg );
1966 }
1967 } /* end while */
1968 } /* getFltgExpr() */
1969
1970
1971 /******************************************************************************/
1972 /* */
1973 /* Function: evalFltg */
1974 /* */
1975 /* Synopsis: Get the value of the current lexeme as a floating point value. */
1976 /* Floating point input is alwasy considered decimal. */
1977 /* The general format of a floating point number is: */
1978 /* +-ddd.dddE+-dd where each d is a decimal digit. */
1979 /* */
1980 /******************************************************************************/
1981 FLTG_T *evalFltg()
1982 {
1983 BYTE current_state;
1984 BYTE current_col;
1985 WORD16 exponent;
1986 FLTG_T *fltg;
1987 WORD32 input_value;
1988 BOOL negate;
1989 BOOL negate_exponent;
1990 BYTE next_state;
1991 int right_digits;
1992
1993 /* This uses a lexical analyzer to parse the floating point format. */
1994 static BYTE state_table[][10] =
1995 {
1996 /* 0 1 2 3 4 5 6 Oolumn index */
1997 /* + - d . E sp p State Comment */
1998 { 2, 1, 3, 4, 10, 10, 10 }, /* 0 Initial state. */
1999 { 11, 11, 3, 4, 11, 11, 11 }, /* 1 - */
2000 { 11, 11, 3, 4, 11, 11, 11 }, /* 2 + */
2001 { 10, 10, 10, 4, 6, 10, 10 }, /* 3 # (+-ddd) */
2002 { 11, 11, 5, 11, 11, 10, 10 }, /* 4 . (+-ddd.) */
2003 { 11, 11, 11, 11, 6, 10, 11 }, /* 5 # (+-ddd.ddd) */
2004 { 8, 7, 9, 11, 11, 11, 11 }, /* 6 E (+-ddd.dddE) */
2005 { 11, 11, 9, 11, 11, 11, 11 }, /* 7 - (+-ddd.dddE- */
2006 { 11, 11, 9, 11, 11, 11, 11 }, /* 8 + (+-ddd.dddE+ */
2007 { 11, 11, 11, 11, 11, 10, 11 } /* 9 # (+-ddd.dddE+-dd */
2008 /* 10 Completion state */
2009 /* 11 Error state. */
2010 };
2011
2012 delimiter = line[lexterm];
2013 fltg = &fltg_ac;
2014 fltg->exponent = 0;
2015 fltg->mantissa = 0;
2016 input_value = 0;
2017 negate = FALSE;
2018 negate_exponent = FALSE;
2019 exponent = 0;
2020 right_digits = 0;
2021 current_state = 0;
2022
2023 while( TRUE )
2024 {
2025 /* Classify character. This is the column index. */
2026 switch( line[lexstart] )
2027 {
2028 case '+':
2029 current_col = 0;
2030 break;
2031
2032 case '-':
2033 current_col = 1;
2034 break;
2035
2036 case '.':
2037 current_col = 3;
2038 break;
2039
2040 case 'E': case 'e':
2041 current_col = 4;
2042 break;
2043
2044 default:
2045 if( isdigit( line[lexstart] ))
2046 {
2047 current_col = 2;
2048 }
2049 else if( isdone( line[lexstart] ))
2050 {
2051 current_col = 5;
2052 }
2053 else
2054 {
2055 current_col = 6;
2056 }
2057 break;
2058 }
2059
2060 next_state = state_table[current_state][current_col];
2061
2062 switch( next_state )
2063 {
2064 case 1: /* - */
2065 negate = TRUE;
2066 case 2: /* + */
2067 delimiter = line[lexterm]; /* Move past the + or - character. */
2068 nextLexBlank();
2069 break;
2070
2071 case 3: /* Number (+-ddd) */
2072 input_value = evalDubl( 0 ); /* Integer part of the number. */
2073 nextLexeme(); /* Move past previous lexeme. */
2074 break;
2075
2076 case 4:
2077 delimiter = line[lexterm];
2078 nextLexBlank(); /* Move past the . character. */
2079 break;
2080
2081 case 5: /* . (+-ddd.ddd) */
2082 /* Fractional part of the number. */
2083 input_value = evalDubl( input_value );
2084 right_digits = lexterm - lexstart;/* Digit count to right of decimal. */
2085 nextLexeme(); /* Move past previous lexeme. */
2086 break;
2087
2088 case 6: /* E (+-ddd.dddE) */
2089 delimiter = line[lexterm]; /* Move past the E. */
2090 nextLexBlank();
2091 break;
2092
2093 case 7: /* - (+-ddd.dddE-) */
2094 negate_exponent = TRUE;
2095 case 8: /* + (+-ddd.dddE+) */
2096 delimiter = line[lexterm]; /* Move past the + or - character. */
2097 nextLexBlank();
2098 break;
2099
2100 case 9: /* # (+-ddd.dddE+-dd) */
2101 exponent = (int)evalDubl( 0 ); /* Exponent of floating point number. */
2102 if( negate_exponent ) { exponent = - exponent; }
2103 nextLexeme(); /* Move past previous lexeme. */
2104 break;
2105
2106 case 10: /* Floating number parsed, convert */
2107 /* the number. */
2108 /* Get the exponent for the number as input. */
2109 exponent -= right_digits;
2110
2111 /* Remove trailing zeros and adjust the exponent accordingly. */
2112 while(( input_value % 10 ) == 0 )
2113 {
2114 input_value /= 10;
2115 exponent++;
2116 }
2117
2118 /* Convert the number to floating point. The number is calculated with */
2119 /* a 27 bit mantissa to improve precision. The extra 3 bits are */
2120 /* discarded after the result has been calculated. */
2121 fltg->exponent = 26;
2122 fltg->mantissa = input_value << 3;
2123 normalizeFltg( fltg );
2124
2125
2126 while( exponent != 0 )
2127 {
2128 if( exponent < 0 )
2129 {
2130 /* Decimal point is to the left. */
2131 fltg->mantissa /= 10;
2132 normalizeFltg( fltg );
2133 exponent++;
2134 }
2135 else if( exponent > 0 )
2136 {
2137 /* Decimal point is to the right. */
2138 fltg->mantissa *= 10;
2139 normalizeFltg( fltg );
2140 exponent--;
2141 }
2142 }
2143
2144 /* Discard the extra precsion used for calculating the number. */
2145 fltg->mantissa >>= 3;
2146 fltg->exponent -= 3;
2147 if( negate )
2148 {
2149 fltg->mantissa = (- fltg->mantissa ) & 077777777L;
2150 }
2151 return( fltg );
2152
2153 case 11: /* Error in format. */
2154 /* Not a properly constructued floating point number. */
2155 return( fltg );
2156 default:
2157 break;
2158 }
2159 /* Set state for next pass through the loop. */
2160 current_state = next_state;
2161 }
2162 } /* evalFltg() */
2163
2164
2165
2166 /******************************************************************************/
2167 /* */
2168 /* Function: normalizeFltg */
2169 /* */
2170 /* Synopsis: Normalize a PDP-8 double precision floating point number. */
2171 /* */
2172 /******************************************************************************/
2173 void normalizeFltg( FLTG_T *fltg )
2174 {
2175 /* Normalize the floating point number. */
2176 if( fltg->mantissa != 0 )
2177 {
2178 if(( fltg->mantissa & ~0x3FFFFFFL ) == 0 )
2179 {
2180 while(( fltg->mantissa & ~0x1FFFFFFL ) == 0 )
2181
2182 {
2183 fltg->mantissa <<= 1;
2184 fltg->exponent--;
2185 }
2186 }
2187 else
2188 {
2189 while(( fltg->mantissa & ~0x3FFFFFFL ) != 0 )
2190 {
2191 fltg->mantissa >>= 1;
2192 fltg->exponent++;
2193 }
2194 }
2195 }
2196 else
2197 {
2198 fltg->exponent = 0;
2199 }
2200 return;
2201 }
2202
2203
2204 /******************************************************************************/
2205 /* */
2206 /* Function: incrementClc */
2207 /* */
2208 /* Synopsis: Set the next assembly location. Test for collision with */
2209 /* the literal tables. */
2210 /* */
2211 /******************************************************************************/
2212 WORD16 incrementClc()
2213 {
2214 testForLiteralCollision( clc );
2215
2216 /* Incrementing the location counter is not to change field setting. */
2217 clc = ( clc & 070000 ) + (( clc + 1 ) & 07777 );
2218 fieldlc = clc & 07777;
2219 return( clc );
2220 } /* incrementClc() */
2221
2222
2223 /******************************************************************************/
2224 /* */
2225 /* Function: testForLiteralCollision */
2226 /* */
2227 /* Synopsis: Test the given location for collision with the literal tables. */
2228 /* */
2229 /******************************************************************************/
2230 BOOL testForLiteralCollision( WORD16 loc )
2231 {
2232 WORD16 pagelc;
2233 BOOL result = FALSE;
2234 WORD16 tmppage;
2235
2236 tmppage = loc & 07600;
2237 pagelc = loc & 00177;
2238
2239 if( tmppage == 0 )
2240 {
2241 if( pagelc >= pz.loc && !pz.error )
2242 {
2243 errorMessage( &pz_literal_overflow, -1 );
2244 pz.error = TRUE;
2245 result = TRUE;
2246 }
2247 }
2248 else
2249 {
2250 if( pagelc >= cp.loc && !cp.error )
2251 {
2252 errorMessage( &literal_overflow, -1 );
2253 cp.error = TRUE;
2254 result = TRUE;
2255 }
2256 }
2257 return( result );
2258 } /* testForLiteralCollision() */
2259
2260
2261 /******************************************************************************/
2262 /* */
2263 /* Function: readLine */
2264 /* */
2265 /* Synopsis: Get next line of input. Print previous line if needed. */
2266 /* */
2267 /******************************************************************************/
2268 void readLine()
2269 {
2270 WORD16 ix;
2271 WORD16 iy;
2272 char inpline[LINELEN];
2273
2274 listLine(); /* List previous line if needed. */
2275 lineno++; /* Count lines read. */
2276 indirect_generated = FALSE; /* Mark no indirect address generated. */
2277 listed = FALSE; /* Mark as not listed. */
2278 cc = 0; /* Initialize column counter. */
2279 lexstartprev = 0;
2280
2281 if(( fgets( inpline, LINELEN - 1, infile )) == NULL )
2282 {
2283 inpline[0] = '$';
2284 inpline[1] = '\n';
2285 inpline[2] = '\0';
2286 error_in_line = TRUE;
2287 }
2288 else
2289 {
2290 error_in_line = FALSE;
2291 }
2292
2293 /* Remove any tabs from the input line by inserting the required number */
2294 /* of spaces to simulate 8 character tab stops. */
2295 for( ix = 0, iy = 0; inpline[ix] != '\0'; ix++ )
2296 {
2297 switch( inpline[ix] )
2298 {
2299 case '\t':
2300 do
2301 {
2302 line[iy] = ' ';
2303 iy++;
2304 }
2305 while(( iy % 8 ) != 0 );
2306 break;
2307
2308 default:
2309 line[iy] = inpline[ix];
2310 iy++;
2311 break;
2312 }
2313 }
2314 line[iy] = '\0';
2315
2316 /* If the line is terminated by CR-LF, remove, the CR. */
2317 if( line[iy - 2] == '\r' )
2318 {
2319 iy--;
2320 line[iy - 1] = line[iy - 0];
2321 line[iy] = '\0';
2322 }
2323 maxcc = iy; /* Save the current line length. */
2324 } /* readLine() */
2325
2326
2327 /******************************************************************************/
2328 /* */
2329 /* Function: listLine */
2330 /* */
2331 /* Synopsis: Output a line to the listing file. */
2332 /* */
2333 /******************************************************************************/
2334 void listLine()
2335 /* generate a line of listing if not already done! */
2336 {
2337 if( listfile != NULL && listed == FALSE )
2338 {
2339 printLine( line, 0, 0, LINE );
2340 }
2341 } /* listLine() */
2342
2343
2344 /******************************************************************************/
2345 /* */
2346 /* Function: printPageBreak */
2347 /* */
2348 /* Synopsis: Output a Top of Form and listing header if new page necessary. */
2349 /* */
2350 /******************************************************************************/
2351 void printPageBreak()
2352 {
2353 if( page_lineno >= LIST_LINES_PER_PAGE )
2354 /* ( list_lineno % LIST_LINES_PER_PAGE ) == 0 ) */
2355 {
2356 if( !list_title_set )
2357 {
2358 strcpy( list_title, line );
2359 if( list_title[strlen(list_title) - 1] == '\n' )
2360 {
2361 list_title[strlen(list_title) - 1] = '\0';
2362 }
2363 if( strlen( list_title ) > TITLELEN )
2364 {
2365 list_title[TITLELEN] = '\0';
2366 }
2367 list_title_set = TRUE;
2368 }
2369 topOfForm( list_title, NULL );
2370
2371 }
2372 } /* printPageBreak() */
2373
2374
2375 /******************************************************************************/
2376 /* */
2377 /* Function: printLine */
2378 /* */
2379 /* Synopsis: Output a line to the listing file with new page if necessary. */
2380 /* */
2381 /******************************************************************************/
2382 void printLine( char *line, WORD16 loc, WORD16 val, LINESTYLE_T linestyle )
2383 {
2384 if( listfile == NULL )
2385 {
2386 save_error_count = 0;
2387 return;
2388 }
2389
2390 printPageBreak();
2391
2392 list_lineno++;
2393 page_lineno++;
2394 switch( linestyle )
2395 {
2396 default:
2397 case LINE:
2398 fprintf(listfile, "%5d ", lineno );
2399 fputs( line, listfile );
2400 listed = TRUE;
2401 break;
2402
2403 case LINE_VAL:
2404 fprintf(listfile, "%5d %4.4o ", lineno, val );
2405 fputs( line, listfile );
2406 listed = TRUE;
2407 break;
2408
2409 case LINE_LOC_VAL:
2410 if( !listed )
2411 {
2412 if( indirect_generated )
2413 {
2414 fprintf( listfile, "%5d %5.5o %4.4o@ ", lineno, loc, val );
2415 }
2416 else
2417 {
2418 fprintf( listfile, "%5d %5.5o %4.4o ", lineno, loc, val );
2419 }
2420 fputs( line, listfile );
2421 listed = TRUE;
2422 }
2423 else
2424 {
2425 fprintf( listfile, " %5.5o %4.4o\n", loc, val );
2426 }
2427 break;
2428
2429 case LOC_VAL:
2430 fprintf( listfile, " %5.5o %4.4o\n", loc, val );
2431 break;
2432 }
2433 printErrorMessages();
2434 } /* printLine() */
2435
2436
2437 /******************************************************************************/
2438 /* */
2439 /* Function: printErrorMessages */
2440 /* */
2441 /* Synopsis: Output any error messages from the current list of errors. */
2442 /* */
2443 /******************************************************************************/
2444 void printErrorMessages()
2445 {
2446 WORD16 ix;
2447 WORD16 iy;
2448
2449 if( listfile != NULL )
2450 {
2451 /* If any errors, display them now. */
2452 for( iy = 0; iy < save_error_count; iy++ )
2453 {
2454 printPageBreak();
2455 fprintf( listfile, "%-18.18s", error_list[iy].mesg );
2456 if( error_list[iy].col >= 0 )
2457 {
2458 for( ix = 0; ix < error_list[iy].col; ix++ )
2459 {
2460 if( line[ix] == '\t' )
2461 {
2462 putc( '\t', listfile );
2463 }
2464 else
2465 {
2466 putc( ' ', listfile );
2467 }
2468 }
2469 fputs( "^", listfile );
2470 list_lineno++;
2471 page_lineno++;
2472 }
2473 fputs( "\n", listfile );
2474 }
2475 }
2476 save_error_count = 0;
2477 } /* printErrorMessages() */
2478
2479
2480 /******************************************************************************/
2481 /* */
2482 /* Function: endOfBinary */
2483 /* */
2484 /* Synopsis: Outputs both literal tables at the end of a binary segment. */
2485 /* */
2486 /******************************************************************************/
2487 void endOfBinary()
2488 {
2489 /* Points to end of page for () operands. */
2490 punchLiteralPool( &cp, clc - 1 );
2491 /* Points to end of page zero for [] operands. */
2492 punchLiteralPool( &pz, 0 );
2493 if( error_in_line )
2494 {
2495 listed = TRUE;
2496 clc = ( clc & 070000 ) + (( clc - 1 ) & 07777 );
2497 errorMessage( &end_of_file, -1 );
2498 clc = ( clc & 070000 ) + (( clc + 1 ) & 07777 );
2499 }
2500 else
2501 {
2502 listLine(); /* List line if not done yet. */
2503 }
2504 return;
2505 } /* endOfBinary() */
2506
2507
2508 /******************************************************************************/
2509 /* */
2510 /* Function: punchChecksum */
2511 /* */
2512 /* Synopsis: Output a checksum if the current mode requires it and an */
2513 /* object file exists. */
2514 /* */
2515 /******************************************************************************/
2516 void punchChecksum()
2517 {
2518 /* If the assembler has output any BIN data output the checksum. */
2519 if( binary_data_output && !rim_mode )
2520 {
2521 punchLocObject( 0, checksum );
2522 }
2523 binary_data_output = FALSE;
2524 checksum = 0;
2525 } /* punchChecksum() */
2526
2527
2528 /******************************************************************************/
2529 /* */
2530 /* Function: punchLeader */
2531 /* */
2532 /* Synopsis: Generate 2 feet of leader on object file, as per DEC */
2533 /* documentation. Paper tape has 10 punches per inch. */
2534 /* */
2535 /******************************************************************************/
2536 void punchLeader( WORD16 count )
2537 {
2538 WORD16 ix;
2539
2540 /* If value is zero, set to the default of 2 feet of leader. */
2541 count = ( count == 0 ) ? 240 : count;
2542
2543 if( objectfile != NULL )
2544 {
2545 for( ix = 0; ix < count; ix++ )
2546 {
2547 fputc( 0200, objectfile );
2548 }
2549 }
2550 } /* punchLeader() */
2551
2552
2553 /******************************************************************************/
2554 /* */
2555 /* Function: punchOrigin */
2556 /* */
2557 /* Synopsis: Output an origin to the object file. */
2558 /* */
2559 /******************************************************************************/
2560 void punchOrigin( WORD16 loc )
2561 {
2562 punchObject((( loc >> 6 ) & 0077 ) | 0100 );
2563 punchObject( loc & 0077 );
2564 } /* punchOrigin() */
2565
2566
2567 /******************************************************************************/
2568 /* */
2569 /* Function: punchObject */
2570 /* */
2571 /* Synopsis: Put one character to object file and include it in checksum. */
2572 /* */
2573 /******************************************************************************/
2574 void punchObject( WORD16 val )
2575 {
2576 val &= 0377;
2577 if( objectfile != NULL )
2578 {
2579 fputc( val, objectfile );
2580 }
2581 checksum += val;
2582 binary_data_output = TRUE;
2583 } /* punchObject() */
2584
2585
2586 /******************************************************************************/
2587 /* */
2588 /* Function: punchOutObject */
2589 /* */
2590 /* Synopsis: Output the current line and then then punch value to the */
2591 /* object file. */
2592 /* */
2593 /******************************************************************************/
2594 void punchOutObject( WORD16 loc, WORD16 val )
2595 {
2596 printLine( line, ( field | loc ), val, LINE_LOC_VAL );
2597 punchLocObject( loc, val );
2598 } /* punchOutObject() */
2599
2600 /******************************************************************************/
2601 /* */
2602 /* Function: punchLocObject */
2603 /* */
2604 /* Synopsis: Output the word (with origin if rim format) to the object file.*/
2605 /* */
2606 /******************************************************************************/
2607 void punchLocObject( WORD16 loc, WORD16 val )
2608 {
2609 if( rim_mode )
2610 {
2611 punchOrigin( loc );
2612 }
2613 punchObject(( val >> 6 ) & 0077 );
2614 punchObject( val & 0077 );
2615 } /* punchLocObject() */
2616
2617
2618 /******************************************************************************/
2619 /* */
2620 /* Function: punchLiteralPool */
2621 /* */
2622 /* Synopsis: Output the current page data. */
2623 /* */
2624 /******************************************************************************/
2625 void punchLiteralPool( LPOOL_T *p, WORD16 lpool_page )
2626 {
2627 WORD16 loc;
2628 WORD16 tmplc;
2629
2630 lpool_page &= 07600;
2631
2632 if( p->loc < 00200 )
2633 {
2634 if( !rim_mode )
2635 {
2636 /* Put out origin if not in rim mode. */
2637 punchOrigin( p->loc | lpool_page );
2638 }
2639 /* Put the literals in the object file. */
2640 for( loc = p->loc; loc < 00200; loc++ )
2641 {
2642 tmplc = loc + lpool_page;
2643 printLine( line, (field | tmplc), p->pool[loc], LOC_VAL );
2644 punchLocObject( tmplc, p->pool[loc] );
2645 }
2646 p->error = FALSE;
2647 p->loc = 00200;
2648 }
2649 } /* punchLiteralPool() */
2650
2651
2652 /******************************************************************************/
2653 /* */
2654 /* Function: insertLiteral */
2655 /* */
2656 /* Synopsis: Add a value to the given literal pool if not already in pool. */
2657 /* Return the location of the value in the pool. */
2658 /* */
2659 /******************************************************************************/
2660 WORD16 insertLiteral( LPOOL_T *pool, WORD16 value )
2661 {
2662 WORD16 ix;
2663 LPOOL_T *p;
2664
2665 p = pool;
2666
2667 /* If page zero is the current page, make sure that literals are inserted */
2668 /* in the page zero literal table. */
2669 if(( clc & 07600 ) == 0 )
2670 {
2671 p = &pz;
2672 }
2673
2674 /* Search the literal pool for any occurence of the needed value. */
2675 ix = PAGE_SIZE - 1;
2676 while( ix >= p->loc && p->pool[ix] != value )
2677 {
2678 ix--;
2679 }
2680
2681 /* Check if value found in literal pool. If not, then insert value. */
2682 if( ix < p->loc )
2683 {
2684 (p->loc)--;
2685 p->pool[p->loc] = value;
2686 ix = p->loc;
2687 }
2688 return( ix );
2689 } /* insertLiteral() */
2690
2691
2692 /******************************************************************************/
2693 /* */
2694 /* Function: printSymbolTable */
2695 /* */
2696 /* Synopsis: Output the symbol table. */
2697 /* */
2698 /******************************************************************************/
2699 void printSymbolTable()
2700 {
2701 int col;
2702 int cx;
2703 char *fmt;
2704 int ix;
2705 char mark;
2706 int page;
2707 int row;
2708 int symbol_base;
2709 int symbol_lines;
2710
2711 symbol_base = number_of_fixed_symbols;
2712
2713 for( page=0, list_lineno=0, col=0, ix=symbol_base; ix < symbol_top; page++ )
2714 {
2715 topOfForm( list_title, s_symtable );
2716 symbol_lines = LIST_LINES_PER_PAGE - page_lineno;
2717
2718 for( row = 0; page_lineno < LIST_LINES_PER_PAGE && ix < symbol_top; row++)
2719 {
2720 list_lineno++;
2721 page_lineno++;
2722 fprintf( listfile, "%5d", list_lineno );
2723
2724 for( col = 0; col < SYMBOL_COLUMNS && ix < symbol_top; col++ )
2725 {
2726 /* Get index of symbol for the current line and column */
2727 cx = symbol_lines * ( SYMBOL_COLUMNS * page + col ) + row;
2728 cx += symbol_base;
2729
2730 /* Make sure that there is a symbol to be printed. */
2731 if( number_of_fixed_symbols <= cx && cx < symbol_top )
2732 {
2733 switch( symtab[cx].type & LABEL )
2734 {
2735 case LABEL:
2736 fmt = " %c%-6.6s %5.5o ";
2737 break;
2738
2739 default:
2740 fmt = " %c%-6.6s %4.4o ";
2741 break;
2742 }
2743
2744 switch( symtab[cx].type & ( DEFINED | REDEFINED ))
2745 {
2746 case UNDEFINED:
2747 mark = '?';
2748 break;
2749
2750 case REDEFINED:
2751 mark = '#';
2752 break;
2753
2754 default:
2755 mark = ' ';
2756 break;
2757 }
2758 fprintf( listfile, fmt, mark, symtab[cx].name, symtab[cx].val );
2759 ix++;
2760 }
2761 }
2762 fprintf( listfile, "\n" );
2763 }
2764 }
2765 } /* printSymbolTable() */
2766
2767
2768 /******************************************************************************/
2769 /* */
2770 /* Function: printPermanentSymbolTable */
2771 /* */
2772 /* Synopsis: Output the permanent symbol table to a file suitable for */
2773 /* being input after the EXPUNGE pseudo-op. */
2774 /* */
2775 /******************************************************************************/
2776 void printPermanentSymbolTable()
2777 {
2778 int ix;
2779 FILE *permfile;
2780 char *s_type;
2781
2782 if(( permfile = fopen( permpathname, "w" )) == NULL )
2783 {
2784 exit( 2 );
2785 }
2786
2787 fprintf( permfile, "/ PERMANENT SYMBOL TABLE\n/\n" );
2788 fprintf( permfile, " EXPUNGE\n/\n" );
2789 /* Print the memory reference instructions first. */
2790 s_type = "FIXMRI";
2791 for( ix = 0; ix < symbol_top; ix++ )
2792 {
2793 if( M_MRI( symtab[ix].type ))
2794 {
2795 fprintf( permfile, "%-7s %s=%4.4o\n",
2796 s_type, symtab[ix].name, symtab[ix].val );
2797 }
2798 }
2799
2800 s_type = " ";
2801 for( ix = 0; ix < symbol_top; ix++ )
2802 {
2803 if( M_FIXED( symtab[ix].type ))
2804 {
2805 if( !M_MRI( symtab[ix].type ) && !M_PSEUDO( symtab[ix].type ))
2806 {
2807 fprintf( permfile, "%-7s %s=%4.4o\n",
2808 s_type, symtab[ix].name, symtab[ix].val );
2809 }
2810 }
2811 }
2812 fprintf( permfile, "/\n FIXTAB\n" );
2813 fclose( permfile );
2814 } /* printPermanentSymbolTable() */
2815
2816
2817 /******************************************************************************/
2818 /* */
2819 /* Function: printCrossReference */
2820 /* */
2821 /* Synopsis: Output a cross reference (concordance) for the file being */
2822 /* assembled. */
2823 /* */
2824 /******************************************************************************/
2825 void printCrossReference()
2826 {
2827 int ix;
2828 int symbol_base;
2829 int xc;
2830 int xc_index;
2831 int xc_refcount;
2832 int xc_cols;
2833
2834 /* Force top of form for first page. */
2835 page_lineno = LIST_LINES_PER_PAGE;
2836
2837 list_lineno = 0;
2838 symbol_base = number_of_fixed_symbols;
2839
2840 for( ix = symbol_base; ix < symbol_top; ix++ )
2841 {
2842 list_lineno++;
2843 page_lineno++;
2844 if( page_lineno >= LIST_LINES_PER_PAGE )
2845 {
2846 topOfForm( list_title, s_xref );
2847 }
2848
2849 fprintf( listfile, "%5d", list_lineno );
2850
2851 /* Get reference count & index into concordance table for this symbol. */
2852 xc_refcount = symtab[ix].xref_count;
2853 xc_index = symtab[ix].xref_index;
2854 /* Determine how to label symbol on concordance. */
2855 switch( symtab[ix].type & ( DEFINED | REDEFINED ))
2856 {
2857 case UNDEFINED:
2858 fprintf( listfile, " U ");
2859 break;
2860
2861 case REDEFINED:
2862 fprintf( listfile, " M %5d ", xreftab[xc_index] );
2863 break;
2864
2865 default:
2866 fprintf( listfile, " A %5d ", xreftab[xc_index] );
2867 break;
2868 }
2869 fprintf( listfile, "%-6.6s ", symtab[ix].name );
2870
2871 /* Output the references, 8 numbers per line after symbol name. */
2872 for( xc_cols = 0, xc = 1; xc < xc_refcount + 1; xc++, xc_cols++ )
2873 {
2874 if( xc_cols >= XREF_COLUMNS )
2875 {
2876 xc_cols = 0;
2877 page_lineno++;
2878 if( page_lineno >= LIST_LINES_PER_PAGE )
2879 {
2880 topOfForm( list_title, s_xref);
2881 }
2882 list_lineno++;
2883 fprintf( listfile, "\n%5d%-19s", list_lineno, " " );
2884 }
2885 fprintf( listfile, " %5d", xreftab[xc_index + xc] );
2886 }
2887 fprintf( listfile, "\n" );
2888 }
2889 } /* printCrossReference() */
2890
2891
2892 /******************************************************************************/
2893 /* */
2894 /* Function: topOfForm */
2895 /* */
2896 /* Synopsis: Prints title and sub-title on top of next page of listing. */
2897 /* */
2898 /******************************************************************************/
2899 void topOfForm( char *title, char *sub_title )
2900 {
2901 char temp[10];
2902
2903 list_pageno++;
2904 strcpy( temp, s_page );
2905 sprintf( temp, "%s %d", s_page, list_pageno );
2906
2907 /* Output a top of form if not the first page of the listing. */
2908 if( list_pageno > 1 )
2909 {
2910 fprintf( listfile, "\f" );
2911 }
2912 fprintf( listfile, "\n\n\n %-63s %10s\n", title, temp );
2913
2914 /* Reset the current page line counter. */
2915 page_lineno = 3;
2916 if( sub_title != NULL )
2917 {
2918 fprintf( listfile, "%80s\n", sub_title );
2919 page_lineno++;
2920 }
2921 else
2922 {
2923 fprintf( listfile, "\n" );
2924 page_lineno++;
2925 }
2926 fprintf( listfile, "\n" );
2927 page_lineno++;
2928 } /* topOfForm() */
2929
2930
2931 /******************************************************************************/
2932 /* */
2933 /* Function: lexemeToName */
2934 /* */
2935 /* Synopsis: Convert the current lexeme into a string. */
2936 /* */
2937 /******************************************************************************/
2938 char *lexemeToName( char *name, WORD16 from, WORD16 term )
2939 {
2940 WORD16 to;
2941
2942 to = 0;
2943
2944 while( from < term && to < ( SYMLEN - 1 ))
2945 {
2946 name[to++] = toupper( line[from++] );
2947 }
2948
2949 while( to < SYMLEN )
2950 {
2951 name[to++] = '\0';
2952 }
2953 return( name );
2954 } /* lexemeToName() */
2955
2956 /******************************************************************************/
2957 /* */
2958 /* Function: defineLexeme */
2959 /* */
2960 /* Synopsis: Put lexeme into symbol table with a value. */
2961 /* */
2962 /******************************************************************************/
2963 SYM_T *defineLexeme( WORD16 start, /* start of lexeme being defined. */
2964 WORD16 term, /* end+1 of lexeme being defined. */
2965 WORD16 val, /* value of lexeme being defined. */
2966 SYMTYP type ) /* how symbol is being defined. */
2967 {
2968 char name[SYMLEN];
2969
2970 lexemeToName( name, start, term);
2971 return( defineSymbol( name, val, type, start ));
2972 } /* defineLexeme() */
2973
2974
2975 /******************************************************************************/
2976 /* */
2977 /* Function: defineSymbol */
2978 /* */
2979 /* Synopsis: Define a symbol in the symbol table, enter symbol name if not */
2980 /* not already in table. */
2981 /* */
2982 /******************************************************************************/
2983 SYM_T *defineSymbol( char *name, WORD16 val, SYMTYP type, WORD16 start )
2984 {
2985 SYM_T *sym;
2986 WORD16 xref_count;
2987
2988 if( strlen( name ) < 1 )
2989 {
2990 return( &sym_undefined ); /* Protect against non-existent names. */
2991 }
2992 sym = lookup( name );
2993 if( M_FIXED( sym->type ))
2994 {
2995 return( sym ); /* Can't modify permanent symbols. */
2996 }
2997
2998 xref_count = 0; /* Set concordance for normal defintion. */
2999
3000 if( M_DEFINED( sym->type ))
3001 {
3002 if( pass == 2 && sym->val != val )
3003 {
3004 /* Generate diagnostic if redefining a symbol. */
3005 if( M_REDEFINED( sym->type ))
3006 {
3007 errorSymbol( &redefined_symbol, sym->name, start );
3008 }
3009 type = type | REDEFINED;
3010 sym->xref_count++; /* Referenced suymbol, count it. */
3011 xref_count = sym->xref_count;
3012 }
3013 }
3014
3015 if( pass == 2 && xref )
3016 {
3017 /* Put the definition line number in the concordance table. */
3018 /* Defined symbols are not counted as references. */
3019 xreftab[sym->xref_index] = lineno;
3020 /* Put the line number in the concordance table. */
3021 xreftab[sym->xref_index + xref_count] = lineno;
3022 }
3023
3024 /* Now set the value and the type. */
3025 sym->val = ( type == LABEL) ? val : val & 07777;
3026 sym->type = ( pass == 1 ) ? ( type | CONDITION ) : type;
3027 return( sym );
3028 } /* defineSymbol() */
3029
3030
3031 /******************************************************************************/
3032 /* */
3033 /* Function: lookup */
3034 /* */
3035 /* Synopsis: Find a symbol in table. If not in table, enter symbol in */
3036 /* table as undefined. Return address of symbol in table. */
3037 /* */
3038 /******************************************************************************/
3039 SYM_T *lookup( char *name )
3040 {
3041 int ix; /* Insertion index */
3042 int lx; /* Left index */
3043 int rx; /* Right index */
3044
3045 /* First search the permanent symbols. */
3046 lx = 0;
3047 ix = binarySearch( name, lx, number_of_fixed_symbols );
3048
3049 /* If symbol not in permanent symbol table. */
3050 if( ix < 0 )
3051 {
3052 /* Now try the user symbol table. */
3053 ix = binarySearch( name, number_of_fixed_symbols, symbol_top );
3054
3055 /* If symbol not in user symbol table. */
3056 if( ix < 0 )
3057 {
3058 /* Must put symbol in table if index is negative. */
3059 ix = ~ix;
3060 if( symbol_top + 1 >= SYMBOL_TABLE_SIZE )
3061 {
3062 errorSymbol( &symbol_table_full, name, lexstart );
3063 exit( 1 );
3064 }
3065
3066 for( rx = symbol_top; rx >= ix; rx-- )
3067 {
3068 symtab[rx + 1] = symtab[rx];
3069 }
3070 symbol_top++;
3071
3072 /* Enter the symbol as UNDEFINED with a value of zero. */
3073 strcpy( symtab[ix].name, name );
3074 symtab[ix].type = UNDEFINED;
3075 symtab[ix].val = 0;
3076 symtab[ix].xref_count = 0;
3077 if( xref && pass == 2 )
3078 {
3079 xreftab[symtab[ix].xref_index] = 0;
3080 }
3081 }
3082 }
3083
3084 return( &symtab[ix] ); /* Return the location of the symbol. */
3085 } /* lookup() */
3086
3087
3088 /******************************************************************************/
3089 /* */
3090 /* Function: binarySearch */
3091 /* */
3092 /* Synopsis: Searches the symbol table within the limits given. If the */
3093 /* symbol is not in the table, it returns the insertion point. */
3094 /* */
3095 /******************************************************************************/
3096 int binarySearch( char *name, int start, int symbol_count )
3097 {
3098 int lx; /* Left index */
3099 int mx; /* Middle index */
3100 int rx; /* Right index */
3101 int compare; /* Results of comparison */
3102
3103 lx = start;
3104 rx = symbol_count - 1;
3105 while( lx <= rx )
3106 {
3107 mx = ( lx + rx ) / 2; /* Find center of search area. */
3108
3109 compare = strcmp( name, symtab[mx].name );
3110
3111 if( compare < 0 )
3112 {
3113 rx = mx - 1;
3114 }
3115 else if( compare > 0 )
3116 {
3117 lx = mx + 1;
3118 }
3119 else
3120 {
3121 return( mx ); /* Found a match in symbol table. */
3122 }
3123 } /* end while */
3124 return( ~lx ); /* Return insertion point. */
3125 } /* binarySearch() */
3126
3127
3128 /******************************************************************************/
3129 /* */
3130 /* Function: compareSymbols */
3131 /* */
3132 /* Synopsis: Used to presort the symbol table when starting assembler. */
3133 /* */
3134 /******************************************************************************/
3135 int compareSymbols( const void *a, const void *b )
3136 {
3137 return( strcmp( ((SYM_T *) a)->name, ((SYM_T *) b)->name ));
3138 } /* compareSymbols() */
3139
3140
3141 /******************************************************************************/
3142 /* */
3143 /* Function: evalSymbol */
3144 /* */
3145 /* Synopsis: Get the pointer for the symbol table entry if exists. */
3146 /* If symbol doesn't exist, return a pointer to the undefined sym */
3147 /* */
3148 /******************************************************************************/
3149 SYM_T *evalSymbol()
3150 {
3151 char name[SYMLEN];
3152 SYM_T *sym;
3153
3154 sym = lookup( lexemeToName( name, lexstart, lexterm ));
3155
3156 sym->xref_count++; /* Count the number of references to symbol. */
3157
3158 if( xref && pass == 2 )
3159 {
3160 /* Put the line number in the concordance table. */
3161 xreftab[sym->xref_index + sym->xref_count] = lineno;
3162 }
3163
3164 return( sym );
3165 } /* evalSymbol() */
3166
3167
3168 /******************************************************************************/
3169 /* */
3170 /* Function: moveToEndOfLine */
3171 /* */
3172 /* Synopsis: Move the parser input to the end of the current input line. */
3173 /* */
3174 /******************************************************************************/
3175 void moveToEndOfLine()
3176 {
3177 while( !isend( line[cc] )) cc++;
3178 lexstart = cc;
3179 lexterm = cc;
3180 lexstartprev = lexstart;
3181 } /* moveToEndOfLine() */
3182
3183 /******************************************************************************/
3184 /* */
3185 /* Function: nextLexeme */
3186 /* */
3187 /* Synopsis: Get the next lexical element from input line. */
3188 /* */
3189 /******************************************************************************/
3190 void nextLexeme()
3191 {
3192 /* Save start column of previous lexeme for diagnostic messages. */
3193 lexstartprev = lexstart;
3194 lextermprev = lexterm;
3195
3196 while( is_blank( line[cc] )) { cc++; }
3197 lexstart = cc;
3198
3199 if( isalnum( line[cc] ))
3200 {
3201 while( isalnum( line[cc] )) { cc++; }
3202 }
3203 else if( isend( line[cc] ))
3204 {
3205 /* End-of-Line, don't advance cc! */
3206 }
3207 else
3208 {
3209 switch( line[cc] )
3210 {
3211 case '"': /* Quoted letter */
3212 if( cc + 2 < maxcc )
3213 {
3214 cc++;
3215 cc++;
3216 }
3217 else
3218 {
3219 errorMessage( &no_literal_value, lexstart );
3220 cc++;
3221 }
3222 break;
3223
3224 case '/': /* Comment, don't advance cc! */
3225 break;
3226
3227 default: /* All other punctuation. */
3228 cc++;
3229 break;
3230 }
3231 }
3232 lexterm = cc;
3233 } /* nextLexeme() */
3234
3235
3236 /******************************************************************************/
3237 /* */
3238 /* Function: nextLexBlank */
3239 /* */
3240 /* Synopsis: Used to prevent illegal blanks in expressions. */
3241 /* */
3242 /******************************************************************************/
3243 void nextLexBlank()
3244 {
3245 nextLexeme();
3246 if( is_blank( delimiter ))
3247 {
3248 errorMessage( &illegal_blank, lexstart - 1 );
3249 }
3250 delimiter = line[lexterm];
3251 } /* nextLexBlank() */
3252
3253
3254
3255 /******************************************************************************/
3256 /* */
3257 /* Function: pseudoOperators */
3258 /* */
3259 /* Synopsis: Process pseudo-ops (directives). */
3260 /* */
3261 /******************************************************************************/
3262 BOOL pseudoOperators( PSEUDO_T val )
3263 {
3264 int count;
3265 int delim;
3266 int index;
3267 int ix;
3268 int lexstartsave;
3269 WORD16 newfield;
3270 WORD16 oldclc;
3271 int pack;
3272 BOOL status;
3273 SYM_T *sym;
3274 FILE *temp;
3275 int term;
3276 WORD16 value;
3277
3278 status = TRUE;
3279 switch( (PSEUDO_T) val )
3280 {
3281 case BANK:
3282 errorSymbol( &no_pseudo_op, "BANK", lexstartprev );
3283 /* should select a different 32K out of 128K */
3284 break;
3285
3286 case BINPUNCH:
3287 /* If there has been data output and this is a mode switch, set up to */
3288 /* output data in BIN mode. */
3289 if( binary_data_output && rim_mode )
3290 {
3291 cp.loc = 00200; /* Clear the literal tables. */
3292 cp.error = FALSE;
3293 pz.loc = 00200;
3294 pz.error = FALSE;
3295 punchLeader( 8 ); /* Generate a short leader/trailer. */
3296 checksum = 0;
3297 binary_data_output = FALSE;
3298 }
3299 rim_mode = FALSE;
3300 break;
3301
3302 case DECIMAL:
3303 radix = 10;
3304 break;
3305
3306 case DUBL:
3307 inputDubl();
3308 break;
3309
3310 case EJECT:
3311 page_lineno = LIST_LINES_PER_PAGE; /* This will force a page break. */
3312 status = FALSE; /* This will force reading of next line */
3313 break;
3314
3315 case ENPUNCH:
3316 if( pass == 2 )
3317 {
3318 objectfile = objectsave;
3319 }
3320 break;
3321
3322 case EXPUNGE: /* Erase symbol table */
3323 if( pass == 1 )
3324 {
3325 symtab[0] = sym_undefined;
3326 symbol_top = 0;
3327 number_of_fixed_symbols = symbol_top;
3328 fixed_symbols = &symtab[symbol_top - 1];
3329
3330 /* Enter the pseudo-ops into the symbol table. */
3331 for( ix = 0; ix < DIM( pseudo ); ix++ )
3332 {
3333 defineSymbol( pseudo[ix].name, pseudo[ix].val, pseudo[ix].type, 0 );
3334 }
3335 number_of_fixed_symbols = symbol_top;
3336 fixed_symbols = &symtab[symbol_top - 1];
3337 }
3338 break;
3339
3340 case FIELD:
3341 punchLiteralPool( &cp, clc - 1 );
3342 punchLiteralPool( &pz, 0 );
3343 newfield = field >> 12;
3344 lexstartsave = lexstartprev;
3345 if( isdone( line[lexstart] ))
3346 {
3347 newfield += 1; /* Blank FIELD directive. */
3348 }
3349 else
3350 {
3351 newfield = (getExpr())->val; /* FIELD with argument. */
3352 }
3353
3354 if( rim_mode )
3355 {
3356 errorMessage( &in_rim_mode, lexstartsave ); /* Can't change fields. */
3357 }
3358 else if( newfield > 7 || newfield < 0 )
3359 {
3360 errorMessage( &illegal_field_value, lexstartprev );
3361 }
3362 else
3363 {
3364 value = (( newfield & 0007 ) << 3 ) | 00300;
3365 punchObject( value );
3366 checksum -= value; /* Field punches are not added to checksum. */
3367 field = newfield << 12;
3368 }
3369
3370 clc = 0200 | field;
3371 fieldlc = clc & 07777;
3372
3373 if( !rim_mode )
3374 {
3375 punchOrigin( clc );
3376 }
3377 break;
3378
3379 case FIXMRI:
3380 if( line[lexterm] == '=' && isalpha( line[lexstart] ))
3381 {
3382 lexstartsave = lexstart;
3383 term = lexterm;
3384 nextLexeme(); /* Skip symbol. */
3385 nextLexeme(); /* Skip trailing = */
3386 defineLexeme( lexstartsave, term, getExprs(), MRI );
3387 }
3388 else
3389 {
3390 errorLexeme( &symbol_syntax, lexstart );
3391 nextLexeme(); /* Skip symbol. */
3392 nextLexeme(); /* Skip trailing = */
3393 (void) getExprs(); /* Skip expression. */
3394 }
3395 break;
3396
3397 case FIXTAB:
3398 /* Mark all current symbols as permanent symbols. */
3399 for( ix = 0; ix < symbol_top; ix++ )
3400 {
3401 symtab[ix].type = symtab[ix].type | FIXED;
3402 }
3403 number_of_fixed_symbols = symbol_top;
3404 fixed_symbols = &symtab[symbol_top - 1];
3405
3406 /* Re-sort the symbol table */
3407 qsort( symtab, symbol_top, sizeof(symtab[0]), compareSymbols );
3408 break;
3409
3410 case FLTG:
3411 inputFltg();
3412 /* errorSymbol( &no_pseudo_op, "FLTG", lexstartprev ); */
3413 break;
3414
3415 case IFDEF:
3416 if( isalpha( line[lexstart] ))
3417 {
3418 sym = evalSymbol();
3419 nextLexeme();
3420 if( M_DEFINED_CONDITIONALLY( sym->type ))
3421 {
3422 conditionTrue();
3423 }
3424 else
3425 {
3426 conditionFalse();
3427 }
3428 }
3429 else
3430 {
3431 errorLexeme( &label_syntax, lexstart );
3432 }
3433 break;
3434
3435 case IFNDEF:
3436 if( isalpha( line[lexstart] ))
3437 {
3438 sym = evalSymbol();
3439 nextLexeme();
3440 if( M_DEFINED_CONDITIONALLY( sym->type ))
3441 {
3442 conditionFalse();
3443 }
3444 else
3445 {
3446 conditionTrue();
3447 }
3448 }
3449 else
3450 {
3451 errorLexeme( &label_syntax, lexstart );
3452 }
3453 break;
3454
3455 case IFNZERO:
3456 if( (getExpr())->val == 0 )
3457 {
3458 conditionFalse();
3459 }
3460 else
3461 {
3462 conditionTrue();
3463 }
3464 break;
3465
3466 case IFZERO:
3467 if( (getExpr())->val == 0 )
3468 {
3469 conditionTrue();
3470 }
3471 else
3472 {
3473 conditionFalse();
3474 }
3475 break;
3476
3477 case NOPUNCH:
3478 if( pass == 2 )
3479 {
3480 objectfile = NULL;
3481 }
3482 break;
3483
3484 case OCTAL:
3485 radix = 8;
3486 break;
3487
3488 case PAGE:
3489 punchLiteralPool( &cp, clc - 1 );
3490 oldclc = clc;
3491 if( isdone( line[lexstart] ))
3492 {
3493 clc = ( clc + 0177 ) & 077600; /* No argumnet. */
3494 fieldlc = clc & 07777;
3495 }
3496 else
3497 {
3498 value = (getExpr())->val;
3499 clc = ( field << 12 ) + (( value & 037 ) << 7 );
3500 fieldlc = clc & 07777;
3501 }
3502 testForLiteralCollision( clc );
3503
3504 if( !rim_mode && clc != oldclc )
3505 {
3506 punchOrigin( clc );
3507 }
3508 break;
3509
3510 case PAUSE:
3511 break;
3512
3513 case RELOC:
3514 if( isdone( line[lexstart] ))
3515 {
3516 reloc = 0; /* Blank RELOC directive. */
3517 }
3518 else
3519 {
3520 value = (getExpr())->val; /* RELOC with argument. */
3521 reloc = value - ( clc + reloc );
3522 }
3523 break;
3524
3525 case RIMPUNCH:
3526 /* If the assembler has output any BIN data, output the literal tables */
3527 /* and the checksum for what has been assembled and setup for RIM mode. */
3528 if( binary_data_output && !rim_mode )
3529 {
3530 endOfBinary();
3531 punchChecksum();
3532 punchLeader( 8 ); /* Generate a short leader/trailer. */
3533 }
3534 rim_mode = TRUE;
3535 break;
3536
3537 case SEGMNT:
3538 punchLiteralPool( &cp, clc - 1 );
3539 if( isdone( line[lexstart] ))
3540 { /* No argument. */
3541 clc = ( clc & 06000 ) + 02000;
3542 fieldlc = clc & 07777;
3543 }
3544 else
3545 {
3546 getExpr();
3547 clc = ( val & 003 ) << 10;
3548 fieldlc = clc & 07777;
3549 }
3550 if( !rim_mode )
3551 {
3552 punchOrigin( clc );
3553 }
3554 testForLiteralCollision( clc );
3555 break;
3556
3557 case TEXT:
3558 delim = line[lexstart];
3559 pack = 0;
3560 count = 0;
3561 index = lexstart + 1;
3562 while( line[index] != delim && !isend( line[index] ))
3563 {
3564 pack = ( pack << 6 ) | ( line[index] & 077 );
3565 count++;
3566 if( count > 1 )
3567 {
3568 punchOutObject( clc, pack );
3569 incrementClc();
3570 count = 0;
3571 pack = 0;
3572 }
3573 index++;
3574 }
3575
3576 if( count != 0 )
3577 {
3578 punchOutObject( clc, pack << 6 );
3579 incrementClc();
3580 }
3581 else
3582 {
3583 punchOutObject( clc, 0 );
3584 incrementClc();
3585 }
3586
3587 if( isend( line[index] ))
3588 {
3589 cc = index;
3590 lexterm = cc;
3591 errorMessage( &text_string, cc );
3592 }
3593 else
3594 {
3595 cc = index + 1;
3596 lexterm = cc;
3597 }
3598 nextLexeme();
3599 break;
3600
3601 case TITLE:
3602 delim = line[lexstart];
3603 ix = lexstart + 1;
3604 /* Find string delimiter. */
3605 do
3606 {
3607 if( list_title[ix] == delim && list_title[ix + 1] == delim )
3608 {
3609 ix++;
3610 }
3611 ix++;
3612 } while( line[ix] != delim && !isend(line[ix]) );
3613
3614 if( !isend( line[ix] ) )
3615 {
3616 count = 0;
3617 ix = lexstart + 1;
3618 do
3619 {
3620 if( list_title[ix] == delim && list_title[ix + 1] == delim )
3621 {
3622 ix++;
3623 }
3624 list_title[count] = line[ix];
3625 count++;
3626 ix++;
3627 } while( line[ix] != delim && !isend(line[ix]) );
3628
3629 if( strlen( list_title ) > TITLELEN )
3630 {
3631 list_title[TITLELEN] = '\0';
3632 }
3633
3634 cc = ix + 1;
3635 lexterm = cc;
3636 page_lineno = LIST_LINES_PER_PAGE;/* Force top of page for new titles. */
3637 list_title_set = TRUE;
3638 }
3639 else
3640 {
3641 cc = ix;
3642 lexterm = cc;
3643 errorMessage( &text_string, cc );
3644 }
3645
3646 nextLexeme();
3647 break;
3648
3649 case XLIST:
3650 if( isdone( line[lexstart] ))
3651 {
3652 temp = listfile; /* Blank XLIST directive. */
3653 listfile = listsave;
3654 listsave = temp;
3655 }
3656 else
3657 {
3658 if( (getExpr())->val == 0 )
3659 {
3660 if( listfile == NULL )
3661 {
3662 listfile = listsave;
3663 listsave = NULL;
3664 }
3665 }
3666 else
3667 {
3668 if( listfile != NULL )
3669 {
3670 listsave = listfile;
3671 listfile = NULL;
3672 }
3673 }
3674 }
3675 break;
3676
3677 case ZBLOCK:
3678 value = (getExpr())->val;
3679 if( value < 0 )
3680 {
3681 errorMessage( &zblock_too_small, lexstartprev );
3682 }
3683 else if( value + ( clc & 07777 ) - 1 > 07777 )
3684 {
3685 errorMessage( &zblock_too_large, lexstartprev );
3686 }
3687 else
3688 {
3689 for( ; value > 0; value-- )
3690 {
3691 punchOutObject( clc, 0 );
3692 incrementClc();
3693 }
3694 }
3695
3696 break;
3697
3698 default:
3699 break;
3700 } /* end switch for pseudo-ops */
3701 return( status );
3702 } /* pseudoOperators() */
3703
3704
3705 /******************************************************************************/
3706 /* */
3707 /* Function: conditionFalse */
3708 /* */
3709 /* Synopsis: Called when a false conditional has been evaluated. */
3710 /* Lex should be the opening <; ignore all text until */
3711 /* the closing >. */
3712 /* */
3713 /******************************************************************************/
3714 void conditionFalse()
3715 {
3716 int level;
3717
3718 if( line[lexstart] == '<' )
3719 {
3720 /* Invariant: line[cc] is the next unexamined character. */
3721 level = 1;
3722 while( level > 0 )
3723 {
3724 if( isend( line[cc] ))
3725 {
3726 readLine();
3727 }
3728 else
3729 {
3730 switch( line[cc] )
3731 {
3732 case '>':
3733 level--;
3734 cc++;
3735 break;
3736
3737 case '<':
3738 level++;
3739 cc++;
3740 break;
3741
3742 case '$':
3743 level = 0;
3744 cc++;
3745 break;
3746
3747 default:
3748 cc++;
3749 break;
3750 } /* end switch */
3751 } /* end if */
3752 } /* end while */
3753 nextLexeme();
3754 }
3755 else
3756 {
3757 errorMessage( &lt_expected, lexstart );
3758 }
3759 } /* conditionFalse() */
3760
3761 /******************************************************************************/
3762 /* */
3763 /* Function: conditionTrue */
3764 /* */
3765 /* Synopsis: Called when a true conditional has been evaluated. */
3766 /* Lex should be the opening <; skip it and setup for */
3767 /* normal assembly. */
3768 /* */
3769 /******************************************************************************/
3770 void conditionTrue()
3771 {
3772 if( line[lexstart] == '<' )
3773 {
3774 nextLexeme(); /* Skip the opening '<' */
3775 }
3776 else
3777 {
3778 errorMessage( &lt_expected, lexstart );
3779 }
3780 } /* conditionTrue() */
3781
3782
3783 /******************************************************************************/
3784 /* */
3785 /* Function: errorLexeme */
3786 /* */
3787 /* Synopsis: Display an error message using the current lexical element. */
3788 /* */
3789 /******************************************************************************/
3790 void errorLexeme( EMSG_T *mesg, WORD16 col )
3791 {
3792 char name[SYMLEN];
3793
3794 errorSymbol( mesg, lexemeToName( name, lexstart, lexterm ), col );
3795 } /* errorLexeme() */
3796
3797
3798 /******************************************************************************/
3799 /* */
3800 /* Function: errorSymbol */
3801 /* */
3802 /* Synopsis: Display an error message with a given string. */
3803 /* */
3804 /******************************************************************************/
3805 void errorSymbol( EMSG_T *mesg, char *name, WORD16 col )
3806 {
3807 char linecol[12];
3808 char *s;
3809
3810 if( pass == 2 )
3811 {
3812 s = ( name == NULL ) ? "" : name ;
3813 errors++;
3814 sprintf( linecol, "(%d:%d)", lineno, col + 1 );
3815 fprintf( errorfile, "%s%-9s : error: %s \"%s\" at Loc = %5.5o\n",
3816 filename, linecol, mesg->file, s, clc );
3817 saveError( mesg->list, col );
3818 }
3819 error_in_line = TRUE;
3820 } /* errorSymbol() */
3821
3822
3823 /******************************************************************************/
3824 /* */
3825 /* Function: errorMessage */
3826 /* */
3827 /* Synopsis: Display an error message without a name argument. */
3828 /* */
3829 /******************************************************************************/
3830 void errorMessage( EMSG_T *mesg, WORD16 col )
3831 {
3832 char linecol[12];
3833
3834 if( pass == 2 )
3835 {
3836 errors++;
3837 sprintf( linecol, "(%d:%d)", lineno, col + 1 );
3838 fprintf( errorfile, "%s%-9s : error: %s at Loc = %5.5o\n",
3839 filename, linecol, mesg->file, clc );
3840 saveError( mesg->list, col );
3841 }
3842 error_in_line = TRUE;
3843 } /* errorMessage() */
3844
3845 /******************************************************************************/
3846 /* */
3847 /* Function: saveError */
3848 /* */
3849 /* Synopsis: Save the current error in a list so it may displayed after the */
3850 /* the current line is printed. */
3851 /* */
3852 /******************************************************************************/
3853 void saveError( char *mesg, WORD16 col )
3854 {
3855 if( save_error_count < DIM( error_list ))
3856 {
3857 error_list[save_error_count].mesg = mesg;
3858 error_list[save_error_count].col = col;
3859 save_error_count++;
3860 }
3861 error_in_line = TRUE;
3862
3863 if( listed )
3864 {
3865 printErrorMessages();
3866 }
3867 } /* saveError() */
3868 /* End-of-File */