mirror of
https://github.com/open-simh/simtools.git
synced 2026-01-18 09:03:39 +00:00
1) The readme is out-of-date, and unreadable on github 2) Some tools have their own directories, some don't 3) Many tools have neither readme nor descriptions. 4) Some files are misplaced This reorganizes so that each tool has its own directory, even if it only has a single file (Hint: If you use a tool, please add/update READMEs) The master README is complete, and readable on github The tools are in alphabetical order within category. There are some cases where this probably isn't the right thing to do, e.g. where there are separate tools that do "to" and "from" conversions. Each tool has at least a 1-line description in the master readme This commit does not change any tool.
3084 lines
114 KiB
C
3084 lines
114 KiB
C
/******************************************************************************/
|
|
/* */
|
|
/* Program: MACRO7 */
|
|
/* File: macro7.c */
|
|
/* Author: Gary A. Messenbrink <gary@netcom.com> */
|
|
/* MACRO7 modifications: Bob Supnik <bob.supnik@ljo.dec.com */
|
|
/* */
|
|
/* Purpose: A 2 pass PDP-7 assembler. */
|
|
/* */
|
|
/* NAME */
|
|
/* macro8x - a PDP-7 assembler. */
|
|
/* */
|
|
/* SYNOPSIS: */
|
|
/* macro7 [ -d -p -m -r -x ] inputfile inputfile... */
|
|
/* */
|
|
/* DESCRIPTION */
|
|
/* This is a cross-assembler to for PDP-7 assembly language programs. */
|
|
/* It will produce an output file in rim format only. */
|
|
/* A listing file is always produced and with an optional symbol table */
|
|
/* and/or a symbol cross-reference (concordance). The permanent symbol */
|
|
/* table can be output in a form that may be read back in so a customized */
|
|
/* permanent symbol table can be produced. Any detected errors are output */
|
|
/* to a separate file giving the filename in which they were detected */
|
|
/* along with the line number, column number and error message as well as */
|
|
/* marking the error in the listing file. */
|
|
/* The following file name extensions are used: */
|
|
/* .7 source code (input) */
|
|
/* .lst assembly listing (output) */
|
|
/* .rim assembly output in DEC's rim format (output) */
|
|
/* .err assembly errors detected (if any) (output) */
|
|
/* .prm permanent symbol table in form suitable for reading after */
|
|
/* the EXPUNGE pseudo-op. */
|
|
/* */
|
|
/* OPTIONS */
|
|
/* -d Dump the symbol table at end of assembly */
|
|
/* -p Generate a file with the permanent symbols in it. */
|
|
/* (To get the current symbol table, assemble a file than has only */
|
|
/* START in it.) */
|
|
/* -x Generate a cross-reference (concordance) of user symbols. */
|
|
/* */
|
|
/* DIAGNOSTICS */
|
|
/* Assembler error diagnostics are output to an error file and inserted */
|
|
/* in the listing file. Each line in the error file has the form */
|
|
/* */
|
|
/* <filename>(<line>:<col>) : error: <message> at Loc = <loc> */
|
|
/* */
|
|
/* An example error message is: */
|
|
/* */
|
|
/* bintst.7(17:9) : error: undefined symbol "UNDEF" at Loc = 07616 */
|
|
/* */
|
|
/* The error diagnostics put in the listing start with a two character */
|
|
/* error code (if appropriate) and a short message. A carat '^' is */
|
|
/* placed under the item in error if appropriate. */
|
|
/* An example error message is: */
|
|
/* */
|
|
/* 17 07616 3000 DAC UNDEF */
|
|
/* UD undefined ^ */
|
|
/* 18 07617 1777 TAD I DUMMY */
|
|
/* */
|
|
/* When an indirect is generated, an at character '@' is placed after the */
|
|
/* the instruction value in the listing as an indicator as follows: */
|
|
/* */
|
|
/* 14 03716 1777@ TAD OFFPAG */
|
|
/* */
|
|
/* Undefined symbols are marked in the symbol table listing by prepending */
|
|
/* a '?' to the symbol. Redefined symbols are marked in the symbol table */
|
|
/* listing by prepending a '#' to the symbol. Examples are: */
|
|
/* */
|
|
/* #REDEF 04567 */
|
|
/* SWITCH 07612 */
|
|
/* ?UNDEF 00000 */
|
|
/* */
|
|
/* Refer to the code for the diagnostic messages generated. */
|
|
/* */
|
|
/* REFERENCES: */
|
|
/* This assembler is based on the pal assember by: */
|
|
/* Douglas Jones <jones@cs.uiowa.edu> and */
|
|
/* Rich Coon <coon@convexw.convex.com> */
|
|
/* */
|
|
/* COPYRIGHT NOTICE: */
|
|
/* This is free software. There is no fee for using it. You may make */
|
|
/* any changes that you wish and also give it away. If you can make */
|
|
/* a commercial product out of it, fine, but do not put any limits on */
|
|
/* the purchaser's right to do the same. If you improve it or fix any */
|
|
/* bugs, it would be nice if you told me and offered me a copy of the */
|
|
/* new version. */
|
|
/* */
|
|
/* */
|
|
/* Amendments Record: */
|
|
/* Version Date by Comments */
|
|
/* ------- ------- --- --------------------------------------------------- */
|
|
/* v1.0 12Apr96 GAM Original */
|
|
/* v1.1 18Nov96 GAM Permanent symbol table initialization error. */
|
|
/* v1.2 20Nov96 GAM Added BINPUNch and RIMPUNch pseudo-operators. */
|
|
/* v1.3 24Nov96 GAM Added DUBL pseudo-op (24 bit integer constants). */
|
|
/* v1.4 29Nov96 GAM Fixed bug in checksum generation. */
|
|
/* v2.1 08Dec96 GAM Added concordance processing (cross reference). */
|
|
/* v2.2 10Dec96 GAM Added FLTG psuedo-op (floating point constants). */
|
|
/* v2.3 2Feb97 GAM Fixed paging problem in cross reference output. */
|
|
/* v3.0 14Feb97 RMS MACRO8X features. */
|
|
/* */
|
|
/******************************************************************************/
|
|
|
|
#include <ctype.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#define LINELEN 96
|
|
#define LIST_LINES_PER_PAGE 60 /* Includes 3 line page header. */
|
|
#define NAMELEN 128
|
|
#define SYMBOL_COLUMNS 5
|
|
#define SYMLEN 7
|
|
#define SYMBOL_TABLE_SIZE 8192
|
|
#define MAC_MAX_ARGS 20 /* Must be < 26 */
|
|
#define MAC_MAX_LENGTH 8192
|
|
#define MAC_TABLE_LENGTH 1024 /* Must be <= 4096. */
|
|
#define TITLELEN 63
|
|
#define XREF_COLUMNS 8
|
|
|
|
#define ADDRESS_FIELD 0017777
|
|
#define LIT_BASE 0017400
|
|
#define INDIRECT_BIT 0020000
|
|
#define LAST_PAGE_LOC 0017777
|
|
#define OP_CODE 0740000
|
|
|
|
/* Macro to get the number of elements in an array. */
|
|
#define DIM(a) (sizeof(a)/sizeof(a[0]))
|
|
|
|
/* Macro to get the address plus one of the end of an array. */
|
|
#define BEYOND(a) ((a) + DIM(A))
|
|
|
|
#define is_blank(c) ((c==' ') || (c=='\f') || (c=='>'))
|
|
#define isend(c) ((c=='\0')|| (c=='\n'))
|
|
#define isdone(c) ((c=='/') || (isend(c)) || (c=='\t'))
|
|
|
|
/* Macros for testing symbol attributes. Each macro evaluates to non-zero */
|
|
/* (true) if the stated condtion is met. */
|
|
/* Use these to test attributes. The proper bits are extracted and then */
|
|
/* tested. */
|
|
#define M_CONDITIONAL(s) ((s & CONDITION) == CONDITION)
|
|
#define M_DEFINED(s) ((s & DEFINED) == DEFINED)
|
|
#define M_DUPLICATE(s) ((s & DUPLICATE) == DUPLICATE)
|
|
#define M_FIXED(s) ((s & FIXED) == FIXED)
|
|
#define M_LABEL(s) ((s & LABEL) == LABEL)
|
|
#define M_MRI(s) ((s & MRI) == MRI)
|
|
#define M_MRIFIX(s) ((s & MRIFIX) == MRIFIX)
|
|
#define M_PSEUDO(s) ((s & PSEUDO) == PSEUDO)
|
|
#define M_REDEFINED(s) ((s & REDEFINED) == REDEFINED)
|
|
#define M_MACRO(s) ((s & MACRO) == MACRO)
|
|
#define M_UNDEFINED(s) (!M_DEFINED(s))
|
|
#define M_NOTRDEF(s) ((s & NOTRDEF) != 0)
|
|
|
|
/* This macro is used to test symbols by the conditional assembly pseudo-ops. */
|
|
#define M_DEF(s) (M_DEFINED(s))
|
|
#define M_COND(s) (M_DEFINED(s))
|
|
#define M_DEFINED_CONDITIONALLY(t) ((M_DEF(t)&&pass==1)||(!M_COND(t)&&pass==2))
|
|
|
|
typedef unsigned char BOOL;
|
|
typedef unsigned char BYTE;
|
|
typedef int WORD32;
|
|
|
|
#ifndef FALSE
|
|
#define FALSE 0
|
|
#define TRUE (!FALSE)
|
|
#endif
|
|
|
|
/* Line listing styles. Used to control listing of lines. */
|
|
enum linestyle_t
|
|
{
|
|
LINE, LINE_VAL, LINE_LOC_VAL, LOC_VAL
|
|
};
|
|
typedef enum linestyle_t LINESTYLE_T;
|
|
|
|
/* Symbol Types. */
|
|
/* Note that the names that have FIX as the suffix contain the FIXED bit */
|
|
/* included in the value. */
|
|
/* */
|
|
/* The CONDITION bit is used when processing the conditional assembly PSEUDO- */
|
|
/* OPs (e.g., IFDEF). During pass 1 of the assembly, the symbol is either */
|
|
/* defined or undefined. The condition bit is set when the symbol is defined */
|
|
/* during pass 1 and reset on pass 2 at the location the symbol was defined */
|
|
/* during pass 1. When processing conditionals during pass 2, if the symbol */
|
|
/* is defined and the condition bit is set, the symbol is treated as if it */
|
|
/* were undefined. This gives consistent behavior of the conditional */
|
|
/* pseudo-ops during both pass 1 and pass 2. */
|
|
enum symtyp
|
|
{
|
|
UNDEFINED = 0000,
|
|
DEFINED = 0001,
|
|
FIXED = 0002,
|
|
MRI = 0004 | DEFINED,
|
|
LABEL = 0010 | DEFINED,
|
|
REDEFINED = 0020 | DEFINED,
|
|
DUPLICATE = 0040 | DEFINED,
|
|
PSEUDO = 0100 | FIXED | DEFINED,
|
|
CONDITION = 0200 | DEFINED,
|
|
MACRO = 0400 | DEFINED,
|
|
MRIFIX = MRI | FIXED | DEFINED,
|
|
DEFFIX = DEFINED | FIXED,
|
|
NOTRDEF = (MACRO | PSEUDO | LABEL | MRI | FIXED) & ~DEFINED
|
|
};
|
|
typedef enum symtyp SYMTYP;
|
|
|
|
enum pseudo_t
|
|
{
|
|
DECIMAL, DEFINE, EJECT, IFDEF, IFNDEF, IFNZERO, IFZERO,
|
|
LIST, NOLIST, OCTAL, START, TEXT, TITLE, VFD
|
|
};
|
|
typedef enum pseudo_t PSEUDO_T;
|
|
|
|
struct sym_t
|
|
{
|
|
SYMTYP type;
|
|
char name[SYMLEN];
|
|
WORD32 val;
|
|
WORD32 xref_index;
|
|
WORD32 xref_count;
|
|
};
|
|
typedef struct sym_t SYM_T;
|
|
|
|
struct lpool_t
|
|
{
|
|
WORD32 error; /* True if error message has been printed. */
|
|
WORD32 pool[LIT_BASE];
|
|
};
|
|
typedef struct lpool_t LPOOL_T;
|
|
|
|
struct emsg_t
|
|
{
|
|
char *list;
|
|
char *file;
|
|
};
|
|
typedef struct emsg_t EMSG_T;
|
|
|
|
struct errsave_t
|
|
{
|
|
char *mesg;
|
|
WORD32 col;
|
|
};
|
|
typedef struct errsave_t ERRSAVE_T;
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
/* Function Prototypes */
|
|
|
|
int binarySearch( char *name, int start, int symbol_count );
|
|
int copyMacLine( int length, int from, int term, int nargs );
|
|
int compareSymbols( const void *a, const void *b );
|
|
void conditionFalse( void );
|
|
void conditionTrue( void );
|
|
SYM_T *defineLexeme( WORD32 start, WORD32 term, WORD32 val, SYMTYP type );
|
|
SYM_T *defineSymbol( char *name, WORD32 val, SYMTYP type, WORD32 start);
|
|
void endOfBinary( void );
|
|
void errorLexeme( EMSG_T *mesg, WORD32 col );
|
|
void errorMessage( EMSG_T *mesg, WORD32 col );
|
|
void errorSymbol( EMSG_T *mesg, char *name, WORD32 col );
|
|
SYM_T *eval( void );
|
|
SYM_T *evalSymbol( void );
|
|
void getArgs( int argc, char *argv[] );
|
|
SYM_T *getExpr( void );
|
|
WORD32 getExprs( void );
|
|
WORD32 incrementClc( void );
|
|
WORD32 insertLiteral( LPOOL_T *pool, WORD32 pool_page, WORD32 value );
|
|
char *lexemeToName( char *name, WORD32 from, WORD32 term );
|
|
void listLine( void );
|
|
SYM_T *lookup( char *name );
|
|
void moveToEndOfLine( void );
|
|
void nextLexBlank( void );
|
|
void nextLexeme( void );
|
|
void onePass( void );
|
|
void printCrossReference( void );
|
|
void printErrorMessages( void );
|
|
void printLine(char *line, WORD32 loc, WORD32 val, LINESTYLE_T linestyle);
|
|
void printPageBreak( void );
|
|
void printPermanentSymbolTable( void );
|
|
void printSymbolTable( void );
|
|
BOOL pseudoOperators( PSEUDO_T val );
|
|
void punchLocObject( WORD32 loc, WORD32 val );
|
|
void punchLiteralPool( LPOOL_T *p, WORD32 lpool_page );
|
|
void punchOutObject( WORD32 loc, WORD32 val );
|
|
void punchLeader( WORD32 count );
|
|
void punchObject( WORD32 val );
|
|
void punchTriplet( WORD32 val );
|
|
void readLine( void );
|
|
void saveError( char *mesg, WORD32 cc );
|
|
BOOL testForLiteralCollision( WORD32 loc );
|
|
void topOfForm( char *title, char *sub_title );
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
/* Table of pseudo-ops (directives) which are used to setup the symbol */
|
|
/* table on startup and when the EXPUNGE pseudo-op is executed. */
|
|
SYM_T pseudo[] =
|
|
{
|
|
{ PSEUDO, "DECIMA", DECIMAL }, /* Read literal constants in base 10. */
|
|
{ PSEUDO, "DEFINE", DEFINE }, /* Define macro. */
|
|
{ PSEUDO, "tEJECT", EJECT }, /* Eject a page in the listing. DISABLED */
|
|
{ PSEUDO, "IFDEF", IFDEF }, /* Assemble if symbol is defined. */
|
|
{ PSEUDO, "IFNDEF", IFNDEF }, /* Assemble if symbol is not defined. */
|
|
{ PSEUDO, "IFNZER", IFNZERO }, /* Assemble if symbol value is not 0. */
|
|
{ PSEUDO, "IFZERO", IFZERO }, /* Assemble if symbol value is 0. */
|
|
{ PSEUDO, "LIST", LIST }, /* Enable listing. */
|
|
{ PSEUDO, "NOLIST", NOLIST }, /* Disable listing. */
|
|
{ PSEUDO, "OCTAL", OCTAL }, /* Read literal constants in base 8. */
|
|
{ PSEUDO, "START", START }, /* Set starting address. */
|
|
{ PSEUDO, "TEXT", TEXT }, /* Pack 6 bit trimmed ASCII into memory. */
|
|
{ PSEUDO, "TITLE", TITLE }, /* Use the text string as a listing title.*/
|
|
{ PSEUDO, "VFD", VFD }, /* Variable field definition. */
|
|
};
|
|
|
|
/* Symbol Table */
|
|
/* The table is put in lexical order on startup, so symbols can be */
|
|
/* inserted as desired into the initial table. */
|
|
#define DAC 0040000
|
|
#define JMP 0600000
|
|
SYM_T permanent_symbols[] =
|
|
{
|
|
/* Memory Reference Instructions */
|
|
{ MRIFIX, "CAL", 0000000 },
|
|
{ MRIFIX, "DAC", 0040000 },
|
|
{ MRIFIX, "JMS", 0100000 },
|
|
{ MRIFIX, "DZM", 0140000 },
|
|
{ MRIFIX, "LAC", 0200000 },
|
|
{ MRIFIX, "XOR", 0240000 },
|
|
{ MRIFIX, "ADD", 0300000 },
|
|
{ MRIFIX, "TAD", 0340000 },
|
|
{ MRIFIX, "XCT", 0400000 },
|
|
{ MRIFIX, "ISZ", 0440000 },
|
|
{ MRIFIX, "AND", 0500000 },
|
|
{ MRIFIX, "SAD", 0540000 },
|
|
{ MRIFIX, "JMP", 0600000 },
|
|
{ MRIFIX, "I", 0020000 },
|
|
{ DEFFIX, "EAE", 0640000 },
|
|
{ DEFFIX, "IOT", 0700000 },
|
|
{ DEFFIX, "OPR", 0740000 },
|
|
{ DEFFIX, "LAW", 0760000 },
|
|
{ DEFFIX, "LAM", 0777777 },
|
|
/* EAE Microinstructions */
|
|
{ DEFFIX, "OSC", 0640001 },
|
|
{ DEFFIX, "LACS", 0641001 },
|
|
{ DEFFIX, "OMQ", 0640002 },
|
|
{ DEFFIX, "LACQ", 0641002 },
|
|
{ DEFFIX, "CMQ", 0640004 },
|
|
{ DEFFIX, "CLQ", 0650000 },
|
|
{ DEFFIX, "LMQ", 0652000 },
|
|
{ DEFFIX, "ABS", 0644000 },
|
|
{ DEFFIX, "GSM", 0664000 },
|
|
{ DEFFIX, "MUL", 0653122 },
|
|
{ DEFFIX, "MULS", 0657122 },
|
|
{ DEFFIX, "DIV", 0640323 },
|
|
{ DEFFIX, "DIVS", 0644323 },
|
|
{ DEFFIX, "IDIV", 0653323 },
|
|
{ DEFFIX, "IDIVS", 0657323 },
|
|
{ DEFFIX, "FRDIV", 0650323 },
|
|
{ DEFFIX, "FRDIVS", 0654323 },
|
|
{ DEFFIX, "NORM", 0640444 },
|
|
{ DEFFIX, "NORMS", 0660444 },
|
|
{ DEFFIX, "LRS", 0640500 },
|
|
{ DEFFIX, "LRSS", 0660500 },
|
|
{ DEFFIX, "LLS", 0640600 },
|
|
{ DEFFIX, "LLSS", 0660600 },
|
|
{ DEFFIX, "ALS", 0640700 },
|
|
{ DEFFIX, "ALSS", 0660700 },
|
|
/* Operate Microinstructions */
|
|
{ DEFFIX, "NOP", 0740000 },
|
|
{ DEFFIX, "CMA", 0740001 },
|
|
{ DEFFIX, "CML", 0740002 },
|
|
{ DEFFIX, "OAS", 0740004 },
|
|
{ DEFFIX, "LAS", 0750004 },
|
|
{ DEFFIX, "RAL", 0740010 },
|
|
{ DEFFIX, "RCL", 0744010 },
|
|
{ DEFFIX, "RTL", 0742010 },
|
|
{ DEFFIX, "RAR", 0740020 },
|
|
{ DEFFIX, "RCR", 0744020 },
|
|
{ DEFFIX, "RTR", 0742020 },
|
|
{ DEFFIX, "HLT", 0740040 },
|
|
{ DEFFIX, "XX", 0740040 },
|
|
{ DEFFIX, "SMA", 0740100 },
|
|
{ DEFFIX, "SZA", 0740200 },
|
|
{ DEFFIX, "SNL", 0740400 },
|
|
{ DEFFIX, "SKP", 0741000 },
|
|
{ DEFFIX, "SPA", 0741100 },
|
|
{ DEFFIX, "SNA", 0741200 },
|
|
{ DEFFIX, "SZL", 0741400 },
|
|
{ DEFFIX, "CLL", 0744000 },
|
|
{ DEFFIX, "STL", 0744002 },
|
|
{ DEFFIX, "CLA", 0750000 },
|
|
{ DEFFIX, "CLC", 0750001 },
|
|
{ DEFFIX, "GLK", 0750010 },
|
|
/* CPU IOT's */
|
|
{ DEFFIX, "CLSF", 0700001 },
|
|
{ DEFFIX, "IOF", 0700002 },
|
|
{ DEFFIX, "ION", 0700042 },
|
|
{ DEFFIX, "ITON", 0700062 },
|
|
{ DEFFIX, "CLOF", 0700004 },
|
|
{ DEFFIX, "CLON", 0700044 },
|
|
{ DEFFIX, "TTS", 0703301 },
|
|
{ DEFFIX, "SKP7", 0703341 },
|
|
{ DEFFIX, "CAF", 0703302 },
|
|
{ DEFFIX, "SEM", 0707701 },
|
|
{ DEFFIX, "EEM", 0707702 },
|
|
{ DEFFIX, "EMIR", 0707742 },
|
|
{ DEFFIX, "LEM", 0707704 },
|
|
/* High Speed Paper Tape Reader */
|
|
{ DEFFIX, "RSF", 0700101 },
|
|
{ DEFFIX, "RRB", 0700112 },
|
|
{ DEFFIX, "RCF", 0700102 },
|
|
{ DEFFIX, "RSA", 0700104 },
|
|
{ DEFFIX, "RSB", 0700144 },
|
|
/* High Speed Paper Tape Punch */
|
|
{ DEFFIX, "PSF", 0700201 },
|
|
{ DEFFIX, "PCF", 0700202 },
|
|
{ DEFFIX, "PSA", 0700204 },
|
|
{ DEFFIX, "PLS", 0700204 },
|
|
{ DEFFIX, "PSB", 0700244 },
|
|
/* Keyboard */
|
|
{ DEFFIX, "KSF", 0700301 },
|
|
{ DEFFIX, "KRB", 0700312 },
|
|
{ DEFFIX, "IORS", 0700314 },
|
|
/* Teleprinter */
|
|
{ DEFFIX, "TSF", 0700401 },
|
|
{ DEFFIX, "TCF", 0700402 },
|
|
{ DEFFIX, "TLS", 0700406 },
|
|
/* Line Printer */
|
|
{ DEFINED, "LPSF", 0706501 },
|
|
{ DEFINED, "LPCB", 0706502 },
|
|
{ DEFINED, "LPB1", 0706566 },
|
|
{ DEFINED, "LPB2", 0706526 },
|
|
{ DEFINED, "LPB3", 0706546 },
|
|
{ DEFINED, "LPSE", 0706601 },
|
|
{ DEFINED, "LPCF", 0706602 },
|
|
{ DEFINED, "LPPB", 0706606 },
|
|
{ DEFINED, "LPLS", 0706626 },
|
|
{ DEFINED, "LPPS", 0706646 },
|
|
/* Card Reader */
|
|
{ DEFFIX, "CRSF", 0706701 },
|
|
{ DEFFIX, "CRRB", 0706712 },
|
|
{ DEFFIX, "CRSA", 0706704 },
|
|
{ DEFFIX, "CRSB", 0706744 },
|
|
/* DECtape */
|
|
{ DEFFIX, "MMDF", 0707501 },
|
|
{ DEFFIX, "MMEF", 0707541 },
|
|
{ DEFFIX, "MMRD", 0707512 },
|
|
{ DEFFIX, "MMWR", 0707504 },
|
|
{ DEFFIX, "MMBF", 0707601 },
|
|
{ DEFFIX, "MMRS", 0707612 },
|
|
{ DEFFIX, "MMLC", 0707604 },
|
|
{ DEFFIX, "MMSE", 0707644 },
|
|
}; /* End-of-Symbols for Permanent Symbol Table */
|
|
|
|
/* Global variables */
|
|
SYM_T *symtab; /* Symbol Table */
|
|
int symbol_top; /* Number of entries in symbol table. */
|
|
|
|
SYM_T *fixed_symbols; /* Start of the fixed symbol table entries. */
|
|
int number_of_fixed_symbols;
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
WORD32 *xreftab; /* Start of the concordance table. */
|
|
|
|
ERRSAVE_T error_list[20];
|
|
int save_error_count;
|
|
|
|
LPOOL_T cp; /* Storage for current page constants. */
|
|
|
|
char s_detected[] = "detected";
|
|
char s_error[] = "error";
|
|
char s_errors[] = "errors";
|
|
char s_no[] = "No";
|
|
char s_page[] = "Page";
|
|
char s_symtable[] = "Symbol Table";
|
|
char s_xref[] = "Cross Reference";
|
|
|
|
/* Assembler diagnostic messages. */
|
|
/* Some attempt has been made to keep continuity with the PAL-III and */
|
|
/* MACRO-8 diagnostic messages. If a diagnostic indicator, (e.g., IC) */
|
|
/* exists, then the indicator is put in the listing as the first two */
|
|
/* characters of the diagnostic message. The PAL-III indicators where used */
|
|
/* when there was a choice between using MACRO-8 and PAL-III indicators. */
|
|
/* The character pairs and their meanings are: */
|
|
/* DT Duplicate Tag (symbol) */
|
|
/* IC Illegal Character */
|
|
/* ID Illegal Redefinition of a symbol. An attempt was made to give */
|
|
/* a symbol a new value not via =. */
|
|
/* IE Illegal Equals An equal sign was used in the wrong context, */
|
|
/* (e.g., A+B=C, or TAD A+=B) */
|
|
/* II Illegal Indirect An off page reference was made, but a literal */
|
|
/* could not be generated because the indirect bit was already set. */
|
|
/* IR Illegal Reference (address is not on current page or page zero) */
|
|
/* PE Current, Non-Zero Page Exceeded (literal table flowed into code) */
|
|
/* RD ReDefintion of a symbol */
|
|
/* ST Symbol Table full */
|
|
/* UA Undefined Address (undefined symbol) */
|
|
/* ZE Zero Page Exceeded (see above, or out of space) */
|
|
EMSG_T duplicate_label = { "DT duplicate", "duplicate label" };
|
|
EMSG_T illegal_blank = { "IC illegal blank", "illegal blank" };
|
|
EMSG_T illegal_character = { "IC illegal char", "illegal character" };
|
|
EMSG_T illegal_expression = { "IC in expression", "illegal expression" };
|
|
EMSG_T label_syntax = { "IC label syntax", "label syntax" };
|
|
EMSG_T not_a_number = { "IC numeric syntax", "numeric syntax of" };
|
|
EMSG_T number_not_radix = { "IC radix", "number not in current radix"};
|
|
EMSG_T symbol_syntax = { "IC symbol syntax", "symbol syntax" };
|
|
EMSG_T illegal_equals = { "IE illegal =", "illegal equals" };
|
|
EMSG_T illegal_indirect = { "II off page", "illegal indirect" };
|
|
EMSG_T illegal_reference = { "IR off page", "illegal reference" };
|
|
EMSG_T undefined_symbol = { "UD undefined", "undefined symbol" };
|
|
EMSG_T misplaced_symbol = { "misplaced symbol", "misplaced symbol" };
|
|
EMSG_T redefined_symbol = { "RD redefined", "redefined symbol" };
|
|
EMSG_T literal_gen_off = { "lit generation off",
|
|
"literal generation disabled" };
|
|
EMSG_T literal_overflow = { "PE page exceeded",
|
|
"current page literal capacity exceeded" };
|
|
EMSG_T zblock_too_small = { "expr too small", "ZBLOCK value too small" };
|
|
EMSG_T zblock_too_large = { "expr too large", "ZBLOCK value too large" };
|
|
EMSG_T no_pseudo_op = { "not implemented", "Unimplemented pseudo-op" };
|
|
EMSG_T illegal_vfd_value = { "width out of range",
|
|
"VFD field width not in range" };
|
|
EMSG_T no_literal_value = { "no value", "No literal value" };
|
|
EMSG_T text_string = { "no delimiter",
|
|
"Text string delimiters not matched" };
|
|
EMSG_T lt_expected = { "'<' expected", "'<' expected" };
|
|
EMSG_T symbol_table_full = { "ST Symbol Tbl full", "Symbol table full" };
|
|
EMSG_T no_macro_name = { "no macro name", "No name following DEFINE" };
|
|
EMSG_T bad_dummy_arg = { "bad dummy arg",
|
|
"Bad dummy argument following DEFINE" };
|
|
EMSG_T macro_too_long = { "macro too long", "Macro too long" };
|
|
EMSG_T no_virtual_memory = { "out of memory",
|
|
"Insufficient memory for macro" };
|
|
EMSG_T macro_table_full = { "Macro Table full", "Macro table full" };
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
FILE *errorfile;
|
|
FILE *infile;
|
|
FILE *listfile;
|
|
FILE *listsave;
|
|
FILE *objectfile;
|
|
FILE *objectsave;
|
|
|
|
char errorpathname[NAMELEN];
|
|
char filename[NAMELEN];
|
|
char listpathname[NAMELEN];
|
|
char objectpathname[NAMELEN];
|
|
char *pathname;
|
|
char permpathname[NAMELEN];
|
|
|
|
char mac_buffer[MAC_MAX_LENGTH + 1];
|
|
char *mac_bodies[MAC_TABLE_LENGTH];
|
|
char mac_arg_name[MAC_MAX_ARGS][SYMLEN];
|
|
int mac_arg_pos[26] = { 0 };
|
|
|
|
int list_lineno;
|
|
int list_pageno;
|
|
char list_title[4*LINELEN];
|
|
BOOL list_title_set; /* Set if TITLE pseudo-op used. */
|
|
char line[4*LINELEN]; /* Input line. */
|
|
int lineno; /* Current line number. */
|
|
char mac_line[4*LINELEN]; /* Saved macro invocation line. */
|
|
int page_lineno; /* print line number on current page. */
|
|
WORD32 listed; /* Listed flag. */
|
|
WORD32 listedsave;
|
|
|
|
WORD32 cc; /* Column Counter (char position in line). */
|
|
WORD32 checksum; /* Generated checksum */
|
|
BOOL binary_data_output; /* Set true when data has been output. */
|
|
WORD32 clc; /* Location counter */
|
|
char delimiter; /* Character immediately after eval'd term. */
|
|
BOOL end_of_input; /* End of all input files. */
|
|
int errors; /* Number of errors found so far. */
|
|
BOOL error_in_line; /* TRUE if error on current line. */
|
|
int errors_pass_1; /* Number of errors on pass 1. */
|
|
int filix_curr; /* Index in argv to current input file. */
|
|
int filix_start; /* Start of input files in argv. */
|
|
BOOL indirect_generated; /* TRUE if an off page address generated. */
|
|
WORD32 lexstartprev; /* Where previous lexeme started. */
|
|
WORD32 lextermprev; /* Where previous lexeme ended. */
|
|
WORD32 lexstart; /* Index of current lexeme on line. */
|
|
WORD32 lexterm; /* Index of character after current lexeme. */
|
|
WORD32 lit_loc; /* Base of literal pool. */
|
|
WORD32 mac_cc; /* Saved cc after macro invocation. */
|
|
WORD32 mac_count; /* Total macros defined. */
|
|
char *mac_ptr; /* Pointer to macro body, NULL if no macro. */
|
|
WORD32 maxcc; /* Current line length. */
|
|
BOOL nomac_exp; /* No macro expansions. */
|
|
WORD32 pass; /* Number of current pass. */
|
|
BOOL print_permanent_symbols;
|
|
WORD32 radix; /* Default number radix. */
|
|
BOOL rim_mode; /* RIM mode output. */
|
|
int save_argc; /* Saved argc. */
|
|
char **save_argv; /* Saved *argv[]. */
|
|
WORD32 start_addr; /* Saved start address. */
|
|
BOOL symtab_print; /* Print symbol table flag */
|
|
BOOL xref;
|
|
|
|
SYM_T sym_eval = { DEFINED, "", 0 }; /* Value holder for eval() */
|
|
SYM_T sym_getexpr = { DEFINED, "", 0 }; /* Value holder for getexpr() */
|
|
SYM_T sym_undefined = { UNDEFINED, "", 0 };/* Symbol Table Terminator */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: main */
|
|
/* */
|
|
/* Synopsis: Starting point. Controls order of assembly. */
|
|
/* */
|
|
/******************************************************************************/
|
|
int main( int argc, char *argv[] )
|
|
{
|
|
int ix;
|
|
int space;
|
|
|
|
save_argc = argc;
|
|
save_argv = argv;
|
|
|
|
/* Set the default values for global symbols. */
|
|
binary_data_output = FALSE;
|
|
print_permanent_symbols = FALSE;
|
|
nomac_exp = TRUE;
|
|
rim_mode = TRUE;
|
|
symtab_print = FALSE;
|
|
xref = FALSE;
|
|
pathname = NULL;
|
|
for( ix = 0; ix < MAC_TABLE_LENGTH; ix++ )
|
|
{
|
|
mac_bodies[ix] = NULL;
|
|
}
|
|
|
|
/* Get the options and pathnames */
|
|
getArgs( argc, argv );
|
|
|
|
/* Setup the error file in case symbol table overflows while installing the */
|
|
/* permanent symbols. */
|
|
errorfile = fopen( errorpathname, "w" );
|
|
errors = 0;
|
|
save_error_count = 0;
|
|
pass = 0; /* This is required for symbol table initialization. */
|
|
symtab = (SYM_T *) malloc( sizeof( SYM_T ) * SYMBOL_TABLE_SIZE );
|
|
|
|
if( symtab == NULL )
|
|
{
|
|
fprintf( stderr, "Could not allocate memory for symbol table.\n");
|
|
exit( -1 );
|
|
}
|
|
|
|
/* Place end marker in symbol table. */
|
|
symtab[0] = sym_undefined;
|
|
symbol_top = 0;
|
|
number_of_fixed_symbols = symbol_top;
|
|
fixed_symbols = &symtab[symbol_top - 1];
|
|
|
|
/* Enter the pseudo-ops into the symbol table */
|
|
for( ix = 0; ix < DIM( pseudo ); ix++ )
|
|
{
|
|
defineSymbol( pseudo[ix].name, pseudo[ix].val, pseudo[ix].type, 0 );
|
|
}
|
|
|
|
/* Enter the predefined symbols into the table. */
|
|
/* Also make them part of the permanent symbol table. */
|
|
for( ix = 0; ix < DIM( permanent_symbols ); ix++ )
|
|
{
|
|
defineSymbol( permanent_symbols[ix].name,
|
|
permanent_symbols[ix].val,
|
|
permanent_symbols[ix].type, 0 );
|
|
}
|
|
|
|
number_of_fixed_symbols = symbol_top;
|
|
fixed_symbols = &symtab[symbol_top - 1];
|
|
|
|
/* Do pass one of the assembly */
|
|
checksum = 0;
|
|
pass = 1;
|
|
onePass();
|
|
errors_pass_1 = errors;
|
|
|
|
/* Set up for pass two */
|
|
errorfile = fopen( errorpathname, "w" );
|
|
objectfile = fopen( objectpathname, "wb" );
|
|
objectsave = objectfile;
|
|
|
|
listfile = fopen( listpathname, "w" );
|
|
listsave = listfile;
|
|
|
|
punchLeader( 0 );
|
|
checksum = 0;
|
|
|
|
/* Do pass two of the assembly */
|
|
errors = 0;
|
|
save_error_count = 0;
|
|
|
|
if( xref )
|
|
{
|
|
/* Get the amount of space that will be required for the concordance. */
|
|
for( space = 0, ix = 0; ix < symbol_top; ix++ )
|
|
{
|
|
symtab[ix].xref_index = space; /* Index into concordance table. */
|
|
space += symtab[ix].xref_count + 1;
|
|
symtab[ix].xref_count = 0; /* Clear the count for pass 2. */
|
|
|
|
}
|
|
/* Allocate the necessary space. */
|
|
xreftab = (WORD32 *) malloc( sizeof( WORD32 ) * space );
|
|
|
|
/* Clear the cross reference space. */
|
|
for( ix = 0; ix < space; ix++ )
|
|
{
|
|
xreftab[ix] = 0;
|
|
}
|
|
}
|
|
pass = 2;
|
|
onePass();
|
|
|
|
/* Undo effects of NOPUNCH for any following checksum */
|
|
objectfile = objectsave;
|
|
|
|
/* Works great for trailer. */
|
|
punchLeader( 1 );
|
|
|
|
/* undo effects of NOLIST for any following output to listing file. */
|
|
listfile = listsave;
|
|
|
|
/* Display value of error counter. */
|
|
if( errors == 0 )
|
|
{
|
|
fprintf( listfile, "\n %s %s %s\n", s_no, s_detected, s_errors );
|
|
}
|
|
else
|
|
{
|
|
fprintf( errorfile, "\n %d %s %s\n", errors, s_detected,
|
|
( errors == 1 ? s_error : s_errors ));
|
|
fprintf( listfile, "\n %d %s %s\n", errors, s_detected,
|
|
( errors == 1 ? s_error : s_errors ));
|
|
fprintf( stderr, " %d %s %s\n", errors, s_detected,
|
|
( errors == 1 ? s_error : s_errors ));
|
|
}
|
|
|
|
if( symtab_print )
|
|
{
|
|
printSymbolTable();
|
|
}
|
|
|
|
if( print_permanent_symbols )
|
|
{
|
|
printPermanentSymbolTable();
|
|
}
|
|
|
|
if( xref )
|
|
{
|
|
printCrossReference();
|
|
}
|
|
|
|
fclose( objectfile );
|
|
fclose( listfile );
|
|
fclose( errorfile );
|
|
if( errors == 0 && errors_pass_1 == 0 )
|
|
{
|
|
remove( errorpathname );
|
|
}
|
|
|
|
return( errors != 0 );
|
|
} /* main() */
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: getArgs */
|
|
/* */
|
|
/* Synopsis: Parse command line, set flags accordingly and setup input and */
|
|
/* output files. */
|
|
/* */
|
|
/******************************************************************************/
|
|
void getArgs( int argc, char *argv[] )
|
|
{
|
|
WORD32 len;
|
|
WORD32 ix, jx;
|
|
|
|
/* Set the defaults */
|
|
errorfile = NULL;
|
|
infile = NULL;
|
|
listfile = NULL;
|
|
listsave = NULL;
|
|
objectfile = NULL;
|
|
objectsave = NULL;
|
|
|
|
for( ix = 1; ix < argc; ix++ )
|
|
{
|
|
if( argv[ix][0] == '-' )
|
|
{
|
|
for( jx = 1; argv[ix][jx] != 0; jx++ )
|
|
{
|
|
switch( argv[ix][jx] )
|
|
{
|
|
case 'd':
|
|
symtab_print = TRUE;
|
|
break;
|
|
|
|
/* case 'r':
|
|
rim_mode = TRUE;
|
|
break;
|
|
*/
|
|
case 'm':
|
|
nomac_exp = FALSE;
|
|
break;
|
|
|
|
case 'p':
|
|
print_permanent_symbols = TRUE;
|
|
break;
|
|
|
|
case 'x':
|
|
xref = TRUE;
|
|
break;
|
|
|
|
default:
|
|
fprintf( stderr, "%s: unknown flag: %s\n", argv[0], argv[ix] );
|
|
fprintf( stderr, " -d -- dump symbol table\n" );
|
|
fprintf( stderr, " -m -- output macro expansions\n" );
|
|
/* fprintf( stderr, " -r -- output rim format file\n" ); */
|
|
fprintf( stderr, " -p -- output permanent symbols to file\n" );
|
|
fprintf( stderr, " -x -- output cross reference to file\n" );
|
|
fflush( stderr );
|
|
exit( -1 );
|
|
} /* end switch */
|
|
} /* end for */
|
|
}
|
|
else
|
|
{
|
|
filix_start = ix;
|
|
pathname = argv[ix];
|
|
break;
|
|
}
|
|
} /* end for */
|
|
|
|
if( pathname == NULL )
|
|
{
|
|
fprintf( stderr, "%s: no input file specified\n", argv[0] );
|
|
exit( -1 );
|
|
}
|
|
|
|
len = strlen( pathname );
|
|
if( len > NAMELEN - 5 )
|
|
{
|
|
fprintf( stderr, "%s: pathname \"%s\" too long\n", argv[0], pathname );
|
|
exit( -1 );
|
|
}
|
|
|
|
/* Now make the pathnames */
|
|
/* Find last '.', if it exists. */
|
|
jx = len - 1;
|
|
while( pathname[jx] != '.' && pathname[jx] != '/'
|
|
&& pathname[jx] != '\\' && jx >= 0 )
|
|
{
|
|
jx--;
|
|
}
|
|
|
|
switch( pathname[jx] )
|
|
{
|
|
case '.':
|
|
break;
|
|
|
|
case '/':
|
|
case '\\':
|
|
jx = len;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* Add the pathname extensions. */
|
|
strncpy( objectpathname, pathname, jx );
|
|
objectpathname[jx] = '\0';
|
|
strcat( objectpathname, rim_mode ? ".rim" : ".bin" );
|
|
|
|
strncpy( listpathname, pathname, jx );
|
|
listpathname[jx] = '\0';
|
|
strcat( listpathname, ".lst" );
|
|
|
|
strncpy( errorpathname, pathname, jx );
|
|
errorpathname[jx] = '\0';
|
|
strcat( errorpathname, ".err" );
|
|
|
|
strncpy( permpathname, pathname, jx );
|
|
permpathname[jx] = '\0';
|
|
strcat( permpathname, ".prm" );
|
|
|
|
/* Extract the filename from the path. */
|
|
if( isalpha( pathname[0] ) && pathname[1] == ':' && pathname[2] != '\\' )
|
|
{
|
|
pathname[1] = '\\'; /* MS-DOS style pathname */
|
|
}
|
|
|
|
jx = len - 1;
|
|
while( pathname[jx] != '/' && pathname[jx] != '\\' && jx >= 0 )
|
|
{
|
|
jx--;
|
|
}
|
|
strcpy( filename, &pathname[jx + 1] );
|
|
|
|
} /* getArgs() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: onePass */
|
|
/* */
|
|
/* Synopsis: Do one assembly pass. */
|
|
/* */
|
|
/******************************************************************************/
|
|
void onePass()
|
|
{
|
|
BOOL blanks;
|
|
int ix;
|
|
int jx;
|
|
char name[SYMLEN];
|
|
WORD32 newclc;
|
|
BOOL scanning_line;
|
|
WORD32 start;
|
|
SYM_T *sym;
|
|
WORD32 term;
|
|
WORD32 val;
|
|
|
|
clc = 0100; /* Default starting address is 100 octal. */
|
|
start_addr = 0100; /* No starting address. */
|
|
lit_loc = LIT_BASE; /* Literal pool base. */
|
|
mac_count = 0; /* No macros defined. */
|
|
mac_ptr = NULL; /* Not in a macro. */
|
|
for( ix = 0; ix < MAC_TABLE_LENGTH; ix++)
|
|
{
|
|
if ( mac_bodies[ix] )
|
|
{
|
|
free( mac_bodies[ix] );
|
|
}
|
|
}
|
|
cp.error = FALSE;
|
|
listed = TRUE;
|
|
lineno = 0;
|
|
list_pageno = 0;
|
|
list_lineno = 0;
|
|
list_title_set = FALSE;
|
|
page_lineno = LIST_LINES_PER_PAGE; /* Force top of page for new titles. */
|
|
radix = 8; /* Initial radix is octal (base 8). */
|
|
|
|
/* Now open the first input file. */
|
|
end_of_input = FALSE;
|
|
filix_curr = filix_start; /* Initialize pointer to input files. */
|
|
if(( infile = fopen( save_argv[filix_curr], "r" )) == NULL )
|
|
{
|
|
fprintf( stderr, "%s: cannot open \"%s\"\n", save_argv[0],
|
|
save_argv[filix_curr] );
|
|
exit( -1 );
|
|
}
|
|
|
|
while( TRUE )
|
|
{
|
|
readLine();
|
|
nextLexeme();
|
|
|
|
scanning_line = TRUE;
|
|
while( scanning_line )
|
|
{
|
|
if( end_of_input )
|
|
{
|
|
endOfBinary();
|
|
fclose( infile );
|
|
return;
|
|
}
|
|
if( isend( line[lexstart] ))
|
|
{
|
|
scanning_line = FALSE;
|
|
}
|
|
else
|
|
{
|
|
switch( line[lexstart] )
|
|
{
|
|
case '/':
|
|
scanning_line = FALSE;
|
|
break;
|
|
|
|
case '\t':
|
|
nextLexeme();
|
|
break;
|
|
|
|
default:
|
|
for( jx = lexstart; jx < maxcc; jx++ )
|
|
{
|
|
if( is_blank( line[jx] ) || isdone( line[jx] )) break;
|
|
}
|
|
if( line[jx] == '/')
|
|
{
|
|
newclc = (getExpr())->val & 077777;
|
|
/* Do not change Current Location Counter if an error occurred. */
|
|
if( !error_in_line )
|
|
{
|
|
clc = newclc;
|
|
}
|
|
printLine( line, 0, newclc, LINE_VAL );
|
|
cc = jx + 1;
|
|
nextLexeme();
|
|
while( line[lexstart] == '\t' ) nextLexeme();
|
|
break;
|
|
}
|
|
|
|
switch( line[lexterm] )
|
|
{
|
|
case ',':
|
|
if( isalpha( line[lexstart] ))
|
|
{
|
|
/* Use lookup so symbol will not be counted as reference. */
|
|
sym = lookup( lexemeToName( name, lexstart, lexterm ));
|
|
if( M_DEFINED( sym->type ))
|
|
{
|
|
if( sym->val != clc && pass == 2 )
|
|
{
|
|
errorSymbol( &duplicate_label, sym->name, lexstart );
|
|
}
|
|
sym->type = sym->type | DUPLICATE;
|
|
}
|
|
/* Must call define on pass 2 to generate concordance. */
|
|
defineLexeme( lexstart, lexterm, clc, LABEL );
|
|
}
|
|
else
|
|
{
|
|
errorLexeme( &label_syntax, lexstart );
|
|
}
|
|
nextLexeme(); /* skip label */
|
|
nextLexeme(); /* skip comma */
|
|
while( line[lexstart] == '\t' ) nextLexeme();
|
|
break;
|
|
|
|
case '=':
|
|
if( isalpha( line[lexstart] ))
|
|
{
|
|
start = lexstart;
|
|
term = lexterm;
|
|
delimiter = line[lexterm];
|
|
nextLexBlank(); /* skip symbol */
|
|
nextLexeme(); /* skip trailing = */
|
|
val = getExprs();
|
|
defineLexeme( start, term, val, DEFINED );
|
|
printLine( line, 0, val, LINE_VAL );
|
|
}
|
|
else
|
|
{
|
|
errorLexeme( &symbol_syntax, lexstartprev );
|
|
nextLexeme(); /* skip symbol */
|
|
nextLexeme(); /* skip trailing = */
|
|
getExprs(); /* skip expression */
|
|
}
|
|
while( line[lexstart] == '\t' ) nextLexeme();
|
|
break;
|
|
|
|
default:
|
|
if( isalpha( line[lexstart] ))
|
|
{
|
|
sym = evalSymbol();
|
|
val = sym->val;
|
|
if( M_MACRO( sym->type ))
|
|
{ /* Find arguments. */
|
|
blanks = TRUE; /* Expecting blanks. */
|
|
for( jx = 0; !isdone( line[cc] ) && ( jx < MAC_MAX_ARGS ); cc++ )
|
|
{
|
|
if(( line[cc] == ',' ) || is_blank( line[cc] )) blanks = TRUE;
|
|
else if( blanks )
|
|
{
|
|
mac_arg_pos[jx++] = cc;
|
|
blanks = FALSE;
|
|
}
|
|
} /* end for */
|
|
for( ; jx < MAC_MAX_ARGS; jx++ )
|
|
{
|
|
mac_arg_pos[jx] = 0;
|
|
}
|
|
for( jx = 0; jx < LINELEN; jx++ )
|
|
{
|
|
mac_line[jx] = line[jx];
|
|
}
|
|
mac_cc = cc; /* Save line and position in line. */
|
|
mac_ptr = mac_bodies[val];
|
|
if( mac_ptr ) scanning_line = FALSE;
|
|
else nextLexeme();
|
|
} /* end if macro */
|
|
else if( M_PSEUDO( sym->type ))
|
|
{
|
|
nextLexeme(); /* Skip symbol */
|
|
scanning_line = pseudoOperators( (PSEUDO_T)val & 0777777 );
|
|
}
|
|
else
|
|
{
|
|
/* Identifier is not a pseudo-op, interpret as load value */
|
|
punchOutObject( clc, getExprs() & 0777777 );
|
|
incrementClc();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Identifier is a value, interpret as load value */
|
|
punchOutObject( clc, getExprs() & 0777777 );
|
|
incrementClc();
|
|
}
|
|
break;
|
|
} /* end switch */
|
|
break;
|
|
} /* end switch */
|
|
} /* end if */
|
|
} /* end while( scanning_line ) */
|
|
} /* end while( TRUE ) */
|
|
} /* onePass() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: getExprs */
|
|
/* */
|
|
/* Synopsis: Or together a list of blank separated expressions, from the */
|
|
/* current lexeme onward. Leave the current lexeme as */
|
|
/* the last one in the list. */
|
|
/* */
|
|
/******************************************************************************/
|
|
WORD32 getExprs()
|
|
{
|
|
SYM_T *symv;
|
|
SYM_T *symt;
|
|
WORD32 temp;
|
|
SYMTYP temp_type;
|
|
WORD32 value;
|
|
SYMTYP value_type;
|
|
|
|
symv = getExpr();
|
|
value = symv->val;
|
|
value_type = symv->type;
|
|
|
|
while( TRUE )
|
|
{
|
|
if( isdone( line[lexstart] ) || line[lexstart] == ')' )
|
|
{
|
|
return( value );
|
|
}
|
|
|
|
/* Interpret space as add */
|
|
symt = getExpr();
|
|
temp = symt->val & 0777777;
|
|
temp_type = symt->type;
|
|
|
|
switch( value_type )
|
|
{
|
|
case MRI:
|
|
case MRIFIX:
|
|
/* Previous symbol was a Memory Reference Instruction. */
|
|
switch( temp_type )
|
|
{
|
|
case MRI:
|
|
case MRIFIX:
|
|
/* Current symbol is also a Memory Reference Instruction. */
|
|
value |= temp; /* Just OR the MRI instructions. */
|
|
break;
|
|
|
|
default:
|
|
/* Now have the address part of the MRI instruction. */
|
|
if(( clc & 060000) == ( temp & 060000))
|
|
{
|
|
value += ( temp & ADDRESS_FIELD ); /* In range MRI. */
|
|
}
|
|
else
|
|
{
|
|
if(( value & INDIRECT_BIT ) == INDIRECT_BIT )
|
|
{
|
|
/* Already indirect, can't generate */
|
|
errorSymbol( &illegal_indirect, symt->name, lexstartprev );
|
|
}
|
|
else
|
|
{
|
|
/* Now fix off page reference. */
|
|
/* Search current page literal pool for needed value. */
|
|
/* Set Indirect */
|
|
value += ( INDIRECT_BIT | insertLiteral( &cp, clc, temp & 077777));
|
|
indirect_generated = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
value = value + temp; /* Normal 18 bit value. */
|
|
if( value >= 0777777 ) value = ( value + 1 ) & 0777777;
|
|
break;
|
|
}
|
|
} /* end while */
|
|
} /* getExprs() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: getExpr */
|
|
/* */
|
|
/* Synopsis: Get an expression, from the current lexeme onward, leave the */
|
|
/* current lexeme as the one after the expression. Expressions */
|
|
/* contain terminal symbols (identifiers) separated by operators. */
|
|
/* */
|
|
/******************************************************************************/
|
|
SYM_T *getExpr()
|
|
{
|
|
delimiter = line[lexterm];
|
|
|
|
if( line[lexstart] == '-' )
|
|
{
|
|
nextLexBlank();
|
|
sym_getexpr = *(eval());
|
|
sym_getexpr.val = sym_getexpr.val ^ 0777777;
|
|
}
|
|
else
|
|
{
|
|
sym_getexpr = *(eval());
|
|
}
|
|
|
|
|
|
if( is_blank( delimiter ))
|
|
{
|
|
return( &sym_getexpr );
|
|
}
|
|
|
|
/* Here we assume the current lexeme is the operator separating the */
|
|
/* previous operator from the next, if any. */
|
|
while( TRUE )
|
|
{
|
|
/* assert line[lexstart] == delimiter */
|
|
if( is_blank( delimiter ))
|
|
{
|
|
return( &sym_getexpr );
|
|
}
|
|
|
|
switch( line[lexstart] )
|
|
{
|
|
case '+': /* add */
|
|
nextLexBlank(); /* skip over the operator */
|
|
sym_getexpr.val += (eval())->val;
|
|
if( sym_getexpr.val >= 01000000 )
|
|
{
|
|
sym_getexpr.val = ( sym_getexpr.val + 1 ) & 0777777;
|
|
}
|
|
break;
|
|
|
|
case '-': /* subtract */
|
|
nextLexBlank(); /* skip over the operator */
|
|
sym_getexpr.val = sym_getexpr.val +
|
|
( (eval())->val ^ 0777777 );
|
|
if( sym_getexpr.val >= 01000000 )
|
|
{
|
|
sym_getexpr.val = ( sym_getexpr.val + 1 ) & 0777777;
|
|
}
|
|
break;
|
|
|
|
case '^': /* multiply */
|
|
nextLexBlank(); /* skip over the operator */
|
|
sym_getexpr.val *= (eval())->val;
|
|
break;
|
|
|
|
case '%': /* divide */
|
|
nextLexBlank(); /* skip over the operator */
|
|
sym_getexpr.val /= (eval())->val;
|
|
break;
|
|
|
|
case '&': /* and */
|
|
nextLexBlank(); /* skip over the operator */
|
|
sym_getexpr.val &= (eval())->val;
|
|
break;
|
|
|
|
case '!': /* or */
|
|
nextLexBlank(); /* skip over the operator */
|
|
sym_getexpr.val |= (eval())->val;
|
|
break;
|
|
|
|
default:
|
|
if( isend( line[lexstart] ))
|
|
{
|
|
return( &sym_getexpr );
|
|
}
|
|
|
|
switch( line[lexstart] )
|
|
{
|
|
case '/':
|
|
case '\t':
|
|
case ')':
|
|
case '<':
|
|
case ':':
|
|
case ',':
|
|
break;
|
|
|
|
case '=':
|
|
errorMessage( &illegal_equals, lexstart );
|
|
moveToEndOfLine();
|
|
sym_getexpr.val = 0;
|
|
break;
|
|
|
|
default:
|
|
errorMessage( &illegal_expression, lexstart );
|
|
moveToEndOfLine();
|
|
sym_getexpr.val = 0;
|
|
break;
|
|
}
|
|
return( &sym_getexpr );
|
|
}
|
|
} /* end while */
|
|
} /* getExpr() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: eval */
|
|
/* */
|
|
/* Synopsis: Get the value of the current lexeme, set delimiter and advance.*/
|
|
/* */
|
|
/******************************************************************************/
|
|
SYM_T *eval()
|
|
{
|
|
WORD32 digit;
|
|
WORD32 from;
|
|
WORD32 loc;
|
|
SYM_T *sym;
|
|
WORD32 val;
|
|
|
|
val = 0;
|
|
|
|
delimiter = line[lexterm];
|
|
if( isalpha( line[lexstart] ))
|
|
{
|
|
sym = evalSymbol();
|
|
if( M_UNDEFINED( sym->type ))
|
|
{
|
|
if( pass == 2 )
|
|
{
|
|
errorSymbol( &undefined_symbol, sym->name, lexstart );
|
|
}
|
|
nextLexeme();
|
|
return( sym );
|
|
}
|
|
else if( M_PSEUDO( sym->type ))
|
|
{
|
|
if( sym->val == DECIMAL )
|
|
{
|
|
radix = 10;
|
|
}
|
|
else if( sym->val == OCTAL )
|
|
{
|
|
radix = 8;
|
|
}
|
|
else if( pass == 2 )
|
|
{
|
|
errorSymbol( &misplaced_symbol, sym->name, lexstart );
|
|
}
|
|
sym_eval.type = sym->type;
|
|
sym_eval.val = 0;
|
|
nextLexeme();
|
|
return( &sym_eval );
|
|
}
|
|
else if( M_MACRO( sym->type ))
|
|
{
|
|
if( pass == 2 )
|
|
{
|
|
errorSymbol( &misplaced_symbol, sym->name, lexstart );
|
|
}
|
|
sym_eval.type = sym->type;
|
|
sym_eval.val = 0;
|
|
nextLexeme();
|
|
return( &sym_eval );
|
|
}
|
|
else
|
|
{
|
|
nextLexeme();
|
|
return( sym );
|
|
}
|
|
}
|
|
else if( isdigit( line[lexstart] ))
|
|
{
|
|
from = lexstart;
|
|
val = 0;
|
|
while( from < lexterm )
|
|
{
|
|
if( isdigit( line[from] ))
|
|
{
|
|
digit = (WORD32) line[from++] - (WORD32) '0';
|
|
if( digit < radix )
|
|
{
|
|
val = val * radix + digit;
|
|
}
|
|
else
|
|
{
|
|
errorLexeme( &number_not_radix, from - 1 );
|
|
val = 0;
|
|
from = lexterm;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
errorLexeme( ¬_a_number, lexstart );
|
|
val = 0;
|
|
from = lexterm;
|
|
}
|
|
}
|
|
nextLexeme();
|
|
sym_eval.val = val;
|
|
return( &sym_eval );
|
|
}
|
|
else
|
|
{
|
|
switch( line[lexstart] )
|
|
{
|
|
case '"': /* Character literal */
|
|
if( cc + 2 < maxcc )
|
|
{
|
|
val = line[lexstart + 1] | 0200;
|
|
delimiter = line[lexstart + 2];
|
|
cc = lexstart + 2;
|
|
}
|
|
else
|
|
{
|
|
errorMessage( &no_literal_value, lexstart );
|
|
}
|
|
nextLexeme();
|
|
break;
|
|
|
|
case '.': /* Value of Current Location Counter */
|
|
val = clc;
|
|
nextLexeme();
|
|
break;
|
|
|
|
case '(': /* Generate literal on current page. */
|
|
nextLexBlank(); /* Skip paren */
|
|
val = getExprs() & 0777777;
|
|
|
|
if( line[lexstart] == ')' )
|
|
{
|
|
delimiter = line[lexterm];
|
|
nextLexeme(); /* Skip end paren */
|
|
}
|
|
else
|
|
{
|
|
/* errorMessage( "parens", NULL ); */
|
|
}
|
|
|
|
loc = insertLiteral( &cp, clc, val );
|
|
sym_eval.val = loc + ( clc & 060000 );
|
|
return( &sym_eval );
|
|
|
|
default:
|
|
switch( line[lexstart] )
|
|
{
|
|
case '=':
|
|
errorMessage( &illegal_equals, lexstart );
|
|
moveToEndOfLine();
|
|
break;
|
|
|
|
default:
|
|
errorMessage( &illegal_character, lexstart );
|
|
break;
|
|
}
|
|
val = 0; /* On error, set value to zero. */
|
|
nextLexBlank(); /* Go past illegal character. */
|
|
}
|
|
}
|
|
sym_eval.val = val;
|
|
return( &sym_eval );
|
|
} /* eval() */
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: incrementClc */
|
|
/* */
|
|
/* Synopsis: Set the next assembly location. Test for collision with */
|
|
/* the literal tables. */
|
|
/* */
|
|
/******************************************************************************/
|
|
WORD32 incrementClc()
|
|
{
|
|
testForLiteralCollision( clc );
|
|
clc = (( clc + 1 ) & ADDRESS_FIELD );
|
|
return( clc );
|
|
} /* incrementClc() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: testForLiteralCollision */
|
|
/* */
|
|
/* Synopsis: Test the given location for collision with the literal tables. */
|
|
/* */
|
|
/******************************************************************************/
|
|
BOOL testForLiteralCollision( WORD32 loc )
|
|
{
|
|
WORD32 pagelc;
|
|
BOOL result = FALSE;
|
|
|
|
pagelc = loc & ADDRESS_FIELD;
|
|
if( ( pagelc >= lit_loc ) && ( lit_loc != LIT_BASE ) && !cp.error )
|
|
{
|
|
errorMessage( &literal_overflow, -1 );
|
|
cp.error = TRUE;
|
|
result = TRUE;
|
|
}
|
|
return( result );
|
|
} /* testForLiteralCollision() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: readLine */
|
|
/* */
|
|
/* Synopsis: Get next line of input. Print previous line if needed. */
|
|
/* */
|
|
/******************************************************************************/
|
|
void readLine()
|
|
{
|
|
BOOL ffseen;
|
|
WORD32 ix;
|
|
WORD32 iy;
|
|
char mc;
|
|
char inpline[4*LINELEN];
|
|
|
|
listLine(); /* List previous line if needed. */
|
|
indirect_generated = FALSE; /* Mark no indirect address generated. */
|
|
error_in_line = FALSE; /* No error in line. */
|
|
|
|
if( mac_ptr && ( *mac_ptr == '\0' )) /* End of macro? */
|
|
{
|
|
mac_ptr = NULL;
|
|
for( ix = 0; ix < LINELEN; ix++ )
|
|
{
|
|
line[ix] = mac_line[ix]; /* Restore invoking line. */
|
|
}
|
|
cc = lexstartprev = mac_cc; /* Restore cc. */
|
|
maxcc = strlen( line ); /* Restore maxcc. */
|
|
listed = TRUE; /* Already listed. */
|
|
return;
|
|
}
|
|
|
|
cc = 0; /* Initialize column counter. */
|
|
lexstartprev = 0;
|
|
if( mac_ptr ) /* Inside macro? */
|
|
{
|
|
maxcc = 0;
|
|
do
|
|
{
|
|
mc = *mac_ptr++; /* Next character. */
|
|
if( islower( mc )) /* Encoded argument number? */
|
|
{
|
|
ix = mc - 'a'; /* Convert to index. */
|
|
if( iy = mac_arg_pos[ix] )
|
|
{
|
|
do /* Copy argument string. */
|
|
{
|
|
line[maxcc++] = mac_line[iy++];
|
|
} while(( mac_line[iy] != ',' ) && ( !is_blank( mac_line[iy] )) &&
|
|
( !isdone( mac_line[iy] )));
|
|
}
|
|
}
|
|
else /* Ordinary character, just copy. */
|
|
{
|
|
line[maxcc++] = mc;
|
|
}
|
|
} while( !isend( mc ));
|
|
line[maxcc] = '\0';
|
|
listed = nomac_exp;
|
|
return;
|
|
}
|
|
|
|
lineno++; /* Count lines read. */
|
|
listed = FALSE; /* Mark as not listed. */
|
|
READ_LINE:
|
|
if(( fgets( inpline, LINELEN - 1, infile )) == NULL )
|
|
{
|
|
filix_curr++; /* Advance to next file. */
|
|
if( filix_curr < save_argc ) /* More files? */
|
|
{
|
|
fclose( infile );
|
|
if(( infile = fopen( save_argv[filix_curr], "r" )) == NULL )
|
|
{
|
|
fprintf( stderr, "%s: cannot open \"%s\"\n", save_argv[0],
|
|
save_argv[filix_curr] );
|
|
exit( -1 );
|
|
}
|
|
goto READ_LINE;
|
|
}
|
|
else
|
|
{
|
|
end_of_input = TRUE;
|
|
}
|
|
}
|
|
|
|
ffseen = FALSE;
|
|
for( ix = 0, iy = 0; inpline[ix] != '\0'; ix++ )
|
|
{
|
|
if( inpline[ix] == '\f' )
|
|
{
|
|
if( !ffseen && list_title_set ) topOfForm( list_title, NULL );
|
|
ffseen = TRUE;
|
|
}
|
|
else
|
|
{
|
|
line[iy++] = inpline[ix];
|
|
}
|
|
}
|
|
line[iy] = '\0';
|
|
|
|
/* If the line is terminated by CR-LF, remove, the CR. */
|
|
if( line[iy - 2] == '\r' )
|
|
{
|
|
iy--;
|
|
line[iy - 1] = line[iy - 0];
|
|
line[iy] = '\0';
|
|
}
|
|
maxcc = iy; /* Save the current line length. */
|
|
} /* readLine() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: listLine */
|
|
/* */
|
|
/* Synopsis: Output a line to the listing file. */
|
|
/* */
|
|
/******************************************************************************/
|
|
void listLine()
|
|
/* generate a line of listing if not already done! */
|
|
{
|
|
if( listfile != NULL && listed == FALSE )
|
|
{
|
|
printLine( line, 0, 0, LINE );
|
|
}
|
|
} /* listLine() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: printPageBreak */
|
|
/* */
|
|
/* Synopsis: Output a Top of Form and listing header if new page necessary. */
|
|
/* */
|
|
/******************************************************************************/
|
|
void printPageBreak()
|
|
{
|
|
if( page_lineno >= LIST_LINES_PER_PAGE )
|
|
/* ( list_lineno % LIST_LINES_PER_PAGE ) == 0 ) */
|
|
{
|
|
if( !list_title_set )
|
|
{
|
|
strcpy( list_title, line );
|
|
if( list_title[strlen(list_title) - 1] == '\n' )
|
|
{
|
|
list_title[strlen(list_title) - 1] = '\0';
|
|
}
|
|
if( strlen( list_title ) > TITLELEN )
|
|
{
|
|
list_title[TITLELEN] = '\0';
|
|
}
|
|
list_title_set = TRUE;
|
|
}
|
|
topOfForm( list_title, NULL );
|
|
|
|
}
|
|
} /* printPageBreak() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: printLine */
|
|
/* */
|
|
/* Synopsis: Output a line to the listing file with new page if necessary. */
|
|
/* */
|
|
/******************************************************************************/
|
|
void printLine( char *line, WORD32 loc, WORD32 val, LINESTYLE_T linestyle )
|
|
{
|
|
if( listfile == NULL )
|
|
{
|
|
save_error_count = 0;
|
|
return;
|
|
}
|
|
|
|
printPageBreak();
|
|
|
|
list_lineno++;
|
|
page_lineno++;
|
|
switch( linestyle )
|
|
{
|
|
default:
|
|
case LINE:
|
|
fprintf( listfile, "%5d ", lineno );
|
|
fputs( line, listfile );
|
|
listed = TRUE;
|
|
break;
|
|
|
|
case LINE_VAL:
|
|
if( !listed )
|
|
{
|
|
fprintf( listfile, "%5d %6.6o ", lineno, val );
|
|
fputs( line, listfile );
|
|
listed = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fprintf( listfile, " %6.6o\n", val );
|
|
}
|
|
break;
|
|
|
|
case LINE_LOC_VAL:
|
|
if( !listed )
|
|
{
|
|
if( indirect_generated )
|
|
{
|
|
fprintf( listfile, "%5d %5.5o %6.6o@ ", lineno, loc, val );
|
|
}
|
|
else
|
|
{
|
|
fprintf( listfile, "%5d %5.5o %6.6o ", lineno, loc, val );
|
|
}
|
|
fputs( line, listfile );
|
|
listed = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fprintf( listfile, " %5.5o %6.6o\n", loc, val );
|
|
}
|
|
break;
|
|
|
|
case LOC_VAL:
|
|
fprintf( listfile, " %5.5o %6.6o\n", loc, val );
|
|
break;
|
|
}
|
|
printErrorMessages();
|
|
} /* printLine() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: printErrorMessages */
|
|
/* */
|
|
/* Synopsis: Output any error messages from the current list of errors. */
|
|
/* */
|
|
/******************************************************************************/
|
|
void printErrorMessages()
|
|
{
|
|
WORD32 ix;
|
|
WORD32 iy;
|
|
|
|
if( listfile != NULL )
|
|
{
|
|
/* If any errors, display them now. */
|
|
for( iy = 0; iy < save_error_count; iy++ )
|
|
{
|
|
printPageBreak();
|
|
fprintf( listfile, "%-18.18s ", error_list[iy].mesg );
|
|
if( error_list[iy].col >= 0 )
|
|
{
|
|
for( ix = 0; ix < error_list[iy].col; ix++ )
|
|
{
|
|
if( line[ix] == '\t' )
|
|
{
|
|
putc( '\t', listfile );
|
|
}
|
|
else
|
|
{
|
|
putc( ' ', listfile );
|
|
}
|
|
}
|
|
fputs( "^", listfile );
|
|
list_lineno++;
|
|
page_lineno++;
|
|
}
|
|
fputs( "\n", listfile );
|
|
}
|
|
}
|
|
save_error_count = 0;
|
|
} /* printErrorMessages() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: endOfBinary */
|
|
/* */
|
|
/* Synopsis: Outputs both literal tables at the end of a binary segment. */
|
|
/* */
|
|
/******************************************************************************/
|
|
void endOfBinary()
|
|
{
|
|
punchLiteralPool( &cp, clc - 1 );
|
|
if( start_addr >= 0)
|
|
{
|
|
punchTriplet( JMP | ( start_addr & 017777 ));
|
|
punchTriplet( 0 );
|
|
}
|
|
return;
|
|
} /* endOfBinary() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: punchLeader */
|
|
/* */
|
|
/* Synopsis: Generate 2 feet of leader on object file, as per DEC */
|
|
/* documentation. Paper tape has 10 punches per inch. */
|
|
/* */
|
|
/******************************************************************************/
|
|
void punchLeader( WORD32 count )
|
|
{
|
|
WORD32 ix;
|
|
|
|
/* If value is zero, set to the default of 2 feet of leader. */
|
|
count = ( count == 0 ) ? 240 : count;
|
|
|
|
if( objectfile != NULL )
|
|
{
|
|
for( ix = 0; ix < count; ix++ )
|
|
{
|
|
fputc( 0, objectfile );
|
|
}
|
|
}
|
|
} /* punchLeader() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: punchObject */
|
|
/* */
|
|
/* Synopsis: Put one character to object file and include it in checksum. */
|
|
/* */
|
|
/******************************************************************************/
|
|
void punchObject( WORD32 val )
|
|
{
|
|
val &= 0377;
|
|
if( objectfile != NULL )
|
|
{
|
|
fputc( val, objectfile );
|
|
}
|
|
checksum += val;
|
|
binary_data_output = TRUE;
|
|
} /* punchObject() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: punchOutObject */
|
|
/* */
|
|
/* Synopsis: Output the current line and then then punch value to the */
|
|
/* object file. */
|
|
/* */
|
|
/******************************************************************************/
|
|
void punchOutObject( WORD32 loc, WORD32 val )
|
|
{
|
|
printLine( line, loc, val, LINE_LOC_VAL );
|
|
punchLocObject( loc, val );
|
|
} /* punchOutObject() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: punchLocObject */
|
|
/* */
|
|
/* Synopsis: Output the word (with origin if rim format) to the object file.*/
|
|
/* */
|
|
/******************************************************************************/
|
|
void punchLocObject( WORD32 loc, WORD32 val )
|
|
{
|
|
punchTriplet( DAC | loc );
|
|
punchTriplet( val );
|
|
} /* punchLocObject() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: punchTriplet */
|
|
/* */
|
|
/* Synopsis: Output 18b word as three 6b characters with ho bit set. */
|
|
/* */
|
|
/******************************************************************************/
|
|
void punchTriplet( WORD32 val )
|
|
{
|
|
punchObject((( val >> 12) & 077) | 0200 );
|
|
punchObject((( val >> 6 ) & 077) | 0200 );
|
|
punchObject(( val & 077) | 0200 );
|
|
} /* punchTriplet */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: punchLiteralPool */
|
|
/* */
|
|
/* Synopsis: Output the current page data. */
|
|
/* */
|
|
/******************************************************************************/
|
|
void punchLiteralPool( LPOOL_T *p, WORD32 lpool_page )
|
|
{
|
|
WORD32 loc;
|
|
WORD32 tmplc;
|
|
|
|
if( lit_loc < LIT_BASE )
|
|
{
|
|
for( loc = lit_loc; loc < LIT_BASE; loc++ )
|
|
{
|
|
tmplc = loc + ( lpool_page & 060000 );
|
|
printLine( line, tmplc, p->pool[loc], LOC_VAL );
|
|
punchLocObject( tmplc, p->pool[loc] );
|
|
}
|
|
p->error = FALSE;
|
|
lit_loc = LIT_BASE;
|
|
}
|
|
} /* punchLiteralPool() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: insertLiteral */
|
|
/* */
|
|
/* Synopsis: Add a value to the given literal pool if not already in pool. */
|
|
/* Return the location of the value in the pool. */
|
|
/* */
|
|
/******************************************************************************/
|
|
WORD32 insertLiteral( LPOOL_T *p, WORD32 pool_page, WORD32 value )
|
|
{
|
|
WORD32 ix;
|
|
|
|
/* Search the literal pool for any occurence of the needed value. */
|
|
ix = LIT_BASE - 1;
|
|
while( ix >= lit_loc && p->pool[ix] != value )
|
|
{
|
|
ix--;
|
|
}
|
|
|
|
/* Check if value found in literal pool. If not, then insert value. */
|
|
if( ix < lit_loc )
|
|
{
|
|
lit_loc--;
|
|
p->pool[lit_loc] = value;
|
|
ix = lit_loc;
|
|
}
|
|
return( ix );
|
|
} /* insertLiteral() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: printSymbolTable */
|
|
/* */
|
|
/* Synopsis: Output the symbol table. */
|
|
/* */
|
|
/******************************************************************************/
|
|
void printSymbolTable()
|
|
{
|
|
int col;
|
|
int cx;
|
|
char *fmt;
|
|
int ix;
|
|
char mark;
|
|
int page;
|
|
int row;
|
|
int symbol_base;
|
|
int symbol_lines;
|
|
|
|
symbol_base = number_of_fixed_symbols;
|
|
|
|
for( page=0, list_lineno=0, col=0, ix=symbol_base; ix < symbol_top; page++ )
|
|
{
|
|
topOfForm( list_title, s_symtable );
|
|
symbol_lines = LIST_LINES_PER_PAGE - page_lineno;
|
|
|
|
for( row = 0; page_lineno < LIST_LINES_PER_PAGE && ix < symbol_top; row++)
|
|
{
|
|
list_lineno++;
|
|
page_lineno++;
|
|
fprintf( listfile, "%5d", list_lineno );
|
|
|
|
for( col = 0; col < SYMBOL_COLUMNS && ix < symbol_top; col++ )
|
|
{
|
|
/* Get index of symbol for the current line and column */
|
|
cx = symbol_lines * ( SYMBOL_COLUMNS * page + col ) + row;
|
|
cx += symbol_base;
|
|
|
|
/* Make sure that there is a symbol to be printed. */
|
|
if( number_of_fixed_symbols <= cx && cx < symbol_top )
|
|
{
|
|
switch( symtab[cx].type & LABEL )
|
|
{
|
|
case LABEL:
|
|
fmt = " %c%-6.6s %5.5o ";
|
|
break;
|
|
|
|
default:
|
|
fmt = " %c%-6.6s %4.4o ";
|
|
break;
|
|
}
|
|
|
|
switch( symtab[cx].type & ( DEFINED | REDEFINED ))
|
|
{
|
|
case UNDEFINED:
|
|
mark = '?';
|
|
break;
|
|
|
|
case REDEFINED:
|
|
mark = '#';
|
|
break;
|
|
|
|
default:
|
|
mark = ' ';
|
|
break;
|
|
}
|
|
fprintf( listfile, fmt, mark, symtab[cx].name, symtab[cx].val );
|
|
ix++;
|
|
}
|
|
}
|
|
fprintf( listfile, "\n" );
|
|
}
|
|
}
|
|
} /* printSymbolTable() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: printPermanentSymbolTable */
|
|
/* */
|
|
/* Synopsis: Output the permanent symbol table to a file suitable for */
|
|
/* being input after the EXPUNGE pseudo-op. */
|
|
/* */
|
|
/******************************************************************************/
|
|
void printPermanentSymbolTable()
|
|
{
|
|
int ix;
|
|
FILE *permfile;
|
|
char *s_type;
|
|
|
|
if(( permfile = fopen( permpathname, "w" )) == NULL )
|
|
{
|
|
exit( 2 );
|
|
}
|
|
|
|
fprintf( permfile, "/ PERMANENT SYMBOL TABLE\n/\n" );
|
|
fprintf( permfile, " EXPUNGE\n/\n" );
|
|
/* Print the memory reference instructions first. */
|
|
s_type = "FIXMRI";
|
|
for( ix = 0; ix < symbol_top; ix++ )
|
|
{
|
|
if( M_MRI( symtab[ix].type ))
|
|
{
|
|
fprintf( permfile, "%-7s %s=%4.4o\n",
|
|
s_type, symtab[ix].name, symtab[ix].val );
|
|
}
|
|
}
|
|
|
|
s_type = " ";
|
|
for( ix = 0; ix < symbol_top; ix++ )
|
|
{
|
|
if( M_FIXED( symtab[ix].type ))
|
|
{
|
|
if( !M_MRI( symtab[ix].type ) && !M_PSEUDO( symtab[ix].type ))
|
|
{
|
|
fprintf( permfile, "%-7s %s=%4.4o\n",
|
|
s_type, symtab[ix].name, symtab[ix].val );
|
|
}
|
|
}
|
|
}
|
|
fprintf( permfile, "/\n FIXTAB\n" );
|
|
fclose( permfile );
|
|
} /* printPermanentSymbolTable() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: printCrossReference */
|
|
/* */
|
|
/* Synopsis: Output a cross reference (concordance) for the file being */
|
|
/* assembled. */
|
|
/* */
|
|
/******************************************************************************/
|
|
void printCrossReference()
|
|
{
|
|
int ix;
|
|
int symbol_base;
|
|
int xc;
|
|
int xc_index;
|
|
int xc_refcount;
|
|
int xc_cols;
|
|
|
|
/* Force top of form for first page. */
|
|
page_lineno = LIST_LINES_PER_PAGE;
|
|
|
|
list_lineno = 0;
|
|
symbol_base = number_of_fixed_symbols;
|
|
|
|
for( ix = symbol_base; ix < symbol_top; ix++ )
|
|
{
|
|
list_lineno++;
|
|
page_lineno++;
|
|
if( page_lineno >= LIST_LINES_PER_PAGE )
|
|
{
|
|
topOfForm( list_title, s_xref );
|
|
}
|
|
|
|
fprintf( listfile, "%5d", list_lineno );
|
|
|
|
/* Get reference count & index into concordance table for this symbol. */
|
|
xc_refcount = symtab[ix].xref_count;
|
|
xc_index = symtab[ix].xref_index;
|
|
/* Determine how to label symbol on concordance. */
|
|
switch( symtab[ix].type & ( DEFINED | REDEFINED ))
|
|
{
|
|
case UNDEFINED:
|
|
fprintf( listfile, " U ");
|
|
break;
|
|
|
|
case REDEFINED:
|
|
fprintf( listfile, " M %5d ", xreftab[xc_index] );
|
|
break;
|
|
|
|
default:
|
|
fprintf( listfile, " A %5d ", xreftab[xc_index] );
|
|
break;
|
|
}
|
|
fprintf( listfile, "%-6.6s ", symtab[ix].name );
|
|
|
|
/* Output the references, 8 numbers per line after symbol name. */
|
|
for( xc_cols = 0, xc = 1; xc < xc_refcount + 1; xc++, xc_cols++ )
|
|
{
|
|
if( xc_cols >= XREF_COLUMNS )
|
|
{
|
|
xc_cols = 0;
|
|
page_lineno++;
|
|
if( page_lineno >= LIST_LINES_PER_PAGE )
|
|
{
|
|
topOfForm( list_title, s_xref);
|
|
}
|
|
list_lineno++;
|
|
fprintf( listfile, "\n%5d%-19s", list_lineno, " " );
|
|
}
|
|
fprintf( listfile, " %5d", xreftab[xc_index + xc] );
|
|
}
|
|
fprintf( listfile, "\n" );
|
|
}
|
|
} /* printCrossReference() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: topOfForm */
|
|
/* */
|
|
/* Synopsis: Prints title and sub-title on top of next page of listing. */
|
|
/* */
|
|
/******************************************************************************/
|
|
void topOfForm( char *title, char *sub_title )
|
|
{
|
|
char temp[10];
|
|
|
|
list_pageno++;
|
|
strcpy( temp, s_page );
|
|
sprintf( temp, "%s %d", s_page, list_pageno );
|
|
|
|
/* Output a top of form if not the first page of the listing. */
|
|
if( list_pageno > 1 )
|
|
{
|
|
fprintf( listfile, "\f" );
|
|
}
|
|
fprintf( listfile, "\n %-63s %10s\n", title, temp );
|
|
|
|
/* Reset the current page line counter. */
|
|
page_lineno = 1;
|
|
if( sub_title != NULL )
|
|
{
|
|
fprintf( listfile, "%80s\n", sub_title );
|
|
page_lineno++;
|
|
}
|
|
else
|
|
{
|
|
fprintf( listfile, "\n" );
|
|
page_lineno++;
|
|
}
|
|
fprintf( listfile, "\n" );
|
|
page_lineno++;
|
|
} /* topOfForm() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: lexemeToName */
|
|
/* */
|
|
/* Synopsis: Convert the current lexeme into a string. */
|
|
/* */
|
|
/******************************************************************************/
|
|
char *lexemeToName( char *name, WORD32 from, WORD32 term )
|
|
{
|
|
WORD32 to;
|
|
|
|
to = 0;
|
|
|
|
while( from < term && to < ( SYMLEN - 1 ))
|
|
{
|
|
name[to++] = toupper( line[from++] );
|
|
}
|
|
|
|
while( to < SYMLEN )
|
|
{
|
|
name[to++] = '\0';
|
|
}
|
|
return( name );
|
|
} /* lexemeToName() */
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: defineLexeme */
|
|
/* */
|
|
/* Synopsis: Put lexeme into symbol table with a value. */
|
|
/* */
|
|
/******************************************************************************/
|
|
SYM_T *defineLexeme( WORD32 start, /* start of lexeme being defined. */
|
|
WORD32 term, /* end+1 of lexeme being defined. */
|
|
WORD32 val, /* value of lexeme being defined. */
|
|
SYMTYP type ) /* how symbol is being defined. */
|
|
{
|
|
char name[SYMLEN];
|
|
|
|
lexemeToName( name, start, term);
|
|
return( defineSymbol( name, val, type, start ));
|
|
} /* defineLexeme() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: defineSymbol */
|
|
/* */
|
|
/* Synopsis: Define a symbol in the symbol table, enter symbol name if not */
|
|
/* not already in table. */
|
|
/* */
|
|
/******************************************************************************/
|
|
SYM_T *defineSymbol( char *name, WORD32 val, SYMTYP type, WORD32 start )
|
|
{
|
|
SYM_T *sym;
|
|
WORD32 xref_count;
|
|
|
|
if( strlen( name ) < 1 )
|
|
{
|
|
return( &sym_undefined ); /* Protect against non-existent names. */
|
|
}
|
|
sym = lookup( name );
|
|
xref_count = 0; /* Set concordance for normal defintion. */
|
|
|
|
if( M_DEFINED( sym->type ) && sym->val != val && M_NOTRDEF( sym -> type ))
|
|
{
|
|
if( pass == 2 )
|
|
{
|
|
errorSymbol( &redefined_symbol, sym->name, start );
|
|
type = type | REDEFINED;
|
|
sym->xref_count++; /* Referenced symbol, count it. */
|
|
xref_count = sym->xref_count;
|
|
}
|
|
return ( sym );
|
|
}
|
|
|
|
if( pass == 2 && xref )
|
|
{
|
|
/* Put the definition line number in the concordance table. */
|
|
/* Defined symbols are not counted as references. */
|
|
xreftab[sym->xref_index] = lineno;
|
|
/* Put the line number in the concordance table. */
|
|
xreftab[sym->xref_index + xref_count] = lineno;
|
|
}
|
|
|
|
/* Now set the value and the type. */
|
|
sym->val = ( type == LABEL) ? val : val & 0777777;
|
|
sym->type = ( pass == 1 ) ? ( type | CONDITION ) : type;
|
|
return( sym );
|
|
} /* defineSymbol() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: lookup */
|
|
/* */
|
|
/* Synopsis: Find a symbol in table. If not in table, enter symbol in */
|
|
/* table as undefined. Return address of symbol in table. */
|
|
/* */
|
|
/******************************************************************************/
|
|
SYM_T *lookup( char *name )
|
|
{
|
|
int ix; /* Insertion index */
|
|
int lx; /* Left index */
|
|
int rx; /* Right index */
|
|
|
|
/* First search the permanent symbols. */
|
|
lx = 0;
|
|
ix = binarySearch( name, lx, number_of_fixed_symbols );
|
|
|
|
/* If symbol not in permanent symbol table. */
|
|
if( ix < 0 )
|
|
{
|
|
/* Now try the user symbol table. */
|
|
ix = binarySearch( name, number_of_fixed_symbols, symbol_top );
|
|
|
|
/* If symbol not in user symbol table. */
|
|
if( ix < 0 )
|
|
{
|
|
/* Must put symbol in table if index is negative. */
|
|
ix = ~ix;
|
|
if( symbol_top + 1 >= SYMBOL_TABLE_SIZE )
|
|
{
|
|
errorSymbol( &symbol_table_full, name, lexstart );
|
|
exit( 1 );
|
|
}
|
|
|
|
for( rx = symbol_top; rx >= ix; rx-- )
|
|
{
|
|
symtab[rx + 1] = symtab[rx];
|
|
}
|
|
symbol_top++;
|
|
|
|
/* Enter the symbol as UNDEFINED with a value of zero. */
|
|
strcpy( symtab[ix].name, name );
|
|
symtab[ix].type = UNDEFINED;
|
|
symtab[ix].val = 0;
|
|
symtab[ix].xref_count = 0;
|
|
if( xref && pass == 2 )
|
|
{
|
|
xreftab[symtab[ix].xref_index] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return( &symtab[ix] ); /* Return the location of the symbol. */
|
|
} /* lookup() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: binarySearch */
|
|
/* */
|
|
/* Synopsis: Searches the symbol table within the limits given. If the */
|
|
/* symbol is not in the table, it returns the insertion point. */
|
|
/* */
|
|
/******************************************************************************/
|
|
int binarySearch( char *name, int start, int symbol_count )
|
|
{
|
|
int lx; /* Left index */
|
|
int mx; /* Middle index */
|
|
int rx; /* Right index */
|
|
int compare; /* Results of comparison */
|
|
|
|
lx = start;
|
|
rx = symbol_count - 1;
|
|
while( lx <= rx )
|
|
{
|
|
mx = ( lx + rx ) / 2; /* Find center of search area. */
|
|
|
|
compare = strcmp( name, symtab[mx].name );
|
|
|
|
if( compare < 0 )
|
|
{
|
|
rx = mx - 1;
|
|
}
|
|
else if( compare > 0 )
|
|
{
|
|
lx = mx + 1;
|
|
}
|
|
else
|
|
{
|
|
return( mx ); /* Found a match in symbol table. */
|
|
}
|
|
} /* end while */
|
|
return( ~lx ); /* Return insertion point. */
|
|
} /* binarySearch() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: compareSymbols */
|
|
/* */
|
|
/* Synopsis: Used to presort the symbol table when starting assembler. */
|
|
/* */
|
|
/******************************************************************************/
|
|
int compareSymbols( const void *a, const void *b )
|
|
{
|
|
return( strcmp( ((SYM_T *) a)->name, ((SYM_T *) b)->name ));
|
|
} /* compareSymbols() */
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: copyMacLine */
|
|
/* */
|
|
/* Synopsis: Used to copy a macro line to the macro buffer. */
|
|
/* */
|
|
/******************************************************************************/
|
|
int copyMacLine( int length, int from, int term, int nargs )
|
|
{
|
|
char name[SYMLEN];
|
|
int ix;
|
|
int jx;
|
|
int kx;
|
|
BOOL bl;
|
|
|
|
bl = TRUE;
|
|
for( ix = from; ix < term; ix++ )
|
|
{
|
|
if( !is_blank( line[ix] ) || ( line[ix] == '\t' )) bl = FALSE;
|
|
}
|
|
if( bl || ( length < 0 )) return length;
|
|
if(( length + term - from + 1) >= MAC_MAX_LENGTH ) return -1;
|
|
for( ix = from; ix < term; )
|
|
{
|
|
if( nargs && isalpha( line[ix] )) /* Start of symbol? */
|
|
{
|
|
for( jx = ix + 1; jx < term; jx++) /* Find end of symbol. */
|
|
{
|
|
if( !isalnum( line[jx] )) break;
|
|
}
|
|
lexemeToName( name, ix, jx ); /* Make into name. */
|
|
for( kx = 0; kx < nargs; kx++ ) /* Compare to arguments. */
|
|
{
|
|
if( strncmp( name, &mac_arg_name[kx + 1][0], SYMLEN ) == 0 )
|
|
{
|
|
mac_buffer[length++] = 'a' + (char) kx;
|
|
for( ix++; ix < jx; ix++ )
|
|
{
|
|
mac_buffer[length++] = 'z';
|
|
}
|
|
break;
|
|
} /* end if strncmp */
|
|
} /* end for kx */
|
|
if( kx >= nargs )
|
|
{
|
|
for ( ; ix < jx; )
|
|
{
|
|
mac_buffer[length++] = toupper( line[ix++] );
|
|
}
|
|
}
|
|
} /*end if nargs */
|
|
else
|
|
{
|
|
mac_buffer[length++] = toupper( line[ix++] );
|
|
} /* end else */
|
|
} /* end for ix */
|
|
mac_buffer[length++] = '\n';
|
|
mac_buffer[length] = 0;
|
|
return length;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: evalSymbol */
|
|
/* */
|
|
/* Synopsis: Get the pointer for the symbol table entry if exists. */
|
|
/* If symbol doesn't exist, return a pointer to the undefined sym */
|
|
/* */
|
|
/******************************************************************************/
|
|
SYM_T *evalSymbol()
|
|
{
|
|
char name[SYMLEN];
|
|
SYM_T *sym;
|
|
|
|
sym = lookup( lexemeToName( name, lexstart, lexterm ));
|
|
|
|
sym->xref_count++; /* Count the number of references to symbol. */
|
|
|
|
if( xref && pass == 2 )
|
|
{
|
|
/* Put the line number in the concordance table. */
|
|
xreftab[sym->xref_index + sym->xref_count] = lineno;
|
|
}
|
|
|
|
return( sym );
|
|
} /* evalSymbol() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: moveToEndOfLine */
|
|
/* */
|
|
/* Synopsis: Move the parser input to the end of the current input line. */
|
|
/* */
|
|
/******************************************************************************/
|
|
void moveToEndOfLine()
|
|
{
|
|
while( !isend( line[cc] )) cc++;
|
|
lexstart = cc;
|
|
lexterm = cc;
|
|
lexstartprev = lexstart;
|
|
} /* moveToEndOfLine() */
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: nextLexeme */
|
|
/* */
|
|
/* Synopsis: Get the next lexical element from input line. */
|
|
/* */
|
|
/******************************************************************************/
|
|
void nextLexeme()
|
|
{
|
|
/* Save start column of previous lexeme for diagnostic messages. */
|
|
lexstartprev = lexstart;
|
|
lextermprev = lexterm;
|
|
|
|
while( is_blank( line[cc] ) ||
|
|
(( line[cc] == '\t' ) && ( line[cc+1] == '\t' )) ||
|
|
(( line[cc] == '\t' ) && isdone( line[cc+1] ))) { cc++; }
|
|
lexstart = cc;
|
|
|
|
if( isalnum( line[cc] ))
|
|
{
|
|
while( isalnum( line[cc] )) { cc++; }
|
|
}
|
|
else if( isend( line[cc] ))
|
|
{
|
|
/* End-of-Line, don't advance cc! */
|
|
}
|
|
else
|
|
{
|
|
switch( line[cc] )
|
|
{
|
|
case '"': /* Quoted letter */
|
|
if( cc + 2 < maxcc )
|
|
{
|
|
cc++;
|
|
cc++;
|
|
}
|
|
else
|
|
{
|
|
errorMessage( &no_literal_value, lexstart );
|
|
cc++;
|
|
}
|
|
break;
|
|
|
|
case '/': /* Comment, don't advance cc! */
|
|
break;
|
|
|
|
default: /* All other punctuation. */
|
|
cc++;
|
|
break;
|
|
}
|
|
}
|
|
lexterm = cc;
|
|
} /* nextLexeme() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: nextLexBlank */
|
|
/* */
|
|
/* Synopsis: Used to prevent illegal blanks in expressions. */
|
|
/* */
|
|
/******************************************************************************/
|
|
void nextLexBlank()
|
|
{
|
|
nextLexeme();
|
|
if( is_blank( delimiter ))
|
|
{
|
|
errorMessage( &illegal_blank, lexstart - 1 );
|
|
}
|
|
delimiter = line[lexterm];
|
|
} /* nextLexBlank() */
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: pseudoOperators */
|
|
/* */
|
|
/* Synopsis: Process pseudo-ops (directives). */
|
|
/* */
|
|
/******************************************************************************/
|
|
BOOL pseudoOperators( PSEUDO_T val )
|
|
{
|
|
int count;
|
|
int delim;
|
|
int index;
|
|
int ix;
|
|
WORD32 length;
|
|
int level;
|
|
int lexstartsave;
|
|
int pack;
|
|
int pos;
|
|
int radixprev;
|
|
BOOL status;
|
|
SYM_T *sym;
|
|
WORD32 value;
|
|
WORD32 word;
|
|
int width;
|
|
static int mask_tab[19] = { 0000000,
|
|
0000001, 0000003, 0000007, 0000017, 0000037, 0000077,
|
|
0000177, 0000377, 0000777, 0001777, 0003777, 0007777,
|
|
0017777, 0037777, 0077777, 0177777, 0377777, 0777777 };
|
|
|
|
status = TRUE;
|
|
switch( (PSEUDO_T) val )
|
|
{
|
|
case DECIMAL:
|
|
radix = 10;
|
|
break;
|
|
|
|
case DEFINE:
|
|
count = 0;
|
|
index = 0;
|
|
lexstartsave = lexstart;
|
|
while(( line[lexstart] != '<' ) && ( !isdone( line[lexstart] )) &&
|
|
( count < MAC_MAX_ARGS ))
|
|
{
|
|
if ( !isalpha( line[lexstart] ) && ( index == 0 ))
|
|
{
|
|
index = lexstart;
|
|
}
|
|
lexemeToName( &mac_arg_name[count++][0], lexstart, lexterm );
|
|
nextLexeme();
|
|
}
|
|
if( count == 0 ) /* No macro name. */
|
|
{
|
|
errorMessage( &no_macro_name, lexstartsave );
|
|
index = 1;
|
|
}
|
|
else if( index ) /* Bad argument name. */
|
|
{
|
|
errorMessage( &bad_dummy_arg, index );
|
|
}
|
|
else if( mac_count >= MAC_TABLE_LENGTH )
|
|
{
|
|
errorMessage( ¯o_table_full, lexstartsave );
|
|
index = 1;
|
|
}
|
|
else
|
|
{
|
|
value = mac_count;
|
|
mac_count++; /* Value is entry in mac_bodies. */
|
|
defineSymbol( &mac_arg_name[0][0], value, MACRO, lexstartsave );
|
|
}
|
|
if( isend( line[lexstart] ) || ( line[lexstart] == '/' ))
|
|
{
|
|
readLine();
|
|
nextLexeme();
|
|
}
|
|
if( index )
|
|
{
|
|
conditionFalse(); /* On error skip macro body. */
|
|
}
|
|
else if( line[lexstart] == '<' )
|
|
{
|
|
/* Invariant: line[cc] is the next unexamined character. */
|
|
index = lexstart + 1;
|
|
length = 0;
|
|
level = 1;
|
|
while( level > 0 )
|
|
{
|
|
if( end_of_input )
|
|
{
|
|
break;
|
|
}
|
|
if( isend( line[cc] ) || ( line[cc] == '/' ))
|
|
{
|
|
length = copyMacLine( length, index, cc, count - 1 );
|
|
readLine();
|
|
index = 0;
|
|
}
|
|
else
|
|
{
|
|
switch( line[cc] )
|
|
{
|
|
case '>':
|
|
level--;
|
|
cc++;
|
|
break;
|
|
|
|
case '<':
|
|
level++;
|
|
cc++;
|
|
break;
|
|
|
|
default:
|
|
cc++;
|
|
break;
|
|
} /* end switch */
|
|
} /* end if */
|
|
} /* end while */
|
|
length = copyMacLine( length, index, cc - 1, count - 1 );
|
|
if( length < 0 )
|
|
{
|
|
errorMessage (¯o_too_long, lexstart );
|
|
}
|
|
else if( length == 0 )
|
|
{
|
|
mac_bodies[value] = NULL;
|
|
}
|
|
else
|
|
{
|
|
mac_bodies[value] = (char *) malloc( length + 1 );
|
|
if( mac_bodies[value] )
|
|
{
|
|
strncpy( mac_bodies[value], mac_buffer, length );
|
|
*( mac_bodies[value] + length ) = 0;
|
|
}
|
|
else
|
|
{
|
|
errorMessage( &no_virtual_memory, lexstart );
|
|
}
|
|
}
|
|
nextLexeme();
|
|
}
|
|
else
|
|
{
|
|
errorMessage( <_expected, lexstart );
|
|
} /* end if */
|
|
break;
|
|
|
|
case EJECT:
|
|
page_lineno = LIST_LINES_PER_PAGE; /* This will force a page break. */
|
|
status = FALSE; /* This will force reading of next line */
|
|
break;
|
|
|
|
case IFDEF:
|
|
if( isalpha( line[lexstart] ))
|
|
{
|
|
sym = evalSymbol();
|
|
nextLexeme();
|
|
if( M_DEFINED_CONDITIONALLY( sym->type ))
|
|
{
|
|
conditionTrue();
|
|
}
|
|
else
|
|
{
|
|
conditionFalse();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
errorLexeme( &label_syntax, lexstart );
|
|
}
|
|
break;
|
|
|
|
case IFNDEF:
|
|
if( isalpha( line[lexstart] ))
|
|
{
|
|
sym = evalSymbol();
|
|
nextLexeme();
|
|
if( M_DEFINED_CONDITIONALLY( sym->type ))
|
|
{
|
|
conditionFalse();
|
|
}
|
|
else
|
|
{
|
|
conditionTrue();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
errorLexeme( &label_syntax, lexstart );
|
|
}
|
|
break;
|
|
|
|
case IFNZERO:
|
|
if( (getExpr())->val == 0 )
|
|
{
|
|
conditionFalse();
|
|
}
|
|
else
|
|
{
|
|
conditionTrue();
|
|
}
|
|
break;
|
|
|
|
case IFZERO:
|
|
if( (getExpr())->val == 0 )
|
|
{
|
|
conditionTrue();
|
|
}
|
|
else
|
|
{
|
|
conditionFalse();
|
|
}
|
|
break;
|
|
|
|
case LIST:
|
|
listfile = listsave;
|
|
break;
|
|
|
|
case NOLIST:
|
|
listfile = NULL;
|
|
break;
|
|
|
|
case OCTAL:
|
|
radix = 8;
|
|
break;
|
|
|
|
case START:
|
|
if( !isdone( line[lexstart] ))
|
|
{
|
|
start_addr = (getExpr())->val & 077777;
|
|
nextLexeme();
|
|
}
|
|
printLine( line, 0, start_addr, LINE_VAL );
|
|
status = FALSE;
|
|
break;
|
|
|
|
case TEXT:
|
|
delim = line[lexstart];
|
|
pack = 0;
|
|
count = 0;
|
|
index = lexstart + 1;
|
|
while( line[index] != delim && !isend( line[index] ))
|
|
{
|
|
pack = ( pack << 6 ) | ( line[index] & 077 );
|
|
count++;
|
|
if( count > 2 )
|
|
{
|
|
punchOutObject( clc, pack );
|
|
incrementClc();
|
|
count = 0;
|
|
pack = 0;
|
|
}
|
|
index++;
|
|
}
|
|
|
|
if( count == 2 )
|
|
{
|
|
punchOutObject( clc, pack << 6 );
|
|
}
|
|
else if (count == 1)
|
|
{
|
|
punchOutObject( clc, pack << 12 );
|
|
}
|
|
else
|
|
{
|
|
punchOutObject( clc, 0 );
|
|
}
|
|
incrementClc();
|
|
|
|
if( isend( line[index] ))
|
|
{
|
|
cc = index;
|
|
lexterm = cc;
|
|
errorMessage( &text_string, cc );
|
|
}
|
|
else
|
|
{
|
|
cc = index + 1;
|
|
lexterm = cc;
|
|
}
|
|
nextLexeme();
|
|
break;
|
|
|
|
case TITLE:
|
|
delim = line[lexstart];
|
|
ix = lexstart + 1;
|
|
/* Find string delimiter. */
|
|
do
|
|
{
|
|
if( list_title[ix] == delim && list_title[ix + 1] == delim )
|
|
{
|
|
ix++;
|
|
}
|
|
ix++;
|
|
} while( line[ix] != delim && !isend(line[ix]) );
|
|
|
|
if( !isend( line[ix] ) )
|
|
{
|
|
count = 0;
|
|
ix = lexstart + 1;
|
|
do
|
|
{
|
|
if( list_title[ix] == delim && list_title[ix + 1] == delim )
|
|
{
|
|
ix++;
|
|
}
|
|
list_title[count] = line[ix];
|
|
count++;
|
|
ix++;
|
|
} while( line[ix] != delim && !isend(line[ix]) );
|
|
|
|
if( strlen( list_title ) > TITLELEN )
|
|
{
|
|
list_title[TITLELEN] = '\0';
|
|
}
|
|
|
|
cc = ix + 1;
|
|
lexterm = cc;
|
|
page_lineno = LIST_LINES_PER_PAGE;/* Force top of page for new titles. */
|
|
list_title_set = TRUE;
|
|
}
|
|
else
|
|
{
|
|
cc = ix;
|
|
lexterm = cc;
|
|
errorMessage( &text_string, cc );
|
|
}
|
|
|
|
nextLexeme();
|
|
break;
|
|
|
|
case VFD:
|
|
pos = 0;
|
|
word = 0;
|
|
radixprev = radix;
|
|
while( !isdone (line[lexstart] ))
|
|
{
|
|
lexstartsave = lexstart;
|
|
radix = 10;
|
|
width = (getExpr())->val; /* Get field width. */
|
|
radix = radixprev;
|
|
if( (width <= 0) || ((width + pos) > 18) || (line[lexstart] != ':') )
|
|
{
|
|
errorMessage( &illegal_vfd_value, lexstartsave );
|
|
}
|
|
nextLexBlank(); /* Skip colon. */
|
|
value = (getExpr())->val; /* Get field value. */
|
|
if( line[lexterm] == ',' ) cc++;
|
|
nextLexeme(); /* Advance to next field. */
|
|
pos = pos + width;
|
|
if( pos <= 18 )
|
|
{
|
|
word = word | ((value & mask_tab[width]) << (18 - pos));
|
|
}
|
|
}
|
|
punchOutObject( clc, word );
|
|
incrementClc();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
} /* end switch for pseudo-ops */
|
|
return( status );
|
|
} /* pseudoOperators() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: conditionFalse */
|
|
/* */
|
|
/* Synopsis: Called when a false conditional has been evaluated. */
|
|
/* Lex should be the opening <; ignore all text until */
|
|
/* the closing >. */
|
|
/* */
|
|
/******************************************************************************/
|
|
void conditionFalse()
|
|
{
|
|
int level;
|
|
|
|
if( line[lexstart] == '<' )
|
|
{
|
|
/* Invariant: line[cc] is the next unexamined character. */
|
|
level = 1;
|
|
while( level > 0 )
|
|
{
|
|
if( end_of_input )
|
|
{
|
|
break;
|
|
}
|
|
if( isend( line[cc] ) || ( line[cc] == '/' ))
|
|
{
|
|
readLine();
|
|
}
|
|
else
|
|
{
|
|
switch( line[cc] )
|
|
{
|
|
case '>':
|
|
level--;
|
|
cc++;
|
|
break;
|
|
|
|
case '<':
|
|
level++;
|
|
cc++;
|
|
break;
|
|
|
|
default:
|
|
cc++;
|
|
break;
|
|
} /* end switch */
|
|
} /* end if */
|
|
} /* end while */
|
|
nextLexeme();
|
|
}
|
|
else
|
|
{
|
|
errorMessage( <_expected, lexstart );
|
|
}
|
|
} /* conditionFalse() */
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: conditionTrue */
|
|
/* */
|
|
/* Synopsis: Called when a true conditional has been evaluated. */
|
|
/* Lex should be the opening <; skip it and setup for */
|
|
/* normal assembly. */
|
|
/* */
|
|
/******************************************************************************/
|
|
void conditionTrue()
|
|
{
|
|
if( line[lexstart] == '<' )
|
|
{
|
|
nextLexeme(); /* Skip the opening '<' */
|
|
}
|
|
else
|
|
{
|
|
errorMessage( <_expected, lexstart );
|
|
}
|
|
} /* conditionTrue() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: errorLexeme */
|
|
/* */
|
|
/* Synopsis: Display an error message using the current lexical element. */
|
|
/* */
|
|
/******************************************************************************/
|
|
void errorLexeme( EMSG_T *mesg, WORD32 col )
|
|
{
|
|
char name[SYMLEN];
|
|
|
|
errorSymbol( mesg, lexemeToName( name, lexstart, lexterm ), col );
|
|
} /* errorLexeme() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: errorSymbol */
|
|
/* */
|
|
/* Synopsis: Display an error message with a given string. */
|
|
/* */
|
|
/******************************************************************************/
|
|
void errorSymbol( EMSG_T *mesg, char *name, WORD32 col )
|
|
{
|
|
char linecol[12];
|
|
char *s;
|
|
|
|
if( pass == 2 )
|
|
{
|
|
s = ( name == NULL ) ? "" : name ;
|
|
errors++;
|
|
sprintf( linecol, "(%d:%d)", lineno, col + 1 );
|
|
fprintf( errorfile, "%s%-9s : error: %s \"%s\" at Loc = %5.5o\n",
|
|
filename, linecol, mesg->file, s, clc );
|
|
saveError( mesg->list, col );
|
|
}
|
|
error_in_line = TRUE;
|
|
} /* errorSymbol() */
|
|
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: errorMessage */
|
|
/* */
|
|
/* Synopsis: Display an error message without a name argument. */
|
|
/* */
|
|
/******************************************************************************/
|
|
void errorMessage( EMSG_T *mesg, WORD32 col )
|
|
{
|
|
char linecol[12];
|
|
|
|
if( pass == 2 )
|
|
{
|
|
errors++;
|
|
sprintf( linecol, "(%d:%d)", lineno, col + 1 );
|
|
fprintf( errorfile, "%s%-9s : error: %s at Loc = %5.5o\n",
|
|
filename, linecol, mesg->file, clc );
|
|
saveError( mesg->list, col );
|
|
}
|
|
error_in_line = TRUE;
|
|
} /* errorMessage() */
|
|
|
|
/******************************************************************************/
|
|
/* */
|
|
/* Function: saveError */
|
|
/* */
|
|
/* Synopsis: Save the current error in a list so it may displayed after the */
|
|
/* the current line is printed. */
|
|
/* */
|
|
/******************************************************************************/
|
|
void saveError( char *mesg, WORD32 col )
|
|
{
|
|
if( save_error_count < DIM( error_list ))
|
|
{
|
|
error_list[save_error_count].mesg = mesg;
|
|
error_list[save_error_count].col = col;
|
|
save_error_count++;
|
|
}
|
|
error_in_line = TRUE;
|
|
|
|
if( listed )
|
|
{
|
|
printErrorMessages();
|
|
}
|
|
} /* saveError() */
|
|
/* End-of-File */
|