home *** CD-ROM | disk | FTP | other *** search
/ ftp.ee.pdx.edu / 2014.02.ftp.ee.pdx.edu.tar / ftp.ee.pdx.edu / pub / users / Harry / Blitz / version-1-0 / BlitzSrc / asm.c next >
C/C++ Source or Header  |  2006-09-25  |  166KB  |  5,407 lines

  1. /* The BLITZ Assembler
  2. **
  3. ** Copyright 2000-2006, Harry H. Porter III
  4. **
  5. ** This file may be freely copied, modified and compiled, on the sole
  6. ** condition that if you modify it...
  7. **   (1) Your name and the date of modification is added to this comment
  8. **       under "Modifications by", and
  9. **   (2) Your name and the date of modification is added to the printHelp()
  10. **       routine under "Modifications by".
  11. **
  12. ** Original Author:
  13. **   11/12/00 - Harry H. Porter III
  14. **
  15. ** Modifcations by:
  16. **   03/15/06 - Harry H. Porter III
  17. **
  18. */
  19.  
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <stdarg.h>
  23. #include <string.h>
  24. #include <float.h>
  25. #include <math.h>
  26.  
  27.  
  28.  
  29. typedef struct Expression Expression;
  30. typedef struct Instruction Instruction;
  31. typedef struct TableEntry TableEntry;
  32. typedef struct String String;
  33.  
  34. union tokenValue {
  35.   TableEntry * tableEntry;
  36.   int          ivalue;
  37.   double       rvalue;
  38. } tokenValue;
  39.  
  40. struct Expression {
  41.   int          op;
  42.   Expression * expr1;
  43.   Expression * expr2;
  44.   TableEntry * tableEntry; /* This field used iff op = ID */
  45.   int          value;      /* The value of this expression */
  46.   double       rvalue;     /* ... possible a double value */
  47.   TableEntry * relativeTo; /* To entry for ABSOLUTE, TEXT,..., or extrn ID */
  48. };
  49.  
  50. struct Instruction {
  51.   int           op;
  52.   int           lineNum;
  53.   int           format;
  54.   int           ra;
  55.   int           rb;
  56.   int           rc;
  57.   Expression *  expr;
  58.   TableEntry *  tableEntry;
  59.   Instruction * next;
  60. };
  61.  
  62. #define MAX_STR_LEN 200          /* Strings are limited to 200 characters. */
  63. #define NUM_KEYWORDS 95
  64.  
  65.  
  66.  
  67. /*****  Symbol Table  *****/
  68.  
  69. struct String {
  70.   int   length;
  71.   char  string [0];
  72. };
  73.  
  74. #define SYMBOL_TABLE_HASH_SIZE 211    /* Size of hash table for sym table */
  75. struct TableEntry {
  76.   int          symbolNum;  /* 1=text,2=data,3=bss,4=absolute,5..N=others */
  77.   TableEntry * next;       /* Link list of TableEntry's */
  78.   int          type;       /* ID, or some keyword like ADD, SUB,... */
  79.   int          offset;     /* The value of this symbol */
  80.   TableEntry * relativeTo; /* To entry for ABSOLUTE, TEXT,..., or extrn ID */
  81.   int          imported;   /* True if this ID appeared in .import */
  82.   int          exported;   /* True if this ID appeared in .export */
  83.   String       string;     /* The length and characters are stored directly */
  84. };
  85. static TableEntry * symbolTableIndex [SYMBOL_TABLE_HASH_SIZE];
  86.  
  87.  
  88.  
  89. /*****  Global variables *****/
  90.  
  91. char * keywords [NUM_KEYWORDS+1];
  92. int keywordTokens [NUM_KEYWORDS+1];
  93. int tableInitialized = 0;
  94. int currentLine;
  95. int errorsDetected;
  96. int nextToken;
  97. Instruction * instrList;
  98. Instruction * lastInstr;
  99. Expression * absoluteZero;
  100. Expression * absoluteMinusOne;
  101. int currentSegment;              /* 0, TEXT, DATA, BSS_SEG */
  102. int textLC;
  103. int dataLC;
  104. int bssLC;
  105. int finalTextLC;
  106. int finalDataLC;
  107. int finalBssLC;
  108. TableEntry * textTableEntry;
  109. TableEntry * dataTableEntry;
  110. TableEntry * bssTableEntry;
  111. TableEntry * absoluteTableEntry;
  112. TableEntry * entryTableEntry;
  113. int sawEntryLabel;               /* True if this .text seg should be 1st */
  114. int unresolvedEquates;           /* True if we need to reprocess equates */
  115. int anyEquatesResolved;          /* True if anything change this iteration */
  116. int commandOptionS = 0;          /* True: print the symbol table */
  117. int commandOptionD = 0;          /* True: print the instruction list */
  118. int commandOptionL = 0;          /* True: print the listing */
  119. char * commandInFileName = NULL; /* The .s filename, if provided */
  120. char * commandOutFileName = NULL;/* The .o filename */
  121. FILE * inputFile;                /* The .s input file */
  122. FILE * outputFile;               /* The .o output file */
  123.  
  124.  
  125.  
  126. /* Function prototypes */
  127.  
  128. void processCommandLine (int argc, char ** argv);
  129. void errorExit ();
  130. void printHelp ();
  131. void printError (char * msg);
  132. void printError2 (char * msg, char * msg2);
  133. void scan ();
  134. void mustHave (int token, char* msg);
  135. int getToken (void);
  136. int scanEscape ();
  137. int isEscape (char ch);
  138. int hexCharToInt (char ch);
  139. char intToHexChar (int i);
  140. void initKeywords ();
  141. TableEntry * lookupAndAdd (char * givenStr, int newType);
  142. TableEntry * lookupAndAdd2 (char * givenStr, int length, int newType);
  143. int bytesEqual (char * p, char * q, int length);
  144. void printSymbolTable ();
  145. void printString (TableEntry *);
  146. String * newString (char * p);
  147. void checkAllExportsImports ();
  148. void checkAllExpressions ();
  149. void printSym (int i);
  150. int hexDigit (char ch);
  151. void addInstrToList (Instruction *, int LCIncrAmount);
  152. void findOpCode (Instruction * instr);
  153. void printInstrList (Instruction * listPtr);
  154. void printInstr (Instruction * instrPtr);
  155. void printExpr (Expression * expr);
  156. Instruction * newInstr (int op);
  157. Expression * newExpression (int op);
  158. void getOneInstruction ();
  159. void scanRestOfLine ();
  160. int categoryOf (int tokType);
  161. int isRegister (int tokType);
  162. int isFRegister (int tokType);
  163. int getRegisterA (Instruction * p);
  164. int getRegisterB (Instruction * p);
  165. int getRegisterC (Instruction * p);
  166. int getFRegisterA (Instruction * p);
  167. int getFRegisterB (Instruction * p);
  168. int getFRegisterC (Instruction * p);
  169. int nextIsNot (int tokType, char * message);
  170. Expression * getExpr ();
  171. Expression * parseExpr0 ();
  172. Expression * parseExpr1 ();
  173. Expression * parseExpr2 ();
  174. Expression * parseExpr3 ();
  175. Expression * parseExpr4 ();
  176. Expression * parseExpr5 ();
  177. Expression * parseExpr6 ();
  178. void setCurrentSegmentTo (int type);
  179. int getLC ();
  180. void incrementLCBy (int incr);
  181. int notInDataOrText ();
  182. void checkBigEndian ();
  183. void resolveEquate (Instruction * instr, int printErrors);
  184. void evalExpr (Expression * expr, int printErrors);
  185. void processEquates ();
  186. void passTwo ();
  187. void printOneLine ();
  188. void writeInteger (int i);
  189. int writeSegment (int segType);
  190. void writeSymbols ();
  191. void writeOutSymbol (TableEntry * entryPtr);
  192. void writeRelocationInfo ();
  193. void writeRelocationEntry (int type, int addr, Expression * expr);
  194. void writeLabels ();
  195.  
  196.  
  197.  
  198. /* These are the BLITZ opcodes. */
  199.  
  200. #define ADD1    96
  201. #define ADD2    128
  202. #define SUB1    97
  203. #define SUB2    129
  204. #define MUL1    98
  205. #define MUL2    130
  206. #define DIV1    99
  207. #define DIV2    131
  208. #define SLL1    100
  209. #define SLL2    132
  210. #define SRL1    101
  211. #define SRL2    133
  212. #define SRA1    102
  213. #define SRA2    134
  214. #define OR1    103
  215. #define OR2    135
  216. #define AND1    104
  217. #define AND2    136
  218. #define ANDN1    105
  219. #define ANDN2    137
  220. #define XOR1    106
  221. #define XOR2    138
  222. #define REM1    115
  223. #define REM2    149
  224. #define LOAD1    107
  225. #define LOAD2    139
  226. #define LOADB1    108
  227. #define LOADB2    140
  228. #define LOADV1    109
  229. #define LOADV2    141
  230. #define LOADBV1    110
  231. #define LOADBV2    142
  232. #define STORE1    111
  233. #define STORE2    143
  234. #define STOREB1    112
  235. #define STOREB2    144
  236. #define STOREV1    113
  237. #define STOREV2    145
  238. #define STOREBV1    114
  239. #define STOREBV2    146
  240. #define CALL1    64
  241. #define CALL2    160
  242. #define JMP1    65
  243. #define JMP2    161
  244. #define BE1    66
  245. #define BE2    162
  246. #define BNE1    67
  247. #define BNE2    163
  248. #define BL1    68
  249. #define BL2    164
  250. #define BLE1    69
  251. #define BLE2    165
  252. #define BG1    70
  253. #define BG2    166
  254. #define BGE1    71
  255. #define BGE2    167
  256. #define BVS1    74
  257. #define BVS2    170
  258. #define BVC1    75
  259. #define BVC2    171
  260. #define BNS1    76
  261. #define BNS2    172
  262. #define BNC1    77
  263. #define BNC2    173
  264. #define BSS1    78
  265. #define BSS2    174
  266. #define BSC1    79
  267. #define BSC2    175
  268. #define BIS1    80
  269. #define BIS2    176
  270. #define BIC1    81
  271. #define BIC2    177
  272. #define BPS1    82
  273. #define BPS2    178
  274. #define BPC1    83
  275. #define BPC2    179
  276. #define PUSH    84
  277. #define POP    85
  278. #define SETHI    192
  279. #define SETLO    193
  280. #define LDADDR    194
  281. #define SYSCALL    195
  282. #define NOP    0
  283. #define WAIT    1
  284. #define DEBUG    2
  285. #define CLEARI    3
  286. #define SETI    4
  287. #define CLEARP    5
  288. #define SETP    6
  289. #define CLEARS    7
  290. #define RETI    8
  291. #define RET     9
  292. #define DEBUG2    10
  293. #define TSET    88
  294. #define READU1    86
  295. #define READU2    147
  296. #define WRITEU1    87
  297. #define WRITEU2    148
  298. #define LDPTBR    32
  299. #define LDPTLR    33
  300. #define FTOI    89
  301. #define ITOF    90
  302. #define FADD    116
  303. #define FSUB    117
  304. #define FMUL    118
  305. #define FDIV    119
  306. #define FCMP    91
  307. #define FSQRT   92
  308. #define FNEG    93
  309. #define FABS    94
  310. #define FLOAD1  120
  311. #define FLOAD2  150
  312. #define FSTORE1 121
  313. #define FSTORE2 151
  314.  
  315.  
  316. /* These are the additional token types. */
  317.  
  318. enum { EOL=256, LABEL, ID, INTEGER, REAL, STRING, ABSOLUTE,
  319.        COMMA, LBRACKET, RBRACKET, PLUS, PLUSPLUS, MINUS, MINUSMINUS,
  320.        COLON, STAR, SLASH, PERCENT, LTLT, GTGT, GTGTGT, LPAREN, RPAREN,
  321.        AMPERSAND, BAR, CARET, TILDE,
  322.  
  323. /* Pseudo-ops */
  324.        TEXT, DATA, BSS_SEG, ASCII, BYTE, WORD, EXPORT, IMPORT, ALIGN, SKIP,
  325.        EQUAL, DOUBLE,
  326.  
  327. /* Instructions with multiple formats */
  328.        ADD, SUB, MUL, DIV, SLL, SRL, SRA, OR, AND, ANDN, XOR, REM,
  329.        LOAD, LOADB, LOADV, LOADBV, STORE, STOREB, STOREV, STOREBV,
  330.        CALL, JMP, BE, BNE, BL, BLE, BG, BGE, BVS, BVC,
  331.        BNS, BNC, BSS_OP, BSC, BIS, BIC, BPS, BPC, READU, WRITEU,
  332.        FLOAD, FSTORE,
  333.  
  334. /* Registers */
  335.        R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15,
  336.        F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15,
  337.  
  338. /* Synthetic instructions */
  339.        MOV, CMP, SET, NEG, NOT, CLR, BTST, BSET, BCLR, BTOG,
  340.  
  341. /* Instruction formats */
  342.        A, B, C, D, E, F, G
  343.      };
  344.  
  345.  
  346.  
  347. /* main()
  348. **
  349. ** Calls getToken in a loop until EOF, printing out each token as it goes.
  350. */
  351. main (int argc, char ** argv) {
  352.     int i;
  353.     errorsDetected = 0;
  354.     currentLine = 1;
  355.     instrList = NULL;
  356.     lastInstr = NULL;
  357.     currentSegment = 0;
  358.     textLC = 0;
  359.     dataLC = 0;
  360.     bssLC = 0;
  361.     sawEntryLabel = 0;
  362.     checkBigEndian ();
  363.     initKeywords ();
  364.     textTableEntry = lookupAndAdd (".text", TEXT);
  365.     textTableEntry->symbolNum = 1;
  366.     dataTableEntry = lookupAndAdd (".data", DATA);
  367.     dataTableEntry->symbolNum = 2;
  368.     bssTableEntry = lookupAndAdd (".bss", BSS_SEG);
  369.     bssTableEntry->symbolNum = 3;
  370.     absoluteTableEntry = lookupAndAdd (".absolute", ABSOLUTE);
  371.     absoluteTableEntry->symbolNum = 4;
  372.     entryTableEntry = lookupAndAdd ("_entry", ID);
  373.     absoluteZero = newExpression (INTEGER);
  374.     absoluteZero->value = 0;
  375.     absoluteZero->relativeTo = absoluteTableEntry;
  376.     absoluteMinusOne = newExpression (INTEGER);
  377.     absoluteMinusOne->value = -1;
  378.     absoluteMinusOne->relativeTo = absoluteTableEntry;
  379.     unresolvedEquates = 0;
  380.     anyEquatesResolved = 0;
  381.     processCommandLine (argc, argv);
  382.     
  383. /*****  Test lexer  *****
  384.     while (1) {
  385.         nextToken = getToken ();
  386.         printf("%d\t", currentLine);
  387.         printSym (nextToken);
  388.         switch (nextToken) {
  389.           case ID: 
  390.             printf("\t");
  391.             printString (tokenValue.tableEntry);
  392.             break;
  393.           case STRING:
  394.             printf("\t\"");
  395.             printString (tokenValue.tableEntry);
  396.             printf("\"");
  397.             break;
  398.           case INTEGER:
  399.             printf("\t%d", tokenValue.ivalue);
  400.             break;
  401.           case REAL:
  402.             printf("\t%.17g", tokenValue.rvalue);
  403.             break;
  404.         }
  405.         printf("\n");
  406.         if (nextToken == EOF) {
  407.           break;
  408.         }
  409.     }
  410.     exit (0);
  411. **********/
  412.     scan ();
  413.     while (nextToken != EOF) {
  414.       getOneInstruction ();
  415.     }
  416.     if (instrList == NULL) {
  417.       printError ("No legal instructions encountered");
  418.       fprintf (stderr, "%d errors were detected!\n", errorsDetected);
  419.       errorExit ();
  420.     }
  421.     finalTextLC = textLC;
  422.     finalDataLC = dataLC;
  423.     finalBssLC = bssLC;
  424.     processEquates ();
  425.     checkAllExportsImports ();
  426.     checkAllExpressions ();
  427.     if (commandOptionS) {
  428.       printSymbolTable ();
  429.     }
  430.     if (commandOptionD) {
  431.       printInstrList (instrList);
  432.     }
  433.     if (errorsDetected) {
  434.       fprintf (stderr, "%d errors were detected!\n", errorsDetected);
  435.       errorExit ();
  436.     }
  437.  
  438.     /* Write the magic numbers and header info to the .o file. */
  439.     writeInteger (0x424C5A6F);   /* "BLZo" as an integer */
  440.     writeInteger (sawEntryLabel);
  441.     writeInteger (textLC);
  442.     writeInteger (dataLC);
  443.     writeInteger (bssLC);
  444.  
  445.     /* Perform "pass 2", creating the listing if desired. */
  446.     passTwo ();
  447.     if ((finalTextLC != textLC)
  448.          || (finalDataLC != dataLC)
  449.          || (finalBssLC != bssLC)) {
  450.       printError ("Program logic error: the LCs do not match after pass two");
  451.     }
  452.  
  453.     /* Write the text segment data. */
  454.     i = writeSegment (TEXT);
  455.     if (i != textLC) {
  456.       printError ("Program logic error: .text segment size not correct");
  457.     }
  458.     writeInteger (0x02a2a2a2a);   /* "****" as an integer */
  459.  
  460.     /* Write the data segment data. */
  461.     i = writeSegment (DATA);
  462.     if (i != dataLC) {
  463.       printError ("Program logic error: .data segment size not correct");
  464.     }
  465.     writeInteger (0x02a2a2a2a);   /* "****" as an integer */
  466.  
  467.     /* Write the imported and exported symbols out. */
  468.     writeSymbols ();
  469.     writeInteger (0);             /* To mark end of symbols */
  470.     writeInteger (0x02a2a2a2a);   /* "****" as an integer */
  471.  
  472.     /* Write out all relocation information. */
  473.     writeRelocationInfo ();
  474.     writeInteger (0);             /* To mark end of reloc. info */
  475.     writeInteger (0x02a2a2a2a);   /* "****" as an integer */
  476.  
  477.     /* Write all the labels out, (used by symbolic debuggers). */
  478.     writeLabels ();
  479.     writeInteger (0);             /* To mark end of labels */
  480.     writeInteger (0x02a2a2a2a);   /* "****" as an integer */
  481.  
  482.     if (errorsDetected) {
  483.       fprintf (stderr, "%d errors were detected!\n", errorsDetected);
  484.       errorExit ();
  485.     }
  486.     exit (0);
  487. }
  488.  
  489.  
  490.  
  491. /* processCommandLine (argc, argv)
  492. **
  493. ** This routine processes the command line options.
  494. */
  495. void processCommandLine (int argc, char ** argv) {
  496.   int argCount;
  497.   int badArgs = 0;
  498.   int len;
  499.   for (argc--, argv++; argc > 0; argc -= argCount, argv += argCount) {
  500.     argCount = 1;
  501.     /* Scan the -h option */
  502.     if (!strcmp (*argv, "-h")) {
  503.       printHelp ();
  504.       exit (1);
  505.     /* Scan the -s option */
  506.     } else if (!strcmp (*argv, "-s")) {
  507.       commandOptionS = 1;
  508.     /* Scan the -d option */
  509.     } else if (!strcmp (*argv, "-d")) {
  510.       commandOptionD = 1;
  511.     /* Scan the -l option */
  512.     } else if (!strcmp (*argv, "-l")) {
  513.       commandOptionL = 1;
  514.     /* Scan the -o option, which should be followed by a file name */
  515.     } else if (!strcmp (*argv, "-o")) {
  516.       if (argc <= 1) {
  517.         fprintf (stderr,
  518.           "Expecting filename after -o option.  Use -h for help display.\n");
  519.         badArgs = 1;
  520.       } else {
  521.         argCount++;
  522.         if (commandOutFileName == NULL) {
  523.           commandOutFileName = *(argv+1);
  524.         } else {
  525.           fprintf (stderr,
  526.             "Invalid command line.  Multiple output files.  Use -h for help display.\n");
  527.           badArgs = 1;
  528.         }
  529.       }
  530.     /* Scan an input file name */
  531.     } else if ((*argv)[0] != '-') {
  532.       if (commandInFileName == NULL) {
  533.         commandInFileName = *argv;
  534.       } else {
  535.         fprintf (stderr,
  536.           "Invalid command line.  Multiple input files.  Use -h for help display.\n");
  537.         badArgs = 1;
  538.       }
  539.     } else {
  540.       fprintf (stderr,
  541.         "Invalid command line option (%s).  Use -h for help display.\n",
  542.         *argv);
  543.       badArgs = 1;
  544.     }
  545.   }
  546.  
  547.   /* Open the input (.s) file */
  548.   if (commandInFileName == NULL) {
  549.     inputFile = stdin;
  550.   } else {
  551.     inputFile = fopen (commandInFileName, "r");
  552.     if (inputFile == NULL) {
  553.       fprintf (stderr,
  554.           "Input file \"%s\" could not be opened\n", commandInFileName);
  555.       badArgs = 1;
  556.     }
  557.   }
  558.  
  559.   /* If command line problems, then abort now. */
  560.   if (badArgs) {
  561.     exit (1);
  562.   }
  563.  
  564.   /* Figure out the name of the .o file. */
  565.   if (commandOutFileName == NULL) {
  566.     if (commandInFileName == NULL) {
  567.       commandOutFileName = "";
  568.       fprintf (stderr,
  569.        "Must use -o option when input is from stdin\n", commandOutFileName);
  570.       exit (1);
  571.     } else {
  572.       len = strlen (commandInFileName);
  573.       if ((len > 2)
  574.             && (commandInFileName [len-2] == '.')
  575.             && (commandInFileName [len-1] == 's')) {
  576.         commandOutFileName = (char *) calloc (1, strlen(commandInFileName) + 1);
  577.         strcpy (commandOutFileName, commandInFileName);
  578.         commandOutFileName [len-2] = '.';
  579.         commandOutFileName [len-1] = 'o';
  580.       } else {
  581.         commandOutFileName = (char *) calloc (1, strlen(commandInFileName) + 3);
  582.         strcpy (commandOutFileName, commandInFileName);
  583.         commandOutFileName [len] = '.';
  584.         commandOutFileName [len+1] = 'o';
  585.       }
  586.     }
  587.   }
  588.  
  589.   /* Open the output (.o) file. */
  590.   outputFile = fopen (commandOutFileName, "wa");
  591.   if (outputFile == NULL) {
  592.     fprintf (stderr,
  593.        "Output file \"%s\" could not be opened\n", commandOutFileName);
  594.     exit (1);
  595.   }
  596. }
  597.  
  598.  
  599.  
  600. /* errorExit ()
  601. **
  602. ** This routine removes the output (.o) file and calls exit(1).
  603. */
  604. void errorExit () {
  605.   remove (commandOutFileName);
  606.   exit (1);
  607. }
  608.  
  609.  
  610.  
  611. /* printHelp ()
  612. **
  613. ** This routine prints some documentation.  It is invoked whenever
  614. ** the -h option is used on the command line.
  615. */
  616. void printHelp () {
  617.   printf (
  618. "=================================\n"
  619. "=====                       =====\n"
  620. "=====  The BLITZ Assembler  =====\n"
  621. "=====                       =====\n"
  622. "=================================\n"
  623. "\n"
  624. "Copyright 2000-2006, Harry H. Porter III\n"
  625. "========================================\n"
  626. "  Original Author:\n"
  627. "    11/12/00 - Harry H. Porter III\n"
  628. "  Modifcations by:\n"
  629. "    03/15/06 - Harry H. Porter III\n"
  630. "\n"
  631. "Command Line Options\n"
  632. "====================\n"
  633. "  Command line options may be given in any order.\n"
  634. "    filename\n"
  635. "      The input source will come from this file.  (Normally this file\n"
  636. "      will end with \".s\".)  If an input file is not given on the command\n"
  637. "      line, the source must come from stdin.  Only one input source is allowed.\n"
  638. "    -h\n"
  639. "      Print this help info.  All other options are ignored.\n"
  640. "    -l\n"
  641. "      Print a listing on stdout.\n"
  642. "    -s\n"
  643. "      Print the symbol table on stdout.\n"
  644. "    -d\n"
  645. "      Print internal assembler info (for debugging asm.c)\n"
  646. "    -o filename\n"
  647. "      If there are no errors, an object file will be created.  This\n"
  648. "      option can be used to give the object file a specific name.\n"
  649. "      If this option is not used, then the input .s file must be named on\n"
  650. "      the command line (i.e., the source must not come from stdin.)  In this\n"
  651. "      case, the name of the object file will be computed from the name of\n"
  652. "      the input file by removing the \".s\" extension, if any, and appending\n"
  653. "      \".o\".  For example:\n"
  654. "           test.s  -->  test.o\n"
  655. "           foo     -->  foo.o\n"
  656. "  \n"
  657. "Lexical issues:\n"
  658. "===============\n"
  659. "  Identifiers - May contain letters, digits, and underscores.  They must\n"
  660. "    begin with a letter or underscore.  Case is significant.  Identifiers\n"
  661. "    are limited in length to 200 characters.\n"
  662. "  Integers - May be specified in decimal or in hex.\n"
  663. "    Integers must range from 0 to 2147483647.  Hex notation is, for\n"
  664. "    example, 0x1234abcd.  0x1234ABCD is equivalent.  Shorter numbers like\n"
  665. "    0xFFFF are not sign-extended.\n"
  666. "  Strings - Use double quotes.  The following escape sequences are allowed:\n"
  667. "      \\0  \\a  \\b  \\t  \\n  \\v  \\f  \\r  \\\"  \\'  \\\\  \\xHH\n"
  668. "    where HH are any two hex digits.  Strings may not contain newlines directly;\n"
  669. "    in other words, a string  may not span multiple lines.  The source file may\n"
  670. "    not contain unprintable ASCII characters; use the escape sequences if you\n"
  671. "    wish to include unprintable characters in string or character constants.\n"
  672. "    String constants are limited in length to 200 characters.\n"
  673. "  Characters - Use single quotes.  The same escape sequences are allowed.\n"
  674. "  Comments - Begin with the exclamation mark (!) and extend thru end-of-line.\n"
  675. "  Punctuation symbols - The following symbols have special meaning:\n"
  676. "      ,  [  ]  :  .  +  ++  -  --  *  /  %  <<  >>  >>>  &  |  ^  ~  (  )  =\n"
  677. "  Keywords - The following classes of keywords are recognized:\n"
  678. "    BLITZ instruction op-codes (e.g., add, sub, syscall, ...)\n"
  679. "    Synthetic instructions (e.g., mov, set, ...)\n"
  680. "    Assembler pseudo-ops (e.g., .text, .import, .byte, ...)\n"
  681. "    Registers (r0, r1, ... r15)\n"
  682. "  White space - Tabs and space characters may be used between tokens.\n"
  683. "  End-of-line - The EOL (newline) character is treated as a token, not\n"
  684. "    as white space; the EOL is significant in syntax parsing.\n"
  685. "\n"
  686. "Assembler pseudo-ops\n"
  687. "====================\n"
  688. "  .text    The following instructions and data will be placed in the\n"
  689. "           \"text\" segment, which will be read-only during execution.\n"
  690. "  .data    The following instructions and data will be placed in the\n"
  691. "           \"data\" segment, which will be read-write during execution.\n"
  692. "  .bss     The following bytes will be reserved in the \"bss\" segment,\n"
  693. "           which will be initialized to zero at program load time.\n"
  694. "  .ascii   This operand expects a single string operand.  These bytes\n"
  695. "           will be loaded into memory.  Note that no terminating NULL\n"
  696. "           ('\\0') character will be added to the end of the string.\n"
  697. "  .byte    This pseudo-op expects a single expression as an operand.\n"
  698. "           This expression will be evaluated at assembly time, the value\n"
  699. "           will be truncated to 8 bits, and the result used to initialize\n"
  700. "           a single byte of memory.\n"
  701. "  .word    This pseudo-op expects a single expression as an operand.\n"
  702. "           This expression will be evaluated at assembly time to a\n"
  703. "           32 bit value, and the result used to initialize four bytes\n"
  704. "           of memory.  The assembler does not require alignment for .word.\n"
  705. "  .export  This pseudo-op expects a single symbol as an operand.  This\n"
  706. "           symbol must be given a value in this file.  This symbol with\n"
  707. "           its value will be placed in the object file and made available\n"
  708. "           during segment linking.\n"
  709. "  .import  This pseudo-op expects a single symbol as an operand.  This\n"
  710. "           symbol must not be given a value in this file; instead it will\n"
  711. "           receive its value from another .s file during segment linking.\n"
  712. "           All uses of this symbol in this file will be replaced by that\n"
  713. "           value at segment-link time.\n"
  714. "  .skip    This pseudo-op expects a single expression as an operand.\n"
  715. "           This expression must evaluate to an absolute value.  The\n"
  716. "           indicated number of bytes will be skipped in the current\n"
  717. "           segment.\n"
  718. "  .align   This instruction will insert 0, 1, 2, or 3 bytes into the\n"
  719. "           current segment as necessary to bring the location up to an\n"
  720. "           even multiple of 4.  No operand is used with .align.\n"
  721. "  =        Symbols may be given values with a line of the following\n"
  722. "           format:\n"
  723. "                        symbol   =   expression\n"
  724. "           These are called \"equates\".  Equates will be processed\n"
  725. "           during the first pass, if possible.  If not, they will be\n"
  726. "           processed after the program has been completely read in.\n"
  727. "           The expression may use symbols that are defined later in the\n"
  728. "           file, but this may cause the equate to be given a value\n"
  729. "           slightly later in the assembly.  After the first pass, an\n"
  730. "           attempt will be made to evaluate all the equates.  At this\n"
  731. "           time, errors may be generated.  After the equates have been\n"
  732. "           processed, the machine code can be generated in the final\n"
  733. "           pass.\n"
  734. "\n"
  735. "Segments\n"
  736. "========\n"
  737. "  This assembler is capable of assembling BLITZ instructions and data\n"
  738. "  and placing them in one of three \"segments\":\n"
  739. "    .text\n"
  740. "    .data\n"
  741. "    .bss\n"
  742. "  \n"
  743. "  At run-time, the bytes placed in the .text segment will be read-only.\n"
  744. "  At run-time, the bytes places in the .data segment will be read-write.\n"
  745. "  At run-time, the bytes places in the .bss segment will be read-write.\n"
  746. "  The read-only nature of the bytes in the .text segment may or may not\n"
  747. "  be enforced by the operating system at run-time.\n"
  748. "\n"
  749. "  Instructions and data may be placed in either the .text or .data\n"
  750. "  segment.  No instructions or data may be placed in the .bss segment.\n"
  751. "  The only things that may follow the .bss pseudo-op are the following\n"
  752. "  pseudo-ops:\n"
  753. "    .skip\n"
  754. "    .align\n"
  755. "  The assembler may reserve bytes in the .bss segment but no initial\n"
  756. "  values may be placed in these locations.  Instead, all bytes of the\n"
  757. "  .bss segment will be initialized to zeros at program-load time.  These\n"
  758. "  addresses may be initialized and modified during program execution.\n"
  759. "\n"
  760. "  Segment control is done using the following pseudo-ops:\n"
  761. "    .text\n"
  762. "    .data\n"
  763. "    .bss\n"
  764. "\n"
  765. "  After any one of these pseudo-ops, all following instructions and data\n"
  766. "  will be placed in the named segment.  A \"location counter\" for each of\n"
  767. "  the three segments is maintained by the assembler.  If, for example, a\n"
  768. "  .text pseudo-op has been used to switch to the \".text\" segment, then\n"
  769. "  all subsequent instructions will be placed in the \".text\" segment.\n"
  770. "  Any labels encountered will be be given values relative to the\n"
  771. "  \".text\" segment.  As each instruction is encountered, the location\n"
  772. "  counter for the \".text\" segment will be incremented.  If a .data\n"
  773. "  pseudo-op is the encountered, all subsequent instructions will be placed\n"
  774. "  in the \".data\" segment.  The location counters are not reset;  if a\n"
  775. "  .text pseudo-op is again encountered, subsequent instructions will be\n"
  776. "  placed in the \".text\" segment following the instructions encountered\n"
  777. "  earlier, before the .data pseudo-op was seen.  Thus, we can \"pick up\"\n"
  778. "  in the .text segment where we left off.\n"
  779. "\n"
  780. "Symbols\n"
  781. "=======\n"
  782. "  The assembler builds a symbol table, mapping identifiers to values.\n"
  783. "  Each symbol is given exactly one value: there is no notion of scope\n"
  784. "  or lexical nesting levels, as in high-level languages.  Each symbol\n"
  785. "  is given a value which will be either:\n"
  786. "    absolute\n"
  787. "    relative\n"
  788. "    external\n"
  789. "  An absolute value consists of a 32-bit quantity.  A relative value \n"
  790. "  consists of a 32-bit (signed) offset relative to either a segment\n"
  791. "  or to an external symbol.  An external symbol will have its value\n"
  792. "  assigned in some other assembly file and its value will not be\n"
  793. "  available to the code in this file until segment-linking time.  However,\n"
  794. "  an external symbol may be used in expressions within this file; the\n"
  795. "  actual data will not be filled in until segment-linking time.\n"
  796. "\n"
  797. "  Symbols may be defined internally or externally.  If a symbol is used\n"
  798. "  in this file, but not defined, then it must be \"imported\" using\n"
  799. "  the .import pseudo-op.  If a symbol is defined in this file and used\n"
  800. "  in other files, then it must be \"exported\" using an .export\n"
  801. "  pseudo-op.  If a symbol is not exported, then its value will not be\n"
  802. "  known to the linker; if this same symbol is imported in other files,\n"
  803. "  then an \"undefined symbol\" error will be generated at segment-linking\n"
  804. "  time.\n"
  805. "\n"
  806. "  Symbols may be defined in either of two ways:\n"
  807. "    labels\n"
  808. "    = equates\n"
  809. "  If a symbol is defined by being used as a label, then it is given a\n"
  810. "  value which consists of an offset relative to the beginning of whichever\n"
  811. "  segment is current when the label is encountered.  This is determined by\n"
  812. "  whether a .text, .data, or .bss pseudo-op was seen last, before the label\n"
  813. "  was encountered.  Each label occurs in a segment and names a location in\n"
  814. "  memory.  At segment-link time, the segments are placed in their final\n"
  815. "  positions in memory.  Only at segment-link time does the actual address of\n"
  816. "  the location in memory become known.  At this time, the label is assigned\n"
  817. "  an absolute value.\n"
  818. "\n"
  819. "Expression Evaluation\n"
  820. "=====================\n"
  821. "  Instructions and pseudo-ops may contain expressions in their operands.\n"
  822. "  Expressions have the form given by the following Context-Free Grammar.\n"
  823. "  (In this grammar, the following meta-notation is used: characters\n"
  824. "  enclosed in double quotes are terminals.  The braces { } are used to\n"
  825. "  mean \"zero or more\" occurences.  The vertical bar | is used to mean\n"
  826. "  alternation.  Parentheses are used for grouping.  The start symbol\n"
  827. "  is \"expr\".)\n"
  828. "    expr  ::= expr1 { \"|\" expr1 }\n"
  829. "    expr1 ::= expr2 { \"^\" expr2 }\n"
  830. "    expr2 ::= expr3 { \"&\" expr3 }\n"
  831. "    expr3 ::= expr4 { ( \"<<\" | \">>\" | \">>>\" ) expr4 }\n"
  832. "    expr4 ::= expr5 { ( \"+\" | \"-\" ) expr5 }\n"
  833. "    expr5 ::= expr6 { ( \"*\" | \"/\" | \"%%\" ) expr6 }\n"
  834. "    expr6 ::= \"+\" expr6 | \"-\" expr6 | \"~\" expr6\n"
  835. "              | ID | INTEGER | STRING | \"(\" expr \")\"\n"
  836. "\n"
  837. "  This syntax results in the following precedences and associativities:\n"
  838. "    highest:    unary+  unary-  ~    (right associative)\n"
  839. "                *  /  %%              (left associative)\n"
  840. "                +  -                 (left associative)\n"
  841. "                <<  >>  >>>          (left associative)\n"
  842. "                &                    (left associative)\n"
  843. "                ^                    (left associative)\n"
  844. "    lowest:     |                    (left associative)\n"
  845. "\n"
  846. "  If a string is used in an expression, it must have exactly 4 characters.\n"
  847. "  The string will be interpreted as a 32 bit integer, based on the ASCII\n"
  848. "  values of the 4 characters.  (\"Big Endian\" order is used: the first\n"
  849. "  character will determine the most significant byte.)\n"
  850. "\n"
  851. "  The following operators are recognized in expressions:\n"
  852. "    unary+    nop\n"
  853. "    unary-    32-bit signed arithmetic negation\n"
  854. "    ~         32-bit logical negation (NOT)\n"
  855. "    *         32-bit multiplication\n"
  856. "    /         32-bit integer division with 32-bit integer result\n"
  857. "    %%         32-bit modulo, with 32-bit result\n"
  858. "    binary+   32-bit signed addition\n"
  859. "    binary-   32-bit signed subtraction\n"
  860. "    <<        left shift logical (i.e., zeros shifted in from right)\n"
  861. "    >>        right shift logical (i.e., zeros shifted in from left)\n"
  862. "    >>>       right shift arithmetic (i.e., sign bit shifted in on left)\n"
  863. "    &         32-bit logical AND\n"
  864. "    ^         32-bit logical Exclusive-OR\n"
  865. "    |         32-bit logical OR\n"
  866. "\n"
  867. "  With the shift operators (<<, >>, and >>>) the second operand must\n"
  868. "  evaluate to an integer between 0 and 31.  With the division operators\n"
  869. "  (/ and %%), the first operand must be non-negative and the second\n"
  870. "  operand must be positive, since these operators are implemented with\n"
  871. "  \"C\" operators, which are machine-dependent with negative operands.\n"
  872. "\n"
  873. "  All operators except addition and subtraction require both operands to\n"
  874. "  evaluate to absolute values.  All arithmetic is done with signed 32-bit\n"
  875. "  values.  The addition operator + requires that at least one of the operands\n"
  876. "  evaluates to an absolute value.  If one operand is relative, then the\n"
  877. "  result will be relative to the same location.  The subtraction operator\n"
  878. "  requires that the second operand evaluates to an absolute value.  If the\n"
  879. "  first operand is relative, then the result will be relative to the same\n"
  880. "  location.  Only absolute values can be negated.\n"
  881. "\n"
  882. "  All expressions are evaluated at assembly-time.  An expression may\n"
  883. "  evaluate to either an absolute 32-bit value, or may evaluate to a\n"
  884. "  relative value.  A relative value is a 32-bit offset relative to some\n"
  885. "  some symbol.  The offset will  be relative to the beginning of the .text\n"
  886. "  segment, the .data segment, or the .bss segment, or the offset will be\n"
  887. "  relative to some external symbol.  If the expression evaluates to a\n"
  888. "  relative value, its value will not be determined until segment-link\n"
  889. "  time.  At this time, the absolute locations of the .text, .data, and\n"
  890. "  .bss segments will be determined and the absolute values of external\n"
  891. "  symbols will be determined.  At segment-link time, the final, absolute\n"
  892. "  values of all expressions will be determined by adding the values of the\n"
  893. "  symbols (or locations of the segments) to the offsets.\n"
  894. "\n"
  895. "  Expressions may be used in:\n"
  896. "    .byte\n"
  897. "    .word\n"
  898. "    .skip\n"
  899. "    =\n"
  900. "    various BLITZ instructions\n"
  901. "  The .skip pseudo-op requires the expression evaluates to an absolute value.\n"
  902. "  In the case of an = (equate) pseudo-op, the expression may evaluate to\n"
  903. "  either a relative or absolute value.  In either case, the equated symbol\n"
  904. "  will be given a relative or absolute value (respectively).  At segment-\n"
  905. "  linking time, when the actual value is determined, the value will be\n"
  906. "  filled in in the byte, word, or appropriate field in the instruction.\n"
  907. "\n"
  908. "Instruction Syntax\n"
  909. "==================\n"
  910. "  Each line in the assembly source file has the following general syntax:\n"
  911. "\n"
  912. "    [ label: ]   [ opcode   operands ]    [ \"!\" comment ]   EOL\n"
  913. "\n"
  914. "  The label is optional.  It need not begin in column one.  It must be\n"
  915. "  followed by a colon token.  A label may be on a line by itself.  If\n"
  916. "  so, it will be given an offset from the current value of the location\n"
  917. "  counter, relative to the current segment.\n"
  918. "\n"
  919. "  The opcode must be a legal BLITZ instruction.  The opcode is given in\n"
  920. "  lowercase.  The exact format of the operands depends on the instruction;\n"
  921. "  some BLITZ instructions take no operands while some require several\n"
  922. "  operands. Operands are separated by commas.\n"
  923. "\n"
  924. "  A comment is optional and extends to the end of the line if present.\n"
  925. "\n"
  926. "  Each line is independent.  End-of-line (EOL) is a separate token.  An\n"
  927. "  instruction must be on only one line, although lines may be arbitrarily long.\n"
  928. "\n"
  929. "  Assembler pseudo-ops have the same general syntax.  Some permit labels\n"
  930. "  and others forbid labels.\n"
  931. "\n"
  932. "  The following formatting and spacing conventions are recommended:\n"
  933. "    Labels should begin in column 1.\n"
  934. "    The op-code should be indented by 1 tab stop.\n"
  935. "    The operands, if any, should be indented by 1 additional tab stop.\n"
  936. "    Each BLITZ instruction should be commented.\n"
  937. "    The comment should be indented by 2 additional tab stops.\n"
  938. "    A single space should follow the ! comment character.\n"
  939. "    Block comments should occur before each routine.\n"
  940. "    Comments should be indented with 2 spaces to show logical organization.\n"
  941. "\n"
  942. "  Here is an example of the recommended style for BLITZ assembly code.\n"
  943. "  (The first line shows standard tab stops.)\n"
  944. "       1       t       t       t       t       t       t\n"
  945. "\n"
  946. "       ! main ()\n"
  947. "       !\n"
  948. "       ! This routine does such and such.\n"
  949. "       !\n"
  950. "               .text\n"
  951. "               .export main\n"
  952. "       main:   push    r1              ! Save registers\n"
  953. "               push    r2              ! .\n"
  954. "       loop:                           ! LOOP\n"
  955. "               cmp     r1,10           !   IF r1>10 THEN\n"
  956. "               ble     endif           !   .\n"
  957. "               sub     r2,1,r2         !     r2--\n"
  958. "       endif:                          !   ENDIF\n"
  959. "               sub     r1,r2,r3        !   r3 := r1-r2\n"
  960. "               ...\n"
  961. "\n"
  962. "Labels\n"
  963. "======\n"
  964. "  A label must be followed by a colon token, but the colon is not part of\n"
  965. "  the label.  A label may appear on a line by itself or the label may appear\n"
  966. "  on a line containing a BLITZ instruction or one of the following pseudo-ops:\n"
  967. "    .ascii  .byte  .word  .skip\n"
  968. "  Labels are not allowed on any other assembler pseudo-ops.\n"
  969. "  The label will define a new symbol, and the symbol will be given an\n"
  970. "  offset relative to the beginning of the current segment.  Labels defined\n"
  971. "  in the current file may be exported and labels defined in other files may\n"
  972. "  be imported.  A label will name an address in memory, and as such a label\n"
  973. "  cannot be given a final value until segment-linking time.  During the\n"
  974. "  assembly of the current file, labels in the file are given offsets relative\n"
  975. "  to either the beginning of the .text, .data, or .bss segments.\n"
  976. "\n"
  977. "Operand Syntax\n"
  978. "==============\n"
  979. "  See the BLITZ instruction reference manual for details about what\n"
  980. "  operands each instruction requires.  Operands are separated by\n"
  981. "  commas.  Registers are specified in lowercase (e.g., r4).  A memory\n"
  982. "  reference may be in one of the following forms, although not all forms\n"
  983. "  are allowed in all instructions.  (Here \"R\" stands for any register.)\n"
  984. "    [R]\n"
  985. "    [R+R]\n"
  986. "    [R+expr]\n"
  987. "    [expr]\n"
  988. "    [--R]\n"
  989. "    [R++]\n"
  990. "  Some instructions allow data to be included directly; in such cases\n"
  991. "  the operand will consist of an expression.  The expression may evaluate\n"
  992. "  to an absolute or relative value.  Certain instructions (like jmp, call,\n"
  993. "  and the branch instructions) require the operand to be relative to the\n"
  994. "  segment in which the instruction occurs.\n"
  995. "\n"
  996. "  Here are several sample instructions to illustrate operand syntax:\n"
  997. "                add     r3,r4,r5\n"
  998. "                mul     r7,size,r7\n"
  999. "                sub     r1, ((x*23) << (y+1)), r1\n"
  1000. "                call    foo\n"
  1001. "                push    r6,[--r14]\n"
  1002. "                pop     [r14++],r6\n"
  1003. "                load    [r3],r9\n"
  1004. "                load    [r3+r4],r9\n"
  1005. "                load    [r3+arrayBase],r9\n"
  1006. "                load    [x],r9\n"
  1007. "                jmp     r3\n"
  1008. "                bne     loop\n"
  1009. "                set     0x12ab34cd,r8\n"
  1010. "                syscall 3\n"
  1011. "                reti\n"
  1012. "                tset    [r4],r9\n"
  1013. "                ldptbr  r5\n"
  1014. "  Note that whenever an instruction reads or writes memory, brackets are\n"
  1015. "  used.\n");
  1016. }
  1017.  
  1018.  
  1019.  
  1020. /* printError (msg)
  1021. **
  1022. ** This routine is called to print an error message and the current line
  1023. ** number.  It returns.
  1024. */
  1025. void printError (char *msg) {
  1026.     fprintf (stderr, "Error on line %d: %s\n", currentLine, msg);
  1027.     errorsDetected++;
  1028. }
  1029.  
  1030.  
  1031.  
  1032. /* printError2 (msg, msg2)
  1033. **
  1034. ** This routine is called to print an error message and the current line
  1035. ** number.  It returns.
  1036. */
  1037. void printError2 (char *msg, char * msg2) {
  1038.     fprintf (stderr, "Error on line %d: %s%s\n", currentLine, msg, msg2);
  1039.     errorsDetected++;
  1040. }
  1041.  
  1042.  
  1043.  
  1044.  
  1045. /* scan ()
  1046. **
  1047. ** This routine advances one token by calling the lexer.
  1048. */
  1049. void scan () {
  1050.     if (nextToken != EOF) {
  1051.         nextToken = getToken ();
  1052.     }
  1053. }
  1054.  
  1055.  
  1056.  
  1057. /* mustHave (token, msg)
  1058. **
  1059. ** The next token must be 'token'.  If so, scan it.  If not, it is
  1060. ** a syntax error.
  1061. */
  1062. void mustHave (int tok, char * msg) {
  1063.     if (nextToken == tok)
  1064.         scan ();
  1065.     else {
  1066.         printError (msg);
  1067.     }
  1068. }
  1069.  
  1070.  
  1071.  
  1072. /* getToken ()
  1073. **
  1074. ** Scan the next token and return it.  Side-effects tokenVal and
  1075. ** currentLine.  Returns EOF repeatedly after enf-of-file is reached.
  1076. */
  1077. int getToken (void) {
  1078.   int ch, ch2, containsDot, lengthError, numDigits;
  1079.   int intVal, t, intOverflow, realOverflow, sign;
  1080.   double realValue, exp, power;
  1081.   char lexError2 [] = "Illegal character xxxxxxx in string ignoredxxxxxx";
  1082.   char buffer [MAX_STR_LEN+1];          /* buffer for saving a string */
  1083.   int next, i;                             /* index into buffer */
  1084.  
  1085.   /* If last token was EOL, then increment line number counter. */
  1086.   if (nextToken == EOL) {
  1087.     currentLine++;
  1088.   }
  1089.   while (1) {
  1090.     ch = getc (inputFile);
  1091.  
  1092.     /* Process enf-of-file... */
  1093.     if (ch == EOF) {
  1094.       ungetc (ch, inputFile);
  1095.       return EOF;
  1096.  
  1097.     /* Process newline... */
  1098.     } else if (ch == '\n') {
  1099.       return EOL;
  1100.  
  1101.     /* Process other white space... */
  1102.     } else if (ch == ' ' || ch == '\t') {
  1103.       /* do nothing */
  1104.  
  1105.     /* Process exclamation and comments... */
  1106.     } else if (ch == '!') {
  1107.       while (1) {
  1108.         ch = getc (inputFile);
  1109.         if (ch == EOF) {
  1110.           printError ("End-of-file encountered within a comment");
  1111.           ungetc (ch, inputFile);
  1112.           return EOF;
  1113.         } else if (ch == '\n') {
  1114.           return EOL;
  1115.         }
  1116.       }
  1117.  
  1118.     /* Process strings... */
  1119.     } else if (ch == '"') {
  1120.       next = 0;
  1121.       lengthError = 0;
  1122.       while (1) {
  1123.         ch2 = getc (inputFile);
  1124.         if (ch2 == '"') {
  1125.           break;
  1126.         } else if (ch2 == '\n') {
  1127.           printError ("End-of-line encountered within a string");
  1128.           ungetc (ch2, inputFile);
  1129.           break;
  1130.         } else if (ch2 == EOF) {
  1131.           printError ("EOF encountered within a string");
  1132.           ungetc (ch2, inputFile);
  1133.           break;
  1134.         } else if ((ch2 < 32) || (ch2 > 126)) {
  1135.           sprintf (lexError2,
  1136.               "Illegal character 0x%02x in string ignored", ch2);
  1137.           printError (lexError2);
  1138.         } else {
  1139.           if (ch2 == '\\') {
  1140.             ch2 = scanEscape ();
  1141.           }
  1142.           if (next >= MAX_STR_LEN) {
  1143.             lengthError = 1;
  1144.           } else {
  1145.             buffer [next++] = ch2;
  1146.           }
  1147.         }
  1148.       }
  1149.       tokenValue.tableEntry = lookupAndAdd2 (buffer, next, ID);
  1150.       if (lengthError) {
  1151.         printError ("Maximum string length exceeded");
  1152.       }
  1153.       return STRING;
  1154.  
  1155.     /* Process identifiers... */
  1156.     } else if (isalpha (ch) || (ch=='.') || (ch=='_')) {
  1157.       lengthError = 0;
  1158.       if (ch=='.') {
  1159.         containsDot = 1;
  1160.       } else {
  1161.         containsDot = 0;
  1162.       }
  1163.       next = 0;
  1164.       while (isalpha (ch) || isdigit (ch) || (ch=='.') || (ch=='_')) {
  1165.         if (ch=='.') {
  1166.           containsDot = 1;
  1167.         }
  1168.         if (next >= MAX_STR_LEN) {
  1169.           lengthError = 1;
  1170.         } else {
  1171.           buffer [next++] = ch;
  1172.         }
  1173.         ch = getc (inputFile);
  1174.       }
  1175.       ungetc (ch, inputFile);
  1176.       tokenValue.tableEntry = lookupAndAdd2 (buffer, next, ID);
  1177.       /* If already there, then its type may be ALIGN, ..., ADD, ..., or ID */
  1178.       if (containsDot && (tokenValue.tableEntry->type == ID)) {
  1179.         printError ("Unexpected period within identifier");
  1180.       }
  1181.       if (lengthError) {
  1182.         printError ("Maximum string length exceeded");
  1183.       }
  1184.       return tokenValue.tableEntry->type;
  1185.  
  1186.     /* Process character constants... */
  1187.     } else if (ch == '\'') {
  1188.       ch2 = getc (inputFile);
  1189.       if (ch2 == '\\') {
  1190.         ch2 = scanEscape ();
  1191.       }
  1192.       tokenValue.ivalue = ch2;
  1193.       ch2 = getc (inputFile);
  1194.       if (ch2 != '\'') {
  1195.         ungetc (ch2, inputFile);
  1196.         printError ("Expecting closing quote in character constant");
  1197.       }
  1198.       return INTEGER;
  1199.  
  1200.     /* Process integers... */
  1201.     } else if (isdigit (ch)) {
  1202.  
  1203.       /* See if we have 0x...*/
  1204.       if (ch == '0') {
  1205.         ch2 = getc (inputFile);
  1206.         if (ch2 == 'x') {
  1207.           numDigits = 0;
  1208.           ch = getc (inputFile);
  1209.           if (hexDigit (ch) < 0) {
  1210.             printError ("Must have a hex digit after 0x");
  1211.           }
  1212.           next = intVal = intOverflow = 0;
  1213.           while (hexDigit (ch) >= 0) {
  1214.             intVal = (intVal << 4) + hexDigit(ch);
  1215.             numDigits++;
  1216.             ch = getc (inputFile);
  1217.           }
  1218.           ungetc (ch, inputFile);
  1219.           if (numDigits > 8) {
  1220.             printError ("Hex constants must be 8 or fewer digits");
  1221.             intVal = 0;
  1222.           }
  1223.           tokenValue.ivalue = intVal;
  1224.           return INTEGER;
  1225.         }
  1226.         ungetc (ch2, inputFile);
  1227.       }
  1228.  
  1229.       /* Otherwise we have a string of decimal numerals. */
  1230.       intVal = intOverflow = realOverflow = 0;
  1231.       exp = 1.0;
  1232.       realValue = 0.0;
  1233.       while (isdigit (ch)) {
  1234.         t = intVal * 10 + (ch - '0');
  1235.         if (t < intVal) {
  1236.           intOverflow = 1;
  1237.         }
  1238.         intVal = t;
  1239.         realValue = (realValue * 10.0) + (double) (ch - '0');
  1240.         if (realValue > DBL_MAX) {
  1241.           realOverflow = 1;
  1242.         }
  1243.         ch = getc (inputFile);
  1244.       }
  1245.  
  1246.       /* If we have a real number... */
  1247.       if ((ch == '.') || (ch == 'e') || (ch == 'E')) {
  1248.         /* Read in the fractional part. */
  1249.         if (ch == '.') {
  1250.           ch = getc (inputFile);
  1251.           if (!isdigit (ch)) {
  1252.             printError ("At least one digit is required after decimal");
  1253.           }
  1254.           while (isdigit (ch)) {
  1255.             exp *= 10.0;
  1256.             realValue = realValue + ((float) (ch - '0') / exp);
  1257.             ch = getc (inputFile);
  1258.           }
  1259.         }
  1260.         intVal = 0;
  1261.         sign = 1;
  1262.         if ((ch == 'e') || (ch == 'E')) {
  1263.           ch = getc (inputFile);
  1264.           /* Process the exponent sign, if there is one. */
  1265.           if (ch == '+') {
  1266.             ch = getc (inputFile);
  1267.           } else if (ch == '-') {
  1268.             ch = getc (inputFile);
  1269.             sign = -1;
  1270.           }
  1271.           /* Read in the exponent integer into intVal. */
  1272.           if (!isdigit (ch)) {
  1273.             printError ("Expecting exponent numerals");
  1274.           } else {
  1275.             intVal = intOverflow = 0;
  1276.             while (isdigit (ch)) {
  1277.               t = intVal * 10 + (ch - '0');
  1278.               if (t < intVal) {
  1279.                 intOverflow = 1;
  1280.               }
  1281.               intVal = t;
  1282.               ch = getc (inputFile);
  1283.             }
  1284.             if (intOverflow) {
  1285.               printError ("Exponent is out of range");
  1286.               intVal = 0;
  1287.             }
  1288.           }
  1289.         }
  1290.         ungetc (ch, inputFile);
  1291.         tokenValue.rvalue = 999.888;
  1292.         power =  pow ((double) 10.0, (double) (sign * intVal));
  1293.         realValue = realValue * power;
  1294.         if (realValue > DBL_MAX) {
  1295.           realOverflow = 1;
  1296.         }
  1297.         tokenValue.rvalue = realValue;
  1298.         if (realOverflow) {
  1299.           printError ("Real number is out of range");
  1300.           tokenValue.rvalue = 0.0;
  1301.         }
  1302.         return REAL;
  1303.       } else {  /* If we have an integer... */
  1304.         ungetc (ch, inputFile);
  1305.         if (intOverflow) {
  1306.           printError ("Integer out of range (0..2147483647); use 0x80000000 for -2147483648");
  1307.           intVal = 0;
  1308.         }
  1309.         tokenValue.ivalue = intVal;
  1310.         return INTEGER;
  1311.       }
  1312.  
  1313.     /* Check for <<... */
  1314.     } else if (ch == '<') {
  1315.       ch2 = getc (inputFile);
  1316.       if (ch2 == '<') {
  1317.         return LTLT;
  1318.       } else {
  1319.         ungetc (ch2, inputFile);
  1320.         printError ("A lone < is not a valid token");
  1321.       }
  1322.  
  1323.     /* Check for >> and >>> */
  1324.     } else if (ch == '>') {
  1325.       ch2 = getc (inputFile);
  1326.       if (ch2 == '>') {
  1327.         ch2 = getc (inputFile);
  1328.         if (ch2 == '>') {
  1329.           return GTGTGT;
  1330.         } else {
  1331.           ungetc (ch2, inputFile);
  1332.           return GTGT;
  1333.         }
  1334.       } else {
  1335.         ungetc (ch2, inputFile);
  1336.         printError ("A lone > is not a valid token");
  1337.       }
  1338.  
  1339.     /* Check for + and ++ ... */
  1340.     } else if (ch == '+') {
  1341.       ch2 = getc (inputFile);
  1342.       if (ch2 == '+') {
  1343.         return PLUSPLUS;
  1344.       } else {
  1345.         ungetc (ch2, inputFile);
  1346.         return PLUS;
  1347.       }
  1348.  
  1349.     /* Check for - and -- ... */
  1350.     } else if (ch == '-') {
  1351.       ch2 = getc (inputFile);
  1352.       if (ch2 == '-') {
  1353.         return MINUSMINUS;
  1354.       } else {
  1355.         ungetc (ch2, inputFile);
  1356.         return MINUS;
  1357.       }
  1358.  
  1359.     /* Check for one character symbols. */
  1360.     } else if (ch == '=') {
  1361.       return EQUAL;
  1362.     } else if (ch == ',') {
  1363.       return COMMA;
  1364.     } else if (ch == '[') {
  1365.       return LBRACKET;
  1366.     } else if (ch == ']') {
  1367.       return RBRACKET;
  1368.     } else if (ch == ':') {
  1369.       return COLON;
  1370.     } else if (ch == '*') {
  1371.       return STAR;
  1372.     } else if (ch == '/') {
  1373.       return SLASH;
  1374.     } else if (ch == '%') {
  1375.       return PERCENT;
  1376.     } else if (ch == '&') {
  1377.       return AMPERSAND;
  1378.     } else if (ch == '|') {
  1379.       return BAR;
  1380.     } else if (ch == '^') {
  1381.       return CARET;
  1382.     } else if (ch == '~') {
  1383.       return TILDE;
  1384.     } else if (ch == '(') {
  1385.       return LPAREN;
  1386.     } else if (ch == ')') {
  1387.       return RPAREN;
  1388.  
  1389.     /* Otherwise, we have an invalid character; ignore it. */
  1390.     } else {
  1391.       if ((ch>=' ') && (ch<='~')) {
  1392.         sprintf (lexError2, "Illegal character '%c' ignored", ch);
  1393.       } else {
  1394.         sprintf (lexError2, "Illegal character 0x%02x ignored", ch);
  1395.       }
  1396.       printError (lexError2);
  1397.     }
  1398.   }
  1399. }
  1400.  
  1401.  
  1402.  
  1403. /* scanEscape ()
  1404. **
  1405. ** This routine is called after we have gotten a back-slash.  It
  1406. ** reads whatever characters follow and returns the character.  If
  1407. ** problems arise it prints a message and returns '?'.  If EOF is
  1408. ** encountered, it prints a message, calls ungetc (EOF, inputFile)
  1409. ** and returns '?'.
  1410. */
  1411. int scanEscape () {
  1412.   int ch, ch2, i, j;
  1413.   ch2 = getc (inputFile);
  1414.   if (ch2 == '\n') {
  1415.     printError ("End-of-line encountered after a \\ escape");
  1416.     ungetc (ch2, inputFile);
  1417.     return '?';
  1418.   }
  1419.   if (ch2 == EOF) {
  1420.     printError ("End-of-file encountered after a \\ escape");
  1421.     ungetc (ch2, inputFile);
  1422.     return '?';
  1423.   }
  1424.   i = isEscape(ch2);
  1425.   if (i != -1) {
  1426.     return i;
  1427.   } else if (ch2 == 'x') {
  1428.     ch = getc (inputFile);  // Get 1st hex digit
  1429.     if (ch == '\n') {
  1430.       printError ("End-of-line encountered after a \\x escape");
  1431.       return '?';
  1432.     }
  1433.     if (ch == EOF) {
  1434.       printError ("End-of-file encountered after a \\x escape");
  1435.       ungetc (ch, inputFile);
  1436.       return '?';
  1437.     }
  1438.     i = hexCharToInt (ch);
  1439.     if (i < 0) {
  1440.       printError ("Must have a hex digit after \\x");
  1441.       return '?';
  1442.     } else {
  1443.       ch2 = getc (inputFile);
  1444.       if (ch2 == '\n') {
  1445.         printError ("End-of-line encountered after a \\x escape");
  1446.         return '?';
  1447.       }
  1448.       if (ch2 == EOF) {
  1449.         printError ("End-of-file encountered after a \\x escape");
  1450.         ungetc (ch2, inputFile);
  1451.         return '?';
  1452.       }
  1453.       j = hexCharToInt (ch2);
  1454.       if (j < 0) {
  1455.         printError ("Must have two hex digits after \\x");
  1456.         return '?';
  1457.       }
  1458.       return (i<<4) + j;
  1459.     }
  1460.   } else {
  1461.     printError ("Illegal escape (only \\0, \\a, \\b, \\t, \\n, \\v, \\f, \\r, \\\", \\\', \\\\, and \\xHH allowed)");
  1462.     return '?';
  1463.   }
  1464. }
  1465.  
  1466.  
  1467.  
  1468. /* isEscapeChar (char)  -->  ASCII Value
  1469. **
  1470. ** This routine is passed a char, such as 'n'.  If this char is one
  1471. ** of the escape characters, (e.g., \n), then this routine returns the
  1472. ** ASCII value (e.g., 10).  Otherwise, it returns -1.
  1473. */
  1474. int isEscape (char ch) {
  1475.   if (ch == '0') {
  1476.     return 0;
  1477.   } else if (ch == 'a') {
  1478.     return '\a';
  1479.   } else if (ch == 'b') {
  1480.     return '\b';
  1481.   } else if (ch == 't') {
  1482.     return '\t';
  1483.   } else if (ch == 'n') {
  1484.     return '\n';
  1485.   } else if (ch == 'v') {
  1486.     return '\v';
  1487.   } else if (ch == 'f') {
  1488.     return '\f';
  1489.   } else if (ch == 'r') {
  1490.     return '\r';
  1491.   } else if (ch == '\"') {
  1492.     return '\"';
  1493.   } else if (ch == '\'') {
  1494.     return '\'';
  1495.   } else if (ch == '\\') {
  1496.     return '\\';
  1497.   } else {
  1498.     return -1;
  1499.   }
  1500. }
  1501.  
  1502.  
  1503.  
  1504. /* hexCharToInt (char)  --> int
  1505. **
  1506. ** This routine is passed a character. If it is a hex digit, i.e.,
  1507. **    0, 1, 2, ... 9, a, b, ... f, A, B, ... F
  1508. ** then it returns its value (0..15).  Otherwise, it returns -1.
  1509. */
  1510. int hexCharToInt (char ch) {
  1511.   if (('0'<=ch) && (ch<='9')) {
  1512.     return ch-'0';
  1513.   } else if (('a'<=ch) && (ch<='f')) {
  1514.     return ch-'a' + 10;
  1515.   } else if (('A'<=ch) && (ch<='F')) {
  1516.     return ch-'A' + 10;
  1517.   } else {
  1518.     return -1;
  1519.   }
  1520. }
  1521.  
  1522.  
  1523.  
  1524. /* intToHexChar (int)
  1525. **
  1526. ** This routine is passed an integer 0..15.  It returns a char
  1527. ** from 0 1 2 3 4 5 6 7 8 9 A B C D E F
  1528. */
  1529. char intToHexChar (int i) {
  1530.   if (i<10) {
  1531.     return '0' + i;
  1532.   } else {
  1533.     return 'A' + (i-10);
  1534.   }
  1535. }
  1536.  
  1537.  
  1538.  
  1539. /* initKeywords ()
  1540. **
  1541. ** This routine adds each keyword to the symbol table with the corresponding
  1542. ** type code.
  1543. */
  1544. void initKeywords () {
  1545.   lookupAndAdd ("add", ADD);
  1546.   lookupAndAdd ("sub", SUB);
  1547.   lookupAndAdd ("mul", MUL);
  1548.   lookupAndAdd ("div", DIV);
  1549.   lookupAndAdd ("sll", SLL);
  1550.   lookupAndAdd ("srl", SRL);
  1551.   lookupAndAdd ("sra", SRA);
  1552.   lookupAndAdd ("or", OR);
  1553.   lookupAndAdd ("and", AND);
  1554.   lookupAndAdd ("andn", ANDN);
  1555.   lookupAndAdd ("xor", XOR);
  1556.   lookupAndAdd ("rem", REM);
  1557.   lookupAndAdd ("load", LOAD);
  1558.   lookupAndAdd ("loadb", LOADB);
  1559.   lookupAndAdd ("loadv", LOADV);
  1560.   lookupAndAdd ("loadbv", LOADBV);
  1561.   lookupAndAdd ("store", STORE);
  1562.   lookupAndAdd ("storeb", STOREB);
  1563.   lookupAndAdd ("storev", STOREV);
  1564.   lookupAndAdd ("storebv", STOREBV);
  1565.   lookupAndAdd ("call", CALL);
  1566.   lookupAndAdd ("jmp", JMP);
  1567.   lookupAndAdd ("be", BE);
  1568.   lookupAndAdd ("bne", BNE);
  1569.   lookupAndAdd ("bl", BL);
  1570.   lookupAndAdd ("ble", BLE);
  1571.   lookupAndAdd ("bg", BG);
  1572.   lookupAndAdd ("bge", BGE);
  1573.   lookupAndAdd ("bvs", BVS);
  1574.   lookupAndAdd ("bvc", BVC);
  1575.   lookupAndAdd ("bns", BNS);
  1576.   lookupAndAdd ("bnc", BNC);
  1577.   lookupAndAdd ("bss", BSS_OP);
  1578.   lookupAndAdd ("bsc", BSC);
  1579.   lookupAndAdd ("bis", BIS);
  1580.   lookupAndAdd ("bic", BIC);
  1581.   lookupAndAdd ("bps", BPS);
  1582.   lookupAndAdd ("bpc", BPC);
  1583.   lookupAndAdd ("push", PUSH);
  1584.   lookupAndAdd ("pop", POP);
  1585.   lookupAndAdd ("sethi", SETHI);
  1586.   lookupAndAdd ("setlo", SETLO);
  1587.   lookupAndAdd ("ldaddr", LDADDR);
  1588.   lookupAndAdd ("syscall", SYSCALL);
  1589.   lookupAndAdd ("nop", NOP);
  1590.   lookupAndAdd ("wait", WAIT);
  1591.   lookupAndAdd ("debug", DEBUG);
  1592.   lookupAndAdd ("cleari", CLEARI);
  1593.   lookupAndAdd ("seti", SETI);
  1594.   lookupAndAdd ("clearp", CLEARP);
  1595.   lookupAndAdd ("setp", SETP);
  1596.   lookupAndAdd ("clears", CLEARS);
  1597.   lookupAndAdd ("reti", RETI);
  1598.   lookupAndAdd ("ret", RET);
  1599.   lookupAndAdd ("debug2", DEBUG2);
  1600.   lookupAndAdd ("tset", TSET);
  1601.   lookupAndAdd ("readu", READU);
  1602.   lookupAndAdd ("writeu", WRITEU);
  1603.   lookupAndAdd ("ldptbr", LDPTBR);
  1604.   lookupAndAdd ("ldptlr", LDPTLR);
  1605.   lookupAndAdd ("ftoi", FTOI);
  1606.   lookupAndAdd ("itof", ITOF);
  1607.   lookupAndAdd ("fadd", FADD);
  1608.   lookupAndAdd ("fsub", FSUB);
  1609.   lookupAndAdd ("fmul", FMUL);
  1610.   lookupAndAdd ("fdiv", FDIV);
  1611.   lookupAndAdd ("fcmp", FCMP);
  1612.   lookupAndAdd ("fsqrt", FSQRT);
  1613.   lookupAndAdd ("fneg", FNEG);
  1614.   lookupAndAdd ("fabs", FABS);
  1615.   lookupAndAdd ("fload", FLOAD);
  1616.   lookupAndAdd ("fstore", FSTORE);
  1617.  
  1618.   lookupAndAdd ("mov", MOV);
  1619.   lookupAndAdd ("cmp", CMP);
  1620.   lookupAndAdd ("set", SET);
  1621.   lookupAndAdd ("neg", NEG);
  1622.   lookupAndAdd ("not", NOT);
  1623.   lookupAndAdd ("clr", CLR);
  1624.   lookupAndAdd ("btst", BTST);
  1625.   lookupAndAdd ("bset", BSET);
  1626.   lookupAndAdd ("bclr", BCLR);
  1627.   lookupAndAdd ("btog", BTOG);
  1628.  
  1629.   lookupAndAdd (".text", TEXT);
  1630.   lookupAndAdd (".data", DATA);
  1631.   lookupAndAdd (".ascii", ASCII);
  1632.   lookupAndAdd (".byte", BYTE);
  1633.   lookupAndAdd (".word", WORD);
  1634.   lookupAndAdd (".double", DOUBLE);
  1635.   lookupAndAdd (".export", EXPORT);
  1636.   lookupAndAdd (".import", IMPORT);
  1637.   lookupAndAdd (".align", ALIGN);
  1638.   lookupAndAdd (".skip", SKIP);
  1639.   lookupAndAdd (".bss", BSS_SEG);
  1640.  
  1641.   lookupAndAdd (".absolute", ABSOLUTE);  /* This is not a keyword */
  1642.  
  1643.   lookupAndAdd ("r0", R0);
  1644.   lookupAndAdd ("r1", R1);
  1645.   lookupAndAdd ("r2", R2);
  1646.   lookupAndAdd ("r3", R3);
  1647.   lookupAndAdd ("r4", R4);
  1648.   lookupAndAdd ("r5", R5);
  1649.   lookupAndAdd ("r6", R6);
  1650.   lookupAndAdd ("r7", R7);
  1651.   lookupAndAdd ("r8", R8);
  1652.   lookupAndAdd ("r9", R9);
  1653.   lookupAndAdd ("r10", R10);
  1654.   lookupAndAdd ("r11", R11);
  1655.   lookupAndAdd ("r12", R12);
  1656.   lookupAndAdd ("r13", R13);
  1657.   lookupAndAdd ("r14", R14);
  1658.   lookupAndAdd ("r15", R15);
  1659.  
  1660.   lookupAndAdd ("f0", F0);
  1661.   lookupAndAdd ("f1", F1);
  1662.   lookupAndAdd ("f2", F2);
  1663.   lookupAndAdd ("f3", F3);
  1664.   lookupAndAdd ("f4", F4);
  1665.   lookupAndAdd ("f5", F5);
  1666.   lookupAndAdd ("f6", F6);
  1667.   lookupAndAdd ("f7", F7);
  1668.   lookupAndAdd ("f8", F8);
  1669.   lookupAndAdd ("f9", F9);
  1670.   lookupAndAdd ("f10", F10);
  1671.   lookupAndAdd ("f11", F11);
  1672.   lookupAndAdd ("f12", F12);
  1673.   lookupAndAdd ("f13", F13);
  1674.   lookupAndAdd ("f14", F14);
  1675.   lookupAndAdd ("f15", F15);
  1676. }
  1677.  
  1678.  
  1679.  
  1680. /* lookupAndAdd (givenStr, newType)
  1681. **
  1682. ** This routine is passed a pointer to a string of characters, terminated
  1683. ** by '\0'.  It looks it up in the table.  If there is already an entry in
  1684. ** the table, it returns a pointer to the previously stored entry.
  1685. ** If not found, it allocates a new table entry, copies the new string into
  1686. ** the table, initializes it's type, and returns a pointer to the new
  1687. ** table entry.
  1688. */
  1689. TableEntry * lookupAndAdd (char * givenStr, int newType) {
  1690.   return lookupAndAdd2 (givenStr, strlen(givenStr), newType);
  1691. }
  1692.  
  1693.  
  1694.  
  1695. /* lookupAndAdd2 (givenStr, length, newType)
  1696. **
  1697. ** This routine is passed a pointer to a sequence of characters (possibly
  1698. ** containing \0, of length "length".  It looks this string up in the
  1699. ** symbol table.  If there is already an entry in the table, it returns
  1700. ** a pointer to the previously stored entry.  If not found, it allocates
  1701. ** a new table entry, copies the new string into the table, initializes
  1702. *  it's type, and returns a pointer to the new table entry.
  1703. */
  1704. TableEntry * lookupAndAdd2 (char * givenStr, int length, int newType) {
  1705.   unsigned hashVal = 0, g;
  1706.   char * p, * q;
  1707.   int i;
  1708.   TableEntry * entryPtr;
  1709.  
  1710.    /* Compute the hash value for the givenStr and set hashVal to it. */
  1711.   for ( p = givenStr, i=0;
  1712.         i < length;
  1713.         p++, i++ ) {
  1714.     hashVal = (hashVal << 4) + (*p);
  1715.     if (g = hashVal & 0xf0000000) {
  1716.       hashVal = hashVal ^ (g >> 24);
  1717.       hashVal = hashVal ^ g;
  1718.     }
  1719.   }
  1720.   hashVal %= SYMBOL_TABLE_HASH_SIZE;
  1721.  
  1722.   /* Search the linked list and return if we find it. */
  1723.   for (entryPtr = symbolTableIndex [hashVal];
  1724.                       entryPtr;
  1725.                       entryPtr = entryPtr->next) {
  1726.     if ((length == entryPtr->string.length) &&
  1727.         (bytesEqual (entryPtr->string.string, givenStr, length))) {
  1728.       return entryPtr;
  1729.     }
  1730.   }
  1731.  
  1732.   /* Create an entry and initialize it. */
  1733.   entryPtr = (TableEntry *)
  1734.                 calloc (1, sizeof (TableEntry) + length + 1);
  1735.   if (entryPtr == 0) {
  1736.     fprintf (stderr, "Calloc failed in lookupAndAdd!");
  1737.     errorExit ();
  1738.   }
  1739.   for (p=givenStr, q=entryPtr->string.string, i=length;
  1740.        i>0;
  1741.        p++, q++, i--) {
  1742.     *q = *p;
  1743.   } 
  1744.   entryPtr->string.length = length;
  1745.   entryPtr->type = newType;
  1746.   entryPtr->offset = 0;
  1747.   entryPtr->relativeTo = NULL;
  1748.   entryPtr->imported = 0;
  1749.   entryPtr->exported = 0;
  1750.  
  1751.   /* Add the new entry to the appropriate linked list and return. */
  1752.   entryPtr->next = symbolTableIndex [hashVal];
  1753.   symbolTableIndex [hashVal] = entryPtr;
  1754.   return entryPtr;
  1755. }
  1756.  
  1757.  
  1758.  
  1759. /* bytesEqual (p, q, length)
  1760. **
  1761. ** This function is passed two pointers to blocks of characters, and a
  1762. ** length.  It compares the two sequences of bytes and returns true iff
  1763. ** they are both equal.
  1764. */
  1765. int bytesEqual (char * p, char * q, int length) {
  1766.   for (; length>0; length--, p++, q++) {
  1767.     if (*p != *q) return 0;
  1768.   }
  1769.   return 1;
  1770. }
  1771.  
  1772.  
  1773.  
  1774. /* printSymbolTable ()
  1775. **
  1776. ** This routine runs through the symbol table and prints each entry.
  1777. */
  1778. void printSymbolTable () {
  1779.   int hashVal;
  1780.   TableEntry * entryPtr;
  1781.   printf ("STRING\tIMPORT\tEXPORT\tOFFSET\tRELATIVE-TO\n");
  1782.   printf ("======\t======\t======\t======\t===========\n");
  1783.   for (hashVal = 0; hashVal<SYMBOL_TABLE_HASH_SIZE; hashVal++) {
  1784.     for (entryPtr = symbolTableIndex [hashVal];
  1785.                        entryPtr;
  1786.                        entryPtr = entryPtr->next) {
  1787.       if (entryPtr->type == ID) {
  1788.         /* printSym (entryPtr->type); */
  1789.         printString (entryPtr);
  1790.         if (entryPtr->imported) {
  1791.           printf ("\timport");
  1792.         } else {
  1793.           printf ("\t");
  1794.         }
  1795.         if (entryPtr->exported) {
  1796.           printf ("\texport");
  1797.         } else {
  1798.           printf ("\t");
  1799.         }
  1800.         printf ("\t%d", entryPtr->offset);
  1801.         if (entryPtr->relativeTo != NULL) {
  1802.           printf ("\t");
  1803.           printString (entryPtr->relativeTo);
  1804.         } else {
  1805.           printf ("\t");
  1806.         }
  1807.         printf ("\n");
  1808.       }
  1809.     }
  1810.   }
  1811. }
  1812.  
  1813.  
  1814.  
  1815. /* printString (tableEntryPtr)
  1816. **
  1817. ** This routine is passed a pointer to a TableEntry.  It prints the
  1818. ** string, translating non-printable characters into escape sequences.
  1819. **
  1820. **     \0   \a   \b  \t   \n   \v   \f   \r   \"   \'   \\   \xHH
  1821. */
  1822. void printString (TableEntry * tableEntryPtr) {
  1823. #define BUF_SIZE 200
  1824.   String * str = &tableEntryPtr->string;
  1825.   int bufPtr, strPtr;
  1826.   char buffer[BUF_SIZE];
  1827.   int c;
  1828.   strPtr = 0;
  1829.   while (1) {
  1830.     /* If all characters printed, then exit. */
  1831.     if (strPtr >= str->length) return;
  1832.     /* Fill up buffer */
  1833.     bufPtr = 0;
  1834.     while ((bufPtr < BUF_SIZE-4) && (strPtr < str->length)) {  // 4=room for \x12
  1835.       c = str->string [strPtr++];
  1836.       if (c == '\0') {
  1837.         buffer[bufPtr++] = '\\';
  1838.         buffer[bufPtr++] = '0';
  1839.       } else if (c == '\a') {
  1840.         buffer[bufPtr++] = '\\';
  1841.         buffer[bufPtr++] = 'a';
  1842.       } else if (c == '\b') {
  1843.         buffer[bufPtr++] = '\\';
  1844.         buffer[bufPtr++] = 'b';
  1845.       } else if (c == '\t') {
  1846.         buffer[bufPtr++] = '\\';
  1847.         buffer[bufPtr++] = 't';
  1848.       } else if (c == '\n') {
  1849.         buffer[bufPtr++] = '\\';
  1850.         buffer[bufPtr++] = 'n';
  1851.       } else if (c == '\v') {
  1852.         buffer[bufPtr++] = '\\';
  1853.         buffer[bufPtr++] = 'v';
  1854.       } else if (c == '\f') {
  1855.         buffer[bufPtr++] = '\\';
  1856.         buffer[bufPtr++] = 'f';
  1857.       } else if (c == '\r') {
  1858.         buffer[bufPtr++] = '\\';
  1859.         buffer[bufPtr++] = 'r';
  1860.       } else if (c == '\\') {
  1861.         buffer[bufPtr++] = '\\';
  1862.         buffer[bufPtr++] = '\\';
  1863.       } else if (c == '\"') {
  1864.         buffer[bufPtr++] = '\\';
  1865.         buffer[bufPtr++] = '\"';
  1866.       } else if (c == '\'') {
  1867.         buffer[bufPtr++] = '\\';
  1868.         buffer[bufPtr++] = '\'';
  1869.       } else if ((c>=32) && (c<127)) {
  1870.         buffer[bufPtr++] = c;
  1871.       } else {
  1872.         buffer[bufPtr++] = '\\';
  1873.         buffer[bufPtr++] = 'x';
  1874.         buffer[bufPtr++] = intToHexChar ((c>>4) & 0x0000000f);
  1875.         buffer[bufPtr++] = intToHexChar (c & 0x0000000f);
  1876.         /*  printError ("Program logic error: String contains unprintable char");  */
  1877.       }
  1878.     }
  1879.     /* Add \0 to buffer */
  1880.     buffer[bufPtr++] = '\0';
  1881.     /* Print buffer */
  1882.     printf ("%s", buffer);
  1883.   }
  1884. }
  1885.  
  1886.  
  1887.  
  1888. /* newString (char *) -> String *
  1889. **
  1890. ** This routine allocates a String, initializes it from the argument,
  1891. ** and returns a pointer to the new String.  The argument is assumed
  1892. ** to be \0 terminated.
  1893. */
  1894. String * newString (char * charPtr) {
  1895.   String * str;
  1896.   str = (String *) calloc (1, strlen (charPtr) + sizeof (String) + 1);
  1897.   printf ("size allocated = %d\n", strlen (charPtr) + sizeof (String));
  1898.   str->length = strlen (charPtr);
  1899.   strcpy (str->string, charPtr);  /* copies all characters plus \0. */
  1900.   return str;
  1901. }
  1902.  
  1903.  
  1904.  
  1905. /* checkAllExportsImports ()
  1906. **
  1907. ** This routine runs through all the instructions, looking at
  1908. ** .import and .export pseudo-ops.  If the symbol is exported, we
  1909. ** make sure it has a value.  If the symbol is imported, we make
  1910. ** sure it is not defined in this file.  This pass must be run after
  1911. ** we process equates, since the processing of equates may assign
  1912. ** values to some symbols.
  1913. */
  1914. void checkAllExportsImports () {
  1915.   Instruction * instrPtr;
  1916.   TableEntry * tableEntry;
  1917.  
  1918.   /* Run through the instruction list. */
  1919.   for (instrPtr=instrList; instrPtr!=NULL; instrPtr=instrPtr->next) {
  1920.     currentLine = instrPtr->lineNum;
  1921.     if (instrPtr->op == IMPORT) {
  1922.       tableEntry = instrPtr->tableEntry;
  1923.       if (!tableEntry->imported) {
  1924.         printError ("Program logic error: Subject of .import not marked");
  1925.       }
  1926.       if (tableEntry->relativeTo != NULL) {
  1927.         printError ("Attempt to import a symbol which is also defined in this file");
  1928.       }
  1929.     }
  1930.     if (instrPtr->op == EXPORT) {
  1931.       tableEntry = instrPtr->tableEntry;
  1932.       if (!tableEntry->exported) {
  1933.         printError ("Program logic error: Subject of .export not marked");
  1934.       }
  1935.       if (tableEntry->relativeTo == NULL) {
  1936.         printError2 ("Attempt to export a symbol which is not defined in this file: ", tableEntry->string.string);
  1937.       }
  1938.     }
  1939.   }
  1940. }
  1941.  
  1942.  
  1943.  
  1944. /* checkAllExpressions ()
  1945. **
  1946. ** This routine runs through all the instructions and evaluates any
  1947. ** expressions found in them, printing errors as they are detected.
  1948. ** This pass must be run after we process equates, since the processing
  1949. ** of equates may assign values to some symbols used in expressions.
  1950. ** We ignore equates, since they have been previously evaluated and doing
  1951. ** it again will cause duplicate error messages.
  1952. */
  1953. void checkAllExpressions () {
  1954.   Instruction * instrPtr;
  1955.   for (instrPtr=instrList; instrPtr!=NULL; instrPtr=instrPtr->next) {
  1956.     currentLine = instrPtr->lineNum;
  1957.     if ((instrPtr->expr != NULL) && (instrPtr->op != EQUAL)) {
  1958.       evalExpr (instrPtr->expr, 1);
  1959.     }
  1960.     if ((instrPtr->format == F)
  1961.            && (instrPtr->expr->relativeTo == absoluteTableEntry)) {
  1962.       printError ("Call, jump, or branch has an absolute value as an operand");
  1963.     }
  1964.   }
  1965. }
  1966.  
  1967.  
  1968.  
  1969. /* printSym (s)
  1970. **
  1971. ** This routine prints the symbol given.
  1972. */
  1973. void printSym (int i) {
  1974.   switch (i) {
  1975.     case ADD1:        printf ("ADD1"); break;
  1976.     case ADD2:        printf ("ADD2"); break;
  1977.     case SUB1:        printf ("SUB1"); break;
  1978.     case SUB2:        printf ("SUB2"); break;
  1979.     case MUL1:        printf ("MUL1"); break;
  1980.     case MUL2:        printf ("MUL2"); break;
  1981.     case DIV1:        printf ("DIV1"); break;
  1982.     case DIV2:        printf ("DIV2"); break;
  1983.     case SLL1:        printf ("SLL1"); break;
  1984.     case SLL2:        printf ("SLL2"); break;
  1985.     case SRL1:        printf ("SRL1"); break;
  1986.     case SRL2:        printf ("SRL2"); break;
  1987.     case SRA1:        printf ("SRA1"); break;
  1988.     case SRA2:        printf ("SRA2"); break;
  1989.     case OR1:        printf ("OR1"); break;
  1990.     case OR2:        printf ("OR2"); break;
  1991.     case AND1:        printf ("AND1"); break;
  1992.     case AND2:        printf ("AND2"); break;
  1993.     case ANDN1:        printf ("ANDN1"); break;
  1994.     case ANDN2:        printf ("ANDN2"); break;
  1995.     case XOR1:        printf ("XOR1"); break;
  1996.     case XOR2:        printf ("XOR2"); break;
  1997.     case REM1:        printf ("REM1"); break;
  1998.     case REM2:        printf ("REM2"); break;
  1999.     case LOAD1:        printf ("LOAD1"); break;
  2000.     case LOAD2:        printf ("LOAD2"); break;
  2001.     case LOADB1:    printf ("LOADB1"); break;
  2002.     case LOADB2:    printf ("LOADB2"); break;
  2003.     case LOADV1:    printf ("LOADV1"); break;
  2004.     case LOADV2:    printf ("LOADV2"); break;
  2005.     case LOADBV1:    printf ("LOADBV1"); break;
  2006.     case LOADBV2:    printf ("LOADBV2"); break;
  2007.     case STORE1:    printf ("STORE1"); break;
  2008.     case STORE2:    printf ("STORE2"); break;
  2009.     case STOREB1:    printf ("STOREB1"); break;
  2010.     case STOREB2:    printf ("STOREB2"); break;
  2011.     case STOREV1:    printf ("STOREV1"); break;
  2012.     case STOREV2:    printf ("STOREV2"); break;
  2013.     case STOREBV1:    printf ("STOREBV1"); break;
  2014.     case STOREBV2:    printf ("STOREBV2"); break;
  2015.     case SETHI:        printf ("SETHI"); break;
  2016.     case SETLO:        printf ("SETLO"); break;
  2017.     case CALL1:        printf ("CALL1"); break;
  2018.     case CALL2:        printf ("CALL2"); break;
  2019.     case JMP1:        printf ("JMP1"); break;
  2020.     case JMP2:        printf ("JMP2"); break;
  2021.     case BE1:        printf ("BE1"); break;
  2022.     case BE2:        printf ("BE2"); break;
  2023.     case BNE1:        printf ("BNE1"); break;
  2024.     case BNE2:        printf ("BNE2"); break;
  2025.     case BL1:        printf ("BL1"); break;
  2026.     case BL2:        printf ("BL2"); break;
  2027.     case BLE1:        printf ("BLE1"); break;
  2028.     case BLE2:        printf ("BLE2"); break;
  2029.     case BG1:        printf ("BG1"); break;
  2030.     case BG2:        printf ("BG2"); break;
  2031.     case BGE1:        printf ("BGE1"); break;
  2032.     case BGE2:        printf ("BGE2"); break;
  2033.     case BVS1:        printf ("BVS1"); break;
  2034.     case BVS2:        printf ("BVS2"); break;
  2035.     case BVC1:        printf ("BVC1"); break;
  2036.     case BVC2:        printf ("BVC2"); break;
  2037.     case BNS1:        printf ("BNS1"); break;
  2038.     case BNS2:        printf ("BNS2"); break;
  2039.     case BNC1:        printf ("BNC1"); break;
  2040.     case BNC2:        printf ("BNC2"); break;
  2041.     case BSS1:        printf ("BSS1"); break;
  2042.     case BSS2:        printf ("BSS2"); break;
  2043.     case BSC1:        printf ("BSC1"); break;
  2044.     case BSC2:        printf ("BSC2"); break;
  2045.     case BIS1:        printf ("BIS1"); break;
  2046.     case BIS2:        printf ("BIS2"); break;
  2047.     case BIC1:        printf ("BIC1"); break;
  2048.     case BIC2:        printf ("BIC2"); break;
  2049.     case BPS1:        printf ("BPS1"); break;
  2050.     case BPS2:        printf ("BPS2"); break;
  2051.     case BPC1:        printf ("BPC1"); break;
  2052.     case BPC2:        printf ("BPC2"); break;
  2053.     case PUSH:        printf ("PUSH"); break;
  2054.     case POP:        printf ("POP"); break;
  2055.     case SYSCALL:    printf ("SYSCALL"); break;
  2056.     case NOP:        printf ("NOP"); break;
  2057.     case WAIT:        printf ("WAIT"); break;
  2058.     case DEBUG:        printf ("DEBUG"); break;
  2059.     case CLEARI:    printf ("CLEARI"); break;
  2060.     case SETI:        printf ("SETI"); break;
  2061.     case CLEARP:    printf ("CLEARP"); break;
  2062.     case SETP:        printf ("SETP"); break;
  2063.     case CLEARS:    printf ("CLEARS"); break;
  2064.     case RETI:        printf ("RETI"); break;
  2065.     case RET:        printf ("RET"); break;
  2066.     case DEBUG2:    printf ("DEBUG2"); break;
  2067.     case READU1:    printf ("READU1"); break;
  2068.     case READU2:    printf ("READU2"); break;
  2069.     case WRITEU1:    printf ("WRITEU1"); break;
  2070.     case WRITEU2:    printf ("WRITEU2"); break;
  2071.     case LDPTBR:    printf ("LDPTBR"); break;
  2072.     case LDPTLR:    printf ("LDPTLR"); break;
  2073.     case ITOF:        printf ("ITOF"); break;
  2074.     case FTOI:        printf ("FTOI"); break;
  2075.     case FADD:        printf ("FADD"); break;
  2076.     case FSUB:        printf ("FSUB"); break;
  2077.     case FMUL:        printf ("FMUL"); break;
  2078.     case FDIV:        printf ("FDIV"); break;
  2079.     case FCMP:        printf ("FCMP"); break;
  2080.     case FSQRT:        printf ("FSQRT"); break;
  2081.     case FNEG:        printf ("FNEG"); break;
  2082.     case FABS:        printf ("FABS"); break;
  2083.     case FLOAD1:    printf ("FLOAD1"); break;
  2084.     case FLOAD2:    printf ("FLOAD2"); break;
  2085.     case FSTORE1:    printf ("FSTORE1"); break;
  2086.     case FSTORE2:    printf ("FSTORE2"); break;
  2087.     case EOL:        printf ("EOL"); break;
  2088.     case LABEL:        printf ("LABEL"); break;
  2089.     case ID:        printf ("ID"); break;
  2090.     case INTEGER:    printf ("INTEGER"); break;
  2091.     case REAL:        printf ("REAL"); break;
  2092.     case STRING:    printf ("STRING"); break;
  2093.     case ABSOLUTE:    printf ("ABSOLUTE"); break;
  2094.     case TEXT:        printf ("TEXT"); break;
  2095.     case DATA:        printf ("DATA"); break;
  2096.     case BSS_SEG:    printf ("BSS_SEG"); break;
  2097.     case ASCII:        printf ("ASCII"); break;
  2098.     case BYTE:        printf ("BYTE"); break;
  2099.     case WORD:        printf ("WORD"); break;
  2100.     case DOUBLE:    printf ("DOUBLE"); break;
  2101.     case EXPORT:    printf ("EXPORT"); break;
  2102.     case IMPORT:    printf ("IMPORT"); break;
  2103.     case ALIGN:        printf ("ALIGN"); break;
  2104.     case SKIP:        printf ("SKIP"); break;
  2105.     case EQUAL:        printf ("EQUAL"); break;
  2106.     case COMMA:        printf ("COMMA"); break;
  2107.     case LBRACKET:    printf ("LBRACKET"); break;
  2108.     case RBRACKET:    printf ("RBRACKET"); break;
  2109.     case PLUS:        printf ("PLUS"); break;
  2110.     case PLUSPLUS:    printf ("PLUSPLUS"); break;
  2111.     case MINUS:        printf ("MINUS"); break;
  2112.     case MINUSMINUS:    printf ("MINUSMINUS"); break;
  2113.     case COLON:        printf ("COLON"); break;
  2114.     case STAR:        printf ("STAR"); break;
  2115.     case SLASH:        printf ("SLASH"); break;
  2116.     case PERCENT:    printf ("PERCENT"); break;
  2117.     case AMPERSAND:    printf ("AMPERSAND"); break;
  2118.     case BAR:        printf ("BAR"); break;
  2119.     case CARET:        printf ("CARET"); break;
  2120.     case TILDE:        printf ("TILDE"); break;
  2121.     case LTLT:        printf ("LTLT"); break;
  2122.     case GTGT:        printf ("GTGT"); break;
  2123.     case GTGTGT:    printf ("GTGTGT"); break;
  2124.     case LPAREN:    printf ("LPAREN"); break;
  2125.     case RPAREN:    printf ("RPAREN"); break;
  2126.     case ADD:        printf ("ADD"); break;
  2127.     case SUB:        printf ("SUB"); break;
  2128.     case MUL:        printf ("MUL"); break;
  2129.     case DIV:        printf ("DIV"); break;
  2130.     case SLL:        printf ("SLL"); break;
  2131.     case SRL:        printf ("SRL"); break;
  2132.     case SRA:        printf ("SRA"); break;
  2133.     case OR:        printf ("OR"); break;
  2134.     case AND:        printf ("AND"); break;
  2135.     case ANDN:        printf ("ANDN"); break;
  2136.     case XOR:        printf ("XOR"); break;
  2137.     case REM:        printf ("REM"); break;
  2138.     case LOAD:        printf ("LOAD"); break;
  2139.     case LOADB:        printf ("LOADB"); break;
  2140.     case LOADV:        printf ("LOADV"); break;
  2141.     case LOADBV:    printf ("LOADBV"); break;
  2142.     case STORE:        printf ("STORE"); break;
  2143.     case STOREB:    printf ("STOREB"); break;
  2144.     case STOREV:    printf ("STOREV"); break;
  2145.     case STOREBV:    printf ("STOREBV"); break;
  2146.     case CALL:        printf ("CALL"); break;
  2147.     case JMP:        printf ("JMP"); break;
  2148.     case BE:        printf ("BE"); break;
  2149.     case BNE:        printf ("BNE"); break;
  2150.     case BL:        printf ("BL"); break;
  2151.     case BLE:        printf ("BLE"); break;
  2152.     case BG:        printf ("BG"); break;
  2153.     case BGE:        printf ("BGE"); break;
  2154.     case BVS:        printf ("BVS"); break;
  2155.     case BVC:        printf ("BVC"); break;
  2156.     case BNS:        printf ("BNS"); break;
  2157.     case BNC:        printf ("BNC"); break;
  2158.     case BSS_OP:    printf ("BSS_OP"); break;
  2159.     case BSC:        printf ("BSC"); break;
  2160.     case BIS:        printf ("BIS"); break;
  2161.     case BIC:        printf ("BIC"); break;
  2162.     case BPS:        printf ("BPS"); break;
  2163.     case BPC:        printf ("BPC"); break;
  2164.     case TSET:        printf ("TSET"); break;
  2165.     case LDADDR:    printf ("LDADDR"); break;
  2166.     case READU:        printf ("READU"); break;
  2167.     case WRITEU:    printf ("WRITEU"); break;
  2168.     case FLOAD:        printf ("FLOAD"); break;
  2169.     case FSTORE:    printf ("FSTORE"); break;
  2170.     case R0:        printf ("R0"); break;
  2171.     case R1:        printf ("R1"); break;
  2172.     case R2:        printf ("R2"); break;
  2173.     case R3:        printf ("R3"); break;
  2174.     case R4:        printf ("R4"); break;
  2175.     case R5:        printf ("R5"); break;
  2176.     case R6:        printf ("R6"); break;
  2177.     case R7:        printf ("R7"); break;
  2178.     case R8:        printf ("R8"); break;
  2179.     case R9:        printf ("R9"); break;
  2180.     case R10:        printf ("R10"); break;
  2181.     case R11:        printf ("R11"); break;
  2182.     case R12:        printf ("R12"); break;
  2183.     case R13:        printf ("R13"); break;
  2184.     case R14:        printf ("R14"); break;
  2185.     case R15:        printf ("R15"); break;
  2186.     case MOV:        printf ("MOV"); break;
  2187.     case CMP:        printf ("CMP"); break;
  2188.     case SET:        printf ("SET"); break;
  2189.     case NEG:        printf ("NEG"); break;
  2190.     case NOT:        printf ("NOT"); break;
  2191.     case CLR:        printf ("CLR"); break;
  2192.     case BTST:        printf ("BTST"); break;
  2193.     case BSET:        printf ("BSET"); break;
  2194.     case BCLR:        printf ("BCLR"); break;
  2195.     case BTOG:        printf ("BTOG"); break;
  2196.     case A:        printf ("A"); break;
  2197.     case B:        printf ("B"); break;
  2198.     case C:        printf ("C"); break;
  2199.     case D:        printf ("D"); break;
  2200.     case E:        printf ("E"); break;
  2201.     case F:        printf ("F"); break;
  2202.     case G:        printf ("G"); break;
  2203.     case EOF:        printf ("EOF"); break;
  2204.     default:        printf ("*****  unknown symbol  *****"); break;
  2205.   }
  2206. }
  2207.  
  2208.  
  2209.  
  2210. /* hexDigit (char)
  2211. **
  2212. ** This routine is passed a character. If it is a hex digit, i.e.,
  2213. **    0, 1, 2, ... 9, a, b, ... f, A, B, ... F
  2214. ** then it returns its value (0..15).  Otherwise, it returns -1.
  2215. */
  2216. int hexDigit (char ch) {
  2217.   if (('0'<=ch) && (ch<='9')) {
  2218.     return ch-'0';
  2219.   } else if (('a'<=ch) && (ch<='f')) {
  2220.     return ch-'a' + 10;
  2221.   } else if (('A'<=ch) && (ch<='F')) {
  2222.     return ch-'A' + 10;
  2223.   } else {
  2224.     return -1;
  2225.   }
  2226. }
  2227.  
  2228.  
  2229.  
  2230. /* addInstrToList (instr)
  2231. **
  2232. ** This routine is passed a pointer to an Instruction; it adds it
  2233. ** to the end of the instruction list.  If it is an executable
  2234. ** BLITZ instruction, this routine looks at its opcode and modifies
  2235. ** that (see findOpCode()).
  2236. */
  2237. void addInstrToList (Instruction * instr, int LCIncrAmount) {
  2238.   if (instrList==NULL) {
  2239.     instrList = instr;
  2240.     lastInstr = instr;
  2241.   } else {
  2242.     lastInstr->next = instr;
  2243.     lastInstr = instr;
  2244.   }
  2245.   findOpCode (instr);
  2246.   /*** printInstr (instr); ***/
  2247.   incrementLCBy (LCIncrAmount);
  2248. }
  2249.  
  2250.  
  2251.  
  2252. /* findOpCode (instr)
  2253. **
  2254. ** This routine is passed a pointer to an instruction with its "op"
  2255. ** and "format" fields filled in.  The "op" will correspond to what
  2256. ** actually appeared in the source, e.g., ADD.  This routine will modify
  2257. ** the "op" field to contain the actual op-code, e.g., ADD1 or ADD2, as
  2258. ** determined by the format code.
  2259. */
  2260. void findOpCode (Instruction * instr) {
  2261.   switch (instr->op) {
  2262.     case ADD:
  2263.       if (instr->format == D) {
  2264.         instr->op = ADD1;
  2265.       } else if (instr->format == E) {
  2266.         instr->op = ADD2;
  2267.       } else {
  2268.         printError ("Program logic error: Invalid format in findOpCode()");
  2269.       }
  2270.       return;
  2271.     case SUB:
  2272.       if (instr->format == D) {
  2273.         instr->op = SUB1;
  2274.       } else if (instr->format == E) {
  2275.         instr->op = SUB2;
  2276.       } else {
  2277.         printError ("Program logic error: Invalid format in findOpCode()");
  2278.       }
  2279.       return;
  2280.     case MUL:
  2281.       if (instr->format == D) {
  2282.         instr->op = MUL1;
  2283.       } else if (instr->format == E) {
  2284.         instr->op = MUL2;
  2285.       } else {
  2286.         printError ("Program logic error: Invalid format in findOpCode()");
  2287.       }
  2288.       return;
  2289.     case DIV:
  2290.       if (instr->format == D) {
  2291.         instr->op = DIV1;
  2292.       } else if (instr->format == E) {
  2293.         instr->op = DIV2;
  2294.       } else {
  2295.         printError ("Program logic error: Invalid format in findOpCode()");
  2296.       }
  2297.       return;
  2298.     case SLL:
  2299.       if (instr->format == D) {
  2300.         instr->op = SLL1;
  2301.       } else if (instr->format == E) {
  2302.         instr->op = SLL2;
  2303.       } else {
  2304.         printError ("Program logic error: Invalid format in findOpCode()");
  2305.       }
  2306.       return;
  2307.     case SRL:
  2308.       if (instr->format == D) {
  2309.         instr->op = SRL1;
  2310.       } else if (instr->format == E) {
  2311.         instr->op = SRL2;
  2312.       } else {
  2313.         printError ("Program logic error: Invalid format in findOpCode()");
  2314.       }
  2315.       return;
  2316.     case SRA:
  2317.       if (instr->format == D) {
  2318.         instr->op = SRA1;
  2319.       } else if (instr->format == E) {
  2320.         instr->op = SRA2;
  2321.       } else {
  2322.         printError ("Program logic error: Invalid format in findOpCode()");
  2323.       }
  2324.       return;
  2325.     case OR:
  2326.       if (instr->format == D) {
  2327.         instr->op = OR1;
  2328.       } else if (instr->format == E) {
  2329.         instr->op = OR2;
  2330.       } else {
  2331.         printError ("Program logic error: Invalid format in findOpCode()");
  2332.       }
  2333.       return;
  2334.     case AND:
  2335.       if (instr->format == D) {
  2336.         instr->op = AND1;
  2337.       } else if (instr->format == E) {
  2338.         instr->op = AND2;
  2339.       } else {
  2340.         printError ("Program logic error: Invalid format in findOpCode()");
  2341.       }
  2342.       return;
  2343.     case ANDN:
  2344.       if (instr->format == D) {
  2345.         instr->op = ANDN1;
  2346.       } else if (instr->format == E) {
  2347.         instr->op = ANDN2;
  2348.       } else {
  2349.         printError ("Program logic error: Invalid format in findOpCode()");
  2350.       }
  2351.       return;
  2352.     case XOR:
  2353.       if (instr->format == D) {
  2354.         instr->op = XOR1;
  2355.       } else if (instr->format == E) {
  2356.         instr->op = XOR2;
  2357.       } else {
  2358.         printError ("Program logic error: Invalid format in findOpCode()");
  2359.       }
  2360.       return;
  2361.     case REM:
  2362.       if (instr->format == D) {
  2363.         instr->op = REM1;
  2364.       } else if (instr->format == E) {
  2365.         instr->op = REM2;
  2366.       } else {
  2367.         printError ("Program logic error: Invalid format in findOpCode()");
  2368.       }
  2369.       return;
  2370.     case LOAD:
  2371.       if (instr->format == D) {
  2372.         instr->op = LOAD1;
  2373.       } else if (instr->format == E) {
  2374.         instr->op = LOAD2;
  2375.       } else {
  2376.         printError ("Program logic error: Invalid format in findOpCode()");
  2377.       }
  2378.       return;
  2379.     case LOADB:
  2380.       if (instr->format == D) {
  2381.         instr->op = LOADB1;
  2382.       } else if (instr->format == E) {
  2383.         instr->op = LOADB2;
  2384.       } else {
  2385.         printError ("Program logic error: Invalid format in findOpCode()");
  2386.       }
  2387.       return;
  2388.     case LOADV:
  2389.       if (instr->format == D) {
  2390.         instr->op = LOADV1;
  2391.       } else if (instr->format == E) {
  2392.         instr->op = LOADV2;
  2393.       } else {
  2394.         printError ("Program logic error: Invalid format in findOpCode()");
  2395.       }
  2396.       return;
  2397.     case LOADBV:
  2398.       if (instr->format == D) {
  2399.         instr->op = LOADBV1;
  2400.       } else if (instr->format == E) {
  2401.         instr->op = LOADBV2;
  2402.       } else {
  2403.         printError ("Program logic error: Invalid format in findOpCode()");
  2404.       }
  2405.       return;
  2406.     case STORE:
  2407.       if (instr->format == D) {
  2408.         instr->op = STORE1;
  2409.       } else if (instr->format == E) {
  2410.         instr->op = STORE2;
  2411.       } else {
  2412.         printError ("Program logic error: Invalid format in findOpCode()");
  2413.       }
  2414.       return;
  2415.     case STOREB:
  2416.       if (instr->format == D) {
  2417.         instr->op = STOREB1;
  2418.       } else if (instr->format == E) {
  2419.         instr->op = STOREB2;
  2420.       } else {
  2421.         printError ("Program logic error: Invalid format in findOpCode()");
  2422.       }
  2423.       return;
  2424.     case STOREV:
  2425.       if (instr->format == D) {
  2426.         instr->op = STOREV1;
  2427.       } else if (instr->format == E) {
  2428.         instr->op = STOREV2;
  2429.       } else {
  2430.         printError ("Program logic error: Invalid format in findOpCode()");
  2431.       }
  2432.       return;
  2433.     case STOREBV:
  2434.       if (instr->format == D) {
  2435.         instr->op = STOREBV1;
  2436.       } else if (instr->format == E) {
  2437.         instr->op = STOREBV2;
  2438.       } else {
  2439.         printError ("Program logic error: Invalid format in findOpCode()");
  2440.       }
  2441.       return;
  2442.     case CALL:
  2443.       if (instr->format == C) {
  2444.         instr->op = CALL1;
  2445.       } else if (instr->format == F) {
  2446.         instr->op = CALL2;
  2447.       } else {
  2448.         printError ("Program logic error: Invalid format in findOpCode()");
  2449.       }
  2450.       return;
  2451.     case JMP:
  2452.       if (instr->format == C) {
  2453.         instr->op = JMP1;
  2454.       } else if (instr->format == F) {
  2455.         instr->op = JMP2;
  2456.       } else {
  2457.         printError ("Program logic error: Invalid format in findOpCode()");
  2458.       }
  2459.       return;
  2460.     case BE:
  2461.       if (instr->format == C) {
  2462.         instr->op = BE1;
  2463.       } else if (instr->format == F) {
  2464.         instr->op = BE2;
  2465.       } else {
  2466.         printError ("Program logic error: Invalid format in findOpCode()");
  2467.       }
  2468.       return;
  2469.     case BNE:
  2470.       if (instr->format == C) {
  2471.         instr->op = BNE1;
  2472.       } else if (instr->format == F) {
  2473.         instr->op = BNE2;
  2474.       } else {
  2475.         printError ("Program logic error: Invalid format in findOpCode()");
  2476.       }
  2477.       return;
  2478.     case BL:
  2479.       if (instr->format == C) {
  2480.         instr->op = BL1;
  2481.       } else if (instr->format == F) {
  2482.         instr->op = BL2;
  2483.       } else {
  2484.         printError ("Program logic error: Invalid format in findOpCode()");
  2485.       }
  2486.       return;
  2487.     case BLE:
  2488.       if (instr->format == C) {
  2489.         instr->op = BLE1;
  2490.       } else if (instr->format == F) {
  2491.         instr->op = BLE2;
  2492.       } else {
  2493.         printError ("Program logic error: Invalid format in findOpCode()");
  2494.       }
  2495.       return;
  2496.     case BG:
  2497.       if (instr->format == C) {
  2498.         instr->op = BG1;
  2499.       } else if (instr->format == F) {
  2500.         instr->op = BG2;
  2501.       } else {
  2502.         printError ("Program logic error: Invalid format in findOpCode()");
  2503.       }
  2504.       return;
  2505.     case BGE:
  2506.       if (instr->format == C) {
  2507.         instr->op = BGE1;
  2508.       } else if (instr->format == F) {
  2509.         instr->op = BGE2;
  2510.       } else {
  2511.         printError ("Program logic error: Invalid format in findOpCode()");
  2512.       }
  2513.       return;
  2514.     case BVS:
  2515.       if (instr->format == C) {
  2516.         instr->op = BVS1;
  2517.       } else if (instr->format == F) {
  2518.         instr->op = BVS2;
  2519.       } else {
  2520.         printError ("Program logic error: Invalid format in findOpCode()");
  2521.       }
  2522.       return;
  2523.     case BVC:
  2524.       if (instr->format == C) {
  2525.         instr->op = BVC1;
  2526.       } else if (instr->format == F) {
  2527.         instr->op = BVC2;
  2528.       } else {
  2529.         printError ("Program logic error: Invalid format in findOpCode()");
  2530.       }
  2531.       return;
  2532.     case BNS:
  2533.       if (instr->format == C) {
  2534.         instr->op = BNS1;
  2535.       } else if (instr->format == F) {
  2536.         instr->op = BNS2;
  2537.       } else {
  2538.         printError ("Program logic error: Invalid format in findOpCode()");
  2539.       }
  2540.       return;
  2541.     case BNC:
  2542.       if (instr->format == C) {
  2543.         instr->op = BNC1;
  2544.       } else if (instr->format == F) {
  2545.         instr->op = BNC2;
  2546.       } else {
  2547.         printError ("Program logic error: Invalid format in findOpCode()");
  2548.       }
  2549.       return;
  2550.     case BSS_OP:
  2551.       if (instr->format == C) {
  2552.         instr->op = BSS1;
  2553.       } else if (instr->format == F) {
  2554.         instr->op = BSS2;
  2555.       } else {
  2556.         printError ("Program logic error: Invalid format in findOpCode()");
  2557.       }
  2558.       return;
  2559.     case BSC:
  2560.       if (instr->format == C) {
  2561.         instr->op = BSC1;
  2562.       } else if (instr->format == F) {
  2563.         instr->op = BSC2;
  2564.       } else {
  2565.         printError ("Program logic error: Invalid format in findOpCode()");
  2566.       }
  2567.       return;
  2568.     case BIS:
  2569.       if (instr->format == C) {
  2570.         instr->op = BIS1;
  2571.       } else if (instr->format == F) {
  2572.         instr->op = BIS2;
  2573.       } else {
  2574.         printError ("Program logic error: Invalid format in findOpCode()");
  2575.       }
  2576.       return;
  2577.     case BIC:
  2578.       if (instr->format == C) {
  2579.         instr->op = BIC1;
  2580.       } else if (instr->format == F) {
  2581.         instr->op = BIC2;
  2582.       } else {
  2583.         printError ("Program logic error: Invalid format in findOpCode()");
  2584.       }
  2585.       return;
  2586.     case BPS:
  2587.       if (instr->format == C) {
  2588.         instr->op = BPS1;
  2589.       } else if (instr->format == F) {
  2590.         instr->op = BPS2;
  2591.       } else {
  2592.         printError ("Program logic error: Invalid format in findOpCode()");
  2593.       }
  2594.       return;
  2595.     case BPC:
  2596.       if (instr->format == C) {
  2597.         instr->op = BPC1;
  2598.       } else if (instr->format == F) {
  2599.         instr->op = BPC2;
  2600.       } else {
  2601.         printError ("Program logic error: Invalid format in findOpCode()");
  2602.       }
  2603.       return;
  2604.     case READU:
  2605.       if (instr->format == C) {
  2606.         instr->op = READU1;
  2607.       } else if (instr->format == E) {
  2608.         instr->op = READU2;
  2609.       } else {
  2610.         printError ("Program logic error: Invalid format in findOpCode()");
  2611.       }
  2612.       return;
  2613.     case WRITEU:
  2614.       if (instr->format == C) {
  2615.         instr->op = WRITEU1;
  2616.       } else if (instr->format == E) {
  2617.         instr->op = WRITEU2;
  2618.       } else {
  2619.         printError ("Program logic error: Invalid format in findOpCode()");
  2620.       }
  2621.       return;
  2622.     case FLOAD:
  2623.       if (instr->format == D) {
  2624.         instr->op = FLOAD1;
  2625.       } else if (instr->format == E) {
  2626.         instr->op = FLOAD2;
  2627.       } else {
  2628.         printError ("Program logic error: Invalid format in findOpCode()");
  2629.       }
  2630.       return;
  2631.     case FSTORE:
  2632.       if (instr->format == D) {
  2633.         instr->op = FSTORE1;
  2634.       } else if (instr->format == E) {
  2635.         instr->op = FSTORE2;
  2636.       } else {
  2637.         printError ("Program logic error: Invalid format in findOpCode()");
  2638.       }
  2639.       return;
  2640.     default:
  2641.       break;
  2642.   }
  2643. }
  2644.  
  2645.  
  2646.  
  2647. /* printInstrList (listPtr)
  2648. **
  2649. ** This routine prints the list of Instructions pointed to by listPtr.
  2650. */
  2651. void printInstrList (Instruction * listPtr) {
  2652.   Instruction * p = listPtr;
  2653.   printf ("line\tformat\topcode\tRa\tRb\tRc\texpr\n");
  2654.   printf ("====\t======\t======\t==\t==\t==\t====\n");
  2655.   while (p != NULL) {
  2656.     printf ("%d\t", p->lineNum);
  2657.     printSym (p->format);
  2658.     printf ("\t");
  2659.     printSym (p->op);
  2660.     printf ("\t%d\t%d\t%d\t", p->ra, p->rb, p->rc);
  2661.     if (p->tableEntry != NULL) {
  2662.       printString (p->tableEntry);
  2663.       printf ("\t");
  2664.     }
  2665.     printExpr (p->expr);
  2666.     printf ("\n");
  2667.     p = p->next;
  2668.   }
  2669. }
  2670.  
  2671.  
  2672.  
  2673. /* printInstr (instrPtr)
  2674. **
  2675. ** This routine prints the Instruction pointed to by instrPtr.
  2676. */
  2677. void printInstr (Instruction * instrPtr) {
  2678.   printf ("textLC\tdataLC\tbssLC\tline\tformat\topcode\tRa\tRb\tRc\texpr\n");
  2679.   printf ("======\t======\t=====\t====\t======\t======\t==\t==\t==\t====\n");
  2680.   printf ("%d\t%d\t%d\t%d\t", textLC, dataLC, bssLC, instrPtr->lineNum);
  2681.   printSym (instrPtr->format);
  2682.   printf ("\t");
  2683.   printSym (instrPtr->op);
  2684.   printf ("\t%d\t%d\t%d\t", instrPtr->ra, instrPtr->rb, instrPtr->rc);
  2685.   if (instrPtr->tableEntry != NULL) {
  2686.     printString (instrPtr->tableEntry);
  2687.     printf ("\t");
  2688.   }
  2689.   printExpr (instrPtr->expr);
  2690.   printf ("\n");
  2691. }
  2692.  
  2693.  
  2694.  
  2695. /* printExpr (p)
  2696. **
  2697. ** This routine is passed a pointer to an expression.  It prints it,
  2698. ** calling itself recursively as necessary.
  2699. */
  2700. void printExpr (Expression * p) {
  2701.   if (p == NULL) return;
  2702.   switch (p->op) {
  2703.     case INTEGER:
  2704.       printf ("%d", p->value);
  2705.       return;
  2706.     case ID:
  2707.       printString (p->tableEntry);
  2708.       return;
  2709.     case STAR:
  2710.       printf ("(");
  2711.       printExpr (p->expr1);
  2712.       printf (" * ");
  2713.       printExpr (p->expr2);
  2714.       printf (")");
  2715.       return;
  2716.     case SLASH:
  2717.       printf ("(");
  2718.       printExpr (p->expr1);
  2719.       printf (" / ");
  2720.       printExpr (p->expr2);
  2721.       printf (")");
  2722.       return;
  2723.     case PERCENT:
  2724.       printf ("(");
  2725.       printExpr (p->expr1);
  2726.       printf (" %% ");
  2727.       printExpr (p->expr2);
  2728.       printf (")");
  2729.       return;
  2730.     case LTLT:
  2731.       printf ("(");
  2732.       printExpr (p->expr1);
  2733.       printf (" << ");
  2734.       printExpr (p->expr2);
  2735.       printf (")");
  2736.       return;
  2737.     case GTGT:
  2738.       printf ("(");
  2739.       printExpr (p->expr1);
  2740.       printf (" >> ");
  2741.       printExpr (p->expr2);
  2742.       printf (")");
  2743.       return;
  2744.     case GTGTGT:
  2745.       printf ("(");
  2746.       printExpr (p->expr1);
  2747.       printf (" >>> ");
  2748.       printExpr (p->expr2);
  2749.       printf (")");
  2750.       return;
  2751.     case AMPERSAND:
  2752.       printf ("(");
  2753.       printExpr (p->expr1);
  2754.       printf (" & ");
  2755.       printExpr (p->expr2);
  2756.       printf (")");
  2757.       return;
  2758.     case CARET:
  2759.       printf ("(");
  2760.       printExpr (p->expr1);
  2761.       printf (" ^ ");
  2762.       printExpr (p->expr2);
  2763.       printf (")");
  2764.       return;
  2765.     case BAR:
  2766.       printf ("(");
  2767.       printExpr (p->expr1);
  2768.       printf (" | ");
  2769.       printExpr (p->expr2);
  2770.       printf (")");
  2771.       return;
  2772.     case TILDE:
  2773.       printf ("(~ ");
  2774.       printExpr (p->expr1);
  2775.       printf (")");
  2776.       return;
  2777.     case PLUS:
  2778.       printf ("(");
  2779.       if (p->expr2 != NULL) {
  2780.         printExpr (p->expr1);
  2781.         printf (" + ");
  2782.         printExpr (p->expr2);
  2783.       } else {
  2784.         printf ("+ ");
  2785.         printExpr (p->expr1);
  2786.       }
  2787.       printf (")");
  2788.       return;
  2789.     case MINUS:
  2790.       printf ("(");
  2791.       if (p->expr2 != NULL) {
  2792.         printExpr (p->expr1);
  2793.         printf (" - ");
  2794.         printExpr (p->expr2);
  2795.       } else {
  2796.         printf ("- ");
  2797.         printExpr (p->expr1);
  2798.       }
  2799.       printf (")");
  2800.       return;
  2801.     default:
  2802.       printf ("***** INVALID OP WITHIN Expression  *****");
  2803.       break;
  2804.   }
  2805. }
  2806.  
  2807.  
  2808.  
  2809. /* newInstr (op)
  2810. **
  2811. ** This routine allocates a new Instruction object and returns
  2812. ** a pointer to it.  It initializes its op field.
  2813. */
  2814. Instruction * newInstr (int op) {
  2815.   Instruction * p;
  2816.   p = (Instruction *) calloc (1, sizeof (Instruction));
  2817.   p->op = op;
  2818.   p->format = EOF;
  2819.   p->expr = NULL;
  2820.   p->lineNum = currentLine;
  2821.   p->ra = 0;
  2822.   p->rb = 0;
  2823.   p->rc = 0;
  2824.   p->next = NULL;
  2825.   return p;
  2826. }
  2827.  
  2828.  
  2829.  
  2830. /* newExpression (op)
  2831. **
  2832. ** This routine allocates a new Expression object and returns
  2833. ** a pointer to it.  It initializes its op field.
  2834. */
  2835. Expression * newExpression (int op) {
  2836.   Expression * p;
  2837.   p = (Expression *) calloc (1, sizeof (Expression));
  2838.   p->op = op;
  2839.   p->value = 0;
  2840.   p->rvalue = 0.0;
  2841.   p->expr1 = NULL;
  2842.   p->expr2 = NULL;
  2843.   p->tableEntry = NULL;
  2844.   return p;
  2845. }
  2846.  
  2847.  
  2848.  
  2849. /* getOneInstruction ()
  2850. **
  2851. ** This routine picks up an instruction and adds it to the growing list.
  2852. ** In parses the following syntax:
  2853. **
  2854. **    [ id ':' ]  [ keyword operands ] EOL
  2855. **
  2856. ** If problems are encountered, it scans forward to the next EOL and
  2857. ** scans it.  If nothing is present, it will add nothing to the list.
  2858. ** It leaves nextToken pointing to the token after the EOL.  If nextToken
  2859. ** is EOF, then it will return immediately.
  2860. */
  2861. void getOneInstruction () {
  2862.   Instruction * p, * q;
  2863.   Expression * ex;
  2864.   TableEntry * tableEntry;
  2865.   String * strPtr;
  2866.   int i, opCode, category, gotLabel, gotMinus;
  2867.   if (nextToken == EOF) {
  2868.     return;
  2869.   }
  2870.   gotLabel = 0;
  2871.   if (nextToken == ID) {
  2872.     tableEntry = tokenValue.tableEntry;
  2873.     scan ();
  2874.     if (nextToken == COLON) {
  2875.       /* Process a label here */
  2876.       gotLabel = 1;
  2877.       if (currentSegment == 0) {
  2878.         printError ("Not in .text, .data, or .bss segment");
  2879.       } else {
  2880.         if ((tableEntry->relativeTo != NULL) || (tableEntry->offset != 0)) {
  2881.           printError ("This symbol is already defined");
  2882.         }
  2883.         tableEntry->offset = getLC ();
  2884.         switch (currentSegment) {
  2885.           case TEXT:
  2886.             tableEntry->relativeTo = textTableEntry;
  2887.             break;
  2888.           case DATA:
  2889.             tableEntry->relativeTo = dataTableEntry;
  2890.             break;
  2891.           case BSS_SEG:
  2892.             tableEntry->relativeTo = bssTableEntry;
  2893.             break;
  2894.         }
  2895.         p = newInstr (LABEL);
  2896.         p->tableEntry = tableEntry;
  2897.         addInstrToList (p, 0);
  2898.         if (tableEntry == entryTableEntry) {
  2899.           if (currentSegment != TEXT) {
  2900.             printError ("\"_entry\" is not in the .text segment");
  2901.           } else if (textLC != 0) {
  2902.             printError ("\"_entry\" not at beginning of .text segment");
  2903.           } else {
  2904.             sawEntryLabel = 1;
  2905.           }
  2906.         }
  2907.       }
  2908.       scan ();
  2909.     } else if (nextToken == EQUAL) {
  2910.       p = newInstr (EQUAL);
  2911.       scan ();
  2912.       ex = getExpr ();
  2913.       if (ex == NULL) return;
  2914.       p->tableEntry = tableEntry;
  2915.       p->expr = ex;
  2916.       /* Attempt to evaluate the expression and update the symbol table */
  2917.       resolveEquate (p, 0);  /* Try to resolve any equates we can. */
  2918.       /* Add this instruction to the list */
  2919.       addInstrToList (p, 0);
  2920.       if (nextIsNot (EOL, "Unexpected tokens after expression")) return;
  2921.       return;
  2922.     } else {
  2923.       printError ("Invalid op-code or missing colon after label");
  2924.       scanRestOfLine ();
  2925.       return;
  2926.     }
  2927.   }
  2928.   if (nextToken == EOL) {
  2929.     scan ();
  2930.     return;
  2931.   }
  2932.   opCode = nextToken;
  2933.   p = newInstr (opCode);
  2934.   switch (opCode) {
  2935.     case TEXT:
  2936.       setCurrentSegmentTo (TEXT);
  2937.       if (gotLabel) {
  2938.         printError ("A label is not allowed on .text");
  2939.       }
  2940.       scan ();
  2941.       addInstrToList (p, 0);
  2942.       if (nextIsNot (EOL, ".text takes no operands")) return;
  2943.       return;
  2944.     case DATA:
  2945.       setCurrentSegmentTo (DATA);
  2946.       if (gotLabel) {
  2947.         printError ("A label is not allowed on .data");
  2948.       }
  2949.       scan ();
  2950.       addInstrToList (p, 0);
  2951.       if (nextIsNot (EOL, ".data takes no operands")) return;
  2952.       return;
  2953.     case BSS_SEG:
  2954.       setCurrentSegmentTo (BSS_SEG);
  2955.       if (gotLabel) {
  2956.         printError ("A label is not allowed on .bss");
  2957.       }
  2958.       scan ();
  2959.       addInstrToList (p, 0);
  2960.       if (nextIsNot (EOL, ".bss takes no operands")) return;
  2961.       return;
  2962.     case ASCII:
  2963.       if (notInDataOrText ()) return;
  2964.       scan ();
  2965.       if (nextToken != STRING) {
  2966.         printError ("Expecting string after .ascii");
  2967.         scanRestOfLine ();
  2968.         return;
  2969.       }
  2970.       tableEntry = tokenValue.tableEntry;
  2971.       p->tableEntry = tableEntry;
  2972.       scan ();
  2973.       addInstrToList (p, tableEntry->string.length);
  2974.       if (nextIsNot (EOL, "Unexpected tokens after string")) return;
  2975.       return;
  2976.     case BYTE:
  2977.       if (notInDataOrText ()) return;
  2978.       scan ();
  2979.       ex = getExpr ();
  2980.       if (ex == NULL) return;
  2981.       p->expr = ex;
  2982.       addInstrToList (p, 1);
  2983.       if (nextIsNot (EOL, "Unexpected tokens after expression")) return;
  2984.       return;
  2985.     case WORD:
  2986.       if (notInDataOrText ()) return;
  2987.       scan ();
  2988.       ex = getExpr ();
  2989.       if (ex == NULL) return;
  2990.       p->expr = ex;
  2991.       addInstrToList (p, 4);
  2992.       if (nextIsNot (EOL, "Unexpected tokens after expression")) return;
  2993.       return;
  2994.     case DOUBLE:
  2995.       if (notInDataOrText ()) return;
  2996.       scan ();
  2997.       gotMinus = 0;
  2998.       if (nextToken == PLUS) {
  2999.         scan ();
  3000.       } else if (nextToken == MINUS) {
  3001.         gotMinus = 1;
  3002.         scan ();
  3003.       }
  3004.       ex = newExpression (REAL);
  3005.       if (nextToken == REAL) {
  3006.         ex->rvalue = tokenValue.rvalue;
  3007.         scan ();
  3008.         if (gotMinus) {
  3009.           ex->rvalue = - (ex->rvalue);
  3010.         }
  3011.       } else {
  3012.         printError ("Expecting a floating point constant");
  3013.       }
  3014.       p->expr = ex;
  3015.       addInstrToList (p, 8);
  3016.       if (nextIsNot (EOL, "Unexpected tokens after floating constant")) return;
  3017.       return;
  3018.     case EXPORT:
  3019.       if (gotLabel) {
  3020.         printError ("A label is not allowed on .export");
  3021.       }
  3022.       scan ();
  3023.       if (nextToken != ID) {
  3024.         printError ("Expecting symbol after .export");
  3025.         scanRestOfLine ();
  3026.         return;
  3027.       }
  3028.       tableEntry = tokenValue.tableEntry;
  3029.       tableEntry->exported = 1;
  3030.       scan ();
  3031.       p->tableEntry = tableEntry;
  3032.       addInstrToList (p, 0);
  3033.       if (nextIsNot (EOL, "Unexpected tokens after symbol")) return;
  3034.       return;
  3035.     case IMPORT:
  3036.       if (gotLabel) {
  3037.         printError ("A label is not allowed on .import");
  3038.       }
  3039.       scan ();
  3040.       if (nextToken != ID) {
  3041.         printError ("Expecting symbol after .import");
  3042.         scanRestOfLine ();
  3043.         return;
  3044.       }
  3045.       tableEntry = tokenValue.tableEntry;
  3046.       tableEntry->imported = 1;
  3047.       scan ();
  3048.       p->tableEntry = tableEntry;
  3049.       addInstrToList (p, 0);
  3050.       if (nextIsNot (EOL, "Unexpected tokens after symbol")) return;
  3051.       return;
  3052.     case ALIGN:
  3053.       if (gotLabel) {
  3054.         printError ("A label is not allowed on .align");
  3055.       }
  3056.       scan ();
  3057.       i = getLC() % 4;
  3058.       if (i != 0) {
  3059.         i = 4 - i;
  3060.         p->op = SKIP;   /* Turn this instruction into a SKIP */
  3061.         p->ra = i;      /* and save number of skipped bytes in p->ra */
  3062.         addInstrToList (p, i);
  3063.       }
  3064.       if (nextIsNot (EOL, ".align takes no operands")) return;
  3065.       return;
  3066.     case SKIP:
  3067.       scan ();
  3068.       i = getLC ();  /* To force an error if not in a segment */
  3069.       ex = getExpr ();
  3070.       if (ex == NULL) return;
  3071.       p->expr = ex;
  3072.       evalExpr (ex, 1);
  3073. /***
  3074.       if (nextToken == INTEGER) {
  3075.         i = tokenValue.ivalue;
  3076.         scan ();
  3077.       } else {
  3078.         printError ("Unimplemented: for now .skip operand must be integer");
  3079.       }
  3080. ***/
  3081.       if (ex->relativeTo == NULL) {
  3082.         /* We already got a message during expression evaluation, but... */
  3083.         printError (".skip expression may not use symbols defined after it");
  3084.         p->ra = 0;
  3085.       } else if (ex->relativeTo != absoluteTableEntry) {
  3086.         printError ("The .skip expression must evaluate to an absolute value");
  3087.         return;
  3088.       } else {
  3089.         p->ra = ex->value;        /* Save number of skipped bytes in p->ra */
  3090.       }
  3091.       addInstrToList (p, ex->value);
  3092.       if (nextIsNot (EOL, "Unexpected tokens after operands")) return;
  3093.       return;
  3094.     default:
  3095.       break;
  3096.   }
  3097.   scan ();
  3098.   category = categoryOf (opCode);
  3099.   if (category < 0) {
  3100.     printError ("Invalid or missing op-code");
  3101.     scanRestOfLine ();
  3102.     return;
  3103.   }
  3104.   if (notInDataOrText ()) return;
  3105.   if ((getLC() % 4) != 0) {
  3106.     fprintf (stderr,
  3107.              "Warning on line %d: Instruction not on aligned address\n",
  3108.              currentLine);
  3109.   }
  3110.   switch (category) {
  3111.     case 1:     /* add, sub, ... */
  3112.       if (getRegisterA (p)) return;
  3113.       if (nextIsNot (COMMA, "Expecting comma")) return;
  3114.       if (isRegister(nextToken) >= 0) {
  3115.         /* Ra, Rb, Rc */
  3116.         p->format = D;
  3117.         if (getRegisterB (p)) return;
  3118.         if (nextIsNot (COMMA, "Expecting comma")) return;
  3119.         if (getRegisterC (p)) return;
  3120.       } else {
  3121.         /* Ra,data16,Rc */
  3122.         p->format = E;
  3123.         p->expr = getExpr ();
  3124.         if (p->expr == NULL) return;
  3125.         if (nextIsNot (COMMA, "Expecting comma")) return;
  3126.         if (getRegisterC (p)) return;
  3127.       }
  3128.       addInstrToList (p, 4);
  3129.       if (nextIsNot (EOL, "Unexpected material after operands")) return;
  3130.       return;
  3131.     case 2:     /* wait, nop, etc. */
  3132.       p->format = A;
  3133.       addInstrToList (p, 4);
  3134.       if (nextIsNot (EOL, "Unexpected material after op-code")) return;
  3135.       return;
  3136.     case 3:     /* load, loadb, loadv, loadbv */
  3137.       if (nextIsNot (LBRACKET, "Expecting [ after op-code")) return;
  3138.       if (getRegisterA (p)) return;
  3139.       if (nextToken == RBRACKET) {
  3140.         /* [Ra],Rc */
  3141.         scan();
  3142.         p->format = D;
  3143.       } else {
  3144.         if (nextIsNot (PLUS, "Expecting + or ]")) return;
  3145.         if (isRegister(nextToken) >= 0) {
  3146.           /* [Ra+Rb],Rc */
  3147.           p->format = D;
  3148.           if (getRegisterB (p)) return;
  3149.         } else {
  3150.           /* [Ra+data16],Rc */
  3151.           p->format = E;
  3152.           p->expr = getExpr ();
  3153.           if (p->expr == NULL) return;
  3154.         }
  3155.         if (nextIsNot (RBRACKET, "Expecting ]")) return;
  3156.       }
  3157.       if (nextIsNot (COMMA, "Expecting comma")) return;
  3158.       if (getRegisterC (p)) return;
  3159.       addInstrToList (p, 4);
  3160.       if (nextIsNot (EOL, "Unexpected material after operands")) return;
  3161.       return;
  3162.     case 4:    /* store, storeb, storev, storebv */
  3163.       if (getRegisterC (p)) return;
  3164.       if (nextIsNot (COMMA, "Expecting comma after reg Rc")) return;
  3165.       if (nextIsNot (LBRACKET, "Expecting [ after comma")) return;
  3166.       if (getRegisterA (p)) return;
  3167.       if (nextToken == RBRACKET) {
  3168.         /* Rc,[Ra] */
  3169.         scan ();
  3170.         p->format = D;
  3171.       } else {
  3172.         if (nextIsNot (PLUS, "Expecting + after reg Ra")) return;
  3173.         if (isRegister(nextToken) >= 0) {
  3174.           /* Rc,[Ra+Rb] */
  3175.           p->format = D;
  3176.           if (getRegisterB (p)) return;
  3177.         } else {
  3178.           /* Rc,[Ra+data16] */
  3179.           p->format = E;
  3180.           p->expr = getExpr ();
  3181.           if (p->expr == NULL) return;
  3182.         }
  3183.         if (nextIsNot (RBRACKET, "Expecting ]")) return;
  3184.       }
  3185.       addInstrToList (p, 4);
  3186.       if (nextIsNot (EOL, "Unexpected material after operands")) return;
  3187.       return;
  3188.     case 5:     /* sethi, setlo */
  3189.       p->format = G;
  3190.       p->expr = getExpr ();
  3191.       if (p->expr == NULL) return;
  3192.       if ((opCode == SETLO) && ((p->expr->value & 0xffff0000) != 0)) {
  3193.         fprintf (stderr,
  3194.                  "Warning on line %d: In SETLO, the data exceeds 16 bits in length\n",
  3195.                  currentLine);
  3196.       }
  3197.       if ((opCode == SETHI) && ((p->expr->value & 0x0000ffff) != 0)) {
  3198.         fprintf (stderr,
  3199.                  "Warning on line %d: In SETHI, the data appears to be in the form 0x1234 instead of 0x12340000 as expected\n",
  3200.                  currentLine);
  3201.       }
  3202.       if (nextIsNot (COMMA, "Expecting comma after expression")) return;
  3203.       if (getRegisterC (p)) return;
  3204.       addInstrToList (p, 4);
  3205.       if (nextIsNot (EOL, "Unexpected material after operands")) return;
  3206.       return;
  3207.     case 6:     /* call, jmp, bxx */
  3208.       if (isRegister(nextToken) >= 0) {
  3209.         p->format = C;
  3210.         if (getRegisterA (p)) return;
  3211.         if (nextToken == EOL) {
  3212.           /* Ra */
  3213.         } else {
  3214.           /* Ra+Rc */
  3215.           if (nextIsNot (PLUS, "Expecting Ra or Ra+Rc")) return;
  3216.           if (getRegisterC (p)) return;
  3217.         }
  3218.       } else {
  3219.         /* data24 */
  3220.         p->format = F;
  3221.         p->expr = getExpr ();
  3222.         if (p->expr == NULL) return;
  3223.       }
  3224.       addInstrToList (p, 4);
  3225.       if (nextIsNot (EOL, "Unexpected material after operands")) return;
  3226.       return;
  3227.     case 7:    /* push */
  3228.       p->format = C;
  3229.       if (getRegisterC (p)) return;
  3230.       if (nextToken == COMMA) {
  3231.         /* Rc,[--Ra] */
  3232.         scan ();
  3233.         if (nextIsNot (LBRACKET, "Expecting [ in Rc,[--Ra]")) return;
  3234.         if (nextIsNot (MINUSMINUS, "Expecting -- in Rc,[--Ra]")) return;
  3235.         if (getRegisterA (p)) return;
  3236.         if (nextIsNot (RBRACKET, "Expecting ] in Rc,[--Ra]")) return;
  3237.       } else {
  3238.         p->ra = 15;
  3239.       }
  3240.       addInstrToList (p, 4);
  3241.       if (nextIsNot (EOL, "Expecting either Rc or Rc,[--Ra]")) return;
  3242.       return;
  3243.     case 8:    /* pop */
  3244.       p->format = C;
  3245.       if (nextToken == LBRACKET) {
  3246.         /* [Ra++],Rc */
  3247.         scan ();
  3248.         if (getRegisterA (p)) return;
  3249.         if (nextIsNot (PLUSPLUS, "Expecting ++ in [Ra++],Rc")) return;
  3250.         if (nextIsNot (RBRACKET, "Expecting ] in [Ra++],Rc")) return;
  3251.         if (nextIsNot (COMMA, "Expecting comma in [Ra++],Rc")) return;
  3252.       } else {
  3253.         p->ra = 15;
  3254.       }
  3255.       if (getRegisterC (p)) return;
  3256.       addInstrToList (p, 4);
  3257.       if (nextIsNot (EOL, "Unexpected material after operands")) return;
  3258.       return;
  3259.     case 9:    /* ldptbr, ldptlr */
  3260.       p->format = B;
  3261.       if (getRegisterC (p)) return;
  3262.       addInstrToList (p, 4);
  3263.       if (nextIsNot (EOL, "Unexpected material after operand Rc")) return;
  3264.       return;
  3265.     case 10:   /* tset [Ra],Rc */
  3266.       p->format = C;
  3267.       if (nextIsNot (LBRACKET, "Expecting [ in [Ra],Rc")) return;
  3268.       if (getRegisterA (p)) return;
  3269.       if (nextIsNot (RBRACKET, "Expecting ] in [Ra],Rc")) return;
  3270.       if (nextIsNot (COMMA, "Expecting comma in [Ra],Rc")) return;
  3271.       if (getRegisterC (p)) return;
  3272.       addInstrToList (p, 4);
  3273.       if (nextIsNot (EOL, "Unexpected material after [Ra],Rc")) return;
  3274.       return;
  3275.     case 11:    /* readu */
  3276.       if (getRegisterC (p)) return;
  3277.       if (nextIsNot (COMMA, "Expecting comma in Rc,Ra or Rc,[Ra+data16]")) return;
  3278.       if (nextToken == LBRACKET) {
  3279.         scan ();
  3280.         p->format = E;
  3281.         if (getRegisterA (p)) return;
  3282.         if (nextToken == PLUS) { /* Rc,[Ra+data16] */
  3283.           scan();
  3284.           p->expr = getExpr ();
  3285.           if (p->expr == NULL) return;
  3286.           if (nextIsNot (RBRACKET, "Expecting ] in Rc,[Ra+data16]")) return;
  3287.         } else { /* Rc,[Ra] */
  3288.           p->expr = absoluteZero;
  3289.           if (nextIsNot (RBRACKET, "Expecting ] or + after Rc,[Ra...")) return;
  3290.         }
  3291.       } else {  /* Rc,Ra */
  3292.         p->format = C;
  3293.         if (getRegisterA (p)) return;
  3294.       }
  3295.       addInstrToList (p, 4);
  3296.       if (nextIsNot (EOL, "Unexpected material after operands")) return;
  3297.       return;
  3298.     case 12:         /* writeu */
  3299.       if (nextToken == LBRACKET) {
  3300.         p->format = E;
  3301.         scan ();
  3302.         if (getRegisterA (p)) return;
  3303.         if (nextToken == PLUS) {      /* [Ra+data16],Rc */
  3304.           scan ();
  3305.           p->expr = getExpr ();
  3306.           if (p->expr == NULL) return;
  3307.           if (nextIsNot (RBRACKET, "Expecting ] in [Ra+data16],Ra")) return;
  3308.         } else {                 /* [Ra],Rc */
  3309.           p->expr = absoluteZero;
  3310.           if (nextIsNot (RBRACKET, "Expecting ] or + after [Ra...")) return;
  3311.         }
  3312.       } else {       /* Ra,Rc */
  3313.         p->format = C;
  3314.         if (getRegisterA (p)) return;
  3315.       }
  3316.       if (nextIsNot (COMMA, "Expecting comma in Ra,Rc or [Ra+data16],Rc")) return;
  3317.       if (getRegisterC (p)) return;
  3318.       addInstrToList (p, 4);
  3319.       if (nextIsNot (EOL, "Unexpected material after operands")) return;
  3320.       return;
  3321.     case 13:    /* syscall */
  3322.       p->format = G;
  3323.       if (isRegister(nextToken) >= 0) { /* Rc */
  3324.         if (getRegisterC (p)) return;
  3325.         if (nextToken != EOL) { /* Rc+data16 */
  3326.           if (nextIsNot (PLUS, "Expecting Rc or Rc+data16")) return;
  3327.           p->expr = getExpr ();
  3328.           if (p->expr == NULL) return;
  3329.         } else {
  3330.           p->expr = absoluteZero;
  3331.         }
  3332.       } else { /* data16 */
  3333.         p->expr = getExpr ();
  3334.         if (p->expr == NULL) return;
  3335.       }
  3336.       addInstrToList (p, 4);
  3337.       if (nextIsNot (EOL, "Unexpected material after operands")) return;
  3338.       return;
  3339.     case 14:    /* Unused case*/
  3340.       printError ("Program Logic Error: Invalid case in switch statement");
  3341.       return;
  3342.     case 15:    /* set data32,Rc */
  3343.       p->format = G;
  3344.       p->op = SETHI;     /* Note, we have not shifted the expression, yet */
  3345.       p->expr = getExpr ();
  3346.       if (p->expr == NULL) return;
  3347.       if (nextIsNot (COMMA, "Expecting comma in data32,Rc")) return;
  3348.       if (getRegisterC (p)) return;
  3349.       addInstrToList (p, 4);
  3350.       /* Make a second instruction and add it to the list also */
  3351.       q = newInstr (SETLO);
  3352.       q->format = G;
  3353.       q->rc = p->rc;
  3354.       q->expr = p->expr;    /* Share the expression */
  3355.       addInstrToList (q, 4);
  3356.       if (nextIsNot (EOL, "Unexpected material after operands")) return;
  3357.       return;
  3358.     case 16:    /* mov */
  3359.       if (isRegister(nextToken) >= 0) { /* Ra,Rc */
  3360.         if (getRegisterA (p)) return;
  3361.         if (nextIsNot (COMMA, "Expecting comma in Ra,Rc")) return;
  3362.         if (getRegisterC (p)) return;
  3363.         p->format = D;
  3364.         p->op = OR;
  3365.       } else {      /* data16,Rc */
  3366.         p->expr = getExpr ();
  3367.         if (p->expr == NULL) return;
  3368.         if (nextIsNot (COMMA, "Expecting comma in data16,Rc")) return;
  3369.         if (getRegisterC (p)) return;
  3370.         p->format = E;
  3371.         p->op = OR;
  3372.       }
  3373.       addInstrToList (p, 4);
  3374.       if (nextIsNot (EOL, "Unexpected material after operands")) return;
  3375.       return;
  3376.     case 17:    /* cmp */
  3377.       if (getRegisterA (p)) return;
  3378.       if (nextIsNot (COMMA, "Expecting comma in Ra,Rb or Ra,data16")) return;
  3379.       if (isRegister(nextToken) >= 0) { /* Ra,Rb */
  3380.         if (getRegisterB (p)) return;
  3381.         p->format = D;
  3382.         p->op = SUB;
  3383.       } else {      /* Ra,data16 */
  3384.         p->expr = getExpr ();
  3385.         if (p->expr == NULL) return;
  3386.         p->format = E;
  3387.         p->op = SUB;
  3388.       }
  3389.       addInstrToList (p, 4);
  3390.       if (nextIsNot (EOL, "Unexpected material after operands")) return;
  3391.       return;
  3392.     case 18:    /* neg */
  3393.       p->op = SUB;
  3394.       p->format = D;
  3395.       if (getRegisterC (p)) return;
  3396.       p->rb = p->rc;
  3397.       if (nextToken == COMMA) {
  3398.         /* Rb,Rc */
  3399.         scan ();
  3400.         if (getRegisterC (p)) return;
  3401.       } else {
  3402.         /* Rc */
  3403.       }
  3404.       addInstrToList (p, 4);
  3405.       if (nextIsNot (EOL, "Unexpected material after operands")) return;
  3406.       return;
  3407.     case 19:    /* not */
  3408.       p->op = XOR;
  3409.       p->format = E;
  3410.       p->expr = absoluteMinusOne;
  3411.       if (getRegisterC (p)) return;
  3412.       p->ra = p->rc;
  3413.       p->expr = absoluteMinusOne;
  3414.       if (nextToken == COMMA) {
  3415.         /* Ra,Rc */
  3416.         scan ();
  3417.         if (getRegisterC (p)) return;
  3418.       } else {
  3419.         /* Rc */
  3420.       }
  3421.       addInstrToList (p, 4);
  3422.       if (nextIsNot (EOL, "Unexpected material after operands")) return;
  3423.       return;
  3424.     case 20:    /* clr */
  3425.       p->op = OR;
  3426.       p->format = D;
  3427.       if (getRegisterC (p)) return;
  3428.       addInstrToList (p, 4);
  3429.       if (nextIsNot (EOL, "Unexpected material after operands")) return;
  3430.       return;
  3431.     case 21:    /* btst */
  3432.       if (isRegister(nextToken) >= 0) { /* Ra,Rb */
  3433.         if (getRegisterA (p)) return;
  3434.         if (nextIsNot (COMMA, "Expecting comma in Ra,Rb")) return;
  3435.         if (getRegisterB (p)) return;
  3436.         p->format = D;
  3437.         p->op = AND;
  3438.       } else {      /* data16,Rb */
  3439.         p->expr = getExpr ();
  3440.         if (p->expr == NULL) return;
  3441.         if (nextIsNot (COMMA, "Expecting comma in data16,Rb")) return;
  3442.         if (getRegisterA (p)) return;
  3443.         p->format = E;
  3444.         p->op = AND;
  3445.       }
  3446.       addInstrToList (p, 4);
  3447.       if (nextIsNot (EOL, "Unexpected material after operands")) return;
  3448.       return;
  3449.     case 22:    /* bset, bclr, btog */
  3450.       if (isRegister(nextToken) >= 0) { /* Rb,Rc */
  3451.         if (getRegisterB (p)) return;
  3452.         if (nextIsNot (COMMA, "Expecting comma in Rb,Rc")) return;
  3453.         if (getRegisterC (p)) return;
  3454.         p->ra = p->rc;
  3455.         p->format = D;
  3456.       } else {      /* data16,Rc */
  3457.         p->expr = getExpr ();
  3458.         if (p->expr == NULL) return;
  3459.         if (nextIsNot (COMMA, "Expecting comma in data16,Rc")) return;
  3460.         if (getRegisterC (p)) return;
  3461.         p->ra = p->rc;
  3462.         p->format = E;
  3463.       }
  3464.       if (opCode == BSET) {
  3465.         p->op = OR;
  3466.       } else if (opCode == BCLR) {
  3467.         p->op = ANDN;
  3468.       } else if (opCode == BTOG) {
  3469.         p->op = XOR;
  3470.       } else {
  3471.         printError ("Program logic error: opcode not in category");
  3472.       }
  3473.       addInstrToList (p, 4);
  3474.       if (nextIsNot (EOL, "Unexpected material after operands")) return;
  3475.       return;
  3476.     case 23:     /* ldaddr data16,Rc */
  3477.       p->format = G;
  3478.       p->expr = getExpr ();
  3479.       if (p->expr == NULL) return;
  3480.       if (nextIsNot (COMMA, "Expecting comma after expression")) return;
  3481.       if (getRegisterC (p)) return;
  3482.       addInstrToList (p, 4);
  3483.       if (nextIsNot (EOL, "Unexpected material after operands")) return;
  3484.       return;
  3485.     case 24:    /* ftoi Fa,Rc */
  3486.       if (getFRegisterA (p)) return;
  3487.       if (nextIsNot (COMMA, "Expecting comma in Fc,Ra")) return;
  3488.       p->format = C;
  3489.       if (getRegisterC (p)) return;
  3490.       addInstrToList (p, 4);
  3491.       if (nextIsNot (EOL, "Unexpected material after operands")) return;
  3492.       return;
  3493.     case 25:    /* itof Ra,Fc */
  3494.       if (getRegisterA (p)) return;
  3495.       if (nextIsNot (COMMA, "Expecting comma in Fc,Ra")) return;
  3496.       p->format = C;
  3497.       if (getFRegisterC (p)) return;
  3498.       addInstrToList (p, 4);
  3499.       if (nextIsNot (EOL, "Unexpected material after operands")) return;
  3500.       return;
  3501.     case 26:    /* fadd Fa,Fb,Fc */
  3502.       if (getFRegisterA (p)) return;
  3503.       if (nextIsNot (COMMA, "Expecting comma")) return;
  3504.       if (getFRegisterB (p)) return;
  3505.       if (nextIsNot (COMMA, "Expecting comma")) return;
  3506.       if (getFRegisterC (p)) return;
  3507.       p->format = D;
  3508.       addInstrToList (p, 4);
  3509.       if (nextIsNot (EOL, "Unexpected material after operands")) return;
  3510.       return;
  3511.     case 27:    /* fcmp Fa,Fc */
  3512.       if (getFRegisterA (p)) return;
  3513.       if (nextIsNot (COMMA, "Expecting comma")) return;
  3514.       if (getFRegisterC (p)) return;
  3515.       p->format = C;
  3516.       addInstrToList (p, 4);
  3517.       if (nextIsNot (EOL, "Unexpected material after operands")) return;
  3518.       return;
  3519.     case 28:    /* fload ...,Fc */
  3520.       if (nextIsNot (LBRACKET, "Expecting [ after op-code")) return;
  3521.       if (getRegisterA (p)) return;
  3522.       if (nextToken == RBRACKET) {
  3523.         /* [Ra],Fc */
  3524.         scan();
  3525.         p->format = D;
  3526.       } else {
  3527.         if (nextIsNot (PLUS, "Expecting + or ]")) return;
  3528.         if (isRegister(nextToken) >= 0) {
  3529.           /* [Ra+Rb],Fc */
  3530.           p->format = D;
  3531.           if (getRegisterB (p)) return;
  3532.         } else {
  3533.           /* [Ra+data16],Fc */
  3534.           p->format = E;
  3535.           p->expr = getExpr ();
  3536.           if (p->expr == NULL) return;
  3537.         }
  3538.         if (nextIsNot (RBRACKET, "Expecting ]")) return;
  3539.       }
  3540.       if (nextIsNot (COMMA, "Expecting comma")) return;
  3541.       if (getFRegisterC (p)) return;
  3542.       addInstrToList (p, 4);
  3543.       if (nextIsNot (EOL, "Unexpected material after operands")) return;
  3544.       return;
  3545.     case 29:    /* fstore Fc,... */
  3546.       if (getFRegisterC (p)) return;
  3547.       if (nextIsNot (COMMA, "Expecting comma after reg Fc")) return;
  3548.       if (nextIsNot (LBRACKET, "Expecting [ after comma")) return;
  3549.       if (getRegisterA (p)) return;
  3550.       if (nextToken == RBRACKET) {
  3551.         /* Fc,[Ra] */
  3552.         scan ();
  3553.         p->format = D;
  3554.       } else {
  3555.         if (nextIsNot (PLUS, "Expecting + after reg Ra")) return;
  3556.         if (isRegister(nextToken) >= 0) {
  3557.           /* Fc,[Ra+Rb] */
  3558.           p->format = D;
  3559.           if (getRegisterB (p)) return;
  3560.         } else {
  3561.           /* Fc,[Ra+data16] */
  3562.           p->format = E;
  3563.           p->expr = getExpr ();
  3564.           if (p->expr == NULL) return;
  3565.         }
  3566.         if (nextIsNot (RBRACKET, "Expecting ]")) return;
  3567.       }
  3568.       addInstrToList (p, 4);
  3569.       if (nextIsNot (EOL, "Unexpected material after operands")) return;
  3570.       return;
  3571.     default:
  3572.       printError ("Logic error: this instruction is in no category");
  3573.       scanRestOfLine ();
  3574.       return;
  3575.   }
  3576. }
  3577.  
  3578.  
  3579.  
  3580. /* scanRestOfLine ()
  3581. **
  3582. ** This routine calls scan() repeatedly until we either get an
  3583. ** EOL or hit EOF.  The tokens are ignored.
  3584. */
  3585. void scanRestOfLine () {
  3586.   while ((nextToken != EOL) && (nextToken != EOF)) {
  3587.     scan ();
  3588.   }
  3589.   if (nextToken == EOL) {
  3590.     scan ();
  3591.   }
  3592. }
  3593.  
  3594.  
  3595.  
  3596. /* categoryOf (tokType)
  3597. **
  3598. ** This routine if this token is a valid op-code (either a BLITZ instruction,
  3599. ** a synthetic instruction, or a psuedo-op), then this routine returns its
  3600. ** category, which will tell what sort of operands it may take.  If it
  3601. ** is not a valid op-code, we return -1.
  3602. */
  3603. int categoryOf (int tokType) {
  3604.   switch (tokType) {
  3605.     case ADD:
  3606.     case SUB:
  3607.     case MUL:
  3608.     case DIV:
  3609.     case SLL:
  3610.     case SRL:
  3611.     case SRA:
  3612.     case OR:
  3613.     case AND:
  3614.     case ANDN:
  3615.     case XOR:
  3616.     case REM:
  3617.       return 1;
  3618.     case LOAD:
  3619.     case LOADB:
  3620.     case LOADV:
  3621.     case LOADBV:
  3622.       return 3;
  3623.     case STORE:
  3624.     case STOREB:
  3625.     case STOREV:
  3626.     case STOREBV:
  3627.       return 4;
  3628.     case SETHI:
  3629.     case SETLO:
  3630.       return 5;
  3631.     case CALL:
  3632.     case JMP:
  3633.     case BE:
  3634.     case BNE:
  3635.     case BL:
  3636.     case BLE:
  3637.     case BG:
  3638.     case BGE:
  3639.     case BVS:
  3640.     case BVC:
  3641.     case BNS:
  3642.     case BNC:
  3643.     case BSS_OP:
  3644.     case BSC:
  3645.     case BIS:
  3646.     case BIC:
  3647.     case BPS:
  3648.     case BPC:
  3649.       return 6;
  3650.     case PUSH:
  3651.       return 7;
  3652.     case POP:
  3653.       return 8;
  3654.     case TSET:
  3655.       return 10;
  3656.     case SYSCALL:
  3657.       return 13;
  3658.     case NOP:
  3659.     case WAIT:
  3660.     case DEBUG:
  3661.     case CLEARI:
  3662.     case SETI:
  3663.     case CLEARP:
  3664.     case SETP:
  3665.     case CLEARS:
  3666.     case RETI:
  3667.     case RET:
  3668.     case DEBUG2:
  3669.       return 2;
  3670.     case READU:
  3671.       return 11;
  3672.     case WRITEU:
  3673.       return 12;
  3674.     case LDPTBR:
  3675.     case LDPTLR:
  3676.       return 9;
  3677.   /* Synthetic instructions */
  3678.     case SET:
  3679.       return 15;
  3680.     case MOV:
  3681.       return 16;
  3682.     case CMP:
  3683.       return 17;
  3684.     case NEG:
  3685.       return 18;
  3686.     case NOT:
  3687.       return 19;
  3688.     case CLR:
  3689.       return 20;
  3690.     case BTST:
  3691.       return 21;
  3692.     case BSET:
  3693.     case BCLR:
  3694.     case BTOG:
  3695.       return 22;
  3696.     case LDADDR:
  3697.       return 23;
  3698.     case FTOI:
  3699.       return 24;
  3700.     case ITOF:
  3701.       return 25;
  3702.     case FADD:
  3703.     case FSUB:
  3704.     case FMUL:
  3705.     case FDIV:
  3706.       return 26;
  3707.     case FCMP:
  3708.     case FSQRT:
  3709.     case FNEG:
  3710.     case FABS:
  3711.       return 27;
  3712.     case FLOAD:
  3713.       return 28;
  3714.     case FSTORE:
  3715.       return 29;
  3716.   /* Pseudo-ops */
  3717.     case TEXT:
  3718.     case DATA:
  3719.     case BSS_SEG:
  3720.     case ASCII:
  3721.     case BYTE:
  3722.     case WORD:
  3723.     case DOUBLE:
  3724.     case EXPORT:
  3725.     case IMPORT:
  3726.     case ALIGN:
  3727.     case SKIP:
  3728.       return 999;
  3729.     default:
  3730.       return -1;
  3731.   }
  3732. }
  3733.  
  3734.  
  3735.  
  3736. /* isRegister (tokType)
  3737. **
  3738. ** This routine returns an integer in 0..15 if this token is a valid
  3739. ** integer register keyword and -1 if not.
  3740. */
  3741. int isRegister (int tokType) {
  3742.   switch (tokType) {
  3743.     case R0: return 0;
  3744.     case R1: return 1;
  3745.     case R2: return 2;
  3746.     case R3: return 3;
  3747.     case R4: return 4;
  3748.     case R5: return 5;
  3749.     case R6: return 6;
  3750.     case R7: return 7;
  3751.     case R8: return 8;
  3752.     case R9: return 9;
  3753.     case R10: return 10;
  3754.     case R11: return 11;
  3755.     case R12: return 12;
  3756.     case R13: return 13;
  3757.     case R14: return 14;
  3758.     case R15: return 15;
  3759.  
  3760.     default: return -1;
  3761.   }
  3762. }
  3763.  
  3764.  
  3765.  
  3766. /* isFRegister (tokType)
  3767. **
  3768. ** This routine returns an integer in 0..15 if this token is a valid
  3769. ** floating-point register keyword and -1 if not.
  3770. */
  3771. int isFRegister (int tokType) {
  3772.   switch (tokType) {
  3773.     case F0: return 0;
  3774.     case F1: return 1;
  3775.     case F2: return 2;
  3776.     case F3: return 3;
  3777.     case F4: return 4;
  3778.     case F5: return 5;
  3779.     case F6: return 6;
  3780.     case F7: return 7;
  3781.     case F8: return 8;
  3782.     case F9: return 9;
  3783.     case F10: return 10;
  3784.     case F11: return 11;
  3785.     case F12: return 12;
  3786.     case F13: return 13;
  3787.     case F14: return 14;
  3788.     case F15: return 15;
  3789.  
  3790.     default: return -1;
  3791.   }
  3792. }
  3793.  
  3794.  
  3795.  
  3796. /* getRegisterA (p)
  3797. **
  3798. ** This routine scans a register and sets p->ra.  If ok, it returns
  3799. ** FALSE, otherwise is prints a message and returns TRUE.
  3800. */
  3801. int getRegisterA (Instruction * p) {
  3802.   int r = isRegister (nextToken);
  3803.   if (r>=0) {
  3804.     scan ();
  3805.     p->ra = r;
  3806.     return 0;
  3807.   } else {
  3808.     printError ("Expecting Register Ra");
  3809.     scanRestOfLine ();
  3810.     return 1;
  3811.   }
  3812. }
  3813.  
  3814.  
  3815.  
  3816. /* getRegisterB (p)
  3817. **
  3818. ** This routine scans a register and sets p->rb.  If ok, it returns
  3819. ** FALSE, otherwise is prints a message and returns TRUE.
  3820. */
  3821. int getRegisterB (Instruction * p) {
  3822.   int r = isRegister (nextToken);
  3823.   if (r>=0) {
  3824.     scan ();
  3825.     p->rb = r;
  3826.     return 0;
  3827.   } else {
  3828.     printError ("Expecting Register Rb");
  3829.     scanRestOfLine ();
  3830.     return 1;
  3831.   }
  3832. }
  3833.  
  3834.  
  3835.  
  3836. /* getRegisterC (p)
  3837. **
  3838. ** This routine scans a register and sets p->rc.  If ok, it returns
  3839. ** FALSE, otherwise is prints a message and returns TRUE.
  3840. */
  3841. int getRegisterC (Instruction * p) {
  3842.   int r = isRegister (nextToken);
  3843.   if (r>=0) {
  3844.     scan ();
  3845.     p->rc = r;
  3846.     return 0;
  3847.   } else {
  3848.     printError ("Expecting Register Rc");
  3849.     scanRestOfLine ();
  3850.     return 1;
  3851.   }
  3852. }
  3853.  
  3854.  
  3855.  
  3856. /* getFRegisterA (p)
  3857. **
  3858. ** This routine scans a register and sets p->ra.  If ok, it returns
  3859. ** FALSE, otherwise is prints a message and returns TRUE.
  3860. */
  3861. int getFRegisterA (Instruction * p) {
  3862.   int r = isFRegister (nextToken);
  3863.   if (r>=0) {
  3864.     scan ();
  3865.     p->ra = r;
  3866.     return 0;
  3867.   } else {
  3868.     printError ("Expecting Register Fa");
  3869.     scanRestOfLine ();
  3870.     return 1;
  3871.   }
  3872. }
  3873.  
  3874.  
  3875.  
  3876. /* getFRegisterB (p)
  3877. **
  3878. ** This routine scans a register and sets p->rb.  If ok, it returns
  3879. ** FALSE, otherwise is prints a message and returns TRUE.
  3880. */
  3881. int getFRegisterB (Instruction * p) {
  3882.   int r = isFRegister (nextToken);
  3883.   if (r>=0) {
  3884.     scan ();
  3885.     p->rb = r;
  3886.     return 0;
  3887.   } else {
  3888.     printError ("Expecting Register Fb");
  3889.     scanRestOfLine ();
  3890.     return 1;
  3891.   }
  3892. }
  3893.  
  3894.  
  3895.  
  3896. /* getFRegisterC (p)
  3897. **
  3898. ** This routine scans a register and sets p->rc.  If ok, it returns
  3899. ** FALSE, otherwise is prints a message and returns TRUE.
  3900. */
  3901. int getFRegisterC (Instruction * p) {
  3902.   int r = isFRegister (nextToken);
  3903.   if (r>=0) {
  3904.     scan ();
  3905.     p->rc = r;
  3906.     return 0;
  3907.   } else {
  3908.     printError ("Expecting Register Fc");
  3909.     scanRestOfLine ();
  3910.     return 1;
  3911.   }
  3912. }
  3913.  
  3914.  
  3915.  
  3916. /* nextIsNot (tokType, message)
  3917. **
  3918. ** This routine checks to make sure the current token matches tokType
  3919. ** and then scans to the next token.  If everything is ok, it returns
  3920. ** FALSE.  If there are problems, it prints an error message, calls
  3921. ** scanRestOfLine () and returns TRUE.
  3922. */
  3923. int nextIsNot (int tokType, char * message) {
  3924.   if (nextToken == tokType) {
  3925.     scan ();
  3926.     return 0;
  3927.   } else {
  3928.     printError (message);
  3929.     scanRestOfLine ();
  3930.     return 1;
  3931.   }
  3932. }
  3933.  
  3934.  
  3935.  
  3936. /* getExpr ()
  3937. **
  3938. ** This routine parses an expression and returns a pointer to
  3939. ** an Expression node.  If there are problems, it will print an
  3940. ** error message, scan all remaining tokens on this line, and return NULL.
  3941. ** In some cases, it may find and return a legal expression, but may
  3942. ** may fail to scan the entire expression.  This will happen when there
  3943. ** is a legal expression following by an error, as in:
  3944. **    3 + 4 : 5
  3945. */
  3946. Expression * getExpr () {
  3947.   Expression * p;
  3948.   p = parseExpr0 ();
  3949.   if (p == NULL) {
  3950.     scanRestOfLine ();
  3951.     return NULL;
  3952.   }
  3953.   return p;
  3954. }
  3955.  
  3956.  
  3957.  
  3958. /* parseExpr0 ()
  3959. **
  3960. ** This routine parsesaccording to the following CFG rule.
  3961. **     expr0 ::= expr1 { "|" expr1 }
  3962. ** If successful, it returns a pointer to an Expression, else it returns NULL.
  3963. */
  3964. Expression * parseExpr0 () {
  3965.   Expression * soFar, * another, * new;
  3966.   int op;
  3967.   soFar = parseExpr1 ();
  3968.   if (soFar == NULL) return NULL;
  3969.   while (1) {
  3970.     op = nextToken;
  3971.     if (nextToken == BAR) {
  3972.       scan ();
  3973.     } else {
  3974.       break;
  3975.     }
  3976.     another = parseExpr1 ();
  3977.     if (another == NULL) return NULL;
  3978.     new = newExpression (op);
  3979.     new->expr1 = soFar;
  3980.     new->expr2 = another;
  3981.     soFar = new;
  3982.   }
  3983.   return soFar;
  3984. }
  3985.  
  3986.  
  3987.  
  3988. /* parseExpr1 ()
  3989. **
  3990. ** This routine parsesaccording to the following CFG rule.
  3991. **     expr1 ::= expr2 { "^" expr2 }
  3992. ** If successful, it returns a pointer to an Expression, else it returns NULL.
  3993. */
  3994. Expression * parseExpr1 () {
  3995.   Expression * soFar, * another, * new;
  3996.   int op;
  3997.   soFar = parseExpr2 ();
  3998.   if (soFar == NULL) return NULL;
  3999.   while (1) {
  4000.     op = nextToken;
  4001.     if (nextToken == CARET) {
  4002.       scan ();
  4003.     } else {
  4004.       break;
  4005.     }
  4006.     another = parseExpr2 ();
  4007.     if (another == NULL) return NULL;
  4008.     new = newExpression (op);
  4009.     new->expr1 = soFar;
  4010.     new->expr2 = another;
  4011.     soFar = new;
  4012.   }
  4013.   return soFar;
  4014. }
  4015.  
  4016.  
  4017.  
  4018. /* parseExpr2 ()
  4019. **
  4020. ** This routine parsesaccording to the following CFG rule.
  4021. **     expr2 ::= expr3 { "&" expr3 }
  4022. ** If successful, it returns a pointer to an Expression, else it returns NULL.
  4023. */
  4024. Expression * parseExpr2 () {
  4025.   Expression * soFar, * another, * new;
  4026.   int op;
  4027.   soFar = parseExpr3 ();
  4028.   if (soFar == NULL) return NULL;
  4029.   while (1) {
  4030.     op = nextToken;
  4031.     if (nextToken == AMPERSAND) {
  4032.       scan ();
  4033.     } else {
  4034.       break;
  4035.     }
  4036.     another = parseExpr3 ();
  4037.     if (another == NULL) return NULL;
  4038.     new = newExpression (op);
  4039.     new->expr1 = soFar;
  4040.     new->expr2 = another;
  4041.     soFar = new;
  4042.   }
  4043.   return soFar;
  4044. }
  4045.  
  4046.  
  4047.  
  4048. /* parseExpr3 ()
  4049. **
  4050. ** This routine parsesaccording to the following CFG rule.
  4051. **     expr3 ::= expr4 { ("<<" | ">>" | ">>>") expr4 }
  4052. ** If successful, it returns a pointer to an Expression, else it returns NULL.
  4053. */
  4054. Expression * parseExpr3 () {
  4055.   Expression * soFar, * another, * new;
  4056.   int op;
  4057.   soFar = parseExpr4 ();
  4058.   if (soFar == NULL) return NULL;
  4059.   while (1) {
  4060.     op = nextToken;
  4061.     if (nextToken == LTLT) {
  4062.       scan ();
  4063.     } else if (nextToken == GTGT) {
  4064.       scan ();
  4065.     } else if (nextToken == GTGTGT) {
  4066.       scan ();
  4067.     } else {
  4068.       break;
  4069.     }
  4070.     another = parseExpr4 ();
  4071.     if (another == NULL) return NULL;
  4072.     new = newExpression (op);
  4073.     new->expr1 = soFar;
  4074.     new->expr2 = another;
  4075.     soFar = new;
  4076.   }
  4077.   return soFar;
  4078. }
  4079.  
  4080.  
  4081.  
  4082. /* parseExpr4 ()
  4083. **
  4084. ** This routine parsesaccording to the following CFG rule.
  4085. **     expr4 ::= expr5 { ("+" | "-") expr5 }
  4086. ** If successful, it returns a pointer to an Expression, else it returns NULL.
  4087. */
  4088. Expression * parseExpr4 () {
  4089.   Expression * soFar, * another, * new;
  4090.   int op;
  4091.   soFar = parseExpr5 ();
  4092.   if (soFar == NULL) return NULL;
  4093.   while (1) {
  4094.     op = nextToken;
  4095.     if (nextToken == PLUS) {
  4096.       scan ();
  4097.     } else if (nextToken == MINUS) {
  4098.       scan ();
  4099.     } else {
  4100.       break;
  4101.     }
  4102.     another = parseExpr5 ();
  4103.     if (another == NULL) return NULL;
  4104.     new = newExpression (op);
  4105.     new->expr1 = soFar;
  4106.     new->expr2 = another;
  4107.     soFar = new;
  4108.   }
  4109.   return soFar;
  4110. }
  4111.  
  4112.  
  4113.  
  4114. /* parseExpr5 ()
  4115. **
  4116. ** This routine parsesaccording to the following CFG rule.
  4117. **     expr5 ::= expr6 { ("*" | "/" | "%") expr6 }
  4118. ** If successful, it returns a pointer to an Expression, else it returns NULL.
  4119. */
  4120. Expression * parseExpr5 () {
  4121.   Expression * soFar, * another, * new;
  4122.   int op;
  4123.   soFar = parseExpr6 ();
  4124.   if (soFar == NULL) return NULL;
  4125.   while (1) {
  4126.     op = nextToken;
  4127.     if (nextToken == STAR) {
  4128.       scan ();
  4129.     } else if (nextToken == SLASH) {
  4130.       scan ();
  4131.     } else if (nextToken == PERCENT) {
  4132.       scan ();
  4133.     } else {
  4134.       return soFar;
  4135.     }
  4136.     another = parseExpr6 ();
  4137.     if (another == NULL) return NULL;
  4138.     new = newExpression (op);
  4139.     new->expr1 = soFar;
  4140.     new->expr2 = another;
  4141.     soFar = new;
  4142.   }
  4143. }
  4144.  
  4145.  
  4146.  
  4147. /* parseExpr6 ()
  4148. **
  4149. ** This routine parsesaccording to the following CFG rule.
  4150. **     expr6 ::= "+" expr6 | "-" expr6 | "~" expr6
  4151. **               | ID | INTEGER | STRING | "(" expr0 ")"
  4152. ** If successful, it returns a pointer to an Expression, else it returns NULL.
  4153. ** If a STRING is present, it must have exactly 4 characters.  These
  4154. ** four characters will be used as an INTEGER.
  4155. */
  4156. Expression * parseExpr6 () {
  4157.   Expression * new, * another;
  4158.   if (nextToken == PLUS) {
  4159.     scan ();
  4160.     another = parseExpr6 ();
  4161.     if (another == NULL) return NULL;
  4162.     new = newExpression (PLUS);
  4163.     new->expr1 = another;
  4164.     return new;
  4165.   } else if (nextToken == MINUS) {
  4166.     scan ();
  4167.     another = parseExpr6 (); if (another == NULL) return NULL;
  4168.     new = newExpression (MINUS);
  4169.     new->expr1 = another;
  4170.     return new;
  4171.   } else if (nextToken == TILDE) {
  4172.     scan ();
  4173.     another = parseExpr6 ();
  4174.     if (another == NULL) return NULL;
  4175.     new = newExpression (TILDE);
  4176.     new->expr1 = another;
  4177.     return new;
  4178.   } else if (nextToken == ID) {
  4179.     new = newExpression (ID);
  4180.     new->tableEntry = tokenValue.tableEntry;
  4181.     scan ();
  4182.     return new;
  4183.   } else if (nextToken == STRING) {
  4184.     new = newExpression (INTEGER);
  4185.     new->value = * ((int *) tokenValue.tableEntry->string.string);
  4186.     new->relativeTo = absoluteTableEntry;
  4187.     if (tokenValue.tableEntry->string.length != 4) {
  4188.       printError ("When strings are used in places expecting a number, the string must be exactly 4 chars long");
  4189.       return NULL;
  4190.     }
  4191.     scan ();
  4192.     return new;
  4193.   } else if (nextToken == INTEGER) {
  4194.     new = newExpression (INTEGER);
  4195.     new->value = tokenValue.ivalue;
  4196.     new->relativeTo = absoluteTableEntry;
  4197.     scan ();
  4198.     return new;
  4199.   } else if (nextToken == LPAREN) {
  4200.     scan ();
  4201.     new = parseExpr0 ();
  4202.     if (new == NULL) return NULL;
  4203.     if (nextIsNot (RPAREN, "Expecting ')' in expression")) return NULL;
  4204.     return new;
  4205.   } else if (nextToken == ID) {
  4206.     new = newExpression (ID);
  4207.     new->tableEntry = tokenValue.tableEntry;
  4208.     scan ();
  4209.     return new;
  4210.   } else {
  4211.     printError ("Expecting expression");
  4212.     return NULL;
  4213.   }
  4214. }
  4215.  
  4216.  
  4217.  
  4218. /* setCurrentSegmentTo (type);
  4219. **
  4220. ** This routine changes the current segment to TEXT, DATA, or BSS_SEG.
  4221. */
  4222. void setCurrentSegmentTo (int type) {
  4223.   switch (type) {
  4224.     case TEXT:
  4225.     case DATA:
  4226.     case BSS_SEG:
  4227.       currentSegment = type;
  4228.       return;
  4229.     default:
  4230.       printError ("Program logic error: bad arg to setCurrentSegmentTo()");
  4231.       return;
  4232.   }
  4233. }
  4234.  
  4235.  
  4236.  
  4237. /* getLC ()
  4238. **
  4239. ** This routine returns the Location Counter for whichever segment is
  4240. ** current.  It prints an error if there is no current segment.
  4241. */
  4242. int getLC () {
  4243.   switch (currentSegment) {
  4244.     case TEXT:
  4245.       return textLC;
  4246.     case DATA:
  4247.       return dataLC;
  4248.     case BSS_SEG:
  4249.       return bssLC;
  4250.     default:
  4251.       printError ("Not currently in a .text, .data, or .bss segment");
  4252.       return;
  4253.   }
  4254. }
  4255.  
  4256.  
  4257.  
  4258. /* incrementLCBy (incr)
  4259. **
  4260. ** This routine increases the current Location Counter by incr.  It
  4261. ** prints an error if there is no current segment.
  4262. */
  4263. void incrementLCBy (int incr) {
  4264.   if (incr == 0) return;
  4265.   switch (currentSegment) {
  4266.     case TEXT:
  4267.       textLC += incr;
  4268.       return;
  4269.     case DATA:
  4270.       dataLC += incr;
  4271.       return;
  4272.     case BSS_SEG:
  4273.       bssLC += incr;
  4274.       return;
  4275.     default:
  4276.       printError ("Not currently in a .text, .data, or .bss segment");
  4277.   }
  4278. }
  4279.  
  4280.  
  4281.  
  4282. /* notInDataOrText ()
  4283. **
  4284. ** This routine prints an error message if we are not in .text or
  4285. ** .data and returns TRUE.  It returns FALSE if all is ok.
  4286. */
  4287. int notInDataOrText () {
  4288.   if (currentSegment == TEXT) return 0;
  4289.   if (currentSegment == DATA) return 0;
  4290.   printError ("We are not currently in the .text or .data segment");
  4291.   scanRestOfLine ();
  4292.   return 1;
  4293. }
  4294.  
  4295.  
  4296.  
  4297. /* checkBigEndian ()
  4298. **
  4299. ** This routine checks to make sure the machine running this
  4300. ** program uses big-endian byte ordering and aborts if not.
  4301. */
  4302. void checkBigEndian () {
  4303.   union fourBytes {
  4304.     char chars [4];
  4305.     unsigned int i;
  4306.   } fourBytes;
  4307.   fourBytes.chars[0] = 0x12;
  4308.   fourBytes.chars[1] = 0x34;
  4309.   fourBytes.chars[2] = 0x56;
  4310.   fourBytes.chars[3] = 0x78;
  4311.   if (fourBytes.i != 0x12345678) {
  4312.     fprintf (stderr, "This program only runs on big-endian computers.\n");
  4313.     errorExit ();
  4314.   }
  4315. }
  4316.  
  4317.  
  4318.  
  4319. /* resolveEquate (instrPtr, printErrors)
  4320. **
  4321. ** This routine is passed a pointer to an EQUAL instruction.  It attempts
  4322. ** to evaluate the expression.  If it can be evaluated (i.e., resolved),
  4323. ** then this routine will set "anyEquatesResolved" to true.  If we are
  4324. ** unable to resolve this equate, it will set "unresolvedEquates" to
  4325. ** TRUE.  When an equate is resolved, we will update the entry in the
  4326. ** symbol table.  If "printErrors" is true, we will print error messages
  4327. ** when we have problems, otherwise error messages will be suppressed.
  4328. */
  4329. void resolveEquate (Instruction * instrPtr, int printErrors) {
  4330.   Expression * expr;
  4331.   TableEntry * tableEntry;
  4332.   if (instrPtr->op != EQUAL) return;
  4333.   expr = instrPtr->expr;
  4334.   tableEntry = instrPtr->tableEntry;
  4335.                     /***
  4336.                     printString (tableEntry);
  4337.                     printf (" = ");
  4338.                     printExpr (expr);
  4339.                     printf ("...\n");
  4340.                     ***/
  4341.   if (tableEntry->relativeTo != NULL) {
  4342.                     /***
  4343.                     printf ("              Previously resolved\n");
  4344.                     ***/
  4345.   } else {
  4346.     evalExpr (expr, printErrors);
  4347.     if (expr->relativeTo != NULL) {
  4348.                     /***
  4349.                     printf ("              value=%d  relativeTo ", expr->value);
  4350.                     printString (expr->relativeTo);
  4351.                     printf ("\n");
  4352.                     ***/
  4353.       anyEquatesResolved = 1;
  4354.       tableEntry->relativeTo = expr->relativeTo;     
  4355.       tableEntry->offset = expr->value;     
  4356.     } else {
  4357.                     /***
  4358.                     printf ("              No value could be computed\n");
  4359.                     ***/
  4360.       unresolvedEquates = 1;
  4361.     }
  4362.   }
  4363. }
  4364.  
  4365.  
  4366.  
  4367. /* evalExpr (exprPtr)
  4368. **
  4369. ** This routine is passed a pointer to an Expression.  It walks the tree
  4370. ** and evaluates the expression.  It fills in the "value" and "relativeTo"
  4371. ** fields.  When "relativeTo" is NULL, it indicates that the Expression
  4372. ** has not yet been evalutated.  If anything goes wrong it will print
  4373. ** an error message if printErrors is TRUE; if printErrors is FALSE it
  4374. ** will not print error messages.  This routine cannot handle a NULL
  4375. ** argument.  (Such NULL expression pointers can arise from syntax errors.)
  4376. ** This routine assumes that the expression it is passed is well formed.
  4377. */
  4378. void evalExpr (Expression * expr, int printErrors) {
  4379.   unsigned a, b, c;
  4380.   int i, j;
  4381.   /*
  4382.     printf ("evalExpr called on...");
  4383.     printExpr (expr);
  4384.     printf ("\n");
  4385.   */
  4386.   /* If this expression has already been given a value, we are done. */
  4387.   if (expr->relativeTo != NULL) {
  4388.     return;
  4389.   }
  4390.   switch (expr->op) {
  4391.     case ID:
  4392.       if (expr->tableEntry->relativeTo != NULL) {
  4393.         expr->relativeTo = expr->tableEntry->relativeTo;
  4394.         expr->value = expr->tableEntry->offset;
  4395.       } else if (expr->tableEntry->imported != 0) { 
  4396.         expr->relativeTo = expr->tableEntry;
  4397.         expr->value = 0;
  4398.       } else {
  4399.         if (printErrors) {
  4400.           printError2 ("Undefined symbol: ", expr->tableEntry->string.string);
  4401.         }
  4402.       }
  4403.       return;
  4404.     case INTEGER:
  4405.       if (expr->relativeTo != absoluteTableEntry) {
  4406.         printError ("Program logic error: Integer in expression is not absolute");
  4407.       }
  4408.       return;
  4409.     case REAL:
  4410.       return;
  4411.     case PLUS:
  4412.       evalExpr (expr->expr1, printErrors);
  4413.       if (expr->expr2 == NULL) {  /* if unary operator */
  4414.         /* unary + is a nop */
  4415.         expr->value = expr->expr1->value;
  4416.         expr->relativeTo = expr->expr1->relativeTo;
  4417.         return;
  4418.       }
  4419.       /* We have a binary + operator. */
  4420.       evalExpr (expr->expr2, printErrors);
  4421.       /* If either operand is unresolved... */
  4422.       if ((expr->expr1->relativeTo == NULL) ||
  4423.           (expr->expr2->relativeTo == NULL)) {
  4424.         return;
  4425.       /* If both operands are absolute... */
  4426.       } else if ((expr->expr1->relativeTo == absoluteTableEntry) &&
  4427.           (expr->expr2->relativeTo == absoluteTableEntry)) {
  4428.         expr->value = expr->expr1->value + expr->expr2->value;
  4429.         expr->relativeTo = absoluteTableEntry;
  4430.       /* If the first operand is relative and the second is absolute... */
  4431.       } else if ((expr->expr1->relativeTo != absoluteTableEntry) &&
  4432.           (expr->expr2->relativeTo == absoluteTableEntry)) {
  4433.         expr->value = expr->expr1->value + expr->expr2->value;
  4434.         expr->relativeTo = expr->expr1->relativeTo;
  4435.  
  4436.       /* If the second operand is relative and the first is absolute... */
  4437.       } else if ((expr->expr1->relativeTo == absoluteTableEntry) &&
  4438.           (expr->expr2->relativeTo != absoluteTableEntry)) {
  4439.         expr->value = expr->expr1->value + expr->expr2->value;
  4440.         expr->relativeTo = expr->expr2->relativeTo;
  4441.       /* Else if both are relative... */
  4442.       } else {
  4443.         if (printErrors) {
  4444.           printError ("Both operands to binary + may not be relative");
  4445.         }
  4446.       }
  4447.       return;
  4448.     case MINUS:
  4449.       evalExpr (expr->expr1, printErrors);
  4450.       if (expr->expr2 == NULL) {  /* if unary operator */
  4451.         if ((expr->expr1->relativeTo != absoluteTableEntry) &&
  4452.           (expr->expr1->relativeTo != NULL)) {
  4453.           if (printErrors) {
  4454.             printError ("The unary - operator requires operand to be an absolute value");
  4455.           }
  4456.           return;
  4457.         }
  4458.         expr->value = - expr->expr1->value;
  4459.         expr->relativeTo = absoluteTableEntry;
  4460.         return;
  4461.       }
  4462.       /* We have a binary - operator. */
  4463.       evalExpr (expr->expr2, printErrors);
  4464.       /* If either operand is unresolved... */
  4465.       if ((expr->expr1->relativeTo == NULL) ||
  4466.           (expr->expr2->relativeTo == NULL)) {
  4467.         return;
  4468.       /* If both operands are absolute... */
  4469.       } else if ((expr->expr1->relativeTo == absoluteTableEntry) &&
  4470.           (expr->expr2->relativeTo == absoluteTableEntry)) {
  4471.         expr->value = expr->expr1->value - expr->expr2->value;
  4472.         expr->relativeTo = absoluteTableEntry;
  4473.       /* If both operands are relative to the same symbol... */
  4474.       } else if (expr->expr1->relativeTo ==
  4475.                  expr->expr2->relativeTo) {
  4476.         expr->value = expr->expr1->value - expr->expr2->value;
  4477.         expr->relativeTo = absoluteTableEntry;
  4478.       /* If the first operand is relative and the second is absolute... */
  4479.       } else if ((expr->expr1->relativeTo != absoluteTableEntry) &&
  4480.           (expr->expr2->relativeTo == absoluteTableEntry)) {
  4481.         expr->value = expr->expr1->value - expr->expr2->value;
  4482.         expr->relativeTo = expr->expr1->relativeTo;
  4483.       /* Else second is relative but not to first, or first is absolute... */
  4484.       } else {
  4485.         if (printErrors) {
  4486.           printError ("Operands to binary - are relative to different symbols");
  4487.         }
  4488.       }
  4489.       return;
  4490.     case STAR:
  4491.       evalExpr (expr->expr1, printErrors);
  4492.       evalExpr (expr->expr2, printErrors);
  4493.       if ((expr->expr1->relativeTo == absoluteTableEntry) &&
  4494.           (expr->expr2->relativeTo == absoluteTableEntry)) {
  4495.         expr->value = expr->expr1->value * expr->expr2->value;
  4496.         expr->relativeTo = absoluteTableEntry;
  4497.         return;
  4498.       }
  4499.       if (printErrors) {
  4500.         if ((expr->expr1->relativeTo != absoluteTableEntry) &&
  4501.           (expr->expr1->relativeTo != NULL)) {
  4502.           printError ("The * operator requires operands to be absolute values");
  4503.         }
  4504.         if ((expr->expr2->relativeTo != absoluteTableEntry) &&
  4505.             (expr->expr2->relativeTo != NULL)) {
  4506.           printError ("The * operator requires operands to be absolute values");
  4507.         }
  4508.       }
  4509.       return;
  4510.     case SLASH:
  4511.       /* The / and % operators are implemented using the "C" /  and %
  4512.          operators.  When both are positive, the division is straightforward:
  4513.          the fractional part is discared.  For example, 7 / 2 will be 3.  When
  4514.          one operand is negative the result is system dependent.  With
  4515.          ANSI C, we are only guaranteed that
  4516.               (a / b) * b + a % b   ==   a
  4517.          will hold.  Because of all this, we simply disallow neg operands. */
  4518.       evalExpr (expr->expr1, printErrors);
  4519.       evalExpr (expr->expr2, printErrors);
  4520.       if ((expr->expr1->relativeTo == absoluteTableEntry) &&
  4521.           (expr->expr2->relativeTo == absoluteTableEntry)) {
  4522.         if ((expr->expr1->value < 0) || (expr->expr2->value <= 0)) {
  4523.           if (printErrors) {
  4524.             printError ("Operands to / must be positive");
  4525.           }
  4526.           return;
  4527.         }
  4528.         expr->value = expr->expr1->value / expr->expr2->value;
  4529.         expr->relativeTo = absoluteTableEntry;
  4530.         return;
  4531.       }
  4532.       if (printErrors) {
  4533.         if ((expr->expr1->relativeTo != absoluteTableEntry) &&
  4534.           (expr->expr1->relativeTo != NULL)) {
  4535.           printError ("The / operator requires operands to be absolute values");
  4536.         }
  4537.         if ((expr->expr2->relativeTo != absoluteTableEntry) &&
  4538.             (expr->expr2->relativeTo != NULL)) {
  4539.           printError ("The / operator requires operands to be absolute values");
  4540.         }
  4541.       }
  4542.       return;
  4543.     case PERCENT:
  4544.       /* The % operator is implemented using the "C" % operator, which
  4545.          is system dependent...  Ugh.  When one operand is negative the
  4546.          value and sign may vary across "C" implementations. */
  4547.       evalExpr (expr->expr1, printErrors);
  4548.       evalExpr (expr->expr2, printErrors);
  4549.       if ((expr->expr1->relativeTo == absoluteTableEntry) &&
  4550.           (expr->expr2->relativeTo == absoluteTableEntry)) {
  4551.         if ((expr->expr1->value < 0) || (expr->expr2->value <= 0)) {
  4552.           if (printErrors) {
  4553.             printError ("Operands to % must be positive");
  4554.           }
  4555.           return;
  4556.         }
  4557.         expr->value = expr->expr1->value % expr->expr2->value;
  4558.         expr->relativeTo = absoluteTableEntry;
  4559.         return;
  4560.       }
  4561.       if (printErrors) {
  4562.         if ((expr->expr1->relativeTo != absoluteTableEntry) &&
  4563.           (expr->expr1->relativeTo != NULL)) {
  4564.           printError ("The % operator requires operands to be absolute values");
  4565.         }
  4566.         if ((expr->expr2->relativeTo != absoluteTableEntry) &&
  4567.             (expr->expr2->relativeTo != NULL)) {
  4568.           printError ("The % operator requires operands to be absolute values");
  4569.         }
  4570.       }
  4571.       return;
  4572.     case LTLT:
  4573.       evalExpr (expr->expr1, printErrors);
  4574.       evalExpr (expr->expr2, printErrors);
  4575.       if ((expr->expr1->relativeTo == absoluteTableEntry) &&
  4576.           (expr->expr2->relativeTo == absoluteTableEntry)) {
  4577.         i = expr->expr2->value;
  4578.         if (i<0 || i>31) {
  4579.           if (printErrors) {
  4580.             printError ("Shift amount must be within 0..31");
  4581.           }
  4582.           return;
  4583.         }
  4584.         expr->value = expr->expr1->value << expr->expr2->value;
  4585.         expr->relativeTo = absoluteTableEntry;
  4586.         return;
  4587.       }
  4588.       if (printErrors) {
  4589.         if ((expr->expr1->relativeTo != absoluteTableEntry) &&
  4590.           (expr->expr1->relativeTo != NULL)) {
  4591.           printError ("The << operator requires operands to be absolute values");
  4592.         }
  4593.         if ((expr->expr2->relativeTo != absoluteTableEntry) &&
  4594.             (expr->expr2->relativeTo != NULL)) {
  4595.           printError ("The << operator requires operands to be absolute values");
  4596.         }
  4597.       }
  4598.       return;
  4599.     case GTGT:
  4600.       evalExpr (expr->expr1, printErrors);
  4601.       evalExpr (expr->expr2, printErrors);
  4602.       if ((expr->expr1->relativeTo == absoluteTableEntry) &&
  4603.           (expr->expr2->relativeTo == absoluteTableEntry)) {
  4604.         i = expr->expr2->value;
  4605.         if (i<0 || i>31) {
  4606.           if (printErrors) {
  4607.             printError ("Shift amount must be within 0..31");
  4608.           }
  4609.           return;
  4610.         }
  4611.         a = expr->expr1->value;
  4612.         b = expr->expr2->value;
  4613.         c = a >> b;  /* With unsigned ints; zeros will be shifted in. */
  4614.         expr->value = c;
  4615.         expr->relativeTo = absoluteTableEntry;
  4616.         return;
  4617.       }
  4618.       if (printErrors) {
  4619.         if ((expr->expr1->relativeTo != absoluteTableEntry) &&
  4620.           (expr->expr1->relativeTo != NULL)) {
  4621.           printError ("The >> operator requires operands to be absolute values");
  4622.         }
  4623.         if ((expr->expr2->relativeTo != absoluteTableEntry) &&
  4624.             (expr->expr2->relativeTo != NULL)) {
  4625.           printError ("The >> operator requires operands to be absolute values");
  4626.         }
  4627.       }
  4628.       return;
  4629.     case GTGTGT:
  4630.       evalExpr (expr->expr1, printErrors);
  4631.       evalExpr (expr->expr2, printErrors);
  4632.       if ((expr->expr1->relativeTo == absoluteTableEntry) &&
  4633.           (expr->expr2->relativeTo == absoluteTableEntry)) {
  4634.         i = expr->expr1->value;
  4635.         j = expr->expr2->value;
  4636.         if (j<0 || j>31) {
  4637.           if (printErrors) {
  4638.             printError ("Shift amount must be within 0..31");
  4639.           }
  4640.           return;
  4641.         }
  4642.         if (j > 32) j = 32;
  4643.         for (; j > 0; j--) {
  4644.           if (i >= 0) {
  4645.             i = (i >> 1) & 0x7fffffff;  /* shift in a 0 */
  4646.           } else {
  4647.             i = (i >> 1) | 0x80000000;  /* shift in a 1 */
  4648.           }
  4649.         }
  4650.         expr->value = i;
  4651.         expr->relativeTo = absoluteTableEntry;
  4652.         return;
  4653.       }
  4654.       if (printErrors) {
  4655.         if ((expr->expr1->relativeTo != absoluteTableEntry) &&
  4656.           (expr->expr1->relativeTo != NULL)) {
  4657.           printError ("The >>> operator requires operands to be absolute values");
  4658.         }
  4659.         if ((expr->expr2->relativeTo != absoluteTableEntry) &&
  4660.             (expr->expr2->relativeTo != NULL)) {
  4661.           printError ("The >>> operator requires operands to be absolute values");
  4662.         }
  4663.       }
  4664.       return;
  4665.     case AMPERSAND:
  4666.       evalExpr (expr->expr1, printErrors);
  4667.       evalExpr (expr->expr2, printErrors);
  4668.       if ((expr->expr1->relativeTo == absoluteTableEntry) &&
  4669.           (expr->expr2->relativeTo == absoluteTableEntry)) {
  4670.         expr->value = expr->expr1->value & expr->expr2->value;
  4671.         expr->relativeTo = absoluteTableEntry;
  4672.         return;
  4673.       }
  4674.       if (printErrors) {
  4675.         if ((expr->expr1->relativeTo != absoluteTableEntry) &&
  4676.           (expr->expr1->relativeTo != NULL)) {
  4677.           printError ("The & operator requires operands to be absolute values");
  4678.         }
  4679.         if ((expr->expr2->relativeTo != absoluteTableEntry) &&
  4680.             (expr->expr2->relativeTo != NULL)) {
  4681.           printError ("The & operator requires operands to be absolute values");
  4682.         }
  4683.       }
  4684.       return;
  4685.     case BAR:
  4686.       evalExpr (expr->expr1, printErrors);
  4687.       evalExpr (expr->expr2, printErrors);
  4688.       if ((expr->expr1->relativeTo == absoluteTableEntry) &&
  4689.           (expr->expr2->relativeTo == absoluteTableEntry)) {
  4690.         expr->value = expr->expr1->value | expr->expr2->value;
  4691.         expr->relativeTo = absoluteTableEntry;
  4692.         return;
  4693.       }
  4694.       if (printErrors) {
  4695.         if ((expr->expr1->relativeTo != absoluteTableEntry) &&
  4696.           (expr->expr1->relativeTo != NULL)) {
  4697.           printError ("The | operator requires operands to be absolute values");
  4698.         }
  4699.         if ((expr->expr2->relativeTo != absoluteTableEntry) &&
  4700.             (expr->expr2->relativeTo != NULL)) {
  4701.           printError ("The | operator requires operands to be absolute values");
  4702.         }
  4703.       }
  4704.       return;
  4705.     case CARET:
  4706.       evalExpr (expr->expr1, printErrors);
  4707.       evalExpr (expr->expr2, printErrors);
  4708.       if ((expr->expr1->relativeTo == absoluteTableEntry) &&
  4709.           (expr->expr2->relativeTo == absoluteTableEntry)) {
  4710.         expr->value = expr->expr1->value ^ expr->expr2->value;
  4711.         expr->relativeTo = absoluteTableEntry;
  4712.         return;
  4713.       }
  4714.       if (printErrors) {
  4715.         if ((expr->expr1->relativeTo != absoluteTableEntry) &&
  4716.           (expr->expr1->relativeTo != NULL)) {
  4717.           printError ("The ^ operator requires operands to be absolute values");
  4718.         }
  4719.         if ((expr->expr2->relativeTo != absoluteTableEntry) &&
  4720.             (expr->expr2->relativeTo != NULL)) {
  4721.           printError ("The ^ operator requires operands to be absolute values");
  4722.         }
  4723.       }
  4724.       return;
  4725.     case TILDE:
  4726.       evalExpr (expr->expr1, printErrors);
  4727.       if (expr->expr1->relativeTo == absoluteTableEntry) {
  4728.         expr->value = ~ ( expr->expr1->value );
  4729.         expr->relativeTo = absoluteTableEntry;
  4730.         return;
  4731.       }
  4732.       if (printErrors) {
  4733.         if ((expr->expr1->relativeTo != absoluteTableEntry) &&
  4734.           (expr->expr1->relativeTo != NULL)) {
  4735.           printError ("The ~ operator requires its operand to be an absolute value");
  4736.         }
  4737.       }
  4738.       return;
  4739.     default:
  4740.       printError ("Program logic error: Unknown operator type in expression");
  4741.       return;
  4742.   }
  4743. }
  4744.  
  4745.  
  4746.  
  4747. /* processEquates ()
  4748. **
  4749. ** This routine runs over the list of instructions looking for "equates".
  4750. ** For each one, it attempts to evaluate the expression and assign a
  4751. ** value to the symbol.  It keeps repeating until it can not do any more.
  4752. ** Then it runs though them one last time, printing error messages.
  4753. */
  4754. void processEquates () {
  4755.   Instruction * instrPtr;
  4756.   anyEquatesResolved = 1;
  4757.   while (anyEquatesResolved && unresolvedEquates) {
  4758.     anyEquatesResolved = 0;
  4759.     /* Run thru the instruction list */
  4760.     for (instrPtr=instrList; instrPtr!=NULL; instrPtr=instrPtr->next) {
  4761.       if (instrPtr->op == EQUAL) {
  4762.         resolveEquate (instrPtr, 0);  /* Try to resolve any equates we can. */
  4763.       }
  4764.     }
  4765.   }
  4766.   /* Run through the equates one last time, printing errors. */
  4767.   for (instrPtr=instrList; instrPtr!=NULL; instrPtr=instrPtr->next) {
  4768.     if (instrPtr->op == EQUAL) {
  4769.       currentLine = instrPtr->lineNum;
  4770.       resolveEquate (instrPtr, 1);  /* Try to resolve any equates we can. */
  4771.     }
  4772.   }
  4773. }
  4774.  
  4775.  
  4776.  
  4777. /* passTwo ()
  4778. **
  4779. ** Run through the instruction list.  Produce the listing, if one is
  4780. ** desired.
  4781. */
  4782. void passTwo () {
  4783.   Instruction * instrPtr;
  4784.   int dontPrintLine;
  4785.   int i, in;
  4786.   int * ip;
  4787.   char c0, c1, c2, c3;
  4788.   int nextLineFromInput = 1;
  4789.   currentSegment = 0;
  4790.   textLC = 0;
  4791.   dataLC = 0;
  4792.   bssLC = 0;
  4793.   setCurrentSegmentTo (TEXT);
  4794.   if (inputFile != stdin) {
  4795.     rewind (inputFile);
  4796.   }
  4797.   for (instrPtr=instrList; instrPtr!=NULL; instrPtr=instrPtr->next) {
  4798.     dontPrintLine = 0;
  4799.     currentLine = instrPtr->lineNum;
  4800.     if (commandOptionL) {
  4801.       while (nextLineFromInput < currentLine) {
  4802.         printf ("                ");
  4803.         printOneLine ();
  4804.         nextLineFromInput++;
  4805.       }
  4806.     }
  4807.     /* process this instr */
  4808.     switch (instrPtr->op) {
  4809.       case TEXT:
  4810.       case DATA:
  4811.       case BSS_SEG:
  4812.         setCurrentSegmentTo (instrPtr->op);
  4813.         if (commandOptionL) {
  4814.           printf ("%06x          ", getLC ());
  4815.         }
  4816.         break;
  4817.       case ASCII:
  4818.         i = instrPtr->tableEntry->string.length;
  4819.         if (commandOptionL) {
  4820.           printf ("%06x ", getLC ());
  4821.           if (i<=0) {
  4822.             printf ("         ");
  4823.           } else if (i==1) {
  4824.             c0 = instrPtr->tableEntry->string.string[0];
  4825.             printf ("%02x       ", c0);
  4826.           } else if (i==2) {
  4827.             c0 = instrPtr->tableEntry->string.string[0];
  4828.             c1 = instrPtr->tableEntry->string.string[1];
  4829.             printf ("%02x%02x     ", c0, c1);
  4830.           } else if (i==3) {
  4831.             c0 = instrPtr->tableEntry->string.string[0];
  4832.             c1 = instrPtr->tableEntry->string.string[1];
  4833.             c2 = instrPtr->tableEntry->string.string[2];
  4834.             printf ("%02x%02x%02x   ", c0, c1, c2);
  4835.           } else {
  4836.             c0 = instrPtr->tableEntry->string.string[0];
  4837.             c1 = instrPtr->tableEntry->string.string[1];
  4838.             c2 = instrPtr->tableEntry->string.string[2];
  4839.             c3 = instrPtr->tableEntry->string.string[3];
  4840.             printf ("%02x%02x%02x%02x ", c0, c1, c2, c3);
  4841.           }
  4842.         }
  4843.         incrementLCBy (i);
  4844.         break;
  4845.       case BYTE:
  4846.         if (commandOptionL) {
  4847.           i = instrPtr->expr->value;
  4848.           i = i & 0x000000ff;
  4849.           printf ("%06x ", getLC ());
  4850.           printf ("%02x       ", i);
  4851.         }
  4852.         incrementLCBy (1);
  4853.         break;
  4854.       case WORD:
  4855.         if (commandOptionL) {
  4856.           printf ("%06x ", getLC ());
  4857.           printf ("%08x ", instrPtr->expr->value);
  4858.         }
  4859.         incrementLCBy (4);
  4860.         break;
  4861.       case DOUBLE:
  4862.         if (commandOptionL) {
  4863.           printf ("%06x ", getLC ());
  4864.           /* Print first 4 bytes of the real constant. */
  4865.           ip = (int *) & (instrPtr->expr->rvalue);
  4866.           /* Print the first 4 bytes of the 8 byte floating number. */
  4867.           printf ("%08x ", *ip);
  4868.           /* printf ("  rvalue = %.17g  ", instrPtr->expr->rvalue); */
  4869.         }
  4870.         incrementLCBy (8);
  4871.         break;
  4872.       case EQUAL:
  4873.         if (commandOptionL) {
  4874.           printf ("       %08x ", instrPtr->expr->value);
  4875.         }
  4876.         break;
  4877.       case EXPORT:
  4878.         if (commandOptionL) {
  4879.           printf ("                ");
  4880.         }
  4881.         break;
  4882.       case IMPORT:
  4883.         if (commandOptionL) {
  4884.           printf ("                ");
  4885.         }
  4886.         break;
  4887.       case ALIGN:
  4888.         printError ("Program logic error: Should have replaced align with skip");
  4889.         break;
  4890.       case SKIP:
  4891.         i = instrPtr->ra;
  4892.         if (commandOptionL) {
  4893.           printf ("%06x ", getLC ());
  4894.           if (i<=0) {
  4895.             printf ("         ");
  4896.           } else if (i==1) {
  4897.             printf ("00       ");
  4898.           } else if (i==2) {
  4899.             printf ("0000     ");
  4900.           } else if (i==3) {
  4901.             printf ("000000   ");
  4902.           } else {
  4903.             printf ("00000000 ");
  4904.           }
  4905.         }
  4906.         incrementLCBy (i);
  4907.         break;
  4908.       case LABEL:
  4909.         if (commandOptionL) {
  4910.           if ((instrPtr->next != NULL)
  4911.               && (instrPtr->next->lineNum != instrPtr->lineNum)) {
  4912.             printf ("%06x          ", getLC ());
  4913.           } else {
  4914.             dontPrintLine = 1;
  4915.           }
  4916.         }
  4917.         break;
  4918.       default:
  4919.         if ((instrPtr->op < 0) || (instrPtr->op > 255)) {
  4920.           printError ("Program logic error: Invalid opcode in passTwo");
  4921.         }
  4922.         in = (instrPtr->op << 24)
  4923.            | (instrPtr->rc << 20)
  4924.            | (instrPtr->ra << 16)
  4925.            | (instrPtr->rb << 12);
  4926.         if (instrPtr->op == SETHI) {
  4927.            in = in | ((instrPtr->expr->value >> 16) & 0x0000ffff);
  4928.         } else if (instrPtr->op == SETLO) {
  4929.            in = in | (instrPtr->expr->value & 0x0000ffff);
  4930.         } else if (instrPtr->op == LDADDR) {
  4931.            in = in | 0;
  4932.         } else if ((instrPtr->format == E) || (instrPtr->format == G)) {
  4933.            i = instrPtr->expr->value;
  4934.            if (((i & 0xffff8000) != 0xffff8000) &&
  4935.                ((i & 0xffff8000) != 0x00000000) &&
  4936.                (instrPtr->expr->relativeTo == absoluteTableEntry)) {
  4937.              fprintf (stderr,
  4938.                  "Warning on line %d: Immediate value (0x%08x) exceeds 16-bit limit.\n",
  4939.                  currentLine, i);
  4940.            }
  4941.            in = in | (i & 0x0000ffff);
  4942.         } else if (instrPtr->format == F) {
  4943.            if ((instrPtr->expr->relativeTo == textTableEntry)
  4944.                   && (currentSegment == TEXT)) {
  4945.              i = instrPtr->expr->value - getLC ();
  4946.            } else if ((instrPtr->expr->relativeTo == dataTableEntry)
  4947.                   && (currentSegment == DATA)) {
  4948.              i = instrPtr->expr->value - getLC ();
  4949.            } else {
  4950.              i = 0;
  4951.            }
  4952.            if (((i & 0xff800000) != 0xff800000) &&
  4953.                ((i & 0xff800000) != 0x00000000)) {
  4954.              fprintf (stderr,
  4955.                  "Warning on line %d: Relative branch offset (%08x) exceeds 24-bit limit.\n",
  4956.                  currentLine, i);
  4957.            }
  4958.            in = in | (i & 0x00ffffff);
  4959.         }
  4960.         if (commandOptionL) {
  4961.           printf ("%06x ", getLC ());
  4962.           printf ("%08x ", in);
  4963.         }
  4964.         incrementLCBy (4);
  4965.         break;
  4966.     }
  4967.     /* print the listing info, if a listing is needed. */
  4968.     if (commandOptionL && !dontPrintLine) {
  4969.       if (nextLineFromInput == currentLine) {
  4970.         printOneLine ();
  4971.         nextLineFromInput++;
  4972.       } else {
  4973.         printf ("\n");
  4974.       }
  4975.     }
  4976.   }
  4977.   if (commandOptionL) {
  4978.     while (1) {
  4979.       c0 = getc (inputFile);
  4980.       if (c0 == EOF) break;
  4981.       printf ("                ");
  4982.       while (c0 != EOF) {
  4983.         putc (c0, stdout);
  4984.         if (c0 == '\n') break;
  4985.         c0 = getc (inputFile);
  4986.       }
  4987.     }
  4988.   }
  4989. }
  4990.  
  4991.  
  4992.  
  4993. /* printOneLine ()
  4994. **
  4995. ** This routine will read one line from inputFile and copy it to
  4996. ** stdout, including the terminating newline.
  4997. */
  4998. void printOneLine () {
  4999.   int c;
  5000.   while (1) {
  5001.     c = getc (inputFile);
  5002.     if (c == EOF) return;
  5003.     putc (c, stdout);
  5004.     if (c == '\n') return;
  5005.   }
  5006. }
  5007.  
  5008.  
  5009.  
  5010. /* writeInteger (i)
  5011. **
  5012. ** This routine writes out 4 bytes to the .o file.
  5013. */
  5014. void writeInteger (int i) {
  5015.   fwrite (&i, 4, 1, outputFile);
  5016. }
  5017.  
  5018.  
  5019.  
  5020. /* writeSegment (segType)
  5021. **
  5022. ** This routine is passed either TEXT or DATA.  It runs through the
  5023. ** instruction list and writes the segment data out to the .o file.
  5024. ** It returns the number of bytes written.
  5025. */
  5026. int writeSegment (int segType) {
  5027.   Instruction * instrPtr;
  5028.   int in, i, len;
  5029.   double d;
  5030.   char * str;
  5031.   char c;
  5032.   int zero = 0;
  5033.   int numberBytesWritten = 0;
  5034.   currentSegment = 0;
  5035.   textLC = 0;
  5036.   dataLC = 0;
  5037.   bssLC = 0;
  5038.   setCurrentSegmentTo (TEXT);
  5039.   for (instrPtr=instrList; instrPtr!=NULL; instrPtr=instrPtr->next) {
  5040.     /* process this instr */
  5041.     switch (instrPtr->op) {
  5042.       case TEXT:
  5043.       case DATA:
  5044.       case BSS_SEG:
  5045.         currentSegment = instrPtr->op;
  5046.         break;
  5047.       case ASCII:
  5048.         len = instrPtr->tableEntry->string.length;
  5049.         if (currentSegment == segType) {
  5050.           str = instrPtr->tableEntry->string.string;
  5051.           for (i=0; i<len; i++) {
  5052.             fwrite (&str[i], 1, 1, outputFile);
  5053.           }
  5054.           numberBytesWritten += len;
  5055.         }
  5056.         incrementLCBy (len);
  5057.         break;
  5058.       case BYTE:
  5059.         if (currentSegment == segType) {
  5060.           i = instrPtr->expr->value;
  5061.           if (instrPtr->expr->relativeTo != absoluteTableEntry) {
  5062.             i = 0;
  5063.           }
  5064.           c = i & 0x000000ff;
  5065.           fwrite (&c, 1, 1, outputFile);
  5066.           numberBytesWritten++;
  5067.         }
  5068.         incrementLCBy (1);
  5069.         break;
  5070.       case WORD:
  5071.         if (currentSegment == segType) {
  5072.           i = instrPtr->expr->value;
  5073.           if (instrPtr->expr->relativeTo != absoluteTableEntry) {
  5074.             i = 0;
  5075.           }
  5076.           fwrite (&i, 1, 4, outputFile);
  5077.           numberBytesWritten += 4;
  5078.         }
  5079.         incrementLCBy (4);
  5080.         break;
  5081.       case DOUBLE:
  5082.         if (currentSegment == segType) {
  5083.           d = instrPtr->expr->rvalue;
  5084.           fwrite (&d, 1, 8, outputFile);
  5085.           numberBytesWritten += 8;
  5086.         }
  5087.         incrementLCBy (8);
  5088.         break;
  5089.       case EQUAL:
  5090.         break;
  5091.       case EXPORT:
  5092.         break;
  5093.       case IMPORT:
  5094.         break;
  5095.       case SKIP:
  5096.         len = instrPtr->ra;
  5097.         if (currentSegment == segType) {
  5098.           for (i=0; i<len; i++) {
  5099.             fwrite (&zero, 1, 1, outputFile);
  5100.           }
  5101.           numberBytesWritten += len;
  5102.         }
  5103.         incrementLCBy (len);
  5104.         break;
  5105.       case LABEL:
  5106.         break;
  5107.       default:
  5108.         if ((instrPtr->op < 0) || (instrPtr->op > 255)) {
  5109.           printError ("Program logic error: Invalid opcode in writeSeg");
  5110.         }
  5111.         if (currentSegment == segType) {
  5112.           in = (instrPtr->op << 24)
  5113.              | (instrPtr->rc << 20)
  5114.              | (instrPtr->ra << 16)
  5115.              | (instrPtr->rb << 12);
  5116.           if (instrPtr->op == SETHI) {
  5117.             i = instrPtr->expr->value;
  5118.             if (instrPtr->expr->relativeTo == absoluteTableEntry) {
  5119.               in = in | ((i>>16) & 0x0000ffff);
  5120.             }
  5121.           } else if (instrPtr->op == LDADDR) {
  5122.             /* Set 16 bits of instruction to zero, which they already are. */
  5123.           } else if ((instrPtr->format == E) || (instrPtr->format == G)) {
  5124.             i = instrPtr->expr->value;
  5125.             if (instrPtr->expr->relativeTo == absoluteTableEntry) {
  5126.               in = in | (i & 0x0000ffff);
  5127.             }
  5128.           } else if (instrPtr->format == F) {
  5129.             if ((instrPtr->expr->relativeTo == textTableEntry)
  5130.                   && (currentSegment == TEXT)) {
  5131.               i = instrPtr->expr->value - getLC ();
  5132.             } else if ((instrPtr->expr->relativeTo == dataTableEntry)
  5133.                   && (currentSegment == DATA)) {
  5134.               i = instrPtr->expr->value - getLC ();
  5135.             } else {
  5136.               i = 0;
  5137.             }
  5138.             in = in | (i & 0x00ffffff);
  5139.           }
  5140.           fwrite (&in, 1, 4, outputFile);
  5141.           numberBytesWritten += 4;
  5142.         }
  5143.         incrementLCBy (4);
  5144.         break;
  5145.     }
  5146.   }
  5147.   return numberBytesWritten;
  5148. }
  5149.  
  5150.  
  5151.  
  5152. /* writeSymbols ()
  5153. **
  5154. ** This routine writes out imported and exported symbols to the .o file.
  5155. */
  5156. void writeSymbols () {
  5157.   int nextSymbolNum = 5;
  5158.   int hashVal;
  5159.   TableEntry * entryPtr;
  5160.   /* Run thru all symbols and assign a number to every imported or
  5161.      exported symbol. */
  5162.   for (hashVal = 0; hashVal<SYMBOL_TABLE_HASH_SIZE; hashVal++) {
  5163.     for (entryPtr = symbolTableIndex [hashVal];
  5164.                        entryPtr;
  5165.                        entryPtr = entryPtr->next) {
  5166.       if ((entryPtr == textTableEntry)
  5167.           || (entryPtr == dataTableEntry)
  5168.           || (entryPtr == bssTableEntry)
  5169.           || (entryPtr == absoluteTableEntry)) {
  5170.         /* ignore */
  5171.       } else if (entryPtr->imported || entryPtr->exported) {
  5172.         entryPtr->symbolNum = nextSymbolNum++;
  5173.       }
  5174.     }
  5175.   }
  5176.   /* Run thru all symbols and add each to the .o file. */
  5177.   writeOutSymbol (textTableEntry);
  5178.   writeOutSymbol (dataTableEntry);
  5179.   writeOutSymbol (bssTableEntry);
  5180.   writeOutSymbol (absoluteTableEntry);
  5181.   for (hashVal = 0; hashVal<SYMBOL_TABLE_HASH_SIZE; hashVal++) {
  5182.     for (entryPtr = symbolTableIndex [hashVal];
  5183.                        entryPtr;
  5184.                        entryPtr = entryPtr->next) {
  5185.       if ((entryPtr == textTableEntry)
  5186.           || (entryPtr == dataTableEntry)
  5187.           || (entryPtr == bssTableEntry)
  5188.           || (entryPtr == absoluteTableEntry)) {
  5189.         /* ignore */
  5190.       } else if (entryPtr->imported || entryPtr->exported) {
  5191.         writeOutSymbol (entryPtr);
  5192.       }
  5193.     }
  5194.   }
  5195. }
  5196.  
  5197.  
  5198.  
  5199. /* writeOutSymbol ()
  5200. **
  5201. ** This routine adds a symbol to the .o file.
  5202. */
  5203. void writeOutSymbol (TableEntry * entry) {
  5204.   int i, len;
  5205.   char * str;
  5206.   writeInteger (entry->symbolNum);
  5207.   writeInteger (entry->offset);
  5208.   if (entry->relativeTo != NULL) {
  5209.     writeInteger (entry->relativeTo->symbolNum);
  5210.   } else {
  5211.     writeInteger (0);
  5212.   }
  5213.   len = entry->string.length;
  5214.   writeInteger (len);
  5215.   str = entry->string.string;
  5216.   for (i=0; i<len; i++) {
  5217.     fwrite (&str[i], 1, 1, outputFile);
  5218.   }
  5219. }
  5220.  
  5221.  
  5222.  
  5223. /* writeRelocationInfo ()
  5224. **
  5225. ** This routine runs through the instruction list and for each instruction
  5226. ** that contains relocatable data, writes out a record saying how the
  5227. ** linker should modify the data.
  5228. */
  5229. void writeRelocationInfo () {
  5230.   Instruction * instrPtr;
  5231.   int i, in, relTo;
  5232.   currentSegment = 0;
  5233.   textLC = 0;
  5234.   dataLC = 0;
  5235.   bssLC = 0;
  5236.   setCurrentSegmentTo (TEXT);
  5237.   for (instrPtr=instrList; instrPtr!=NULL; instrPtr=instrPtr->next) {
  5238.     currentLine = instrPtr->lineNum;
  5239.     switch (instrPtr->op) {
  5240.       case TEXT:
  5241.       case DATA:
  5242.       case BSS_SEG:
  5243.         setCurrentSegmentTo (instrPtr->op);
  5244.         break;
  5245.       case ASCII:
  5246.         i = instrPtr->tableEntry->string.length;
  5247.         incrementLCBy (i);
  5248.         break;
  5249.       case BYTE:
  5250.         writeRelocationEntry (1, getLC(), instrPtr->expr);
  5251. /***
  5252.         if (instrPtr->expr->relativeTo != absoluteTableEntry) {
  5253.           writeInteger (1);
  5254.           writeInteger (getLC ());
  5255.           if (currentSegment == TEXT) writeInteger (1);
  5256.           if (currentSegment == DATA) writeInteger (2);
  5257.           writeInteger (instrPtr->expr->value);
  5258.           relTo = instrPtr->expr->relativeTo->symbolNum;
  5259.           if (relTo == 0) {
  5260.             printError ("Program logic error: relativeTo has no symbolNum");
  5261.           }
  5262.           writeInteger (relTo);
  5263.         }
  5264. ***/
  5265.         incrementLCBy (1);
  5266.         break;
  5267.       case WORD:
  5268.         writeRelocationEntry (4, getLC(), instrPtr->expr);
  5269. /***
  5270.         if (instrPtr->expr->relativeTo != absoluteTableEntry) {
  5271.           writeInteger (4);
  5272.           writeInteger (getLC ());
  5273.           if (currentSegment == TEXT) writeInteger (1);
  5274.           if (currentSegment == DATA) writeInteger (2);
  5275.           writeInteger (instrPtr->expr->value);
  5276.           relTo = instrPtr->expr->relativeTo->symbolNum;
  5277.           if (relTo == 0) {
  5278.             printError ("Program logic error: relativeTo has no symbolNum");
  5279.           }
  5280.           writeInteger (relTo);
  5281.         }
  5282. ***/
  5283.         incrementLCBy (4);
  5284.         break;
  5285.       case DOUBLE:
  5286.         incrementLCBy (8);
  5287.         break;
  5288.       case EQUAL:
  5289.       case EXPORT:
  5290.       case IMPORT:
  5291.       case ALIGN:
  5292.       case LABEL:
  5293.         break;
  5294.       case SKIP:
  5295.         i = instrPtr->ra;
  5296.         incrementLCBy (i);
  5297.         break;
  5298.       default:
  5299.         if ((instrPtr->op < 0) || (instrPtr->op > 255)) {
  5300.           printError ("Program logic error: Invalid opcode in passTwo");
  5301.         }
  5302.         if (instrPtr->op == SETHI) {
  5303.           /* 16-bit SETHI update.  Use loc=addr of the 16-bits. */
  5304.           writeRelocationEntry (5, getLC () + 2, instrPtr->expr);
  5305.         } else if (instrPtr->op == SETLO) {
  5306.           /* 16-bit SETLO update.  Use loc=addr of the 16-bits. */
  5307.           writeRelocationEntry (6, getLC () + 2, instrPtr->expr);
  5308.         } else if (instrPtr->op == LDADDR) {
  5309.           /* 16-bit relative.  Use loc=addr of the 16-bits. */
  5310.           writeRelocationEntry (7, getLC (), instrPtr->expr);
  5311.         } else if ((instrPtr->format == E) || (instrPtr->format == G)) {
  5312.           /* 16-bit update.  Use loc=addr of the 16-bits. */
  5313.           writeRelocationEntry (2, getLC () + 2, instrPtr->expr);
  5314.         } else if (instrPtr->format == F) {
  5315.           /* 24-bit update.  Use loc=addr of the instruction. */
  5316.           if ((instrPtr->expr->relativeTo == textTableEntry)
  5317.                 && (currentSegment == TEXT)) {
  5318.           } else if ((instrPtr->expr->relativeTo == dataTableEntry)
  5319.                 && (currentSegment == DATA)) {
  5320.           } else {
  5321.             writeRelocationEntry (3, getLC () + 0, instrPtr->expr);
  5322.           }
  5323.         }
  5324.         incrementLCBy (4);
  5325.         break;
  5326.     }
  5327.   }
  5328. }
  5329.  
  5330.  
  5331.  
  5332. /* writeRelocationEntry (type, addr, expr)
  5333. **
  5334. ** This routine writes a single relocation entry to the .o file.
  5335. */
  5336. void writeRelocationEntry (int type, int addr, Expression * expr) {
  5337.   
  5338.   if (expr->relativeTo == NULL) {
  5339.     printError ("Program logic error: relativeTo has no symbolNum");
  5340.   } else if (expr->relativeTo != absoluteTableEntry) {
  5341.     writeInteger (type);
  5342.     writeInteger (addr);
  5343.     if (currentSegment == TEXT) writeInteger (1);
  5344.     if (currentSegment == DATA) writeInteger (2);
  5345.     writeInteger (expr->value);
  5346.     if (expr->relativeTo->symbolNum == 0) {
  5347.       printError ("Program logic error: relativeTo has no symbolNum");
  5348.     }
  5349.     writeInteger (expr->relativeTo->symbolNum);
  5350.     writeInteger (currentLine);
  5351.   }
  5352. }
  5353.  
  5354.  
  5355.  
  5356. /* writeLabels ()
  5357. **
  5358. ** This routine runs through the instruction list and writes
  5359. ** out each label to the .o output file.
  5360. */
  5361. void writeLabels () {
  5362.   Instruction * instrPtr;
  5363.   TableEntry * relTo;
  5364.   int offset, i, len;
  5365.   char * str;
  5366.   currentSegment = 0;
  5367.   for (instrPtr=instrList; instrPtr!=NULL; instrPtr=instrPtr->next) {
  5368.     /* process this instr */
  5369.     switch (instrPtr->op) {
  5370.       case TEXT:
  5371.       case DATA:
  5372.       case BSS_SEG:
  5373.         currentSegment = instrPtr->op;
  5374.         break;
  5375.       case LABEL:
  5376.         relTo = instrPtr->tableEntry->relativeTo;
  5377.         if (currentSegment == TEXT) {
  5378.           if (relTo != textTableEntry) {
  5379.             printError ("Program logic error: problem with label");
  5380.           }
  5381.           writeInteger (1);
  5382.         } else if (currentSegment == DATA) {
  5383.           if (relTo != dataTableEntry) {
  5384.             printError ("Program logic error: problem with label");
  5385.           }
  5386.           writeInteger (2);
  5387.         } else if (currentSegment == BSS_SEG) {
  5388.           if (relTo != bssTableEntry) {
  5389.             printError ("Program logic error: problem with label");
  5390.           }
  5391.           writeInteger (3);
  5392.         }
  5393.         offset = instrPtr->tableEntry->offset;
  5394.         writeInteger (offset);
  5395.         len = instrPtr->tableEntry->string.length;
  5396.         writeInteger (len);
  5397.         str = instrPtr->tableEntry->string.string;
  5398.         for (i=0; i<len; i++) {
  5399.           fwrite (&str[i], 1, 1, outputFile);
  5400.         }
  5401.         break;
  5402.       default:
  5403.         break;
  5404.     }
  5405.   }
  5406. }
  5407.