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 / Beta / asm.c next >
C/C++ Source or Header  |  2007-09-04  |  173KB  |  5,625 lines

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