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 / main.cc < prev    next >
C/C++ Source or Header  |  2007-09-04  |  51KB  |  1,628 lines

  1. // main.cc  --  Driver routine for the compiler; basic control routines
  2. //
  3. // KPL Compiler
  4. //
  5. // Copyright 2002-2007, Harry H. Porter III
  6. //
  7. // This file may be freely copied, modified and compiled, on the sole
  8. // condition that if you modify it...
  9. //   (1) Your name and the date of modification is added to this comment
  10. //       under "Modifications by", and
  11. //   (2) Your name and the date of modification is added to the printHelp()
  12. //       routine under "Modifications by".
  13. //
  14. // Original Author:
  15. //   06/15/02 - Harry H. Porter III
  16. //
  17. // Modifcations by:
  18. //   03/15/06 - Harry H. Porter III
  19. //
  20.  
  21. #include <signal.h>  
  22. #include "main.h"
  23.  
  24.  
  25.  
  26. //---------------  Global Variables  ---------------
  27.  
  28. TokenValue currentTokenValue;          // Used in lexer only
  29. Token tokenMinusOne, token, token2, token3, token4, token5;
  30. int currentInputFileIndex = -1;        // These describe the current position in the file
  31. int currentLineOfToken;                // .
  32. int currentCharPosOfToken;             // .   
  33. int posOfNextToken;                    // Position of the next token
  34. int eofCount;                          // Used to check for looping on EOF
  35. char * inputFileNames [MAX_INPUT_FILES+1];   // Array of ptrs to file names
  36. int errorsDetected;                    // Count of errors detected so far
  37. int tokenPosOfLastError;               // Used to suppress extraneous syntax errors
  38. int hashVal = 0;                       // The running hash code for this file
  39. int hashCount = 0;                     // Used in computing the hashVal
  40. char * commandPackageName = NULL;      // The package name, NULL = missing
  41. char * commandDirectoryName;           // The search directory name, NULL = missing
  42. char * headerFileName = NULL;          // The header file name, NULL = missing
  43. char * codeFileName = NULL;            // The code file name, NULL = missing
  44. char * outputFileName = NULL;          // The .s filename, NULL = missing
  45. FILE * inputFile;                      // The input file, e.g., stdin
  46. FILE * outputFile;                     // The output file, e.g., stdout
  47. int commandOptionS = 0;                // True: print the symbol table
  48. int commandOptionP = 0;                // True: pretty-print the AST
  49. int commandOptionAST = 0;              // True: print the full AST
  50. int commandOptionTestLexer = 0;        // True: stop after lexer & print tokens
  51. int commandOptionTestParser = 0;       // True: stop after parser & print AST
  52. int safe = 1;                          // True: only allow safe constructs
  53. Header * headerList = NULL;            // List of all headers
  54. Header * headerListLast = NULL;        // .
  55. Mapping <String, Header> *             // Strings --> Headers
  56.   headerMapping = NULL;                // .
  57. Code * code = NULL;                    // The thing being compiled
  58. Header * mainHeader = NULL;            // The corresponding header
  59. Interface * tempInterList = NULL;      // Used in topoProcessInterfaces
  60. ClassDef * tempClassList = NULL;       // Used in topoProcessClasses
  61. int changed = 0;                       // Used in assignOffsets
  62. int quo = 0;                           // Used in integer division
  63. int rem = 0;                           // .
  64. ClassDef * currentClass = NULL;        // The class we are currently processing
  65. Header * currentHeader = NULL;         // The header we are currently processing
  66. int recursionCounter = 0;              // Used to detect recursive types
  67. IntConst * memoryStart;                // Used to compute memory usage by compiler
  68. IR * firstInstruction = NULL;          // List of IR instructions
  69. IR * lastInstruction = NULL;           // .
  70. int maxArgBytesSoFar = -1;             // Used in setting fun/meth->maxArgBytes
  71. DoubleConst * floatList = NULL;        // Used during code gen
  72. StringConst * stringList = NULL;       // Used during code gen
  73. MethOrFunction * currentFunOrMeth = NULL;     // Used during code gen
  74. Offset * firstDispatchOffset = NULL;   // Ptr to linked list: 4,8,12,16,...
  75.  
  76.  
  77.  
  78. // The String Table, for all Strings and IDs.
  79. String * stringTableIndex [STRING_TABLE_HASH_SIZE];
  80.  
  81.  
  82. char buffer [BUFF_LEN];     // Misc. use, e.g., "_Person__Constructor"
  83.  
  84.  
  85. // These are initialized in "initializeConstants"...
  86. String * stringUnaryBang;
  87. String * stringUnaryStar;
  88. String * stringUnaryAmp;
  89. String * stringUnaryMinus;
  90.  
  91. String * stringPlus;
  92. String * stringMinus;
  93. String * stringStar;
  94. String * stringSlash;
  95. String * stringPercent;
  96. String * stringBar;
  97. String * stringCaret;
  98. String * stringAmp;
  99. String * stringBarBar;
  100. String * stringAmpAmp;
  101. String * stringEqualEqual;
  102. String * stringNotEqual;
  103. String * stringLess;
  104. String * stringLessEqual;
  105. String * stringGreater;
  106. String * stringGreaterEqual;
  107. String * stringLessLess;
  108. String * stringGreaterGreater;
  109. String * stringGreaterGreaterGreater;
  110. String * stringIntToDouble;
  111. String * stringDoubleToInt;
  112. String * stringIntToChar;
  113. String * stringCharToInt;
  114. String * stringPtrToBool;
  115. String * stringPosInf;
  116. String * stringNegInf;
  117. String * stringNegZero;
  118. String * stringIIsZero;
  119. String * stringINotZero;
  120. String * stringObject;
  121. String * stringMain;
  122.  
  123. CharType * basicCharType;
  124. IntType  * basicIntType;
  125. DoubleType * basicDoubleType;
  126. BoolType * basicBoolType;
  127. VoidType * basicVoidType;
  128. TypeOfNullType * basicTypeOfNullType;
  129. AnyType * basicAnyType;
  130. PtrType * basicCharArrayPtrType;
  131. PtrType * basicVoidPtrType;
  132. PtrType * basicAnyPtrType;
  133.  
  134. IntConst * constantIntZero;
  135. IntConst * constantIntOne;
  136. IntConst * constantIntMinusOne;
  137. BoolConst * constantFalse;
  138. BoolConst * constantTrue;
  139.  
  140.  
  141. /*****
  142.  
  143. DoubleExpr * constantDoubleZero;
  144. DoubleExpr * constantDoubleOne;
  145. CharExpr * constantCharNull;
  146. BoolExpr * constantFalse;
  147. BoolExpr * constantTrue;
  148. NullExpr * constantNull;
  149. String * stringUninitialized;
  150. String * stringGenericDestructor;
  151. String * stringThis;
  152.  
  153.  
  154. Quad * firstQuad;
  155. Quad * lastQuad;
  156. StringExpr * stringList;
  157. DoubleExpr * floatList;
  158.  
  159.  
  160. AstNode * currentMethOrFun;
  161. Class * currentClass;
  162.  
  163. *****/
  164.  
  165.  
  166.  
  167. // main (argc, argv)
  168. //
  169. // The compiler main.
  170. //
  171. main (int argc, char ** argv) {
  172.   Expression * expr;
  173.   Header * hdr, * newHeader;
  174.   Uses * uses;
  175.   String * newPackName;
  176.   AstNode * ast;
  177.   int len;
  178.   char * fileName;
  179.   Type * t;
  180.   int saveSafe;
  181.   int wantProgress = 0;
  182.  
  183. /*****
  184.   Function * function;
  185.   Method * meth;
  186.   Class * cl;
  187.   Function * fun;
  188.   Expression * exp;
  189.   Statement * stmtList;
  190.   Type * type;
  191.   TypeParm * templateParms;
  192.   int isLone = 0;
  193.  
  194.  
  195.   String *s1, *s2, *s3, *s4, *s5, *s6, *s7, *s8, *s9;
  196.   Decl * decl;
  197. *****/
  198.  
  199.   memoryStart = new IntConst ();
  200.   // printf ("Starting memory address = 0x%08x\n", (int) memoryStart);
  201.  
  202.   errorsDetected = 0;
  203.   tokenPosOfLastError = -1;  // FF=255, LLLL=65535, PP=255
  204.   initKeywords ();
  205.   checkHostCompatibility ();
  206.  
  207.   // Debugging: test the "Mapping" class...
  208.   // testMapping ();
  209.  
  210.   processCommandLine (argc, argv);
  211.  
  212.   initializeConstants ();
  213.  
  214. //  // print various global variables and command line options.
  215. //  printf ("safe = %d\n", safe);
  216. //  printf ("commandOptionTestLexer = %d\n", commandOptionTestLexer);
  217. //  printf ("commandOptionTestParser = %d\n", commandOptionTestParser);
  218. //  if (commandPackageName == NULL) {
  219. //    printf ("commandPackageName = NULL\n");
  220. //  } else {
  221. //    printf ("commandPackageName = %s\n", commandPackageName);
  222. //  }
  223. //  if (commandDirectoryName == NULL) {
  224. //    printf ("commandDirectoryName = NULL\n");
  225. //  } else {
  226. //    printf ("commandDirectoryName = %s\n", commandDirectoryName);
  227. //  }
  228. //  if (headerFileName == NULL) {
  229. //    printf ("headerFileName = NULL\n");
  230. //  } else {
  231. //    printf ("headerFileName = %s\n", headerFileName);
  232. //  }
  233. //  if (codeFileName == NULL) {
  234. //    printf ("codeFileName = NULL\n");
  235. //  } else {
  236. //    printf ("codeFileName = %s\n", codeFileName);
  237. //  }
  238. //  if (outputFileName == NULL) {
  239. //    printf ("outputFileName = NULL\n");
  240. //  } else {
  241. //    printf ("outputFileName = %s\n", outputFileName);
  242. //  }
  243.  
  244.   // If -testLexer command line option present...
  245.   if (commandOptionTestLexer) {
  246.     printf("file-name\tline\tchar\ttoken-type\tother-info\n");
  247.     printf("=========\t====\t====\t==========\t==========\n");
  248.     // initScanner ("temp1.h");
  249.     // testLexer ();
  250.     // initScanner ("temp2.h");
  251.     // testLexer ();
  252.     // initScanner ("temp3.h");
  253.     // testLexer ();
  254.     if (initScanner (headerFileName) != NULL) {
  255.       testLexer ();
  256.     }
  257.  
  258.     terminateCompiler ();
  259.   }
  260.  
  261. /*****
  262.   printf ("INPUT FILE NAMES\n");
  263.   printf ("================\n");
  264.   for (int i=0; i<=currentInputFileIndex; i++) {
  265.     printf ("%d:  %s\n", i, inputFileNames [i]);
  266.   }
  267.   terminateCompiler ();
  268. *****/
  269.  
  270.   headerMapping = new Mapping<String, Header> (15, NULL);
  271.  
  272.   // If -testParser command line option present...
  273.   if (commandOptionTestParser) {
  274.     if (initScanner (headerFileName)) {
  275.       if (token.type == FUNCTION) {
  276.         ast = parseFunction (1);  // 1=expecting ID
  277.       } else if (token.type == METHOD) {
  278.         ast = parseMethod ();
  279.       } else if (token.type == HEADER) {
  280.         ast = parseHeader ();
  281.       } else if (token.type == CODE) {
  282.         ast = parseCode ();
  283.       } else if (token.type == DO) {
  284.         scan ();
  285.         ast = parseExpr ("Expecting test expression after 'do'");
  286.       }
  287.  
  288.       if (commandOptionAST) {
  289.         printAst (6, ast);
  290.       }
  291.  
  292.       if (commandOptionP) {
  293.         printf ("========  PRETTY PRINT  ========\n");
  294.         pretty (ast);
  295.         printf ("\n================================\n");
  296.       }
  297.     }
  298.  
  299.     terminateCompiler ();
  300.   }
  301.  
  302.   // Make sure the user specified a package name on the command line.
  303.   if (commandPackageName == NULL) {
  304.     fprintf (stderr, "*****  ERROR: Missing package name on command line\n");
  305.     errorsDetected++;
  306.     terminateCompiler ();
  307.   }
  308.   if ((codeFileName == NULL) || (headerFileName == NULL)) {
  309.     programLogicError ("File names should have been created from package name");
  310.   }
  311.  
  312.   if (wantProgress) printf ("Parsing...\n");
  313.  
  314.   // Parse the code file...
  315.   if (initScanner (codeFileName)) {
  316.     code = parseCode ();
  317.     // printf ("\n================  CODE  ================\n");
  318.     // printAst (6, code);
  319.     // pretty (code);
  320.     // printf ("================================\n");
  321.  
  322.   } else {
  323.     code = NULL;
  324.   }
  325.  
  326.   // Parse the main header file...
  327.   fileName = initScanner (headerFileName);
  328.   if (fileName != NULL) {
  329. //    mainHeader = parseHeader (commandPackageName);
  330.     mainHeader = parseHeader ();
  331.     headerList = mainHeader;
  332.     headerListLast = mainHeader;
  333.     if (mainHeader) {
  334. //      headerMapping->enter (mainHeader->packageName, mainHeader);
  335.       headerMapping->enter (lookupAndAdd (commandPackageName, ID), mainHeader);
  336.     }
  337.   } else {
  338.     mainHeader = NULL;
  339.     headerList = NULL;
  340.     headerListLast = NULL;
  341.   }
  342.  
  343.   // Run through the headerList.  For every header on it, see which
  344.   // packages it uses.  For each, if it has not already been parsed
  345.   // then parse it and add it to the headerMapping.
  346.   hdr = headerList;
  347.   while (hdr != NULL) {
  348.     // Look at the next "hdr"...
  349.     // Run through the list of packages this "hdr" uses...
  350.     uses = hdr->uses;
  351.     while (uses != NULL) {
  352.       newPackName = uses->id;
  353.  
  354.       // If this package has not been seen before...
  355.       if (! headerMapping->alreadyDefined (newPackName)) {
  356.  
  357.         // Figure out the name of the .h header file...
  358.         len = strlen (newPackName->chars);
  359.         fileName = (char *) calloc (1, len + 4);
  360.         strcpy (fileName, newPackName->chars);
  361.         fileName [len] = '.';
  362.         fileName [len+1] = 'h';
  363.         fileName [len+2] = '\0';
  364.         fileName = initScanner (fileName);
  365.         if (fileName != NULL) {
  366.         
  367.           // Parse the new package...
  368.           //      newHeader = parseHeader (newPackName->chars);
  369.           newHeader = parseHeader ();
  370.           if (newHeader != NULL) {
  371.  
  372.             // Add the new package to headerMapping...
  373.             // (NOTE: the keys will not contain any "-d" directory prefixes.)
  374.             // printf ("ADDING TO HEADERMAPPING: filename=%s, newHeader=%s\n",
  375.             //          newPackName->chars, newHeader->packageName->chars);
  376.             headerMapping->enter (newPackName, newHeader);
  377.  
  378.             // Add the new package to the end of headerList...
  379.             headerListLast->next = newHeader;
  380.             headerListLast = newHeader;
  381.           }
  382.         }
  383.       }
  384.       uses = uses->next;
  385.     }
  386.  
  387.     // Move to next header on the headerList
  388.     hdr = hdr->next;
  389.   }
  390.  
  391.   // printAllData ();
  392.   // dump ("After parsing...");
  393.  
  394.   // Check for package-uses circularity and re-order all packages...
  395.   if (wantProgress) printf ("Finding a topological-sort order for packages...\n");
  396.   topoProcessAllPackages ();
  397.  
  398.   // Must stop here if errors, since one error is cyclic package-use.  From
  399.   // here on out, we're assuming our super-packages have already been done first.
  400.   if (errorsDetected) {
  401.     terminateCompiler ();
  402.   }
  403.  
  404.   saveSafe = safe;
  405.  
  406.   // Run through all headers and process each in turn...
  407.   for (hdr=headerList; hdr!=NULL; hdr=hdr->next) {
  408.     if (wantProgress) printf ("Processing package \"%s\"...\n", hdr->packageName->chars);
  409.     currentHeader = hdr;
  410.  
  411.     if (currentHeader == mainHeader) {
  412.       safe = saveSafe;
  413.     } else {
  414.       safe = 0;    // Allow unsafe constructs in any header we are using.
  415.     }
  416.  
  417.     // Build the symbol tables...
  418.     if (wantProgress) printf ("  Building symbol tables...\n");
  419.     buildPackageMapping (hdr);
  420.  
  421.     // Topo-process the interfaces...
  422.     if (wantProgress) printf ("  Topologically sorting interfaces...\n");
  423.     topoProcessInterfaces (hdr);
  424.  
  425.     // Topo-process the classes...
  426.     if (wantProgress) printf ("  Topologically sorting classes...\n");
  427.     topoProcessClasses (hdr);
  428.  
  429.     // Bind Types...
  430.     if (wantProgress) printf ("  Binding types...\n");
  431.     bindTypeNames (hdr, NULL);
  432.  
  433.     // Check TypeDef circularity...
  434.     if (wantProgress) printf ("  Checking type def circularity...\n");
  435.     checkTypeDefCircularity (hdr);
  436.  
  437.     // Inherit Class Fields...
  438.     if (wantProgress) printf ("  Inheriting class fields...\n");
  439.     inheritFields (hdr);
  440.  
  441.     // Inherit MethodProtos...
  442.     if (wantProgress) printf ("  Inheriting method prototypes...\n");
  443.     inheritMethodProtos (hdr);
  444.  
  445.     // Inherit messages for interface "extends" hierarchy...
  446.     if (wantProgress) printf ("  Inheriting messages in interfaces...\n");
  447.     inheritMessages (hdr);
  448.  
  449.     // Bind variable names...
  450.     if (wantProgress) printf ("  Binding variable names...\n");
  451.     bindVarNames (hdr, NULL);
  452.  
  453.     // Assign offsets and evaluate expressions...
  454.     if (wantProgress) printf ("  Assigning offsets and evaluating static expressions...\n");
  455.     assignOffsetsAndEvalExprs (hdr);
  456.  
  457.     // The subtype test is operative after this point.
  458.     // testSubType (hdr);
  459.     // break;
  460.  
  461.     // Check class-interface "implements" hierarchy...
  462.     if (wantProgress) printf ("  Checking class/interface implements...\n");
  463.     checkImplements (hdr);
  464.  
  465.     // Check method prototypes...
  466.     if (wantProgress) printf ("  Checking method prototypes...\n");
  467.     checkMethodProtos (hdr);
  468.  
  469.     // Check interface extends...
  470.     if (wantProgress) printf ("  Checking interface extends...\n");
  471.     checkExtends (hdr);
  472.  
  473.     // Check types...
  474.     if (wantProgress) printf ("  Checking types...\n");
  475.     t = checkTypes (hdr);
  476.  
  477.     // Evaluate expressions again; to handle anything introduced by checkTypes...
  478.     if (wantProgress) printf ("  Evaluating static expressions...\n");
  479.     changed = 1;
  480.     while (changed) {
  481.       changed = 0;
  482.       evalExprsIn (hdr);
  483.       // The test called "bizarre" will print this message...
  484.       //   if (changed) {
  485.       //     printf ("LOOKS LIKE WE NEEDED A SECOND PASS!!!\n");
  486.       //   }
  487.     }
  488.  
  489.     // Make sure the recursionCounter is OK...
  490.     if (recursionCounter != 0) {
  491.       printf ("recursionCounter = %d\n", recursionCounter);
  492.       programLogicError ("recursionCounter not incremented and decremented equally");
  493.     }
  494.  
  495.     // Check flow of control...
  496.     if (wantProgress) printf ("  Checking flow of control...\n");
  497.     fallsThru (hdr);
  498.  
  499.     // Assign Dispatch Table Offsets...
  500.     if (wantProgress) printf ("  Assigning Dispatch Table Offsets...\n");
  501.     assignDispatchTableOffsets (hdr);
  502.  
  503.     // Assign offsets to locals and parms in functions and closures...
  504.     //   printf ("  Asigning offsets to local variables and parameters...\n");
  505.     //   assignLocalOffsets (hdr);
  506.  
  507.     // printf ("\n==========  HERE IS THE PACKAGE WE JUST FINISHED  ==========\n");
  508.     // hdr->prettyPrint (4);
  509.     // printf ("\n============================================================\n");
  510.  
  511.   }
  512.  
  513.   safe = saveSafe;
  514.  
  515.   // Make sure the recursionCounter is OK...
  516.   if (recursionCounter != 0) {
  517.     printf ("recursionCounter = %d\n", recursionCounter);
  518.     programLogicError ("recursionCounter not incremented and decremented equally");
  519.   }
  520.  
  521.   // Stop here if errors...
  522.   if (commandOptionAST) {     //       && errorsDetected) {
  523.     printAllData ();
  524.   }
  525.   if (commandOptionP) {     //       && errorsDetected) {
  526.     dump ("After semantic processing...");
  527.   }
  528.   if (errorsDetected) {
  529.     terminateCompiler ();
  530.   }
  531.  
  532.   // Generating IR code...
  533.   if (wantProgress) printf ("  Generating IR code...\n");
  534.   generateIR ();
  535.  
  536.   // Assign offsets to locals and parms in functions and closures...
  537.   if (wantProgress) printf ("  Asigning offsets to local variables and parameters...\n");
  538.   assignLocalOffsets (mainHeader);
  539.  
  540.   // Print the IR code...
  541.   if (wantProgress) printf ("  Writing .s file...\n");
  542.   printIR ();
  543.  
  544.   // Print the full AST in all detail, if requested...
  545.   if (commandOptionAST) {
  546.     printAllData ();
  547.   }
  548.  
  549.   // Pretty-print the AST, if requested...
  550.   if (commandOptionP) {
  551.     dump ("After code generation...");
  552.   }
  553.  
  554.   terminateCompiler ();
  555.  
  556. }
  557.  
  558.  
  559.  
  560. // initializeConstants ()
  561. //
  562. // This routine initializes various constants that will be used during the
  563. // compilation. 
  564. //
  565. void initializeConstants () {
  566.   ArrayType * arrayType;
  567.  
  568.   // The nodes created here will be positioned at "(null):0:"
  569.   token.value.svalue = NULL;
  570.   token.tokenPos = 0;
  571.  
  572.   stringUnaryBang =             lookupAndAdd ("_prefix_!", OPERATOR);
  573.   stringUnaryStar =             lookupAndAdd ("_prefix_*", OPERATOR);
  574.   stringUnaryAmp =              lookupAndAdd ("_prefix_&", OPERATOR);
  575.   stringUnaryMinus =            lookupAndAdd ("_prefix_-", OPERATOR);
  576.  
  577.   stringPlus =                  lookupAndAdd ("+", OPERATOR);
  578.   stringMinus =                 lookupAndAdd ("-", OPERATOR);
  579.   stringStar =                  lookupAndAdd ("*", OPERATOR);
  580.   stringSlash =                 lookupAndAdd ("/", OPERATOR);
  581.   stringPercent =               lookupAndAdd ("%", OPERATOR);
  582.   stringBar =                   lookupAndAdd ("|", OPERATOR);
  583.   stringCaret =                 lookupAndAdd ("^", OPERATOR);
  584.   stringAmp =                   lookupAndAdd ("&", OPERATOR);
  585.   stringBarBar =                lookupAndAdd ("||", OPERATOR);
  586.   stringAmpAmp =                lookupAndAdd ("&&", OPERATOR);
  587.   stringEqualEqual =            lookupAndAdd ("==", OPERATOR);
  588.   stringNotEqual =              lookupAndAdd ("!=", OPERATOR);
  589.   stringLess =                  lookupAndAdd ("<", OPERATOR);
  590.   stringLessEqual =             lookupAndAdd ("<=", OPERATOR);
  591.   stringGreater =               lookupAndAdd (">", OPERATOR);
  592.   stringGreaterEqual =          lookupAndAdd (">=", OPERATOR);
  593.   stringLessLess =              lookupAndAdd ("<<", OPERATOR);
  594.   stringGreaterGreater =        lookupAndAdd (">>", OPERATOR);
  595.   stringGreaterGreaterGreater = lookupAndAdd (">>>", OPERATOR);
  596.  
  597.   stringIntToDouble =           lookupAndAdd ("intToDouble", ID);
  598.   stringDoubleToInt =           lookupAndAdd ("doubleToInt", ID);
  599.   stringIntToChar =             lookupAndAdd ("intToChar", ID);
  600.   stringCharToInt =             lookupAndAdd ("charToInt", ID);
  601.   stringPtrToBool =             lookupAndAdd ("ptrToBool", ID);
  602.   stringPosInf =                lookupAndAdd ("posInf", ID);
  603.   stringNegInf =                lookupAndAdd ("negInf", ID);
  604.   stringNegZero =               lookupAndAdd ("negZero", ID);
  605.   stringIIsZero =               lookupAndAdd ("iIsZero", ID);   // hidden function
  606.   stringINotZero =              lookupAndAdd ("iNotZero", ID);  // hidden function
  607.   stringObject =                lookupAndAdd ("Object", ID);
  608.   stringMain =                  lookupAndAdd ("main", ID);
  609.  
  610.   // Initialize nodes corresponding to basic types...
  611.  
  612.   token.type = CHAR;
  613.   basicCharType = new CharType ();
  614.  
  615.   token.type = INT;
  616.   basicIntType = new IntType ();
  617.  
  618.   token.type = DOUBLE;
  619.   basicDoubleType = new DoubleType ();
  620.  
  621.   token.type = BOOL;
  622.   basicBoolType = new BoolType ();
  623.  
  624.   token.type = VOID;
  625.   basicVoidType = new VoidType ();
  626.  
  627.   token.type = TYPE_OF_NULL;
  628.   basicTypeOfNullType = new TypeOfNullType ();
  629.  
  630.   token.type = ANY_TYPE;
  631.   basicAnyType = new AnyType ();
  632.  
  633.   token.type = ARRAY;                         // array [*] of char
  634.   arrayType = new ArrayType ();
  635.   arrayType->baseType = basicCharType;
  636.   arrayType->sizeOfElements = 1;
  637.   
  638.   token.type = PTR;                           // ptr to array [*] of char
  639.   basicCharArrayPtrType = new PtrType ();
  640.   basicCharArrayPtrType->baseType = arrayType;
  641.  
  642.   token.type = PTR;                           // ptr to void
  643.   basicVoidPtrType = new PtrType ();
  644.   basicVoidPtrType->baseType = basicVoidType;
  645.  
  646.   token.type = PTR;                           // ptr to anyType
  647.   basicAnyPtrType = new PtrType ();
  648.   basicAnyPtrType->baseType = basicAnyType;
  649.  
  650. /*****
  651.   printf ("==========  Basic Type Nodes  ==========\n");
  652.   printf ("basicCharType = ");          pretty (basicCharType);
  653.   printf ("basicIntType = ");           pretty (basicIntType);
  654.   printf ("basicDoubleType = ");        pretty (basicDoubleType);
  655.   printf ("basicBoolType = ");          pretty (basicBoolType);
  656.   printf ("basicVoidType = ");          pretty (basicVoidType);
  657.   printf ("basicTypeOfNullType = ");    pretty (basicTypeOfNullType);
  658.   printf ("basicCharArrayPtrType = ");  pretty (basicCharArrayPtrType);
  659.   printf ("basicVoidPtrType = ");       pretty (basicVoidPtrType);
  660.   printf ("basicAnyType = ");           pretty (basicAnyType);
  661.   printf ("========================================\n");
  662.   error (basicVoidPtrType, "Testing...");
  663. *****/
  664.  
  665.   // Some functions and messages are "primitives".  Examples include "+" and
  666.   // "doubleToInt".  Mark these symbols so that they can be easily tested later.
  667.   stringUnaryBang->primitiveSymbol  = UNARY_BANG;
  668.   stringUnaryStar->primitiveSymbol  = UNARY_STAR;
  669.   stringUnaryAmp->primitiveSymbol   = UNARY_AMP;
  670.   stringUnaryMinus->primitiveSymbol = UNARY_MINUS;
  671.  
  672.   stringPlus->primitiveSymbol = PLUS;
  673.   stringMinus->primitiveSymbol = MINUS;
  674.   stringStar->primitiveSymbol = STAR;
  675.   stringSlash->primitiveSymbol = SLASH;
  676.   stringPercent->primitiveSymbol = PERCENT;
  677.   stringBar->primitiveSymbol = BAR;
  678.   stringCaret->primitiveSymbol = CARET;
  679.   stringAmp->primitiveSymbol = AMP;
  680.   stringBarBar->primitiveSymbol = BAR_BAR;
  681.   stringAmpAmp->primitiveSymbol = AMP_AMP;
  682.   stringEqualEqual->primitiveSymbol = EQUAL_EQUAL;
  683.   stringNotEqual->primitiveSymbol = NOT_EQUAL;
  684.   stringLess->primitiveSymbol = LESS;
  685.   stringLessEqual->primitiveSymbol = LESS_EQUAL;
  686.   stringGreater->primitiveSymbol = GREATER;
  687.   stringGreaterEqual->primitiveSymbol = GREATER_EQUAL;
  688.   stringLessLess->primitiveSymbol = LESS_LESS;
  689.   stringGreaterGreater->primitiveSymbol = GREATER_GREATER;
  690.   stringGreaterGreaterGreater->primitiveSymbol = GREATER_GREATER_GREATER;
  691.   stringIntToDouble->primitiveSymbol = INT_TO_DOUBLE;
  692.   stringDoubleToInt->primitiveSymbol = DOUBLE_TO_INT;
  693.   stringIntToChar->primitiveSymbol = INT_TO_CHAR;
  694.   stringCharToInt->primitiveSymbol = CHAR_TO_INT;
  695.   stringPtrToBool->primitiveSymbol = PTR_TO_BOOL;
  696.   stringPosInf->primitiveSymbol = POS_INF;
  697.   stringNegInf->primitiveSymbol = NEG_INF;
  698.   stringNegZero->primitiveSymbol = NEG_ZERO;
  699.   stringIIsZero->primitiveSymbol = I_IS_ZERO;
  700.   stringINotZero->primitiveSymbol = I_NOT_ZERO;
  701.  
  702.   // Set up some constants...
  703.   constantIntZero = new IntConst ();
  704.   constantIntOne = new IntConst ();
  705.   constantIntOne->ivalue = 1;
  706.   constantIntMinusOne = new IntConst ();
  707.   constantIntMinusOne->ivalue = -1;
  708.   constantFalse = new BoolConst (0);
  709.   constantTrue = new BoolConst (1);
  710.  
  711.  
  712. /*****
  713.   constantDoubleZero = new DoubleExpr ();
  714.   constantDoubleOne = new DoubleExpr ();
  715.   constantDoubleOne->rvalue = 1.0;
  716.   constantCharNull = new CharExpr ();
  717.   constantNull = new NullExpr ();
  718.   stringUninitialized = lookupAndAdd ("<uninitialized string>", ID);
  719.   stringGenericDestructor = lookupAndAdd ("_Generic_Destructor", ID);
  720.   stringThis = lookupAndAdd ("_this", ID);
  721. *****/
  722.  
  723. }
  724.  
  725.  
  726.  
  727. // printAllData ()
  728. //
  729. // This routine prints out all the data structures using printAst().
  730. // in full and gory detail.
  731. //
  732. void printAllData () {
  733.  
  734.   fflush (stdout);
  735.   printf ("\n================  HEADER LIST  ================\n");
  736.   printAst (6, headerList);
  737.   printf ("================================\n");
  738.  
  739.   // printf ("\n================  CODE  ================\n");
  740.   // printAst (6, code);
  741.   // printf ("================================\n");
  742.  
  743. /*****
  744.   printf ("constantIntZero:\n");
  745.   printAst (6, constantIntZero);
  746.   printf ("constantIntOne:\n");
  747.   printAst (6, constantIntOne);
  748.   printf ("constantIntMinusOne:\n");
  749.   printAst (6, constantIntMinusOne);
  750.   printf ("constantDoubleZero:\n");
  751.   printAst (6, constantDoubleZero);
  752.   printf ("constantDoubleOne:\n");
  753.   printAst (6, constantDoubleOne);
  754.   printf ("constantCharNull:\n");
  755.   printAst (6, constantCharNull);
  756.   printf ("constantFalse:\n");
  757.   printAst (6, constantFalse);
  758.   printf ("constantTrue:\n");
  759.   printAst (6, constantTrue);
  760.   printf ("constantNull:\n");
  761.   printAst (6, constantNull);
  762.   printf ("basicTypeInt:\n");
  763.   printAst (6, basicTypeInt);
  764.   printf ("basicTypeDouble:\n");
  765.   printAst (6, basicTypeDouble);
  766.   printf ("basicTypeChar:\n");
  767.   printAst (6, basicTypeChar);
  768.   printf ("basicTypeBool:\n");
  769.   printAst (6, basicTypeBool);
  770.   printf ("basicTypeVoid:\n");
  771.   printAst (6, basicTypeVoid);
  772.   printf ("basicTypeNull:\n");
  773.   printAst (6, basicTypeNull);
  774.   printf ("basicTypeCharPtr:\n");
  775.   printAst (6, basicTypeCharPtr);
  776.   printf ("basicTypeVoidPtr:\n");
  777.   printAst (6, basicTypeVoidPtr);
  778. *****/
  779.  
  780.   fflush (stdout);
  781. }
  782.  
  783.  
  784.  
  785. // dump (message)
  786. //
  787. // This routine prints out various data structures, using "prettyPrinting".
  788. //
  789. void dump (char * message) {
  790.   Header * hdr;
  791.  
  792.   fflush (stdout);
  793.   printf ("\n***************\n");
  794.   printf ("**           **\n");
  795.   printf ("**  DUMPING  **  %s\n", message);
  796.   printf ("**           **\n");
  797.   printf ("***************\n\n");
  798.  
  799.  
  800.   // Print out the headerList...
  801.   hdr = headerList;
  802.   printf ("\n================  HEADER LIST  ================\n");
  803.   while (hdr) {
  804.     hdr->prettyPrint (4);
  805.     // if (hdr->packageMapping) {
  806.     //   hdr->packageMapping->print (4);
  807.     // }
  808.     printf ("================================\n");
  809.     hdr = hdr->next;
  810.   }
  811.  
  812. /*****
  813.   if (code) {
  814.     printf ("\n================  CODE  ================\n");
  815.     code->prettyPrint (4);
  816.     printf ("================================\n");
  817.   }
  818. *****/
  819.  
  820.   // Print out the headerMapping...
  821.   // printf ("\n\n");
  822.   // headerMapping->print (0);
  823.  
  824.   fflush (stdout);
  825.  
  826. }
  827.  
  828.  
  829.  
  830. // testLexer ()
  831. //
  832. // This routine can be used to test the lexer portion of the compiler.
  833. //
  834. void testLexer () {
  835.   while (1) {
  836.     printToken (token);
  837. /*****
  838.     printf ("\t\t\t");
  839.     printToken (token2);
  840.     printf ("\t\t\t\t");
  841.     printToken (token3);
  842.     printf ("\t\t\t\t\t");
  843.     printToken (token4);
  844.     printf ("\t\t\t\t\t\t");
  845.     printToken (token5);
  846. *****/
  847.     if (token.type == EOF) {
  848.       break;
  849.     }
  850.     scan ();
  851.   }
  852. //  printStringTable ();
  853. }
  854.  
  855.  
  856.  
  857. // printToken (token)
  858. //
  859. // This routine prints a token in a form such as...
  860. //      7    ID            abc
  861. //      8    INT           1234
  862. //      9    STRING_CONST  "abc"
  863. //      10   CHAR_CONST    0x61     97      'a'
  864. //      11   WHILE
  865. //
  866. void printToken (Token token) {
  867.   int i;
  868.   printf("%s\t%d\t%d\t%s",
  869.          extractFilename (token),
  870.          extractLineNumber (token),
  871.          extractCharPos (token),
  872.          symbolName (token.type));
  873.   switch (token.type) {
  874.     case ID:
  875.       printf("\t");
  876.       printString (stdout, token.value.svalue);
  877.       break;
  878.     case OPERATOR:
  879.       printf("\t");
  880.       printString (stdout, token.value.svalue);
  881.       break;
  882.     case STRING_CONST:
  883.       printf("\t\"");
  884.       printString (stdout, token.value.svalue);
  885.       printf("\"");
  886.       break;
  887.     case CHAR_CONST:
  888.       i = token.value.ivalue;
  889.       printf("\t%02x\t%d", i, i);
  890.       if ((i >= ' ') && (i <= '~')) {
  891.         printf("\t\'%c\'", i);
  892.       }
  893.       break;
  894.     case INT_CONST:
  895.       printf("\t0x%08x\t%d", token.value.ivalue, token.value.ivalue);
  896.       break;
  897.     case DOUBLE_CONST:
  898.       printf("\t%.16g", token.value.rvalue);
  899.       break;
  900.   }
  901.   printf("\n");
  902. }
  903.  
  904.  
  905.  
  906. // programLogicError (msg)
  907. //
  908. // This routine prints the message and terminates the compiler.
  909. //
  910. void programLogicError (char * msg) {
  911.   fprintf (stderr,
  912. "********************************************************************\n"
  913. "*****\n"
  914. "*****  PROGRAM LOGIC ERROR\n"
  915. "*****\n"
  916. "*****  It appears that this compiler contains a software bug.\n"
  917. "*****  I apologize for the inconvenience it causes you.\n"
  918. "*****\n"
  919. "*****  Error message: \"%s\"\n"
  920. "*****\n"
  921. "********************************************************************\n", msg);
  922.   errorsDetected++;
  923.   terminateCompiler ();
  924. }
  925.  
  926.  
  927.  
  928. // terminateCompiler ()
  929. //
  930. // Print out the number of errors (if any) and terminate of the compiler.  If errors, then
  931. // remove the output file (if any).  If no errors, the close the output file normally.
  932. //
  933. void terminateCompiler () {
  934.  
  935.   // fprintf (stderr,
  936.   //          "Estimated memory usage = %d bytes\n",
  937.   //          ((int) new IntConst)- ((int) memoryStart));
  938.  
  939.   if (errorsDetected == 0) {
  940.     if (outputFileName != NULL) {
  941.       fclose (outputFile);
  942.     }
  943.     // fprintf (stderr, "\n**********  Normal exit  **********\n");
  944.     exit (0);
  945.   } else if (errorsDetected == 1) {
  946.     fprintf (stderr, "\n**********  1 error detected!  **********\n");
  947.   } else {
  948.     fprintf (stderr, "\n**********  %d errors detected!  **********\n",
  949.              errorsDetected);
  950.   }
  951.  
  952.   if (outputFileName != NULL) {
  953.     fclose (outputFile);
  954.     remove (outputFileName);
  955.   }
  956.   exit (1);
  957. }
  958.  
  959.  
  960.  
  961. // fatalError (msg)
  962. //
  963. // This routine is called to print an error message and the current line
  964. // number of the curent token.  It aborts the compiler.
  965. //
  966. void fatalError (char *msg) {
  967.   errorsDetected++;
  968.   doMessage (token, "*****  FATAL ERROR", msg);
  969.   terminateCompiler ();
  970. }
  971.  
  972.  
  973.  
  974. // error (node, msg)
  975. //
  976. // This routine is called to print an error message.  It returns; it
  977. // does not terminate the program after printing.  The "node" parameter
  978. // is used to print additional information about the position of the error.
  979. //
  980. void error (AstNode * node, char * msg) {
  981.   errorsDetected++;
  982.   doMessage (node->tokn, "*****  ERROR", msg);
  983. }
  984.  
  985.  
  986.  
  987. // error2 (node, msg)
  988. //
  989. // This routine is called to print an error message.  It returns; it
  990. // does not terminate the program after printing.  The "node" parameter
  991. // is used to print additional information about the position of the error.
  992. // It differs from "error()" in that it does not print "*****  ERRROR"; it is
  993. // used to print additional info after the initial error message.
  994. //
  995. void error2 (AstNode * node, char * msg) {
  996.   // errorsDetected++;
  997.   doMessage (node->tokn, "            ", msg);
  998. }
  999.  
  1000.  
  1001.  
  1002. // syntaxError (msg)
  1003. //
  1004. // This routine is called to print a syntax error message.
  1005. //
  1006. // This routine returns; it does not terminate the compiler after printing.
  1007. //
  1008. // It uses the current token to print additional information about the
  1009. // position of the error.
  1010. //
  1011. void syntaxError (char * msg) {
  1012.   syntaxErrorWithToken (token, msg);
  1013. }
  1014.  
  1015.  
  1016.  
  1017. // syntaxErrorWithToken (tok, msg)
  1018. //
  1019. // This routine is called to do the work of printing a syntax error message,
  1020. // position on 'tok'.
  1021. //
  1022. void syntaxErrorWithToken (Token tok, char * msg) {
  1023.   // If the last message was on this token, then suppress this message.
  1024.   if (tok.tokenPos != tokenPosOfLastError) {
  1025.     errorsDetected++;
  1026.     doMessage (tok, "*****  SYNTAX ERROR", msg);
  1027.   }
  1028.   tokenPosOfLastError = tok.tokenPos;
  1029. }
  1030.  
  1031.  
  1032.  
  1033. // doMessage (tok, prefix, msg)
  1034. //
  1035. // Print info about the current token and the given "msg".
  1036. //
  1037. void doMessage (Token tok, char * prefix, char * msg) {
  1038.   fprintf (stderr, "%s:%d: %s at ",
  1039.                      extractFilename (tok),
  1040.                      extractLineNumber (tok),
  1041.                      prefix);
  1042.   switch (tok.type) {
  1043.     case ID:
  1044.       fprintf (stderr, "\'");
  1045.       printString (stderr, tok.value.svalue);
  1046.       fprintf (stderr, "\'");
  1047.       break;
  1048.     case STRING_CONST:
  1049.       fprintf (stderr, "\"");
  1050.       printString (stderr, tok.value.svalue);
  1051.       fprintf (stderr, "\"");
  1052.       break;
  1053.     case CHAR_CONST:
  1054.       fprintf (stderr, "\'");
  1055.       printChar (stderr, tok.value.ivalue);
  1056.       fprintf (stderr, "\'");
  1057.       break;
  1058.     case INT_CONST:
  1059.       fprintf (stderr, "\'%d\'", tok.value.ivalue);
  1060.       break;
  1061.     case DOUBLE_CONST:
  1062.       fprintf (stderr, "%.16g", tok.value.rvalue);
  1063.       break;
  1064.     case OPERATOR:
  1065.       fprintf (stderr, "\"");
  1066.       printString (stderr, tok.value.svalue);
  1067.       fprintf (stderr, "\"");
  1068.       break;
  1069.     default:
  1070.       fprintf (stderr, "%s", symbolName (tok.type));
  1071.   }
  1072.   fprintf (stderr, ": %s\n", msg);
  1073.   fflush (stderr);
  1074.   if (errorsDetected >= MAX_NUMBER_OF_ERRORS) {
  1075.     fprintf (stderr, "%s:%d: *****  Too many errors - I'm giving up\n",
  1076.                      extractFilename (tok),
  1077.                      extractLineNumber (tok));
  1078.     terminateCompiler ();
  1079.   }
  1080. }
  1081.  
  1082.  
  1083.  
  1084. // errorWithType (msg, type)
  1085. //
  1086. // This routine is called to print an error message.  It returns; it does not
  1087. // terminate the program unless we've had too many errors.
  1088. //
  1089. // The "type" parameter is printed after the message.  For example, if msg is
  1090. //    "The expected type is"
  1091. // the following might get printed:
  1092. //    test.c:26:         The expected type is: ptr to array [*] of char
  1093. //
  1094. // This routine calls "resolveNamedType" so it prints out the underlying
  1095. // type, getting rid of aliases.
  1096. //
  1097. void errorWithType (char * msg, Type * type) {
  1098.   Token tok;
  1099.   if (type == NULL) {
  1100.     tok.tokenPos = 0;
  1101.   } else {
  1102.     tok = type->tokn;
  1103.   }
  1104.   fprintf (stderr, "%s:%d:              %s: ",
  1105.                      extractFilename (tok),
  1106.                      extractLineNumber (tok),
  1107.                      msg);
  1108.   fpretty (type);
  1109.   fprintf (stderr, "\n");
  1110.   fflush (stderr);
  1111.   // errorsDetected++;
  1112.   // if (errorsDetected >= MAX_NUMBER_OF_ERRORS) {
  1113.   //   fprintf (stderr, "%s:%d: *****  Too many errors - I'm giving up\n",
  1114.   //                    extractFilename (tok),
  1115.   //                    extractLineNumber (tok));
  1116.   //   terminateCompiler ();
  1117.   // }
  1118. }
  1119.  
  1120.  
  1121.  
  1122. // checkTokenSkipping (count)
  1123. //
  1124. // "count" is the number of tokens we just skipped over.  If it exceeds a
  1125. // threshhold, then print a message, using the current token as the position
  1126. // of the message.  Also, watch out for hitting EOF.
  1127. //
  1128. void checkTokenSkipping (int count) {
  1129.   if (count > TOKEN_SKIP_COUNT) {
  1130.     fprintf (stderr, "%s:%d:        Skipping %d tokens...\n",
  1131.                      extractFilename (token),
  1132.                      extractLineNumber (token),
  1133.                      count);
  1134.   }
  1135.   if (token.type == EOF) {
  1136.     fprintf (stderr, "%s:%d: *****  SYNTAX ERROR: Unexpected EOF... aborting\n",
  1137.                      extractFilename (token),
  1138.                      extractLineNumber (token));
  1139.     terminateCompiler ();
  1140.   }
  1141. }
  1142.  
  1143.  
  1144.  
  1145. // processCommandLine (argc, argv)
  1146. //
  1147. // This routine processes the command line options.
  1148. //
  1149. void processCommandLine (int argc, char ** argv) {
  1150.   int argCount;
  1151.   int badArgs = 0;
  1152.   int len;
  1153.   for (argc--, argv++; argc > 0; argc -= argCount, argv += argCount) {
  1154.     argCount = 1;
  1155.     // Scan the -h option
  1156.     if (!strcmp (*argv, "-h")) {
  1157.       printHelp ();
  1158.       exit (1);
  1159.  
  1160.     // Check for the -s option
  1161.     } else if (!strcmp (*argv, "-s")) {
  1162.       commandOptionS = 1;
  1163.  
  1164.     // Check for the -p option
  1165.     } else if (!strcmp (*argv, "-p")) {
  1166.       commandOptionP = 1;
  1167.  
  1168.     // Check for the -ast option
  1169.     } else if (!strcmp (*argv, "-ast")) {
  1170.       commandOptionAST = 1;
  1171.  
  1172.     // Check for the -testLexer option
  1173.     } else if (!strcmp (*argv, "-testLexer")) {
  1174.       commandOptionTestLexer = 1;
  1175.  
  1176.     // Check for the -testParser option
  1177.     } else if (!strcmp (*argv, "-testParser")) {
  1178.       commandOptionTestParser = 1;
  1179.  
  1180.     // Check for the -unsafe option
  1181.     } else if (!strcmp (*argv, "-unsafe")) {
  1182.       safe = 0;
  1183.  
  1184.     // Check for the -o option, which should be followed by a file name
  1185.     } else if (!strcmp (*argv, "-o")) {
  1186.       if (argc <= 1) {
  1187.         fprintf (stderr,
  1188.           "Expecting filename after -o option.  Use -h for help display.\n");
  1189.         badArgs = 1;
  1190.       } else {
  1191.         argCount++;
  1192.         if (outputFileName == NULL) {
  1193.           outputFileName = *(argv+1);
  1194.         } else {
  1195.           fprintf (stderr,
  1196.             "Invalid command line:  Multiple output files.  Use -h for help display.\n");
  1197.           badArgs = 1;
  1198.         }
  1199.       }
  1200.  
  1201.     // Check for the search directory name
  1202.     } else if (!strcmp (*argv, "-d")) {
  1203.       if (argc <= 1) {
  1204.         fprintf (stderr,
  1205.           "Expecting search directory prefix after -d option.  Use -h for help display.\n");
  1206.         badArgs = 1;
  1207.       } else {
  1208.         argCount++;
  1209.         if (commandDirectoryName == NULL) {
  1210.           commandDirectoryName = *(argv+1);
  1211.         } else {
  1212.           fprintf (stderr,
  1213.             "Invalid command line:  Multiple search directories.  Use -h for help display.\n");
  1214.           badArgs = 1;
  1215.         }
  1216.       }
  1217.  
  1218.     // Check for the package file name
  1219.     } else if ((*argv)[0] != '-') {
  1220.       if (commandPackageName == NULL) {
  1221.         commandPackageName = *argv;
  1222.       } else {
  1223.         fprintf (stderr,
  1224.           "Invalid command line:  Multiple package names.  Use -h for help display.\n");
  1225.         badArgs = 1;
  1226.       }
  1227.     } else {
  1228.       fprintf (stderr,
  1229.         "Invalid command line option (%s).  Use -h for help display.\n", *argv);
  1230.       badArgs = 1;
  1231.     }
  1232.   }
  1233.  
  1234.   // If command line problems, then abort now.
  1235.   if (badArgs) {
  1236.     exit (1);
  1237.   }
  1238.  
  1239.   // Figure out the name of the .h header file.
  1240.   if (commandPackageName != NULL) {
  1241.     len = strlen (commandPackageName);
  1242.     headerFileName = (char *) calloc (1, len + 4);
  1243.     strcpy (headerFileName, commandPackageName);
  1244.     headerFileName [len] = '.';
  1245.     headerFileName [len+1] = 'h';
  1246.     headerFileName [len+2] = '\0';
  1247.   }
  1248.  
  1249.   // Figure out the name of the .c code file.
  1250.   if (commandPackageName != NULL) {
  1251.     codeFileName = (char *) calloc (1, len + 4);
  1252.     strcpy (codeFileName, commandPackageName);
  1253.     codeFileName [len] = '.';
  1254.     codeFileName [len+1] = 'c';
  1255.     codeFileName [len+2] = '\0';
  1256.   }
  1257.  
  1258.   // Figure out the name of the .s output file.
  1259.   if (outputFileName == NULL) {
  1260.     if (commandPackageName != NULL) {
  1261.       outputFileName = (char *) calloc (1, len + 4);
  1262.       strcpy (outputFileName, commandPackageName);
  1263.       outputFileName [len] = '.';
  1264.       outputFileName [len+1] = 's';
  1265.       outputFileName [len+2] = '\0';
  1266.     }
  1267.   }
  1268.  
  1269.   // Open the output (.s) file.
  1270.   if (outputFileName == NULL) {
  1271.     outputFile = stdout;
  1272.   } else {
  1273.     outputFile = fopen (outputFileName, "w");
  1274.     if (outputFile == NULL) {
  1275.       fprintf (stderr, "File \"%s\" could not be opened for writing\n", outputFileName);
  1276.       exit (1);
  1277.     }
  1278.   }
  1279.  
  1280. }
  1281.  
  1282.  
  1283.  
  1284. // printHelp ()
  1285. //
  1286. // This routine prints some documentation.  It is invoked whenever
  1287. // the -h option is used on the command line.
  1288. //
  1289. void printHelp () {
  1290.   printf (
  1291. "==============================\n"
  1292. "=====                    =====\n"
  1293. "=====  The KPL Compiler  =====\n"
  1294. "=====                    =====\n"
  1295. "==============================\n"
  1296. "\n"
  1297. "Copyright 200-2006, Harry H. Porter III\n"
  1298. "========================================\n"
  1299. "  Original Author:\n"
  1300. "    06/15/02 - Harry H. Porter III\n"
  1301. "  Modifcations by:\n"
  1302. "    03/15/06 - Harry H. Porter III\n"
  1303. "\n"
  1304. "Command Line Options\n"
  1305. "====================\n"
  1306. "  Command line options may be given in any order.\n"
  1307. "    -h\n"
  1308. "      Print this help info.  All other options are ignored.\n"
  1309. "    packageName\n"
  1310. "      Compile the package with this name.  The input will come from the files\n"
  1311. "      called \"packageName.h\" and \"packageName.c\".  No extension should be\n"
  1312. "      given on the command line.  Only one package may be compiled at once.\n"
  1313. "      The packageName is required.\n"
  1314. "    -d directoryPrefix\n"
  1315. "      When looking for header and code files, the default is to look in the\n"
  1316. "      current directory.  With this option, the current directory is first\n"
  1317. "      searched.  If that fails, then the directoryPrefix is prepended to the\n"
  1318. "      file name and the resulting file name is used.  For example:\n"
  1319. "          kpl myPack -d ~harry/BlitzLib/\n"
  1320. "      will first try to open \"myPack.h\" and, if that fails, will try to open\n"
  1321. "      \"~harry/BlitzLib/myPack.h\".\n"
  1322. "    -unsafe\n"
  1323. "      Allow unsafe language constructs.\n"
  1324. "    -o filename\n"
  1325. "      If there are no errors, an assembly code file will be created.  This \n"
  1326. "      option can be used to give the output file a specific name.  If \n"
  1327. "      missing, the name of the output file will be computed from the name of\n"
  1328. "      the package and appending \".s\".  For example:\n"
  1329. "           myPackage  -->  myPackage.s\n"
  1330. "      COMPILER DEBUGGING: If packageName and output filename are missing,\n"
  1331. "      stdout will be used.\n"
  1332. "    -testLexer\n"
  1333. "      COMPILER DEBUGGING: Scan tokens only, and print tokens out.  Input may\n"
  1334. "      come from stdin.\n"
  1335. "    -testParser\n"
  1336. "      COMPILER DEBUGGING: Parse program only, and print data structures out.\n"
  1337. "      Input may come from stdin.\n"
  1338. "    -s\n"
  1339. "      COMPILER DEBUGGING: Print the symbol table on stdout.\n"
  1340. "    -p\n"
  1341. "      COMPILER DEBUGGING: Pretty-print the AST.\n"
  1342. "    -ast\n"
  1343. "      COMPILER DEBUGGING: Dump the full AST.\n"
  1344.   );
  1345. }
  1346.  
  1347.  
  1348.  
  1349. // checkHostCompatibility ()
  1350. //
  1351. // This routine checks that the host implementation of C++ meets certain
  1352. // requirements.
  1353. //
  1354. // (1) This routine checks that integers are represented using exactly 4
  1355. // bytes.
  1356. //
  1357. // (2) This routine checks that integers are stored in the expected
  1358. // Big or Little Endian order.
  1359. //
  1360. // (3) This routine checks that integer overflow behavior is as expected
  1361. // with two's complement arithmetic.
  1362. //
  1363. // (4) This routine checks that doubles are implemented using 8-bytes in
  1364. // the IEEE standard, with the bytes in correct Big/Little Endian order.
  1365. //
  1366. // (5) This routine checks that the double->int conversion works as
  1367. // expected.  If this is not the case, then truncateToInt() will need to
  1368. // be changed.
  1369. //
  1370. void checkHostCompatibility () {
  1371.   union fourBytes {
  1372.     char chars [4];
  1373.     unsigned int i;
  1374.   } fourBytes;
  1375.   double d;
  1376.   char * p, * q;
  1377.   int i, i1, i2, i3;
  1378.  
  1379.   // Check that ints are in the expected Big/Little Endian order.
  1380.   fourBytes.chars[0] = 0x12;
  1381.   fourBytes.chars[1] = 0x34;
  1382.   fourBytes.chars[2] = 0x56;
  1383.   fourBytes.chars[3] = 0x78;
  1384.   if (SWAP_BYTES(fourBytes.i) != 0x12345678) {
  1385.     fatalError ("There is a big/little endian byte ordering problem.");
  1386.   }
  1387.  
  1388.   // Check that we have at least 4 bytes of precision.
  1389.   i = 0x00000001;
  1390.   i <<= 20;
  1391.   i <<= 10;
  1392.   i >>= 20;
  1393.   i >>= 10;
  1394.   if (i != 0x00000001) {
  1395.     fatalError ("This program only runs on computers with 4 byte integers - 1");
  1396.   }
  1397.  
  1398.   // Check that we have no more than 4 bytes of precision.
  1399.   i = 0x00000001;
  1400.   i <<= 20;
  1401.   i <<= 13;   // Some compilers treat <<33 as a nop!
  1402.   i >>= 20;
  1403.   i >>= 13;
  1404.   if (i != 0x00000000) {
  1405.     fatalError ("This program only runs on computers with 4 byte integers - 2");
  1406.   }
  1407.  
  1408.   // Check that we have the expected overflow behavior for ints.
  1409.   i = -2147483647;
  1410.   i = i - 2;
  1411.   if (i != 2147483647) {
  1412.     fatalError ("This program only runs on computers with 4 byte integers - 3");
  1413.   }
  1414.  
  1415.   // Check that doubles are represented as we expect.
  1416.   d = 123.456e37;
  1417.   p = (char *) &d;
  1418.   q = p;
  1419.   // If doubles are stored in Big Endian byte order....
  1420.   if ((*p++ == '\x48') &&
  1421.       (*p++ == '\x0d') &&
  1422.       (*p++ == '\x06') &&
  1423.       (*p++ == '\x3c') &&
  1424.       (*p++ == '\xdb') &&
  1425.       (*p++ == '\x93') &&
  1426.       (*p++ == '\x27') &&
  1427.       (*p++ == '\xcf')) {
  1428. #ifdef BLITZ_HOST_IS_LITTLE_ENDIAN
  1429.     fatalError ("There is a big/little endian byte ordering problem with doubles - 1.");
  1430. #endif
  1431.  
  1432.   // Else, if doubles are stored in Little Endian byte order...
  1433.   } else if ((*q++ == '\xcf') &&
  1434.              (*q++ == '\x27') &&
  1435.              (*q++ == '\x93') &&
  1436.              (*q++ == '\xdb') &&
  1437.              (*q++ == '\x3c') &&
  1438.              (*q++ == '\x06') &&
  1439.              (*q++ == '\x0d') &&
  1440.              (*q++ == '\x48')) {
  1441. #ifdef BLITZ_HOST_IS_LITTLE_ENDIAN
  1442.  
  1443. #else
  1444.     fatalError ("There is a big/little endian byte ordering problem with doubles - 2.");
  1445. #endif
  1446.  
  1447.   // Else, if doubles are stored in some other way...
  1448.   } else {
  1449.     fatalError ("The host implementation of 'double' is not what I expect.");
  1450.   }
  1451.  
  1452.   // There is variation in the way different hosts handle double->int conversion
  1453.   // when the double is too large to represent as an integer.  When checking
  1454.   // we must do the conversion in two steps, since some compilers perform the
  1455.   // conversion at compile time, and will do the conversion differently than
  1456.   // the host machine.  Truly appalling, isn't it!
  1457.   //   On PPC,   (int) 9e99 is 0x7fffffff
  1458.   //   On PPC,   (int) d    is 0x7fffffff
  1459.   //   On Intel, (int) 9e99 is 0x7fffffff
  1460.   //   On Intel, (int) d    is 0x80000000
  1461.   //
  1462.   i = (int) 9e99;
  1463.   // printf ("(int) 9e99 is 0x%08x\n", i);
  1464.   d = 9e99;
  1465.   i = (int) d;  // Note: ((int) 9e99 == 0 while ((int) d) == 2147483647)!!!
  1466.   // printf ("(int) d is 0x%08x\n", i);
  1467.  
  1468.   // Check that double->int conversion works as expected.
  1469.   d = 4.9;
  1470.   i1 = (int) d;
  1471.   d = -4.9;
  1472.   i2 = (int) d;
  1473.   d = -9e99;
  1474.   i3 = (int) d;
  1475.   if ((i1 !=  4) ||
  1476.       (i2 != -4) ||
  1477.       (i3 != 0x80000000)) {
  1478.     printf ("%d %d %d %d\n", i1, i2, i3);
  1479.     fatalError ("The host implementation of double->int casting is not what I expect.");
  1480.   }
  1481.  
  1482. }
  1483.  
  1484.  
  1485. // appendStrings (char *, char *, char *)
  1486. //
  1487. // Allocate and a new char array and fill it in from the
  1488. // characters in the strings.  Return a pointer to it.
  1489. //
  1490. char * appendStrings (char * str1, char * str2, char * str3) {
  1491.   int len = strlen (str1) + strlen (str2) + strlen (str3);
  1492.   char * newStr, * to, * from ;
  1493.   newStr = (char *) calloc (1, len+1);
  1494.   to = newStr;
  1495.   for (from=str1; *from != 0; to++, from++) {
  1496.     *to = *from;
  1497.   }
  1498.   for (from=str2; *from != 0; to++, from++) {
  1499.     *to = *from;
  1500.   }
  1501.   for (from=str3; *from != 0; to++, from++) {
  1502.     *to = *from;
  1503.   }
  1504.   *to = 0;
  1505.   return newStr;
  1506. }
  1507.  
  1508.  
  1509.  
  1510. // divide (a, b)
  1511. //
  1512. // This routine is passed two integers ("a" and "b").  It divides a by b
  1513. // to get a quotient ("q") and remainder ("r"), such that
  1514. //
  1515. //       a = b*q + r
  1516. //
  1517. // Furthermore, the remainder follows the mathematical definition of the
  1518. // "modulo" operator, namely that the remainder will have the same sign
  1519. // as b and that
  1520. //
  1521. //       0 <= abs(r) < abs(b)
  1522. //
  1523. // Another way to look at this is that the quotient is the real quotient,
  1524. // rounded down to the nearest integer.
  1525. //
  1526. // For example:
  1527. //
  1528. //       a   b     q   r     a =  b *  q +  r     a/b   rounded
  1529. //      ==  ==    ==  ==    =================    ====   =======
  1530. //       7   3     2   1     7 =  3 *  2 +  1     2.3      2
  1531. //      -7   3    -3   2    -7 =  3 * -3 +  2    -2.3     -3
  1532. //       7  -3    -3  -2     7 = -3 * -3 + -2    -2.3     -3
  1533. //      -7  -3     2  -1    -7 = -3 *  2 + -1     2.3      2
  1534. //
  1535. // This routine modifies global variables "qqo" and "rem".  If b=0 it
  1536. // sets q and r to zero and returns immediately.
  1537. //
  1538. // With this definition of "q" and "r", overflow can and will occur in only
  1539. // one situation.  Assuming that we are using 32-bit signed integers, the
  1540. // following inputs cause a problem...
  1541. //      a = -2147483648
  1542. //      b = -1
  1543. // The mathematically correct answer is...
  1544. //      q = +2147483648
  1545. //      r = 0
  1546. // Unfortunately, this value of q is not representable.  The underlying
  1547. // implementation of the C operators / and % will normally fail, and will
  1548. // quietly return the wrong answer...
  1549. //      q = -2147483648
  1550. //      r = 0
  1551. // This routine will simply return these incorrect values.
  1552. //
  1553. // The C language does not define the / and % operators precisely, but
  1554. // only requires that a = b*q + r be true.  This routine is designed to
  1555. // return consistent, "correct" answers, regardless of the underlying
  1556. // implementation of / and %.
  1557. //
  1558. // Typical variations in integer division are...
  1559. //
  1560. // (1) "r" is always non-negative.  0 <= r < abs(b)
  1561. //     "q" will be negative when either a or b (but not both) are negative.
  1562. //         a   b     q   r     a =  b *  q +  r
  1563. //        ==  ==    ==  ==    =================
  1564. //         7   3     2   1     7 =  3 *  2 +  1
  1565. //        -7   3    -3   2    -7 =  3 * -3 +  2
  1566. //         7  -3    -2   1     7 = -3 * -2 +  1
  1567. //        -7  -3     3   2    -7 = -3 *  3 +  2
  1568. //
  1569. // (2) Real division, rounded toward zero.
  1570. //     "q" = a/b, rounded toward zero.
  1571. //     "q" will be negative when either a or b (but not both) are negative.
  1572. //     The sign of "r" will be the same as the sign of "a".
  1573. //         a   b     q   r     a =  b *  q +  r     a/b   rounded
  1574. //        ==  ==    ==  ==    =================    ====   =======
  1575. //         7   3     2   1     7 =  3 *  2 +  1     2.3      2
  1576. //        -7   3    -2  -1    -7 =  3 * -2 + -1    -2.3     -2
  1577. //         7  -3    -2   1     7 = -3 * -2 +  1    -2.3     -2
  1578. //        -7  -3     2  -1    -7 = -3 *  2 + -1     2.3      2
  1579. //
  1580. // (3) Real division, rounded toward negative infinity.
  1581. //     "q" = a/b, rounded toward negative infinity.
  1582. //     This results in "r" being the mathematically correct "modulo".
  1583. //     "q" will be negative when either a or b (but not both) are negative.
  1584. //     "r" will be negative whenever "b" is negative.
  1585. //
  1586. // This routine implements option number (3).  It works assuming that
  1587. // the underlying C implementation uses options (1), (2), or (3).
  1588. //
  1589. // Overflow cannot occur in this routine, assuming 2's complement
  1590. // representation of integers.
  1591. //
  1592. void divide (int a, int b) {
  1593.   if (b==0) {
  1594.     quo = rem = 0;
  1595.     return;
  1596.   }
  1597.   quo = a/b;
  1598.   rem = a%b;
  1599.   if (b>0) {
  1600.     if (rem<0) {
  1601.       quo--;          // Overflow iff q=MIN; but then b=1 and r=0... can't be.
  1602.       rem = rem + b;  // r is neg, b is pos; cannot overflow.
  1603.     }
  1604.   } else {
  1605.     if (rem>0) {
  1606.       quo--;          // Overflow iff q=MIN; but then b=1 and r=0... can't be.
  1607.       rem = rem + b;  // r is pos, b is neg; cannot overflow.
  1608.     }
  1609.   }
  1610. }
  1611.  
  1612.  
  1613.  
  1614. // truncateToInt (double) --> int
  1615. //
  1616. // This routine is passed a double; it returns an int by truncating the arg
  1617. // to the next integal value toward zero.  For example:
  1618. //
  1619. //     4.9 -->  4
  1620. //    -4.9 --> -4
  1621. //    9e99 -->  2,147,483,647
  1622. //   -9e99 --> -2,147,483,648
  1623. //
  1624. int truncateToInt (double d) {
  1625.   return (int) (d);
  1626. }
  1627.  
  1628.