1 /******************************************************************************/
3 /* Program: PAL (BART version) */
5 /* Author: Gary A. Messenbrink <gary@netcom.com> */
7 /* Purpose: A 2 pass PDP-8 pal-like assembler. */
12 /* pal - a PDP/8 pal-like assembler. */
15 /* pal [ -d -l -p -r -x ] inputfile */
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. */
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 */
43 /* -r Produce output in rim format (default is bin format) */
44 /* -x Generate a cross-reference (concordance) of user symbols. */
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 */
50 /* <filename>(<line>:<col>) : error: <message> at Loc = <loc> */
52 /* An example error message is: */
54 /* bintst.pal(17:9) : error: undefined symbol "UNDEF" at Loc = 07616 */
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: */
61 /* 17 07616 3000 DCA UNDEF */
63 /* 18 07617 1777 TAD I DUMMY */
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: */
68 /* 14 03716 1777@ TAD OFFPAG */
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: */
78 /* Refer to the code for the diagnostic messages generated. */
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. */
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 */
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. */
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. */
107 /* On UNIX type systems, store the the program as the pal command */
108 /* and on PC type systems, store it as pal.exe */
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. */
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> */
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. */
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. */
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 */
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. */
155 /******************************************************************************/
163 #define LIST_LINES_PER_PAGE 55 /* Includes 5 line page header. */
165 #define SYMBOL_COLUMNS 5
167 #define SYMBOL_TABLE_SIZE 1024
169 #define XREF_COLUMNS 8
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
181 #define PAGE_SIZE 00200
183 #define PAGE_FIELD 07600
184 #define PAGE_ZERO_END 00200
186 /* Macro to get the number of elements in an array. */
187 #define DIM(a) (sizeof(a)/sizeof(a[0]))
189 /* Macro to get the address plus one of the end of an array. */
190 #define BEYOND(a) ((a) + DIM(A))
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==';'))
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 */
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))
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))
216 typedef unsigned char BOOL
;
217 typedef unsigned char BYTE
;
218 typedef short int WORD16
;
219 typedef long int WORD32
;
223 #define TRUE (!FALSE)
226 /* Line listing styles. Used to control listing of lines. */
229 LINE
, LINE_VAL
, LINE_LOC_VAL
, LOC_VAL
231 typedef enum linestyle_t LINESTYLE_T
;
234 /* Note that the names that have FIX as the suffix contain the FIXED bit */
235 /* included in the value. */
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. */
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
259 typedef enum symtyp SYMTYP
;
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
,
268 typedef enum pseudo_t PSEUDO_T
;
278 typedef struct sym_t SYM_T
;
282 WORD16 error
; /* True if error message has been printed. */
284 WORD16 pool
[PAGE_SIZE
];
286 typedef struct lpool_t LPOOL_T
;
293 typedef struct emsg_t EMSG_T
;
300 typedef struct errsave_t ERRSAVE_T
;
307 typedef struct fltg_ FLTG_T
;
309 /*----------------------------------------------------------------------------*/
311 /* Function Prototypes */
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
);
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
);
365 /*----------------------------------------------------------------------------*/
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. */
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. */
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
[] =
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 */
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 */
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 */
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 */
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 */
587 { FIXED
, "TTXOF", 06422 }, /* Clock 1 is disabled from causing a */
588 /* program interrupt and clock 1 flag */
590 }; /* End-of-Symbols for Permanent Symbol Table */
592 /* Global variables */
593 SYM_T
*symtab
; /* Symbol Table */
594 int symbol_top
; /* Number of entries in symbol table. */
596 SYM_T
*fixed_symbols
; /* Start of the fixed symbol table entries. */
597 int number_of_fixed_symbols
;
599 /*----------------------------------------------------------------------------*/
601 WORD16
*xreftab
; /* Start of the concordance table. */
603 ERRSAVE_T error_list
[20];
604 int save_error_count
;
606 LPOOL_T pz
; /* Storage for page zero constants. */
607 LPOOL_T cp
; /* Storage for current page constants. */
609 char s_detected
[] = "detected";
610 char s_error
[] = "error";
611 char s_errors
[] = "errors";
613 char s_page
[] = "Page";
614 char s_symtable
[] = "Symbol Table";
615 char s_xref
[] = "Cross Reference";
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" };
676 /*----------------------------------------------------------------------------*/
685 char errorpathname
[NAMELEN
];
686 char filename
[NAMELEN
];
687 char listpathname
[NAMELEN
];
688 char objectpathname
[NAMELEN
];
690 char permpathname
[NAMELEN
];
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. */
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 */
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 */
737 /******************************************************************************/
741 /* Synopsis: Starting point. Controls order of assembly. */
743 /******************************************************************************/
744 int main( int argc
, char *argv
[] )
749 /* Set the default values for global symbols. */
750 binary_data_output
= FALSE
;
753 print_permanent_symbols
= FALSE
;
755 symtab_print
= FALSE
;
759 /* Get the options and pathnames */
760 getArgs( argc
, argv
);
762 /* Setup the error file in case symbol table overflows while installing the */
763 /* permanent symbols. */
764 errorfile
= fopen( errorpathname
, "w" );
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
);
772 fprintf( stderr
, "Could not allocate memory for symbol table.\n");
776 /* Place end marker in symbol table. */
777 symtab
[0] = sym_undefined
;
779 number_of_fixed_symbols
= symbol_top
;
780 fixed_symbols
= &symtab
[symbol_top
- 1];
782 /* Enter the pseudo-ops into the symbol table */
783 for( ix
= 0; ix
< DIM( pseudo
); ix
++ )
785 defineSymbol( pseudo
[ix
].name
, pseudo
[ix
].val
, pseudo
[ix
].type
, 0 );
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
++ )
792 defineSymbol( permanent_symbols
[ix
].name
,
793 permanent_symbols
[ix
].val
,
794 permanent_symbols
[ix
].type
| DEFFIX
, 0 );
797 number_of_fixed_symbols
= symbol_top
;
798 fixed_symbols
= &symtab
[symbol_top
- 1];
800 /* Do pass one of the assembly */
804 errors_pass_1
= errors
;
806 /* Set up for pass two */
808 errorfile
= fopen( errorpathname
, "w" );
809 objectfile
= fopen( objectpathname
, "wb" );
810 objectsave
= objectfile
;
812 listfile
= fopen( listpathname
, "w" );
818 /* Do pass two of the assembly */
820 save_error_count
= 0;
824 /* Get the amount of space that will be required for the concordance. */
825 for( space
= 0, ix
= 0; ix
< symbol_top
; ix
++ )
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. */
832 /* Allocate the necessary space. */
833 xreftab
= (WORD16
*) malloc( sizeof( WORD16
) * space
);
835 /* Clear the cross reference space. */
836 for( ix
= 0; ix
< space
; ix
++ )
844 /* Undo effects of NOPUNCH for any following checksum */
845 objectfile
= objectsave
;
848 /* Works great for trailer. */
851 /* undo effects of XLIST for any following output to listing file. */
852 if( listfile
== NULL
)
857 /* Display value of error counter. */
860 fprintf( listfile
, "\n %s %s %s\n", s_no
, s_detected
, s_errors
);
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
));
877 if( print_permanent_symbols
)
879 printPermanentSymbolTable();
884 printCrossReference();
887 fclose( objectfile
);
890 if( errors
== 0 && errors_pass_1
== 0 )
892 remove( errorpathname
);
895 return( errors
!= 0 );
898 /******************************************************************************/
900 /* Function: getArgs */
902 /* Synopsis: Parse command line, set flags accordingly and setup input and */
905 /******************************************************************************/
906 void getArgs( int argc
, char *argv
[] )
911 /* Set the defaults */
919 for( ix
= 1; ix
< argc
; ix
++ )
921 if( argv
[ix
][0] == '-' )
923 for( jx
= 1; argv
[ix
][jx
] != 0; jx
++ )
925 switch( argv
[ix
][jx
] )
940 print_permanent_symbols
= TRUE
;
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" );
961 if( pathname
!= NULL
)
963 fprintf( stderr
, "%s: too many input files\n", argv
[0] );
966 pathname
= &argv
[ix
][0];
970 if( pathname
== NULL
)
972 fprintf( stderr
, "%s: no input file specified\n", argv
[0] );
976 len
= strlen( pathname
);
977 if( len
> NAMELEN
- 5 )
979 fprintf( stderr
, "%s: pathname \"%s\" too long\n", argv
[0], pathname
);
983 /* Now open the input file. */
984 if(( infile
= fopen( pathname
, "r" )) == NULL
)
986 fprintf( stderr
, "%s: cannot open \"%s\"\n", argv
[0], pathname
);
990 /* Now make the pathnames */
991 /* Find last '.', if it exists. */
993 while( pathname
[jx
] != '.' && pathname
[jx
] != '/'
994 && pathname
[jx
] != '\\' && jx
>= 0 )
999 switch( pathname
[jx
] )
1013 /* Add the pathname extensions. */
1014 strncpy( objectpathname
, pathname
, jx
);
1015 objectpathname
[jx
] = '\0';
1016 strcat( objectpathname
, rim_mode
? ".rim" : ".bin" );
1018 strncpy( listpathname
, pathname
, jx
);
1019 listpathname
[jx
] = '\0';
1020 strcat( listpathname
, ".lst" );
1022 strncpy( errorpathname
, pathname
, jx
);
1023 errorpathname
[jx
] = '\0';
1024 strcat( errorpathname
, ".err" );
1026 strncpy( permpathname
, pathname
, jx
);
1027 permpathname
[jx
] = '\0';
1028 strcat( permpathname
, ".prm" );
1030 /* Extract the filename from the path. */
1031 if( isalpha( pathname
[0] ) && pathname
[1] == ':' && pathname
[2] != '\\' )
1033 pathname
[1] = '\\'; /* MS-DOS style pathname */
1037 while( pathname
[jx
] != '/' && pathname
[jx
] != '\\' && jx
>= 0 )
1041 strcpy( filename
, &pathname
[jx
+ 1] );
1046 /******************************************************************************/
1048 /* Function: onePass */
1050 /* Synopsis: Do one assembly pass. */
1052 /******************************************************************************/
1063 clc
= 0200; /* Default starting address is 200 octal. */
1067 cp
.loc
= 00200; /* Points to end of page for [] operands. */
1068 pz
.loc
= 00200; /* Points to end of page for () operands. */
1075 list_title_set
= FALSE
;
1076 radix
= 8; /* Initial radix is octal (base 8). */
1083 scanning_line
= TRUE
;
1084 while( scanning_line
)
1086 if( isend( line
[lexstart
] ))
1088 scanning_line
= FALSE
;
1092 switch( line
[lexstart
] )
1095 scanning_line
= FALSE
;
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
)
1112 if(( newclc
& 07600 ) != ( clc
& 07600 ))
1114 /* Current page has changed. */
1115 punchLiteralPool( &cp
, clc
- 1 );
1117 clc
= newclc
- reloc
;
1118 fieldlc
= clc
& 07777;
1122 /* Not rim mode, put out origin. */
1125 printLine( line
, 0, fieldlc
, LINE_VAL
);
1130 switch( line
[lexterm
] )
1133 if( isalpha( line
[lexstart
] ))
1135 /* Use lookup so symbol will not be counted as reference. */
1136 sym
= lookup( lexemeToName( name
, lexstart
, lexterm
));
1137 if( M_DEFINED( sym
->type
))
1139 if( sym
->val
!= clc
&& pass
== 2 )
1141 errorSymbol( &duplicate_label
, sym
->name
, lexstart
);
1143 sym
->type
= sym
->type
| DUPLICATE
;
1145 /* Must call define on pass 2 to generate concordance. */
1146 defineLexeme( lexstart
, lexterm
, ( clc
+reloc
), LABEL
);
1150 errorLexeme( &label_syntax
, lexstart
);
1152 nextLexeme(); /* skip label */
1153 nextLexeme(); /* skip comma */
1157 if( isalpha( line
[lexstart
] ))
1161 delimiter
= line
[lexterm
];
1162 nextLexBlank(); /* skip symbol */
1163 nextLexBlank(); /* skip trailing = */
1165 defineLexeme( start
, term
, val
, DEFINED
);
1166 printLine( line
, 0, val
, LINE_VAL
);
1170 errorLexeme( &symbol_syntax
, lexstartprev
);
1171 nextLexeme(); /* skip symbol */
1172 nextLexeme(); /* skip trailing = */
1173 getExprs(); /* skip expression */
1178 if( isalpha( line
[lexstart
] ))
1182 if( M_PSEUDO( sym
->type
))
1184 nextLexeme(); /* Skip symbol */
1185 scanning_line
= pseudoOperators( (PSEUDO_T
)val
& 07777 );
1189 /* Identifier is not a pseudo-op, interpret as load value */
1190 punchOutObject( clc
, getExprs() & 07777 );
1196 /* Identifier is a value, interpret as load value */
1197 punchOutObject( clc
, getExprs() & 07777 );
1205 } /* end while( scanning_line ) */
1206 } /* end while( TRUE ) */
1210 /******************************************************************************/
1212 /* Function: getExprs */
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. */
1218 /******************************************************************************/
1230 value_type
= symv
->type
;
1234 if( isdone( line
[lexstart
] ))
1238 switch( line
[lexstart
] )
1248 /* Interpret space as logical or */
1250 temp
= symt
->val
& 07777;
1251 temp_type
= symt
->type
;
1253 switch( value_type
)
1257 /* Previous symbol was a Memory Reference Instruction. */
1262 /* Current symbol is also a Memory Reference Instruction. */
1263 value
|= temp
; /* Just OR the MRI instructions. */
1267 /* Now have the address part of the MRI instruction. */
1270 value
|= temp
; /* Page zero MRI. */
1272 else if( (( fieldlc
+ reloc
) & 07600 ) <= temp
1273 && temp
<= (( fieldlc
+ reloc
) | 0177 ))
1275 value
|= ( PAGE_BIT
| (temp
& ADDRESS_FIELD
)); /* Current page MRI */
1279 if(( value
& INDIRECT_BIT
) == INDIRECT_BIT
)
1281 /* Already indirect, can't generate */
1282 errorSymbol( &illegal_indirect
, symt
->name
, lexstartprev
);
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
;
1296 errorSymbol( &illegal_reference
, symt
->name
, lexstartprev
);
1297 value
|= ( temp
& 0177 );
1306 value
|= temp
; /* Normal 12 bit value. */
1313 /******************************************************************************/
1315 /* Function: getExpr */
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. */
1321 /******************************************************************************/
1324 delimiter
= line
[lexterm
];
1326 if( line
[lexstart
] == '-' )
1329 sym_getexpr
= *(eval());
1330 sym_getexpr
.val
= ( - sym_getexpr
.val
);
1334 sym_getexpr
= *(eval());
1338 if( is_blank( delimiter
))
1340 return( &sym_getexpr
);
1343 /* Here we assume the current lexeme is the operator separating the */
1344 /* previous operator from the next, if any. */
1347 /* assert line[lexstart] == delimiter */
1348 if( is_blank( delimiter
))
1350 return( &sym_getexpr
);
1353 switch( line
[lexstart
] )
1356 nextLexBlank(); /* skip over the operator */
1357 sym_getexpr
.val
+= (eval())->val
;
1360 case '-': /* subtract */
1361 nextLexBlank(); /* skip over the operator */
1362 sym_getexpr
.val
-= (eval())->val
;
1365 case '^': /* multiply */
1366 nextLexBlank(); /* skip over the operator */
1367 sym_getexpr
.val
*= (eval())->val
;
1370 case '%': /* divide */
1371 nextLexBlank(); /* skip over the operator */
1372 sym_getexpr
.val
/= (eval())->val
;
1376 nextLexBlank(); /* skip over the operator */
1377 sym_getexpr
.val
&= (eval())->val
;
1381 nextLexBlank(); /* skip over the operator */
1382 sym_getexpr
.val
|= (eval())->val
;
1386 if( isend( line
[lexstart
] ))
1388 return( &sym_getexpr
);
1391 switch( line
[lexstart
] )
1401 errorMessage( &illegal_equals
, lexstart
);
1403 sym_getexpr
.val
= 0;
1407 errorMessage( &illegal_expression
, lexstart
);
1409 sym_getexpr
.val
= 0;
1412 return( &sym_getexpr
);
1418 /******************************************************************************/
1420 /* Function: eval */
1422 /* Synopsis: Get the value of the current lexeme, set delimiter and advance.*/
1424 /******************************************************************************/
1435 delimiter
= line
[lexterm
];
1436 if( isalpha( line
[lexstart
] ))
1439 if( M_UNDEFINED( sym
->type
) && pass
== 2 )
1441 errorSymbol( &undefined_symbol
, sym
->name
, lexstart
);
1451 else if( isdigit( line
[lexstart
] ))
1455 while( from
< lexterm
)
1457 if( isdigit( line
[from
] ))
1459 digit
= (WORD16
) line
[from
++] - (WORD16
) '0';
1462 val
= val
* radix
+ digit
;
1466 errorLexeme( &number_not_radix
, from
- 1 );
1473 errorLexeme( ¬_a_number
, lexstart
);
1480 return( &sym_eval
);
1484 switch( line
[lexstart
] )
1486 case '"': /* Character literal */
1487 if( cc
+ 2 < maxcc
)
1489 val
= line
[lexstart
+ 1] | 0200;
1490 delimiter
= line
[lexstart
+ 2];
1495 errorMessage( &no_literal_value
, lexstart
);
1500 case '.': /* Value of Current Location Counter */
1505 case '[': /* Generate literal on page zero. */
1508 errorMessage( &literal_gen_off
, lexstart
);
1510 nextLexBlank(); /* Skip bracket */
1511 val
= (getExpr())->val
& 07777;
1512 if( line
[lexstart
] == ']' )
1514 nextLexBlank(); /* Skip end bracket */
1518 /* errorMessage( "parens", lexstart ); */
1520 sym_eval
.val
= literals_on
? insertLiteral( &pz
, val
) : 0;
1521 return( &sym_eval
);
1523 case '(': /* Generate literal on current page. */
1526 errorMessage( &literal_gen_off
, lexstart
);
1529 nextLexBlank(); /* Skip paren */
1530 val
= getExprs() & 07777;
1532 if( line
[lexstart
] == ')' )
1534 nextLexBlank(); /* Skip end paren */
1538 /* errorMessage( "parens", NULL ); */
1541 loc
= literals_on
? insertLiteral( &cp
, val
) : 0;
1542 sym_eval
.val
= loc
+ (( clc
+ reloc
) & 077600 );
1543 return( &sym_eval
);
1546 switch( line
[lexstart
] )
1549 errorMessage( &illegal_equals
, lexstart
);
1554 errorMessage( &illegal_character
, lexstart
);
1557 val
= 0; /* On error, set value to zero. */
1558 nextLexBlank(); /* Go past illegal character. */
1562 return( &sym_eval
);
1566 /******************************************************************************/
1568 /* Function: inputDubl */
1570 /* Synopsis: Get the value of the current lexeme as a double word. */
1572 /******************************************************************************/
1578 scanning_line
= TRUE
;
1581 while( scanning_line
)
1583 if( isend( line
[lexstart
] ))
1585 scanning_line
= FALSE
;
1589 switch( line
[lexstart
] )
1592 scanning_line
= FALSE
;
1600 delimiter
= line
[lexterm
];
1604 if( isdigit( line
[lexstart
] ) || line
[lexstart
] == '-' )
1606 dublvalue
= getDublExprs();
1607 punchOutObject( clc
, (WORD16
)(( dublvalue
>> 12 ) & 07777 ));
1609 punchOutObject( clc
, (WORD16
)( dublvalue
& 07777 ));
1614 return; /* Non-numeric input, back to assembly. */
1622 return; /* Error occurred, exit DUBL input mode. */
1624 } /* end while( scanning_line ) */
1627 scanning_line
= TRUE
;
1633 /******************************************************************************/
1635 /* Function: getDublExprs */
1637 /* Synopsis: Get a DUBL expression. */
1639 /******************************************************************************/
1640 WORD32
getDublExprs()
1644 dublvalue
= getDublExpr();
1648 if( isdone( line
[lexstart
] ))
1650 return( dublvalue
);
1654 errorMessage( &illegal_expression
, lexstart
- 1 );
1658 } /* getDublExprs() */
1661 /******************************************************************************/
1663 /* Function: getDublExpr */
1665 /* Synopsis: Get the value of the current lexeme as a double word. The */
1666 /* number is always considered to have a decimal radix. */
1668 /******************************************************************************/
1669 WORD32
getDublExpr()
1673 delimiter
= line
[lexterm
];
1674 if( line
[lexstart
] == '-' )
1677 dublvalue
= evalDubl( 0 );
1679 /* Test for any value greater than 23 bits in length. */
1680 if( (unsigned long int)dublvalue
> 040000000L )
1682 errorMessage( &dubl_overflow
, lexstart
);
1685 dublvalue
= -dublvalue
;
1689 dublvalue
= evalDubl( 0 );
1691 /* Test for any value greater than 23 bits in length. */
1692 if( (unsigned long int)dublvalue
> 037777777L )
1694 errorMessage( &dubl_overflow
, lexstart
);
1699 if( is_blank( delimiter
))
1701 return( dublvalue
);
1704 /* Here we assume the current lexeme is the operator separating the */
1705 /* previous operator from the next, if any. */
1708 /* assert line[lexstart] == delimiter */
1709 if( is_blank( delimiter
))
1711 errorMessage( &illegal_expression
, lexstart
);
1714 return( dublvalue
);
1717 switch( line
[lexstart
] )
1720 case '-': /* subtract */
1721 case '^': /* multiply */
1722 case '%': /* divide */
1725 errorMessage( &illegal_expression
, lexstart
);
1731 if( isend( line
[lexstart
] ))
1733 return( dublvalue
);
1736 switch( line
[lexstart
] )
1743 errorMessage( &illegal_expression
, lexstart
);
1748 return( dublvalue
);
1751 } /* getDublExpr() */
1754 /******************************************************************************/
1756 /* Function: evalDubl */
1758 /* Synopsis: Get the value of the current lexeme as a double word. The */
1759 /* number is always considered to have a decimal radix. */
1761 /******************************************************************************/
1762 WORD32
evalDubl( WORD32 initial_value
)
1767 WORD32 olddublvalue
;
1770 delimiter
= line
[lexterm
];
1772 dublvalue
= initial_value
;
1774 while( from
< lexterm
)
1776 if( isdigit( line
[from
] ))
1778 olddublvalue
= dublvalue
;
1779 digit
= (WORD32
)( line
[from
++] - '0' );
1780 dublvalue
= dublvalue
* 10 + digit
;
1781 if( dublvalue
< olddublvalue
)
1788 errorLexeme( ¬_a_number
, from
);
1793 return( dublvalue
);
1797 /******************************************************************************/
1799 /* Function: inputFltg */
1801 /* Synopsis: Get the value of the current lexeme as a Floating Point const. */
1803 /******************************************************************************/
1809 fltg_input
= TRUE
; /* Set lexeme scanner for floating point. */
1810 scanning_line
= TRUE
;
1813 while( scanning_line
)
1815 if( isend( line
[lexstart
] ))
1817 scanning_line
= FALSE
;
1821 switch( line
[lexstart
] )
1824 scanning_line
= FALSE
;
1832 delimiter
= line
[lexterm
];
1836 if( isdigit( line
[lexstart
] ) || line
[lexstart
] == '-' )
1838 fltg
= getFltgExprs();
1839 punchOutObject( clc
, ( fltg
->exponent
& 07777 ));
1841 punchOutObject( clc
, (WORD16
)(( fltg
->mantissa
>> 12 ) & 07777 ));
1843 punchOutObject( clc
, (WORD16
)( fltg
->mantissa
& 07777 ));
1848 fltg_input
= FALSE
; /* Reset lexeme scanner. */
1849 return; /* Non-numeric input, back to assembly. */
1857 fltg_input
= FALSE
; /* Reset lexeme scanner. */
1858 return; /* Error occurred, exit FLTG input mode. */
1860 } /* end while( scanning_line ) */
1863 scanning_line
= TRUE
;
1868 /******************************************************************************/
1870 /* Function: getFltgExprs */
1872 /* Synopsis: Get a FLTG expression. */
1874 /******************************************************************************/
1875 FLTG_T
*getFltgExprs()
1879 fltg
= getFltgExpr();
1883 if( isdone( line
[lexstart
] ))
1889 errorMessage( &illegal_expression
, lexstart
- 1 );
1893 } /* getFltgExprs() */
1896 /******************************************************************************/
1898 /* Function: getFltgExpr */
1900 /* Synopsis: Get the value of the current lexeme as a double word. The */
1901 /* number is always considered to have a decimal radix. */
1903 /******************************************************************************/
1904 FLTG_T
*getFltgExpr()
1908 delimiter
= line
[lexterm
];
1910 /* Test for any value greater than 23 bits in length. */
1911 if( (unsigned long int)fltg
->mantissa
> 077777777L )
1913 errorMessage( &fltg_overflow
, lexstart
);
1916 if( is_blank( delimiter
))
1921 /* Here we assume the current lexeme is the operator separating the */
1922 /* previous operator from the next, if any. */
1925 /* assert line[lexstart] == delimiter */
1926 if( is_blank( delimiter
))
1928 errorMessage( &illegal_expression
, lexstart
);
1934 switch( line
[lexstart
] )
1937 case '-': /* subtract */
1938 case '^': /* multiply */
1939 case '%': /* divide */
1942 errorMessage( &illegal_expression
, lexstart
);
1948 if( isend( line
[lexstart
] ))
1953 switch( line
[lexstart
] )
1960 errorMessage( &illegal_expression
, lexstart
);
1968 } /* getFltgExpr() */
1971 /******************************************************************************/
1973 /* Function: evalFltg */
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. */
1980 /******************************************************************************/
1989 BOOL negate_exponent
;
1993 /* This uses a lexical analyzer to parse the floating point format. */
1994 static BYTE state_table
[][10] =
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. */
2012 delimiter
= line
[lexterm
];
2018 negate_exponent
= FALSE
;
2025 /* Classify character. This is the column index. */
2026 switch( line
[lexstart
] )
2045 if( isdigit( line
[lexstart
] ))
2049 else if( isdone( line
[lexstart
] ))
2060 next_state
= state_table
[current_state
][current_col
];
2062 switch( next_state
)
2067 delimiter
= line
[lexterm
]; /* Move past the + or - character. */
2071 case 3: /* Number (+-ddd) */
2072 input_value
= evalDubl( 0 ); /* Integer part of the number. */
2073 nextLexeme(); /* Move past previous lexeme. */
2077 delimiter
= line
[lexterm
];
2078 nextLexBlank(); /* Move past the . character. */
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. */
2088 case 6: /* E (+-ddd.dddE) */
2089 delimiter
= line
[lexterm
]; /* Move past the E. */
2093 case 7: /* - (+-ddd.dddE-) */
2094 negate_exponent
= TRUE
;
2095 case 8: /* + (+-ddd.dddE+) */
2096 delimiter
= line
[lexterm
]; /* Move past the + or - character. */
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. */
2106 case 10: /* Floating number parsed, convert */
2108 /* Get the exponent for the number as input. */
2109 exponent
-= right_digits
;
2111 /* Remove trailing zeros and adjust the exponent accordingly. */
2112 while(( input_value
% 10 ) == 0 )
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
);
2126 while( exponent
!= 0 )
2130 /* Decimal point is to the left. */
2131 fltg
->mantissa
/= 10;
2132 normalizeFltg( fltg
);
2135 else if( exponent
> 0 )
2137 /* Decimal point is to the right. */
2138 fltg
->mantissa
*= 10;
2139 normalizeFltg( fltg
);
2144 /* Discard the extra precsion used for calculating the number. */
2145 fltg
->mantissa
>>= 3;
2146 fltg
->exponent
-= 3;
2149 fltg
->mantissa
= (- fltg
->mantissa
) & 077777777L;
2153 case 11: /* Error in format. */
2154 /* Not a properly constructued floating point number. */
2159 /* Set state for next pass through the loop. */
2160 current_state
= next_state
;
2166 /******************************************************************************/
2168 /* Function: normalizeFltg */
2170 /* Synopsis: Normalize a PDP-8 double precision floating point number. */
2172 /******************************************************************************/
2173 void normalizeFltg( FLTG_T
*fltg
)
2175 /* Normalize the floating point number. */
2176 if( fltg
->mantissa
!= 0 )
2178 if(( fltg
->mantissa
& ~0x3FFFFFFL
) == 0 )
2180 while(( fltg
->mantissa
& ~0x1FFFFFFL
) == 0 )
2183 fltg
->mantissa
<<= 1;
2189 while(( fltg
->mantissa
& ~0x3FFFFFFL
) != 0 )
2191 fltg
->mantissa
>>= 1;
2204 /******************************************************************************/
2206 /* Function: incrementClc */
2208 /* Synopsis: Set the next assembly location. Test for collision with */
2209 /* the literal tables. */
2211 /******************************************************************************/
2212 WORD16
incrementClc()
2214 testForLiteralCollision( clc
);
2216 /* Incrementing the location counter is not to change field setting. */
2217 clc
= ( clc
& 070000 ) + (( clc
+ 1 ) & 07777 );
2218 fieldlc
= clc
& 07777;
2220 } /* incrementClc() */
2223 /******************************************************************************/
2225 /* Function: testForLiteralCollision */
2227 /* Synopsis: Test the given location for collision with the literal tables. */
2229 /******************************************************************************/
2230 BOOL
testForLiteralCollision( WORD16 loc
)
2233 BOOL result
= FALSE
;
2236 tmppage
= loc
& 07600;
2237 pagelc
= loc
& 00177;
2241 if( pagelc
>= pz
.loc
&& !pz
.error
)
2243 errorMessage( &pz_literal_overflow
, -1 );
2250 if( pagelc
>= cp
.loc
&& !cp
.error
)
2252 errorMessage( &literal_overflow
, -1 );
2258 } /* testForLiteralCollision() */
2261 /******************************************************************************/
2263 /* Function: readLine */
2265 /* Synopsis: Get next line of input. Print previous line if needed. */
2267 /******************************************************************************/
2272 char inpline
[LINELEN
];
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. */
2281 if(( fgets( inpline
, LINELEN
- 1, infile
)) == NULL
)
2286 error_in_line
= TRUE
;
2290 error_in_line
= FALSE
;
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
++ )
2297 switch( inpline
[ix
] )
2305 while(( iy
% 8 ) != 0 );
2309 line
[iy
] = inpline
[ix
];
2316 /* If the line is terminated by CR-LF, remove, the CR. */
2317 if( line
[iy
- 2] == '\r' )
2320 line
[iy
- 1] = line
[iy
- 0];
2323 maxcc
= iy
; /* Save the current line length. */
2327 /******************************************************************************/
2329 /* Function: listLine */
2331 /* Synopsis: Output a line to the listing file. */
2333 /******************************************************************************/
2335 /* generate a line of listing if not already done! */
2337 if( listfile
!= NULL
&& listed
== FALSE
)
2339 printLine( line
, 0, 0, LINE
);
2344 /******************************************************************************/
2346 /* Function: printPageBreak */
2348 /* Synopsis: Output a Top of Form and listing header if new page necessary. */
2350 /******************************************************************************/
2351 void printPageBreak()
2353 if( page_lineno
>= LIST_LINES_PER_PAGE
)
2354 /* ( list_lineno % LIST_LINES_PER_PAGE ) == 0 ) */
2356 if( !list_title_set
)
2358 strcpy( list_title
, line
);
2359 if( list_title
[strlen(list_title
) - 1] == '\n' )
2361 list_title
[strlen(list_title
) - 1] = '\0';
2363 if( strlen( list_title
) > TITLELEN
)
2365 list_title
[TITLELEN
] = '\0';
2367 list_title_set
= TRUE
;
2369 topOfForm( list_title
, NULL
);
2372 } /* printPageBreak() */
2375 /******************************************************************************/
2377 /* Function: printLine */
2379 /* Synopsis: Output a line to the listing file with new page if necessary. */
2381 /******************************************************************************/
2382 void printLine( char *line
, WORD16 loc
, WORD16 val
, LINESTYLE_T linestyle
)
2384 if( listfile
== NULL
)
2386 save_error_count
= 0;
2398 fprintf(listfile
, "%5d ", lineno
);
2399 fputs( line
, listfile
);
2404 fprintf(listfile
, "%5d %4.4o ", lineno
, val
);
2405 fputs( line
, listfile
);
2412 if( indirect_generated
)
2414 fprintf( listfile
, "%5d %5.5o %4.4o@ ", lineno
, loc
, val
);
2418 fprintf( listfile
, "%5d %5.5o %4.4o ", lineno
, loc
, val
);
2420 fputs( line
, listfile
);
2425 fprintf( listfile
, " %5.5o %4.4o\n", loc
, val
);
2430 fprintf( listfile
, " %5.5o %4.4o\n", loc
, val
);
2433 printErrorMessages();
2437 /******************************************************************************/
2439 /* Function: printErrorMessages */
2441 /* Synopsis: Output any error messages from the current list of errors. */
2443 /******************************************************************************/
2444 void printErrorMessages()
2449 if( listfile
!= NULL
)
2451 /* If any errors, display them now. */
2452 for( iy
= 0; iy
< save_error_count
; iy
++ )
2455 fprintf( listfile
, "%-18.18s", error_list
[iy
].mesg
);
2456 if( error_list
[iy
].col
>= 0 )
2458 for( ix
= 0; ix
< error_list
[iy
].col
; ix
++ )
2460 if( line
[ix
] == '\t' )
2462 putc( '\t', listfile
);
2466 putc( ' ', listfile
);
2469 fputs( "^", listfile
);
2473 fputs( "\n", listfile
);
2476 save_error_count
= 0;
2477 } /* printErrorMessages() */
2480 /******************************************************************************/
2482 /* Function: endOfBinary */
2484 /* Synopsis: Outputs both literal tables at the end of a binary segment. */
2486 /******************************************************************************/
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 );
2496 clc
= ( clc
& 070000 ) + (( clc
- 1 ) & 07777 );
2497 errorMessage( &end_of_file
, -1 );
2498 clc
= ( clc
& 070000 ) + (( clc
+ 1 ) & 07777 );
2502 listLine(); /* List line if not done yet. */
2505 } /* endOfBinary() */
2508 /******************************************************************************/
2510 /* Function: punchChecksum */
2512 /* Synopsis: Output a checksum if the current mode requires it and an */
2513 /* object file exists. */
2515 /******************************************************************************/
2516 void punchChecksum()
2518 /* If the assembler has output any BIN data output the checksum. */
2519 if( binary_data_output
&& !rim_mode
)
2521 punchLocObject( 0, checksum
);
2523 binary_data_output
= FALSE
;
2525 } /* punchChecksum() */
2528 /******************************************************************************/
2530 /* Function: punchLeader */
2532 /* Synopsis: Generate 2 feet of leader on object file, as per DEC */
2533 /* documentation. Paper tape has 10 punches per inch. */
2535 /******************************************************************************/
2536 void punchLeader( WORD16 count
)
2540 /* If value is zero, set to the default of 2 feet of leader. */
2541 count
= ( count
== 0 ) ? 240 : count
;
2543 if( objectfile
!= NULL
)
2545 for( ix
= 0; ix
< count
; ix
++ )
2547 fputc( 0200, objectfile
);
2550 } /* punchLeader() */
2553 /******************************************************************************/
2555 /* Function: punchOrigin */
2557 /* Synopsis: Output an origin to the object file. */
2559 /******************************************************************************/
2560 void punchOrigin( WORD16 loc
)
2562 punchObject((( loc
>> 6 ) & 0077 ) | 0100 );
2563 punchObject( loc
& 0077 );
2564 } /* punchOrigin() */
2567 /******************************************************************************/
2569 /* Function: punchObject */
2571 /* Synopsis: Put one character to object file and include it in checksum. */
2573 /******************************************************************************/
2574 void punchObject( WORD16 val
)
2577 if( objectfile
!= NULL
)
2579 fputc( val
, objectfile
);
2582 binary_data_output
= TRUE
;
2583 } /* punchObject() */
2586 /******************************************************************************/
2588 /* Function: punchOutObject */
2590 /* Synopsis: Output the current line and then then punch value to the */
2593 /******************************************************************************/
2594 void punchOutObject( WORD16 loc
, WORD16 val
)
2596 printLine( line
, ( field
| loc
), val
, LINE_LOC_VAL
);
2597 punchLocObject( loc
, val
);
2598 } /* punchOutObject() */
2600 /******************************************************************************/
2602 /* Function: punchLocObject */
2604 /* Synopsis: Output the word (with origin if rim format) to the object file.*/
2606 /******************************************************************************/
2607 void punchLocObject( WORD16 loc
, WORD16 val
)
2613 punchObject(( val
>> 6 ) & 0077 );
2614 punchObject( val
& 0077 );
2615 } /* punchLocObject() */
2618 /******************************************************************************/
2620 /* Function: punchLiteralPool */
2622 /* Synopsis: Output the current page data. */
2624 /******************************************************************************/
2625 void punchLiteralPool( LPOOL_T
*p
, WORD16 lpool_page
)
2630 lpool_page
&= 07600;
2632 if( p
->loc
< 00200 )
2636 /* Put out origin if not in rim mode. */
2637 punchOrigin( p
->loc
| lpool_page
);
2639 /* Put the literals in the object file. */
2640 for( loc
= p
->loc
; loc
< 00200; loc
++ )
2642 tmplc
= loc
+ lpool_page
;
2643 printLine( line
, (field
| tmplc
), p
->pool
[loc
], LOC_VAL
);
2644 punchLocObject( tmplc
, p
->pool
[loc
] );
2649 } /* punchLiteralPool() */
2652 /******************************************************************************/
2654 /* Function: insertLiteral */
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. */
2659 /******************************************************************************/
2660 WORD16
insertLiteral( LPOOL_T
*pool
, WORD16 value
)
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 )
2674 /* Search the literal pool for any occurence of the needed value. */
2676 while( ix
>= p
->loc
&& p
->pool
[ix
] != value
)
2681 /* Check if value found in literal pool. If not, then insert value. */
2685 p
->pool
[p
->loc
] = value
;
2689 } /* insertLiteral() */
2692 /******************************************************************************/
2694 /* Function: printSymbolTable */
2696 /* Synopsis: Output the symbol table. */
2698 /******************************************************************************/
2699 void printSymbolTable()
2711 symbol_base
= number_of_fixed_symbols
;
2713 for( page
=0, list_lineno
=0, col
=0, ix
=symbol_base
; ix
< symbol_top
; page
++ )
2715 topOfForm( list_title
, s_symtable
);
2716 symbol_lines
= LIST_LINES_PER_PAGE
- page_lineno
;
2718 for( row
= 0; page_lineno
< LIST_LINES_PER_PAGE
&& ix
< symbol_top
; row
++)
2722 fprintf( listfile
, "%5d", list_lineno
);
2724 for( col
= 0; col
< SYMBOL_COLUMNS
&& ix
< symbol_top
; col
++ )
2726 /* Get index of symbol for the current line and column */
2727 cx
= symbol_lines
* ( SYMBOL_COLUMNS
* page
+ col
) + row
;
2730 /* Make sure that there is a symbol to be printed. */
2731 if( number_of_fixed_symbols
<= cx
&& cx
< symbol_top
)
2733 switch( symtab
[cx
].type
& LABEL
)
2736 fmt
= " %c%-6.6s %5.5o ";
2740 fmt
= " %c%-6.6s %4.4o ";
2744 switch( symtab
[cx
].type
& ( DEFINED
| REDEFINED
))
2758 fprintf( listfile
, fmt
, mark
, symtab
[cx
].name
, symtab
[cx
].val
);
2762 fprintf( listfile
, "\n" );
2765 } /* printSymbolTable() */
2768 /******************************************************************************/
2770 /* Function: printPermanentSymbolTable */
2772 /* Synopsis: Output the permanent symbol table to a file suitable for */
2773 /* being input after the EXPUNGE pseudo-op. */
2775 /******************************************************************************/
2776 void printPermanentSymbolTable()
2782 if(( permfile
= fopen( permpathname
, "w" )) == NULL
)
2787 fprintf( permfile
, "/ PERMANENT SYMBOL TABLE\n/\n" );
2788 fprintf( permfile
, " EXPUNGE\n/\n" );
2789 /* Print the memory reference instructions first. */
2791 for( ix
= 0; ix
< symbol_top
; ix
++ )
2793 if( M_MRI( symtab
[ix
].type
))
2795 fprintf( permfile
, "%-7s %s=%4.4o\n",
2796 s_type
, symtab
[ix
].name
, symtab
[ix
].val
);
2801 for( ix
= 0; ix
< symbol_top
; ix
++ )
2803 if( M_FIXED( symtab
[ix
].type
))
2805 if( !M_MRI( symtab
[ix
].type
) && !M_PSEUDO( symtab
[ix
].type
))
2807 fprintf( permfile
, "%-7s %s=%4.4o\n",
2808 s_type
, symtab
[ix
].name
, symtab
[ix
].val
);
2812 fprintf( permfile
, "/\n FIXTAB\n" );
2814 } /* printPermanentSymbolTable() */
2817 /******************************************************************************/
2819 /* Function: printCrossReference */
2821 /* Synopsis: Output a cross reference (concordance) for the file being */
2824 /******************************************************************************/
2825 void printCrossReference()
2834 /* Force top of form for first page. */
2835 page_lineno
= LIST_LINES_PER_PAGE
;
2838 symbol_base
= number_of_fixed_symbols
;
2840 for( ix
= symbol_base
; ix
< symbol_top
; ix
++ )
2844 if( page_lineno
>= LIST_LINES_PER_PAGE
)
2846 topOfForm( list_title
, s_xref
);
2849 fprintf( listfile
, "%5d", list_lineno
);
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
))
2858 fprintf( listfile
, " U ");
2862 fprintf( listfile
, " M %5d ", xreftab
[xc_index
] );
2866 fprintf( listfile
, " A %5d ", xreftab
[xc_index
] );
2869 fprintf( listfile
, "%-6.6s ", symtab
[ix
].name
);
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
++ )
2874 if( xc_cols
>= XREF_COLUMNS
)
2878 if( page_lineno
>= LIST_LINES_PER_PAGE
)
2880 topOfForm( list_title
, s_xref
);
2883 fprintf( listfile
, "\n%5d%-19s", list_lineno
, " " );
2885 fprintf( listfile
, " %5d", xreftab
[xc_index
+ xc
] );
2887 fprintf( listfile
, "\n" );
2889 } /* printCrossReference() */
2892 /******************************************************************************/
2894 /* Function: topOfForm */
2896 /* Synopsis: Prints title and sub-title on top of next page of listing. */
2898 /******************************************************************************/
2899 void topOfForm( char *title
, char *sub_title
)
2904 strcpy( temp
, s_page
);
2905 sprintf( temp
, "%s %d", s_page
, list_pageno
);
2907 /* Output a top of form if not the first page of the listing. */
2908 if( list_pageno
> 1 )
2910 fprintf( listfile
, "\f" );
2912 fprintf( listfile
, "\n\n\n %-63s %10s\n", title
, temp
);
2914 /* Reset the current page line counter. */
2916 if( sub_title
!= NULL
)
2918 fprintf( listfile
, "%80s\n", sub_title
);
2923 fprintf( listfile
, "\n" );
2926 fprintf( listfile
, "\n" );
2931 /******************************************************************************/
2933 /* Function: lexemeToName */
2935 /* Synopsis: Convert the current lexeme into a string. */
2937 /******************************************************************************/
2938 char *lexemeToName( char *name
, WORD16 from
, WORD16 term
)
2944 while( from
< term
&& to
< ( SYMLEN
- 1 ))
2946 name
[to
++] = toupper( line
[from
++] );
2949 while( to
< SYMLEN
)
2954 } /* lexemeToName() */
2956 /******************************************************************************/
2958 /* Function: defineLexeme */
2960 /* Synopsis: Put lexeme into symbol table with a value. */
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. */
2970 lexemeToName( name
, start
, term
);
2971 return( defineSymbol( name
, val
, type
, start
));
2972 } /* defineLexeme() */
2975 /******************************************************************************/
2977 /* Function: defineSymbol */
2979 /* Synopsis: Define a symbol in the symbol table, enter symbol name if not */
2980 /* not already in table. */
2982 /******************************************************************************/
2983 SYM_T
*defineSymbol( char *name
, WORD16 val
, SYMTYP type
, WORD16 start
)
2988 if( strlen( name
) < 1 )
2990 return( &sym_undefined
); /* Protect against non-existent names. */
2992 sym
= lookup( name
);
2993 if( M_FIXED( sym
->type
))
2995 return( sym
); /* Can't modify permanent symbols. */
2998 xref_count
= 0; /* Set concordance for normal defintion. */
3000 if( M_DEFINED( sym
->type
))
3002 if( pass
== 2 && sym
->val
!= val
)
3004 /* Generate diagnostic if redefining a symbol. */
3005 if( M_REDEFINED( sym
->type
))
3007 errorSymbol( &redefined_symbol
, sym
->name
, start
);
3009 type
= type
| REDEFINED
;
3010 sym
->xref_count
++; /* Referenced suymbol, count it. */
3011 xref_count
= sym
->xref_count
;
3015 if( pass
== 2 && xref
)
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
;
3024 /* Now set the value and the type. */
3025 sym
->val
= ( type
== LABEL
) ? val
: val
& 07777;
3026 sym
->type
= ( pass
== 1 ) ? ( type
| CONDITION
) : type
;
3028 } /* defineSymbol() */
3031 /******************************************************************************/
3033 /* Function: lookup */
3035 /* Synopsis: Find a symbol in table. If not in table, enter symbol in */
3036 /* table as undefined. Return address of symbol in table. */
3038 /******************************************************************************/
3039 SYM_T
*lookup( char *name
)
3041 int ix
; /* Insertion index */
3042 int lx
; /* Left index */
3043 int rx
; /* Right index */
3045 /* First search the permanent symbols. */
3047 ix
= binarySearch( name
, lx
, number_of_fixed_symbols
);
3049 /* If symbol not in permanent symbol table. */
3052 /* Now try the user symbol table. */
3053 ix
= binarySearch( name
, number_of_fixed_symbols
, symbol_top
);
3055 /* If symbol not in user symbol table. */
3058 /* Must put symbol in table if index is negative. */
3060 if( symbol_top
+ 1 >= SYMBOL_TABLE_SIZE
)
3062 errorSymbol( &symbol_table_full
, name
, lexstart
);
3066 for( rx
= symbol_top
; rx
>= ix
; rx
-- )
3068 symtab
[rx
+ 1] = symtab
[rx
];
3072 /* Enter the symbol as UNDEFINED with a value of zero. */
3073 strcpy( symtab
[ix
].name
, name
);
3074 symtab
[ix
].type
= UNDEFINED
;
3076 symtab
[ix
].xref_count
= 0;
3077 if( xref
&& pass
== 2 )
3079 xreftab
[symtab
[ix
].xref_index
] = 0;
3084 return( &symtab
[ix
] ); /* Return the location of the symbol. */
3088 /******************************************************************************/
3090 /* Function: binarySearch */
3092 /* Synopsis: Searches the symbol table within the limits given. If the */
3093 /* symbol is not in the table, it returns the insertion point. */
3095 /******************************************************************************/
3096 int binarySearch( char *name
, int start
, int symbol_count
)
3098 int lx
; /* Left index */
3099 int mx
; /* Middle index */
3100 int rx
; /* Right index */
3101 int compare
; /* Results of comparison */
3104 rx
= symbol_count
- 1;
3107 mx
= ( lx
+ rx
) / 2; /* Find center of search area. */
3109 compare
= strcmp( name
, symtab
[mx
].name
);
3115 else if( compare
> 0 )
3121 return( mx
); /* Found a match in symbol table. */
3124 return( ~lx
); /* Return insertion point. */
3125 } /* binarySearch() */
3128 /******************************************************************************/
3130 /* Function: compareSymbols */
3132 /* Synopsis: Used to presort the symbol table when starting assembler. */
3134 /******************************************************************************/
3135 int compareSymbols( const void *a
, const void *b
)
3137 return( strcmp( ((SYM_T
*) a
)->name
, ((SYM_T
*) b
)->name
));
3138 } /* compareSymbols() */
3141 /******************************************************************************/
3143 /* Function: evalSymbol */
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 */
3148 /******************************************************************************/
3154 sym
= lookup( lexemeToName( name
, lexstart
, lexterm
));
3156 sym
->xref_count
++; /* Count the number of references to symbol. */
3158 if( xref
&& pass
== 2 )
3160 /* Put the line number in the concordance table. */
3161 xreftab
[sym
->xref_index
+ sym
->xref_count
] = lineno
;
3165 } /* evalSymbol() */
3168 /******************************************************************************/
3170 /* Function: moveToEndOfLine */
3172 /* Synopsis: Move the parser input to the end of the current input line. */
3174 /******************************************************************************/
3175 void moveToEndOfLine()
3177 while( !isend( line
[cc
] )) cc
++;
3180 lexstartprev
= lexstart
;
3181 } /* moveToEndOfLine() */
3183 /******************************************************************************/
3185 /* Function: nextLexeme */
3187 /* Synopsis: Get the next lexical element from input line. */
3189 /******************************************************************************/
3192 /* Save start column of previous lexeme for diagnostic messages. */
3193 lexstartprev
= lexstart
;
3194 lextermprev
= lexterm
;
3196 while( is_blank( line
[cc
] )) { cc
++; }
3199 if( isalnum( line
[cc
] ))
3201 while( isalnum( line
[cc
] )) { cc
++; }
3203 else if( isend( line
[cc
] ))
3205 /* End-of-Line, don't advance cc! */
3211 case '"': /* Quoted letter */
3212 if( cc
+ 2 < maxcc
)
3219 errorMessage( &no_literal_value
, lexstart
);
3224 case '/': /* Comment, don't advance cc! */
3227 default: /* All other punctuation. */
3233 } /* nextLexeme() */
3236 /******************************************************************************/
3238 /* Function: nextLexBlank */
3240 /* Synopsis: Used to prevent illegal blanks in expressions. */
3242 /******************************************************************************/
3246 if( is_blank( delimiter
))
3248 errorMessage( &illegal_blank
, lexstart
- 1 );
3250 delimiter
= line
[lexterm
];
3251 } /* nextLexBlank() */
3255 /******************************************************************************/
3257 /* Function: pseudoOperators */
3259 /* Synopsis: Process pseudo-ops (directives). */
3261 /******************************************************************************/
3262 BOOL
pseudoOperators( PSEUDO_T val
)
3279 switch( (PSEUDO_T
) val
)
3282 errorSymbol( &no_pseudo_op
, "BANK", lexstartprev
);
3283 /* should select a different 32K out of 128K */
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
)
3291 cp
.loc
= 00200; /* Clear the literal tables. */
3295 punchLeader( 8 ); /* Generate a short leader/trailer. */
3297 binary_data_output
= FALSE
;
3311 page_lineno
= LIST_LINES_PER_PAGE
; /* This will force a page break. */
3312 status
= FALSE
; /* This will force reading of next line */
3318 objectfile
= objectsave
;
3322 case EXPUNGE
: /* Erase symbol table */
3325 symtab
[0] = sym_undefined
;
3327 number_of_fixed_symbols
= symbol_top
;
3328 fixed_symbols
= &symtab
[symbol_top
- 1];
3330 /* Enter the pseudo-ops into the symbol table. */
3331 for( ix
= 0; ix
< DIM( pseudo
); ix
++ )
3333 defineSymbol( pseudo
[ix
].name
, pseudo
[ix
].val
, pseudo
[ix
].type
, 0 );
3335 number_of_fixed_symbols
= symbol_top
;
3336 fixed_symbols
= &symtab
[symbol_top
- 1];
3341 punchLiteralPool( &cp
, clc
- 1 );
3342 punchLiteralPool( &pz
, 0 );
3343 newfield
= field
>> 12;
3344 lexstartsave
= lexstartprev
;
3345 if( isdone( line
[lexstart
] ))
3347 newfield
+= 1; /* Blank FIELD directive. */
3351 newfield
= (getExpr())->val
; /* FIELD with argument. */
3356 errorMessage( &in_rim_mode
, lexstartsave
); /* Can't change fields. */
3358 else if( newfield
> 7 || newfield
< 0 )
3360 errorMessage( &illegal_field_value
, lexstartprev
);
3364 value
= (( newfield
& 0007 ) << 3 ) | 00300;
3365 punchObject( value
);
3366 checksum
-= value
; /* Field punches are not added to checksum. */
3367 field
= newfield
<< 12;
3371 fieldlc
= clc
& 07777;
3380 if( line
[lexterm
] == '=' && isalpha( line
[lexstart
] ))
3382 lexstartsave
= lexstart
;
3384 nextLexeme(); /* Skip symbol. */
3385 nextLexeme(); /* Skip trailing = */
3386 defineLexeme( lexstartsave
, term
, getExprs(), MRI
);
3390 errorLexeme( &symbol_syntax
, lexstart
);
3391 nextLexeme(); /* Skip symbol. */
3392 nextLexeme(); /* Skip trailing = */
3393 (void) getExprs(); /* Skip expression. */
3398 /* Mark all current symbols as permanent symbols. */
3399 for( ix
= 0; ix
< symbol_top
; ix
++ )
3401 symtab
[ix
].type
= symtab
[ix
].type
| FIXED
;
3403 number_of_fixed_symbols
= symbol_top
;
3404 fixed_symbols
= &symtab
[symbol_top
- 1];
3406 /* Re-sort the symbol table */
3407 qsort( symtab
, symbol_top
, sizeof(symtab
[0]), compareSymbols
);
3412 /* errorSymbol( &no_pseudo_op, "FLTG", lexstartprev ); */
3416 if( isalpha( line
[lexstart
] ))
3420 if( M_DEFINED_CONDITIONALLY( sym
->type
))
3431 errorLexeme( &label_syntax
, lexstart
);
3436 if( isalpha( line
[lexstart
] ))
3440 if( M_DEFINED_CONDITIONALLY( sym
->type
))
3451 errorLexeme( &label_syntax
, lexstart
);
3456 if( (getExpr())->val
== 0 )
3467 if( (getExpr())->val
== 0 )
3489 punchLiteralPool( &cp
, clc
- 1 );
3491 if( isdone( line
[lexstart
] ))
3493 clc
= ( clc
+ 0177 ) & 077600; /* No argumnet. */
3494 fieldlc
= clc
& 07777;
3498 value
= (getExpr())->val
;
3499 clc
= ( field
<< 12 ) + (( value
& 037 ) << 7 );
3500 fieldlc
= clc
& 07777;
3502 testForLiteralCollision( clc
);
3504 if( !rim_mode
&& clc
!= oldclc
)
3514 if( isdone( line
[lexstart
] ))
3516 reloc
= 0; /* Blank RELOC directive. */
3520 value
= (getExpr())->val
; /* RELOC with argument. */
3521 reloc
= value
- ( clc
+ reloc
);
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
)
3532 punchLeader( 8 ); /* Generate a short leader/trailer. */
3538 punchLiteralPool( &cp
, clc
- 1 );
3539 if( isdone( line
[lexstart
] ))
3540 { /* No argument. */
3541 clc
= ( clc
& 06000 ) + 02000;
3542 fieldlc
= clc
& 07777;
3547 clc
= ( val
& 003 ) << 10;
3548 fieldlc
= clc
& 07777;
3554 testForLiteralCollision( clc
);
3558 delim
= line
[lexstart
];
3561 index
= lexstart
+ 1;
3562 while( line
[index
] != delim
&& !isend( line
[index
] ))
3564 pack
= ( pack
<< 6 ) | ( line
[index
] & 077 );
3568 punchOutObject( clc
, pack
);
3578 punchOutObject( clc
, pack
<< 6 );
3583 punchOutObject( clc
, 0 );
3587 if( isend( line
[index
] ))
3591 errorMessage( &text_string
, cc
);
3602 delim
= line
[lexstart
];
3604 /* Find string delimiter. */
3607 if( list_title
[ix
] == delim
&& list_title
[ix
+ 1] == delim
)
3612 } while( line
[ix
] != delim
&& !isend(line
[ix
]) );
3614 if( !isend( line
[ix
] ) )
3620 if( list_title
[ix
] == delim
&& list_title
[ix
+ 1] == delim
)
3624 list_title
[count
] = line
[ix
];
3627 } while( line
[ix
] != delim
&& !isend(line
[ix
]) );
3629 if( strlen( list_title
) > TITLELEN
)
3631 list_title
[TITLELEN
] = '\0';
3636 page_lineno
= LIST_LINES_PER_PAGE
;/* Force top of page for new titles. */
3637 list_title_set
= TRUE
;
3643 errorMessage( &text_string
, cc
);
3650 if( isdone( line
[lexstart
] ))
3652 temp
= listfile
; /* Blank XLIST directive. */
3653 listfile
= listsave
;
3658 if( (getExpr())->val
== 0 )
3660 if( listfile
== NULL
)
3662 listfile
= listsave
;
3668 if( listfile
!= NULL
)
3670 listsave
= listfile
;
3678 value
= (getExpr())->val
;
3681 errorMessage( &zblock_too_small
, lexstartprev
);
3683 else if( value
+ ( clc
& 07777 ) - 1 > 07777 )
3685 errorMessage( &zblock_too_large
, lexstartprev
);
3689 for( ; value
> 0; value
-- )
3691 punchOutObject( clc
, 0 );
3700 } /* end switch for pseudo-ops */
3702 } /* pseudoOperators() */
3705 /******************************************************************************/
3707 /* Function: conditionFalse */
3709 /* Synopsis: Called when a false conditional has been evaluated. */
3710 /* Lex should be the opening <; ignore all text until */
3711 /* the closing >. */
3713 /******************************************************************************/
3714 void conditionFalse()
3718 if( line
[lexstart
] == '<' )
3720 /* Invariant: line[cc] is the next unexamined character. */
3724 if( isend( line
[cc
] ))
3757 errorMessage( <_expected
, lexstart
);
3759 } /* conditionFalse() */
3761 /******************************************************************************/
3763 /* Function: conditionTrue */
3765 /* Synopsis: Called when a true conditional has been evaluated. */
3766 /* Lex should be the opening <; skip it and setup for */
3767 /* normal assembly. */
3769 /******************************************************************************/
3770 void conditionTrue()
3772 if( line
[lexstart
] == '<' )
3774 nextLexeme(); /* Skip the opening '<' */
3778 errorMessage( <_expected
, lexstart
);
3780 } /* conditionTrue() */
3783 /******************************************************************************/
3785 /* Function: errorLexeme */
3787 /* Synopsis: Display an error message using the current lexical element. */
3789 /******************************************************************************/
3790 void errorLexeme( EMSG_T
*mesg
, WORD16 col
)
3794 errorSymbol( mesg
, lexemeToName( name
, lexstart
, lexterm
), col
);
3795 } /* errorLexeme() */
3798 /******************************************************************************/
3800 /* Function: errorSymbol */
3802 /* Synopsis: Display an error message with a given string. */
3804 /******************************************************************************/
3805 void errorSymbol( EMSG_T
*mesg
, char *name
, WORD16 col
)
3812 s
= ( name
== NULL
) ? "" : name
;
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
);
3819 error_in_line
= TRUE
;
3820 } /* errorSymbol() */
3823 /******************************************************************************/
3825 /* Function: errorMessage */
3827 /* Synopsis: Display an error message without a name argument. */
3829 /******************************************************************************/
3830 void errorMessage( EMSG_T
*mesg
, WORD16 col
)
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
);
3842 error_in_line
= TRUE
;
3843 } /* errorMessage() */
3845 /******************************************************************************/
3847 /* Function: saveError */
3849 /* Synopsis: Save the current error in a list so it may displayed after the */
3850 /* the current line is printed. */
3852 /******************************************************************************/
3853 void saveError( char *mesg
, WORD16 col
)
3855 if( save_error_count
< DIM( error_list
))
3857 error_list
[save_error_count
].mesg
= mesg
;
3858 error_list
[save_error_count
].col
= col
;
3861 error_in_line
= TRUE
;
3865 printErrorMessages();