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 / BlitzSrc / main.cc < prev    next >
C/C++ Source or Header  |  2007-09-19  |  51KB  |  1,632 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.     // printf ("=================== Before checkTypes =========================\n");
  474.     // printAst (6, hdr);
  475.     // printf ("===============================================================\n");
  476.  
  477.     // Check types...
  478.     if (wantProgress) printf ("  Checking types...\n");
  479.     t = checkTypes (hdr);
  480.  
  481.     // Evaluate expressions again; to handle anything introduced by checkTypes...
  482.     if (wantProgress) printf ("  Evaluating static expressions...\n");
  483.     changed = 1;
  484.     while (changed) {
  485.       changed = 0;
  486.       evalExprsIn (hdr);
  487.       // The test called "bizarre" will print this message...
  488.       //   if (changed) {
  489.       //     printf ("LOOKS LIKE WE NEEDED A SECOND PASS!!!\n");
  490.       //   }
  491.     }
  492.  
  493.     // Make sure the recursionCounter is OK...
  494.     if (recursionCounter != 0) {
  495.       printf ("recursionCounter = %d\n", recursionCounter);
  496.       programLogicError ("recursionCounter not incremented and decremented equally");
  497.     }
  498.  
  499.     // Check flow of control...
  500.     if (wantProgress) printf ("  Checking flow of control...\n");
  501.     fallsThru (hdr);
  502.  
  503.     // Assign Dispatch Table Offsets...
  504.     if (wantProgress) printf ("  Assigning Dispatch Table Offsets...\n");
  505.     assignDispatchTableOffsets (hdr);
  506.  
  507.     // Assign offsets to locals and parms in functions and closures...
  508.     //   printf ("  Asigning offsets to local variables and parameters...\n");
  509.     //   assignLocalOffsets (hdr);
  510.  
  511.     // printf ("\n==========  HERE IS THE PACKAGE WE JUST FINISHED  ==========\n");
  512.     // hdr->prettyPrint (4);
  513.     // printf ("\n============================================================\n");
  514.  
  515.   }
  516.  
  517.   safe = saveSafe;
  518.  
  519.   // Make sure the recursionCounter is OK...
  520.   if (recursionCounter != 0) {
  521.     printf ("recursionCounter = %d\n", recursionCounter);
  522.     programLogicError ("recursionCounter not incremented and decremented equally");
  523.   }
  524.  
  525.   // Stop here if errors...
  526.   if (commandOptionAST) {     //       && errorsDetected) {
  527.     printAllData ();
  528.   }
  529.   if (commandOptionP) {     //       && errorsDetected) {
  530.     dump ("After semantic processing...");
  531.   }
  532.   if (errorsDetected) {
  533.     terminateCompiler ();
  534.   }
  535.  
  536.   // Generating IR code...
  537.   if (wantProgress) printf ("  Generating IR code...\n");
  538.   generateIR ();
  539.  
  540.   // Assign offsets to locals and parms in functions and closures...
  541.   if (wantProgress) printf ("  Asigning offsets to local variables and parameters...\n");
  542.   assignLocalOffsets (mainHeader);
  543.  
  544.   // Print the IR code...
  545.   if (wantProgress) printf ("  Writing .s file...\n");
  546.   printIR ();
  547.  
  548.   // Print the full AST in all detail, if requested...
  549.   if (commandOptionAST) {
  550.     printAllData ();
  551.   }
  552.  
  553.   // Pretty-print the AST, if requested...
  554.   if (commandOptionP) {
  555.     dump ("After code generation...");
  556.   }
  557.  
  558.   terminateCompiler ();
  559.  
  560. }
  561.  
  562.  
  563.  
  564. // initializeConstants ()
  565. //
  566. // This routine initializes various constants that will be used during the
  567. // compilation. 
  568. //
  569. void initializeConstants () {
  570.   ArrayType * arrayType;
  571.  
  572.   // The nodes created here will be positioned at "(null):0:"
  573.   token.value.svalue = NULL;
  574.   token.tokenPos = 0;
  575.  
  576.   stringUnaryBang =             lookupAndAdd ("_prefix_!", OPERATOR);
  577.   stringUnaryStar =             lookupAndAdd ("_prefix_*", OPERATOR);
  578.   stringUnaryAmp =              lookupAndAdd ("_prefix_&", OPERATOR);
  579.   stringUnaryMinus =            lookupAndAdd ("_prefix_-", OPERATOR);
  580.  
  581.   stringPlus =                  lookupAndAdd ("+", OPERATOR);
  582.   stringMinus =                 lookupAndAdd ("-", OPERATOR);
  583.   stringStar =                  lookupAndAdd ("*", OPERATOR);
  584.   stringSlash =                 lookupAndAdd ("/", OPERATOR);
  585.   stringPercent =               lookupAndAdd ("%", OPERATOR);
  586.   stringBar =                   lookupAndAdd ("|", OPERATOR);
  587.   stringCaret =                 lookupAndAdd ("^", OPERATOR);
  588.   stringAmp =                   lookupAndAdd ("&", OPERATOR);
  589.   stringBarBar =                lookupAndAdd ("||", OPERATOR);
  590.   stringAmpAmp =                lookupAndAdd ("&&", OPERATOR);
  591.   stringEqualEqual =            lookupAndAdd ("==", OPERATOR);
  592.   stringNotEqual =              lookupAndAdd ("!=", OPERATOR);
  593.   stringLess =                  lookupAndAdd ("<", OPERATOR);
  594.   stringLessEqual =             lookupAndAdd ("<=", OPERATOR);
  595.   stringGreater =               lookupAndAdd (">", OPERATOR);
  596.   stringGreaterEqual =          lookupAndAdd (">=", OPERATOR);
  597.   stringLessLess =              lookupAndAdd ("<<", OPERATOR);
  598.   stringGreaterGreater =        lookupAndAdd (">>", OPERATOR);
  599.   stringGreaterGreaterGreater = lookupAndAdd (">>>", OPERATOR);
  600.  
  601.   stringIntToDouble =           lookupAndAdd ("intToDouble", ID);
  602.   stringDoubleToInt =           lookupAndAdd ("doubleToInt", ID);
  603.   stringIntToChar =             lookupAndAdd ("intToChar", ID);
  604.   stringCharToInt =             lookupAndAdd ("charToInt", ID);
  605.   stringPtrToBool =             lookupAndAdd ("ptrToBool", ID);
  606.   stringPosInf =                lookupAndAdd ("posInf", ID);
  607.   stringNegInf =                lookupAndAdd ("negInf", ID);
  608.   stringNegZero =               lookupAndAdd ("negZero", ID);
  609.   stringIIsZero =               lookupAndAdd ("iIsZero", ID);   // hidden function
  610.   stringINotZero =              lookupAndAdd ("iNotZero", ID);  // hidden function
  611.   stringObject =                lookupAndAdd ("Object", ID);
  612.   stringMain =                  lookupAndAdd ("main", ID);
  613.  
  614.   // Initialize nodes corresponding to basic types...
  615.  
  616.   token.type = CHAR;
  617.   basicCharType = new CharType ();
  618.  
  619.   token.type = INT;
  620.   basicIntType = new IntType ();
  621.  
  622.   token.type = DOUBLE;
  623.   basicDoubleType = new DoubleType ();
  624.  
  625.   token.type = BOOL;
  626.   basicBoolType = new BoolType ();
  627.  
  628.   token.type = VOID;
  629.   basicVoidType = new VoidType ();
  630.  
  631.   token.type = TYPE_OF_NULL;
  632.   basicTypeOfNullType = new TypeOfNullType ();
  633.  
  634.   token.type = ANY_TYPE;
  635.   basicAnyType = new AnyType ();
  636.  
  637.   token.type = ARRAY;                         // array [*] of char
  638.   arrayType = new ArrayType ();
  639.   arrayType->baseType = basicCharType;
  640.   arrayType->sizeOfElements = 1;
  641.   
  642.   token.type = PTR;                           // ptr to array [*] of char
  643.   basicCharArrayPtrType = new PtrType ();
  644.   basicCharArrayPtrType->baseType = arrayType;
  645.  
  646.   token.type = PTR;                           // ptr to void
  647.   basicVoidPtrType = new PtrType ();
  648.   basicVoidPtrType->baseType = basicVoidType;
  649.  
  650.   token.type = PTR;                           // ptr to anyType
  651.   basicAnyPtrType = new PtrType ();
  652.   basicAnyPtrType->baseType = basicAnyType;
  653.  
  654. /*****
  655.   printf ("==========  Basic Type Nodes  ==========\n");
  656.   printf ("basicCharType = ");          pretty (basicCharType);
  657.   printf ("basicIntType = ");           pretty (basicIntType);
  658.   printf ("basicDoubleType = ");        pretty (basicDoubleType);
  659.   printf ("basicBoolType = ");          pretty (basicBoolType);
  660.   printf ("basicVoidType = ");          pretty (basicVoidType);
  661.   printf ("basicTypeOfNullType = ");    pretty (basicTypeOfNullType);
  662.   printf ("basicCharArrayPtrType = ");  pretty (basicCharArrayPtrType);
  663.   printf ("basicVoidPtrType = ");       pretty (basicVoidPtrType);
  664.   printf ("basicAnyType = ");           pretty (basicAnyType);
  665.   printf ("========================================\n");
  666.   error (basicVoidPtrType, "Testing...");
  667. *****/
  668.  
  669.   // Some functions and messages are "primitives".  Examples include "+" and
  670.   // "doubleToInt".  Mark these symbols so that they can be easily tested later.
  671.   stringUnaryBang->primitiveSymbol  = UNARY_BANG;
  672.   stringUnaryStar->primitiveSymbol  = UNARY_STAR;
  673.   stringUnaryAmp->primitiveSymbol   = UNARY_AMP;
  674.   stringUnaryMinus->primitiveSymbol = UNARY_MINUS;
  675.  
  676.   stringPlus->primitiveSymbol = PLUS;
  677.   stringMinus->primitiveSymbol = MINUS;
  678.   stringStar->primitiveSymbol = STAR;
  679.   stringSlash->primitiveSymbol = SLASH;
  680.   stringPercent->primitiveSymbol = PERCENT;
  681.   stringBar->primitiveSymbol = BAR;
  682.   stringCaret->primitiveSymbol = CARET;
  683.   stringAmp->primitiveSymbol = AMP;
  684.   stringBarBar->primitiveSymbol = BAR_BAR;
  685.   stringAmpAmp->primitiveSymbol = AMP_AMP;
  686.   stringEqualEqual->primitiveSymbol = EQUAL_EQUAL;
  687.   stringNotEqual->primitiveSymbol = NOT_EQUAL;
  688.   stringLess->primitiveSymbol = LESS;
  689.   stringLessEqual->primitiveSymbol = LESS_EQUAL;
  690.   stringGreater->primitiveSymbol = GREATER;
  691.   stringGreaterEqual->primitiveSymbol = GREATER_EQUAL;
  692.   stringLessLess->primitiveSymbol = LESS_LESS;
  693.   stringGreaterGreater->primitiveSymbol = GREATER_GREATER;
  694.   stringGreaterGreaterGreater->primitiveSymbol = GREATER_GREATER_GREATER;
  695.   stringIntToDouble->primitiveSymbol = INT_TO_DOUBLE;
  696.   stringDoubleToInt->primitiveSymbol = DOUBLE_TO_INT;
  697.   stringIntToChar->primitiveSymbol = INT_TO_CHAR;
  698.   stringCharToInt->primitiveSymbol = CHAR_TO_INT;
  699.   stringPtrToBool->primitiveSymbol = PTR_TO_BOOL;
  700.   stringPosInf->primitiveSymbol = POS_INF;
  701.   stringNegInf->primitiveSymbol = NEG_INF;
  702.   stringNegZero->primitiveSymbol = NEG_ZERO;
  703.   stringIIsZero->primitiveSymbol = I_IS_ZERO;
  704.   stringINotZero->primitiveSymbol = I_NOT_ZERO;
  705.  
  706.   // Set up some constants...
  707.   constantIntZero = new IntConst ();
  708.   constantIntOne = new IntConst ();
  709.   constantIntOne->ivalue = 1;
  710.   constantIntMinusOne = new IntConst ();
  711.   constantIntMinusOne->ivalue = -1;
  712.   constantFalse = new BoolConst (0);
  713.   constantTrue = new BoolConst (1);
  714.  
  715.  
  716. /*****
  717.   constantDoubleZero = new DoubleExpr ();
  718.   constantDoubleOne = new DoubleExpr ();
  719.   constantDoubleOne->rvalue = 1.0;
  720.   constantCharNull = new CharExpr ();
  721.   constantNull = new NullExpr ();
  722.   stringUninitialized = lookupAndAdd ("<uninitialized string>", ID);
  723.   stringGenericDestructor = lookupAndAdd ("_Generic_Destructor", ID);
  724.   stringThis = lookupAndAdd ("_this", ID);
  725. *****/
  726.  
  727. }
  728.  
  729.  
  730.  
  731. // printAllData ()
  732. //
  733. // This routine prints out all the data structures using printAst().
  734. // in full and gory detail.
  735. //
  736. void printAllData () {
  737.  
  738.   fflush (stdout);
  739.   printf ("\n================  HEADER LIST  ================\n");
  740.   printAst (6, headerList);
  741.   printf ("================================\n");
  742.  
  743.   // printf ("\n================  CODE  ================\n");
  744.   // printAst (6, code);
  745.   // printf ("================================\n");
  746.  
  747. /*****
  748.   printf ("constantIntZero:\n");
  749.   printAst (6, constantIntZero);
  750.   printf ("constantIntOne:\n");
  751.   printAst (6, constantIntOne);
  752.   printf ("constantIntMinusOne:\n");
  753.   printAst (6, constantIntMinusOne);
  754.   printf ("constantDoubleZero:\n");
  755.   printAst (6, constantDoubleZero);
  756.   printf ("constantDoubleOne:\n");
  757.   printAst (6, constantDoubleOne);
  758.   printf ("constantCharNull:\n");
  759.   printAst (6, constantCharNull);
  760.   printf ("constantFalse:\n");
  761.   printAst (6, constantFalse);
  762.   printf ("constantTrue:\n");
  763.   printAst (6, constantTrue);
  764.   printf ("constantNull:\n");
  765.   printAst (6, constantNull);
  766.   printf ("basicTypeInt:\n");
  767.   printAst (6, basicTypeInt);
  768.   printf ("basicTypeDouble:\n");
  769.   printAst (6, basicTypeDouble);
  770.   printf ("basicTypeChar:\n");
  771.   printAst (6, basicTypeChar);
  772.   printf ("basicTypeBool:\n");
  773.   printAst (6, basicTypeBool);
  774.   printf ("basicTypeVoid:\n");
  775.   printAst (6, basicTypeVoid);
  776.   printf ("basicTypeNull:\n");
  777.   printAst (6, basicTypeNull);
  778.   printf ("basicTypeCharPtr:\n");
  779.   printAst (6, basicTypeCharPtr);
  780.   printf ("basicTypeVoidPtr:\n");
  781.   printAst (6, basicTypeVoidPtr);
  782. *****/
  783.  
  784.   fflush (stdout);
  785. }
  786.  
  787.  
  788.  
  789. // dump (message)
  790. //
  791. // This routine prints out various data structures, using "prettyPrinting".
  792. //
  793. void dump (char * message) {
  794.   Header * hdr;
  795.  
  796.   fflush (stdout);
  797.   printf ("\n***************\n");
  798.   printf ("**           **\n");
  799.   printf ("**  DUMPING  **  %s\n", message);
  800.   printf ("**           **\n");
  801.   printf ("***************\n\n");
  802.  
  803.  
  804.   // Print out the headerList...
  805.   hdr = headerList;
  806.   printf ("\n================  HEADER LIST  ================\n");
  807.   while (hdr) {
  808.     hdr->prettyPrint (4);
  809.     // if (hdr->packageMapping) {
  810.     //   hdr->packageMapping->print (4);
  811.     // }
  812.     printf ("================================\n");
  813.     hdr = hdr->next;
  814.   }
  815.  
  816. /*****
  817.   if (code) {
  818.     printf ("\n================  CODE  ================\n");
  819.     code->prettyPrint (4);
  820.     printf ("================================\n");
  821.   }
  822. *****/
  823.  
  824.   // Print out the headerMapping...
  825.   // printf ("\n\n");
  826.   // headerMapping->print (0);
  827.  
  828.   fflush (stdout);
  829.  
  830. }
  831.  
  832.  
  833.  
  834. // testLexer ()
  835. //
  836. // This routine can be used to test the lexer portion of the compiler.
  837. //
  838. void testLexer () {
  839.   while (1) {
  840.     printToken (token);
  841. /*****
  842.     printf ("\t\t\t");
  843.     printToken (token2);
  844.     printf ("\t\t\t\t");
  845.     printToken (token3);
  846.     printf ("\t\t\t\t\t");
  847.     printToken (token4);
  848.     printf ("\t\t\t\t\t\t");
  849.     printToken (token5);
  850. *****/
  851.     if (token.type == EOF) {
  852.       break;
  853.     }
  854.     scan ();
  855.   }
  856. //  printStringTable ();
  857. }
  858.  
  859.  
  860.  
  861. // printToken (token)
  862. //
  863. // This routine prints a token in a form such as...
  864. //      7    ID            abc
  865. //      8    INT           1234
  866. //      9    STRING_CONST  "abc"
  867. //      10   CHAR_CONST    0x61     97      'a'
  868. //      11   WHILE
  869. //
  870. void printToken (Token token) {
  871.   int i;
  872.   printf("%s\t%d\t%d\t%s",
  873.          extractFilename (token),
  874.          extractLineNumber (token),
  875.          extractCharPos (token),
  876.          symbolName (token.type));
  877.   switch (token.type) {
  878.     case ID:
  879.       printf("\t");
  880.       printString (stdout, token.value.svalue);
  881.       break;
  882.     case OPERATOR:
  883.       printf("\t");
  884.       printString (stdout, token.value.svalue);
  885.       break;
  886.     case STRING_CONST:
  887.       printf("\t\"");
  888.       printString (stdout, token.value.svalue);
  889.       printf("\"");
  890.       break;
  891.     case CHAR_CONST:
  892.       i = token.value.ivalue;
  893.       printf("\t%02x\t%d", i, i);
  894.       if ((i >= ' ') && (i <= '~')) {
  895.         printf("\t\'%c\'", i);
  896.       }
  897.       break;
  898.     case INT_CONST:
  899.       printf("\t0x%08x\t%d", token.value.ivalue, token.value.ivalue);
  900.       break;
  901.     case DOUBLE_CONST:
  902.       printf("\t%.16g", token.value.rvalue);
  903.       break;
  904.   }
  905.   printf("\n");
  906. }
  907.  
  908.  
  909.  
  910. // programLogicError (msg)
  911. //
  912. // This routine prints the message and terminates the compiler.
  913. //
  914. void programLogicError (char * msg) {
  915.   fprintf (stderr,
  916. "********************************************************************\n"
  917. "*****\n"
  918. "*****  PROGRAM LOGIC ERROR\n"
  919. "*****\n"
  920. "*****  It appears that this compiler contains a software bug.\n"
  921. "*****  I apologize for the inconvenience it causes you.\n"
  922. "*****\n"
  923. "*****  Error message: \"%s\"\n"
  924. "*****\n"
  925. "********************************************************************\n", msg);
  926.   errorsDetected++;
  927.   terminateCompiler ();
  928. }
  929.  
  930.  
  931.  
  932. // terminateCompiler ()
  933. //
  934. // Print out the number of errors (if any) and terminate of the compiler.  If errors, then
  935. // remove the output file (if any).  If no errors, the close the output file normally.
  936. //
  937. void terminateCompiler () {
  938.  
  939.   // fprintf (stderr,
  940.   //          "Estimated memory usage = %d bytes\n",
  941.   //          ((int) new IntConst)- ((int) memoryStart));
  942.  
  943.   if (errorsDetected == 0) {
  944.     if (outputFileName != NULL) {
  945.       fclose (outputFile);
  946.     }
  947.     // fprintf (stderr, "\n**********  Normal exit  **********\n");
  948.     exit (0);
  949.   } else if (errorsDetected == 1) {
  950.     fprintf (stderr, "\n**********  1 error detected!  **********\n");
  951.   } else {
  952.     fprintf (stderr, "\n**********  %d errors detected!  **********\n",
  953.              errorsDetected);
  954.   }
  955.  
  956.   if (outputFileName != NULL) {
  957.     fclose (outputFile);
  958.     remove (outputFileName);
  959.   }
  960.   exit (1);
  961. }
  962.  
  963.  
  964.  
  965. // fatalError (msg)
  966. //
  967. // This routine is called to print an error message and the current line
  968. // number of the curent token.  It aborts the compiler.
  969. //
  970. void fatalError (char *msg) {
  971.   errorsDetected++;
  972.   doMessage (token, "*****  FATAL ERROR", msg);
  973.   terminateCompiler ();
  974. }
  975.  
  976.  
  977.  
  978. // error (node, msg)
  979. //
  980. // This routine is called to print an error message.  It returns; it
  981. // does not terminate the program after printing.  The "node" parameter
  982. // is used to print additional information about the position of the error.
  983. //
  984. void error (AstNode * node, char * msg) {
  985.   errorsDetected++;
  986.   doMessage (node->tokn, "*****  ERROR", msg);
  987. }
  988.  
  989.  
  990.  
  991. // error2 (node, msg)
  992. //
  993. // This routine is called to print an error message.  It returns; it
  994. // does not terminate the program after printing.  The "node" parameter
  995. // is used to print additional information about the position of the error.
  996. // It differs from "error()" in that it does not print "*****  ERRROR"; it is
  997. // used to print additional info after the initial error message.
  998. //
  999. void error2 (AstNode * node, char * msg) {
  1000.   // errorsDetected++;
  1001.   doMessage (node->tokn, "            ", msg);
  1002. }
  1003.  
  1004.  
  1005.  
  1006. // syntaxError (msg)
  1007. //
  1008. // This routine is called to print a syntax error message.
  1009. //
  1010. // This routine returns; it does not terminate the compiler after printing.
  1011. //
  1012. // It uses the current token to print additional information about the
  1013. // position of the error.
  1014. //
  1015. void syntaxError (char * msg) {
  1016.   syntaxErrorWithToken (token, msg);
  1017. }
  1018.  
  1019.  
  1020.  
  1021. // syntaxErrorWithToken (tok, msg)
  1022. //
  1023. // This routine is called to do the work of printing a syntax error message,
  1024. // position on 'tok'.
  1025. //
  1026. void syntaxErrorWithToken (Token tok, char * msg) {
  1027.   // If the last message was on this token, then suppress this message.
  1028.   if (tok.tokenPos != tokenPosOfLastError) {
  1029.     errorsDetected++;
  1030.     doMessage (tok, "*****  SYNTAX ERROR", msg);
  1031.   }
  1032.   tokenPosOfLastError = tok.tokenPos;
  1033. }
  1034.  
  1035.  
  1036.  
  1037. // doMessage (tok, prefix, msg)
  1038. //
  1039. // Print info about the current token and the given "msg".
  1040. //
  1041. void doMessage (Token tok, char * prefix, char * msg) {
  1042.   fprintf (stderr, "%s:%d: %s at ",
  1043.                      extractFilename (tok),
  1044.                      extractLineNumber (tok),
  1045.                      prefix);
  1046.   switch (tok.type) {
  1047.     case ID:
  1048.       fprintf (stderr, "\'");
  1049.       printString (stderr, tok.value.svalue);
  1050.       fprintf (stderr, "\'");
  1051.       break;
  1052.     case STRING_CONST:
  1053.       fprintf (stderr, "\"");
  1054.       printString (stderr, tok.value.svalue);
  1055.       fprintf (stderr, "\"");
  1056.       break;
  1057.     case CHAR_CONST:
  1058.       fprintf (stderr, "\'");
  1059.       printChar (stderr, tok.value.ivalue);
  1060.       fprintf (stderr, "\'");
  1061.       break;
  1062.     case INT_CONST:
  1063.       fprintf (stderr, "\'%d\'", tok.value.ivalue);
  1064.       break;
  1065.     case DOUBLE_CONST:
  1066.       fprintf (stderr, "%.16g", tok.value.rvalue);
  1067.       break;
  1068.     case OPERATOR:
  1069.       fprintf (stderr, "\"");
  1070.       printString (stderr, tok.value.svalue);
  1071.       fprintf (stderr, "\"");
  1072.       break;
  1073.     default:
  1074.       fprintf (stderr, "%s", symbolName (tok.type));
  1075.   }
  1076.   fprintf (stderr, ": %s\n", msg);
  1077.   fflush (stderr);
  1078.   if (errorsDetected >= MAX_NUMBER_OF_ERRORS) {
  1079.     fprintf (stderr, "%s:%d: *****  Too many errors - I'm giving up\n",
  1080.                      extractFilename (tok),
  1081.                      extractLineNumber (tok));
  1082.     terminateCompiler ();
  1083.   }
  1084. }
  1085.  
  1086.  
  1087.  
  1088. // errorWithType (msg, type)
  1089. //
  1090. // This routine is called to print an error message.  It returns; it does not
  1091. // terminate the program unless we've had too many errors.
  1092. //
  1093. // The "type" parameter is printed after the message.  For example, if msg is
  1094. //    "The expected type is"
  1095. // the following might get printed:
  1096. //    test.c:26:         The expected type is: ptr to array [*] of char
  1097. //
  1098. // This routine calls "resolveNamedType" so it prints out the underlying
  1099. // type, getting rid of aliases.
  1100. //
  1101. void errorWithType (char * msg, Type * type) {
  1102.   Token tok;
  1103.   if (type == NULL) {
  1104.     tok.tokenPos = 0;
  1105.   } else {
  1106.     tok = type->tokn;
  1107.   }
  1108.   fprintf (stderr, "%s:%d:              %s: ",
  1109.                      extractFilename (tok),
  1110.                      extractLineNumber (tok),
  1111.                      msg);
  1112.   fpretty (type);
  1113.   fprintf (stderr, "\n");
  1114.   fflush (stderr);
  1115.   // errorsDetected++;
  1116.   // if (errorsDetected >= MAX_NUMBER_OF_ERRORS) {
  1117.   //   fprintf (stderr, "%s:%d: *****  Too many errors - I'm giving up\n",
  1118.   //                    extractFilename (tok),
  1119.   //                    extractLineNumber (tok));
  1120.   //   terminateCompiler ();
  1121.   // }
  1122. }
  1123.  
  1124.  
  1125.  
  1126. // checkTokenSkipping (count)
  1127. //
  1128. // "count" is the number of tokens we just skipped over.  If it exceeds a
  1129. // threshhold, then print a message, using the current token as the position
  1130. // of the message.  Also, watch out for hitting EOF.
  1131. //
  1132. void checkTokenSkipping (int count) {
  1133.   if (count > TOKEN_SKIP_COUNT) {
  1134.     fprintf (stderr, "%s:%d:        Skipping %d tokens...\n",
  1135.                      extractFilename (token),
  1136.                      extractLineNumber (token),
  1137.                      count);
  1138.   }
  1139.   if (token.type == EOF) {
  1140.     fprintf (stderr, "%s:%d: *****  SYNTAX ERROR: Unexpected EOF... aborting\n",
  1141.                      extractFilename (token),
  1142.                      extractLineNumber (token));
  1143.     terminateCompiler ();
  1144.   }
  1145. }
  1146.  
  1147.  
  1148.  
  1149. // processCommandLine (argc, argv)
  1150. //
  1151. // This routine processes the command line options.
  1152. //
  1153. void processCommandLine (int argc, char ** argv) {
  1154.   int argCount;
  1155.   int badArgs = 0;
  1156.   int len;
  1157.   for (argc--, argv++; argc > 0; argc -= argCount, argv += argCount) {
  1158.     argCount = 1;
  1159.     // Scan the -h option
  1160.     if (!strcmp (*argv, "-h")) {
  1161.       printHelp ();
  1162.       exit (1);
  1163.  
  1164.     // Check for the -s option
  1165.     } else if (!strcmp (*argv, "-s")) {
  1166.       commandOptionS = 1;
  1167.  
  1168.     // Check for the -p option
  1169.     } else if (!strcmp (*argv, "-p")) {
  1170.       commandOptionP = 1;
  1171.  
  1172.     // Check for the -ast option
  1173.     } else if (!strcmp (*argv, "-ast")) {
  1174.       commandOptionAST = 1;
  1175.  
  1176.     // Check for the -testLexer option
  1177.     } else if (!strcmp (*argv, "-testLexer")) {
  1178.       commandOptionTestLexer = 1;
  1179.  
  1180.     // Check for the -testParser option
  1181.     } else if (!strcmp (*argv, "-testParser")) {
  1182.       commandOptionTestParser = 1;
  1183.  
  1184.     // Check for the -unsafe option
  1185.     } else if (!strcmp (*argv, "-unsafe")) {
  1186.       safe = 0;
  1187.  
  1188.     // Check for the -o option, which should be followed by a file name
  1189.     } else if (!strcmp (*argv, "-o")) {
  1190.       if (argc <= 1) {
  1191.         fprintf (stderr,
  1192.           "Expecting filename after -o option.  Use -h for help display.\n");
  1193.         badArgs = 1;
  1194.       } else {
  1195.         argCount++;
  1196.         if (outputFileName == NULL) {
  1197.           outputFileName = *(argv+1);
  1198.         } else {
  1199.           fprintf (stderr,
  1200.             "Invalid command line:  Multiple output files.  Use -h for help display.\n");
  1201.           badArgs = 1;
  1202.         }
  1203.       }
  1204.  
  1205.     // Check for the search directory name
  1206.     } else if (!strcmp (*argv, "-d")) {
  1207.       if (argc <= 1) {
  1208.         fprintf (stderr,
  1209.           "Expecting search directory prefix after -d option.  Use -h for help display.\n");
  1210.         badArgs = 1;
  1211.       } else {
  1212.         argCount++;
  1213.         if (commandDirectoryName == NULL) {
  1214.           commandDirectoryName = *(argv+1);
  1215.         } else {
  1216.           fprintf (stderr,
  1217.             "Invalid command line:  Multiple search directories.  Use -h for help display.\n");
  1218.           badArgs = 1;
  1219.         }
  1220.       }
  1221.  
  1222.     // Check for the package file name
  1223.     } else if ((*argv)[0] != '-') {
  1224.       if (commandPackageName == NULL) {
  1225.         commandPackageName = *argv;
  1226.       } else {
  1227.         fprintf (stderr,
  1228.           "Invalid command line:  Multiple package names.  Use -h for help display.\n");
  1229.         badArgs = 1;
  1230.       }
  1231.     } else {
  1232.       fprintf (stderr,
  1233.         "Invalid command line option (%s).  Use -h for help display.\n", *argv);
  1234.       badArgs = 1;
  1235.     }
  1236.   }
  1237.  
  1238.   // If command line problems, then abort now.
  1239.   if (badArgs) {
  1240.     exit (1);
  1241.   }
  1242.  
  1243.   // Figure out the name of the .h header file.
  1244.   if (commandPackageName != NULL) {
  1245.     len = strlen (commandPackageName);
  1246.     headerFileName = (char *) calloc (1, len + 4);
  1247.     strcpy (headerFileName, commandPackageName);
  1248.     headerFileName [len] = '.';
  1249.     headerFileName [len+1] = 'h';
  1250.     headerFileName [len+2] = '\0';
  1251.   }
  1252.  
  1253.   // Figure out the name of the .c code file.
  1254.   if (commandPackageName != NULL) {
  1255.     codeFileName = (char *) calloc (1, len + 4);
  1256.     strcpy (codeFileName, commandPackageName);
  1257.     codeFileName [len] = '.';
  1258.     codeFileName [len+1] = 'c';
  1259.     codeFileName [len+2] = '\0';
  1260.   }
  1261.  
  1262.   // Figure out the name of the .s output file.
  1263.   if (outputFileName == NULL) {
  1264.     if (commandPackageName != NULL) {
  1265.       outputFileName = (char *) calloc (1, len + 4);
  1266.       strcpy (outputFileName, commandPackageName);
  1267.       outputFileName [len] = '.';
  1268.       outputFileName [len+1] = 's';
  1269.       outputFileName [len+2] = '\0';
  1270.     }
  1271.   }
  1272.  
  1273.   // Open the output (.s) file.
  1274.   if (outputFileName == NULL) {
  1275.     outputFile = stdout;
  1276.   } else {
  1277.     outputFile = fopen (outputFileName, "w");
  1278.     if (outputFile == NULL) {
  1279.       fprintf (stderr, "File \"%s\" could not be opened for writing\n", outputFileName);
  1280.       exit (1);
  1281.     }
  1282.   }
  1283.  
  1284. }
  1285.  
  1286.  
  1287.  
  1288. // printHelp ()
  1289. //
  1290. // This routine prints some documentation.  It is invoked whenever
  1291. // the -h option is used on the command line.
  1292. //
  1293. void printHelp () {
  1294.   printf (
  1295. "==============================\n"
  1296. "=====                    =====\n"
  1297. "=====  The KPL Compiler  =====\n"
  1298. "=====                    =====\n"
  1299. "==============================\n"
  1300. "\n"
  1301. "Copyright 2002-2007, Harry H. Porter III\n"
  1302. "========================================\n"
  1303. "  Original Author:\n"
  1304. "    06/15/02 - Harry H. Porter III\n"
  1305. "  Modifcations by:\n"
  1306. "    03/15/06 - Harry H. Porter III\n"
  1307. "\n"
  1308. "Command Line Options\n"
  1309. "====================\n"
  1310. "  Command line options may be given in any order.\n"
  1311. "    -h\n"
  1312. "      Print this help info.  All other options are ignored.\n"
  1313. "    packageName\n"
  1314. "      Compile the package with this name.  The input will come from the files\n"
  1315. "      called \"packageName.h\" and \"packageName.c\".  No extension should be\n"
  1316. "      given on the command line.  Only one package may be compiled at once.\n"
  1317. "      The packageName is required.\n"
  1318. "    -d directoryPrefix\n"
  1319. "      When looking for header and code files, the default is to look in the\n"
  1320. "      current directory.  With this option, the current directory is first\n"
  1321. "      searched.  If that fails, then the directoryPrefix is prepended to the\n"
  1322. "      file name and the resulting file name is used.  For example:\n"
  1323. "          kpl myPack -d ~harry/BlitzLib/\n"
  1324. "      will first try to open \"myPack.h\" and, if that fails, will try to open\n"
  1325. "      \"~harry/BlitzLib/myPack.h\".\n"
  1326. "    -unsafe\n"
  1327. "      Allow unsafe language constructs.\n"
  1328. "    -o filename\n"
  1329. "      If there are no errors, an assembly code file will be created.  This \n"
  1330. "      option can be used to give the output file a specific name.  If \n"
  1331. "      missing, the name of the output file will be computed from the name of\n"
  1332. "      the package and appending \".s\".  For example:\n"
  1333. "           myPackage  -->  myPackage.s\n"
  1334. "      COMPILER DEBUGGING: If packageName and output filename are missing,\n"
  1335. "      stdout will be used.\n"
  1336. "    -testLexer\n"
  1337. "      COMPILER DEBUGGING: Scan tokens only, and print tokens out.  Input may\n"
  1338. "      come from stdin.\n"
  1339. "    -testParser\n"
  1340. "      COMPILER DEBUGGING: Parse program only, and print data structures out.\n"
  1341. "      Input may come from stdin.\n"
  1342. "    -s\n"
  1343. "      COMPILER DEBUGGING: Print the symbol table on stdout.\n"
  1344. "    -p\n"
  1345. "      COMPILER DEBUGGING: Pretty-print the AST.\n"
  1346. "    -ast\n"
  1347. "      COMPILER DEBUGGING: Dump the full AST.\n"
  1348.   );
  1349. }
  1350.  
  1351.  
  1352.  
  1353. // checkHostCompatibility ()
  1354. //
  1355. // This routine checks that the host implementation of C++ meets certain
  1356. // requirements.
  1357. //
  1358. // (1) This routine checks that integers are represented using exactly 4
  1359. // bytes.
  1360. //
  1361. // (2) This routine checks that integers are stored in the expected
  1362. // Big or Little Endian order.
  1363. //
  1364. // (3) This routine checks that integer overflow behavior is as expected
  1365. // with two's complement arithmetic.
  1366. //
  1367. // (4) This routine checks that doubles are implemented using 8-bytes in
  1368. // the IEEE standard, with the bytes in correct Big/Little Endian order.
  1369. //
  1370. // (5) This routine checks that the double->int conversion works as
  1371. // expected.  If this is not the case, then truncateToInt() will need to
  1372. // be changed.
  1373. //
  1374. void checkHostCompatibility () {
  1375.   union fourBytes {
  1376.     char chars [4];
  1377.     unsigned int i;
  1378.   } fourBytes;
  1379.   double d;
  1380.   char * p, * q;
  1381.   int i, i1, i2, i3;
  1382.  
  1383.   // Check that ints are in the expected Big/Little Endian order.
  1384.   fourBytes.chars[0] = 0x12;
  1385.   fourBytes.chars[1] = 0x34;
  1386.   fourBytes.chars[2] = 0x56;
  1387.   fourBytes.chars[3] = 0x78;
  1388.   if (SWAP_BYTES(fourBytes.i) != 0x12345678) {
  1389.     fatalError ("There is a big/little endian byte ordering problem.");
  1390.   }
  1391.  
  1392.   // Check that we have at least 4 bytes of precision.
  1393.   i = 0x00000001;
  1394.   i <<= 20;
  1395.   i <<= 10;
  1396.   i >>= 20;
  1397.   i >>= 10;
  1398.   if (i != 0x00000001) {
  1399.     fatalError ("This program only runs on computers with 4 byte integers - 1");
  1400.   }
  1401.  
  1402.   // Check that we have no more than 4 bytes of precision.
  1403.   i = 0x00000001;
  1404.   i <<= 20;
  1405.   i <<= 13;   // Some compilers treat <<33 as a nop!
  1406.   i >>= 20;
  1407.   i >>= 13;
  1408.   if (i != 0x00000000) {
  1409.     fatalError ("This program only runs on computers with 4 byte integers - 2");
  1410.   }
  1411.  
  1412.   // Check that we have the expected overflow behavior for ints.
  1413.   i = -2147483647;
  1414.   i = i - 2;
  1415.   if (i != 2147483647) {
  1416.     fatalError ("This program only runs on computers with 4 byte integers - 3");
  1417.   }
  1418.  
  1419.   // Check that doubles are represented as we expect.
  1420.   d = 123.456e37;
  1421.   p = (char *) &d;
  1422.   q = p;
  1423.   // If doubles are stored in Big Endian byte order....
  1424.   if ((*p++ == '\x48') &&
  1425.       (*p++ == '\x0d') &&
  1426.       (*p++ == '\x06') &&
  1427.       (*p++ == '\x3c') &&
  1428.       (*p++ == '\xdb') &&
  1429.       (*p++ == '\x93') &&
  1430.       (*p++ == '\x27') &&
  1431.       (*p++ == '\xcf')) {
  1432. #ifdef BLITZ_HOST_IS_LITTLE_ENDIAN
  1433.     fatalError ("There is a big/little endian byte ordering problem with doubles - 1.");
  1434. #endif
  1435.  
  1436.   // Else, if doubles are stored in Little Endian byte order...
  1437.   } else if ((*q++ == '\xcf') &&
  1438.              (*q++ == '\x27') &&
  1439.              (*q++ == '\x93') &&
  1440.              (*q++ == '\xdb') &&
  1441.              (*q++ == '\x3c') &&
  1442.              (*q++ == '\x06') &&
  1443.              (*q++ == '\x0d') &&
  1444.              (*q++ == '\x48')) {
  1445. #ifdef BLITZ_HOST_IS_LITTLE_ENDIAN
  1446.  
  1447. #else
  1448.     fatalError ("There is a big/little endian byte ordering problem with doubles - 2.");
  1449. #endif
  1450.  
  1451.   // Else, if doubles are stored in some other way...
  1452.   } else {
  1453.     fatalError ("The host implementation of 'double' is not what I expect.");
  1454.   }
  1455.  
  1456.   // There is variation in the way different hosts handle double->int conversion
  1457.   // when the double is too large to represent as an integer.  When checking
  1458.   // we must do the conversion in two steps, since some compilers perform the
  1459.   // conversion at compile time, and will do the conversion differently than
  1460.   // the host machine.  Truly appalling, isn't it!
  1461.   //   On PPC,   (int) 9e99 is 0x7fffffff
  1462.   //   On PPC,   (int) d    is 0x7fffffff
  1463.   //   On Intel, (int) 9e99 is 0x7fffffff
  1464.   //   On Intel, (int) d    is 0x80000000
  1465.   //
  1466.   i = (int) 9e99;
  1467.   // printf ("(int) 9e99 is 0x%08x\n", i);
  1468.   d = 9e99;
  1469.   i = (int) d;  // Note: ((int) 9e99 == 0 while ((int) d) == 2147483647)!!!
  1470.   // printf ("(int) d is 0x%08x\n", i);
  1471.  
  1472.   // Check that double->int conversion works as expected.
  1473.   d = 4.9;
  1474.   i1 = (int) d;
  1475.   d = -4.9;
  1476.   i2 = (int) d;
  1477.   d = -9e99;
  1478.   i3 = (int) d;
  1479.   if ((i1 !=  4) ||
  1480.       (i2 != -4) ||
  1481.       (i3 != 0x80000000)) {
  1482.     printf ("%d %d %d %d\n", i1, i2, i3);
  1483.     fatalError ("The host implementation of double->int casting is not what I expect.");
  1484.   }
  1485.  
  1486. }
  1487.  
  1488.  
  1489. // appendStrings (char *, char *, char *)
  1490. //
  1491. // Allocate and a new char array and fill it in from the
  1492. // characters in the strings.  Return a pointer to it.
  1493. //
  1494. char * appendStrings (char * str1, char * str2, char * str3) {
  1495.   int len = strlen (str1) + strlen (str2) + strlen (str3);
  1496.   char * newStr, * to, * from ;
  1497.   newStr = (char *) calloc (1, len+1);
  1498.   to = newStr;
  1499.   for (from=str1; *from != 0; to++, from++) {
  1500.     *to = *from;
  1501.   }
  1502.   for (from=str2; *from != 0; to++, from++) {
  1503.     *to = *from;
  1504.   }
  1505.   for (from=str3; *from != 0; to++, from++) {
  1506.     *to = *from;
  1507.   }
  1508.   *to = 0;
  1509.   return newStr;
  1510. }
  1511.  
  1512.  
  1513.  
  1514. // divide (a, b)
  1515. //
  1516. // This routine is passed two integers ("a" and "b").  It divides a by b
  1517. // to get a quotient ("q") and remainder ("r"), such that
  1518. //
  1519. //       a = b*q + r
  1520. //
  1521. // Furthermore, the remainder follows the mathematical definition of the
  1522. // "modulo" operator, namely that the remainder will have the same sign
  1523. // as b and that
  1524. //
  1525. //       0 <= abs(r) < abs(b)
  1526. //
  1527. // Another way to look at this is that the quotient is the real quotient,
  1528. // rounded down to the nearest integer.
  1529. //
  1530. // For example:
  1531. //
  1532. //       a   b     q   r     a =  b *  q +  r     a/b   rounded
  1533. //      ==  ==    ==  ==    =================    ====   =======
  1534. //       7   3     2   1     7 =  3 *  2 +  1     2.3      2
  1535. //      -7   3    -3   2    -7 =  3 * -3 +  2    -2.3     -3
  1536. //       7  -3    -3  -2     7 = -3 * -3 + -2    -2.3     -3
  1537. //      -7  -3     2  -1    -7 = -3 *  2 + -1     2.3      2
  1538. //
  1539. // This routine modifies global variables "qqo" and "rem".  If b=0 it
  1540. // sets q and r to zero and returns immediately.
  1541. //
  1542. // With this definition of "q" and "r", overflow can and will occur in only
  1543. // one situation.  Assuming that we are using 32-bit signed integers, the
  1544. // following inputs cause a problem...
  1545. //      a = -2147483648
  1546. //      b = -1
  1547. // The mathematically correct answer is...
  1548. //      q = +2147483648
  1549. //      r = 0
  1550. // Unfortunately, this value of q is not representable.  The underlying
  1551. // implementation of the C operators / and % will normally fail, and will
  1552. // quietly return the wrong answer...
  1553. //      q = -2147483648
  1554. //      r = 0
  1555. // This routine will simply return these incorrect values.
  1556. //
  1557. // The C language does not define the / and % operators precisely, but
  1558. // only requires that a = b*q + r be true.  This routine is designed to
  1559. // return consistent, "correct" answers, regardless of the underlying
  1560. // implementation of / and %.
  1561. //
  1562. // Typical variations in integer division are...
  1563. //
  1564. // (1) "r" is always non-negative.  0 <= r < abs(b)
  1565. //     "q" will be negative when either a or b (but not both) are negative.
  1566. //         a   b     q   r     a =  b *  q +  r
  1567. //        ==  ==    ==  ==    =================
  1568. //         7   3     2   1     7 =  3 *  2 +  1
  1569. //        -7   3    -3   2    -7 =  3 * -3 +  2
  1570. //         7  -3    -2   1     7 = -3 * -2 +  1
  1571. //        -7  -3     3   2    -7 = -3 *  3 +  2
  1572. //
  1573. // (2) Real division, rounded toward zero.
  1574. //     "q" = a/b, rounded toward zero.
  1575. //     "q" will be negative when either a or b (but not both) are negative.
  1576. //     The sign of "r" will be the same as the sign of "a".
  1577. //         a   b     q   r     a =  b *  q +  r     a/b   rounded
  1578. //        ==  ==    ==  ==    =================    ====   =======
  1579. //         7   3     2   1     7 =  3 *  2 +  1     2.3      2
  1580. //        -7   3    -2  -1    -7 =  3 * -2 + -1    -2.3     -2
  1581. //         7  -3    -2   1     7 = -3 * -2 +  1    -2.3     -2
  1582. //        -7  -3     2  -1    -7 = -3 *  2 + -1     2.3      2
  1583. //
  1584. // (3) Real division, rounded toward negative infinity.
  1585. //     "q" = a/b, rounded toward negative infinity.
  1586. //     This results in "r" being the mathematically correct "modulo".
  1587. //     "q" will be negative when either a or b (but not both) are negative.
  1588. //     "r" will be negative whenever "b" is negative.
  1589. //
  1590. // This routine implements option number (3).  It works assuming that
  1591. // the underlying C implementation uses options (1), (2), or (3).
  1592. //
  1593. // Overflow cannot occur in this routine, assuming 2's complement
  1594. // representation of integers.
  1595. //
  1596. void divide (int a, int b) {
  1597.   if (b==0) {
  1598.     quo = rem = 0;
  1599.     return;
  1600.   }
  1601.   quo = a/b;
  1602.   rem = a%b;
  1603.   if (b>0) {
  1604.     if (rem<0) {
  1605.       quo--;          // Overflow iff q=MIN; but then b=1 and r=0... can't be.
  1606.       rem = rem + b;  // r is neg, b is pos; cannot overflow.
  1607.     }
  1608.   } else {
  1609.     if (rem>0) {
  1610.       quo--;          // Overflow iff q=MIN; but then b=1 and r=0... can't be.
  1611.       rem = rem + b;  // r is pos, b is neg; cannot overflow.
  1612.     }
  1613.   }
  1614. }
  1615.  
  1616.  
  1617.  
  1618. // truncateToInt (double) --> int
  1619. //
  1620. // This routine is passed a double; it returns an int by truncating the arg
  1621. // to the next integal value toward zero.  For example:
  1622. //
  1623. //     4.9 -->  4
  1624. //    -4.9 --> -4
  1625. //    9e99 -->  2,147,483,647
  1626. //   -9e99 --> -2,147,483,648
  1627. //
  1628. int truncateToInt (double d) {
  1629.   return (int) (d);
  1630. }
  1631.  
  1632.