home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 June / MacFormat 25.iso / Shareware City / Developers / OutOfPhase1.1 Source / OutOfPhase Folder / CompilerRoot.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-27  |  28.3 KB  |  857 lines  |  [TEXT/KAHL]

  1. /* CompilerRoot.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    Out Of Phase:  Digital Music Synthesis on General Purpose Computers    */
  5. /*    Copyright (C) 1994  Thomas R. Lawrence                                 */
  6. /*                                                                           */
  7. /*    This program is free software; you can redistribute it and/or modify   */
  8. /*    it under the terms of the GNU General Public License as published by   */
  9. /*    the Free Software Foundation; either version 2 of the License, or      */
  10. /*    (at your option) any later version.                                    */
  11. /*                                                                           */
  12. /*    This program is distributed in the hope that it will be useful,        */
  13. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  14. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
  15. /*    GNU General Public License for more details.                           */
  16. /*                                                                           */
  17. /*    You should have received a copy of the GNU General Public License      */
  18. /*    along with this program; if not, write to the Free Software            */
  19. /*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
  20. /*                                                                           */
  21. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  22. /*                                                                           */
  23. /*****************************************************************************/
  24.  
  25. #include "MiscInfo.h"
  26. #include "Audit.h"
  27. #include "Debug.h"
  28. #include "Definitions.h"
  29.  
  30. #include "CompilerRoot.h"
  31. #include "Memory.h"
  32. #include "CompilerScanner.h"
  33. #include "TrashTracker.h"
  34. #include "CompilerParser.h"
  35. #include "SymbolTable.h"
  36. #include "SymbolTableEntry.h"
  37. #include "ASTExpression.h"
  38. #include "PromotableTypeCheck.h"
  39. #include "SymbolList.h"
  40. #include "CodeCenter.h"
  41. #include "FunctionCode.h"
  42. #include "PeepholeOptimizer.h"
  43. #include "DataMunging.h"
  44. #include "ASTExpressionList.h"
  45.  
  46.  
  47. #define OPAREN "("
  48. #define CPAREN ")"
  49. #define OBRACKET "["
  50. #define CBRACKET "]"
  51.  
  52.  
  53.  
  54.  
  55. /* auxilliary routine for loading keywords */
  56. static void                LoadKeywordsIntoScanner(ScannerRec* Scanner)
  57.     {
  58.         CheckPtrExistence(Scanner);
  59.         AddKeywordToScanner(Scanner,"func",eKeywordFunc);
  60.         AddKeywordToScanner(Scanner,"proto",eKeywordProto);
  61.         AddKeywordToScanner(Scanner,"void",eKeywordVoid);
  62.         AddKeywordToScanner(Scanner,"bool",eKeywordBool);
  63.         AddKeywordToScanner(Scanner,"int",eKeywordInt);
  64.         AddKeywordToScanner(Scanner,"single",eKeywordSingle);
  65.         AddKeywordToScanner(Scanner,"double",eKeywordDouble);
  66.         AddKeywordToScanner(Scanner,"fixed",eKeywordFixed);
  67.         AddKeywordToScanner(Scanner,"boolarray",eKeywordBoolarray);
  68.         AddKeywordToScanner(Scanner,"intarray",eKeywordIntarray);
  69.         AddKeywordToScanner(Scanner,"singlearray",eKeywordSinglearray);
  70.         AddKeywordToScanner(Scanner,"doublearray",eKeywordDoublearray);
  71.         AddKeywordToScanner(Scanner,"fixedarray",eKeywordFixedarray);
  72.         AddKeywordToScanner(Scanner,"var",eKeywordVar);
  73.         AddKeywordToScanner(Scanner,"if",eKeywordIf);
  74.         AddKeywordToScanner(Scanner,"while",eKeywordWhile);
  75.         AddKeywordToScanner(Scanner,"do",eKeywordDo);
  76.         AddKeywordToScanner(Scanner,"until",eKeywordUntil);
  77.         AddKeywordToScanner(Scanner,"set",eKeywordSet);
  78.         AddKeywordToScanner(Scanner,"resize",eKeywordResize);
  79.         AddKeywordToScanner(Scanner,"to",eKeywordTo);
  80.         AddKeywordToScanner(Scanner,"error",eKeywordError);
  81.         AddKeywordToScanner(Scanner,"resumable",eKeywordResumable);
  82.         AddKeywordToScanner(Scanner,"not",eKeywordNot);
  83.         AddKeywordToScanner(Scanner,"sin",eKeywordSin);
  84.         AddKeywordToScanner(Scanner,"cos",eKeywordCos);
  85.         AddKeywordToScanner(Scanner,"tan",eKeywordTan);
  86.         AddKeywordToScanner(Scanner,"asin",eKeywordAsin);
  87.         AddKeywordToScanner(Scanner,"acos",eKeywordAcos);
  88.         AddKeywordToScanner(Scanner,"atan",eKeywordAtan);
  89.         AddKeywordToScanner(Scanner,"ln",eKeywordLn);
  90.         AddKeywordToScanner(Scanner,"exp",eKeywordExp);
  91.         AddKeywordToScanner(Scanner,"sqr",eKeywordSqr);
  92.         AddKeywordToScanner(Scanner,"sqrt",eKeywordSqrt);
  93.         AddKeywordToScanner(Scanner,"abs",eKeywordAbs);
  94.         AddKeywordToScanner(Scanner,"neg",eKeywordNeg);
  95.         AddKeywordToScanner(Scanner,"sign",eKeywordSign);
  96.         AddKeywordToScanner(Scanner,"length",eKeywordLength);
  97.         AddKeywordToScanner(Scanner,"pi",eKeywordPi);
  98.         AddKeywordToScanner(Scanner,"true",eKeywordTrue);
  99.         AddKeywordToScanner(Scanner,"false",eKeywordFalse);
  100.         AddKeywordToScanner(Scanner,"then",eKeywordThen);
  101.         AddKeywordToScanner(Scanner,"else",eKeywordElse);
  102.         AddKeywordToScanner(Scanner,"elseif",eKeywordElseif);
  103.         AddKeywordToScanner(Scanner,"and",eKeywordAnd);
  104.         AddKeywordToScanner(Scanner,"or",eKeywordOr);
  105.         AddKeywordToScanner(Scanner,"xor",eKeywordXor);
  106.         AddKeywordToScanner(Scanner,"div",eKeywordDiv);
  107.         AddKeywordToScanner(Scanner,"mod",eKeywordMod);
  108.         AddKeywordToScanner(Scanner,"getsampleleft",eKeywordGetsampleleft);
  109.         AddKeywordToScanner(Scanner,"getsampleright",eKeywordGetsampleright);
  110.         AddKeywordToScanner(Scanner,"getsample",eKeywordGetsample);
  111.         AddKeywordToScanner(Scanner,"getwavenumframes",eKeywordGetwavenumframes);
  112.         AddKeywordToScanner(Scanner,"getwavenumtables",eKeywordGetwavenumtables);
  113.         AddKeywordToScanner(Scanner,"getwavedata",eKeywordGetwavedata);
  114.         AddKeywordToScanner(Scanner,"print",eKeywordPrint);
  115.     }
  116.  
  117.  
  118.  
  119.  
  120. /* compile a module.  a module is a text block with a series of function definitions. */
  121. /* if compilation succeeds, the functions are added to the CodeCenter object. */
  122. /* the text data is NOT altered. */
  123. CompileErrors            CompileModule(long* ErrorLineNumber, char* TextData, void* Signature,
  124.                                         struct CodeCenterRec* CodeCenter)
  125.     {
  126.         TrashTrackRec*    TheTrashCan;
  127.         ScannerRec*            TheScanner;
  128.         MyBoolean                LoopFlag;
  129.         SymbolTableRec*    TheSymbolTable;
  130.         CompileErrors        FinalErrorThing;
  131.  
  132.         EXECUTE(*ErrorLineNumber = 0x81818181;)
  133.         CheckPtrExistence(TextData);
  134.         CheckPtrExistence(CodeCenter);
  135.         FinalErrorThing = eCompileNoError;
  136.  
  137.         TheTrashCan = NewTrashTracker();
  138.         if (TheTrashCan == NIL)
  139.             {
  140.              NoMemoryPoint1:
  141.                 if (FinalErrorThing != eCompileNoError)
  142.                     {
  143.                         /* since we're aborting, dump any functions we've already created */
  144.                         FlushModulesCompiledFunctions(CodeCenter,Signature);
  145.                     }
  146.                 *ErrorLineNumber = 1;
  147.                 return eCompileOutOfMemory;
  148.             }
  149.  
  150.         TheScanner = NewScanner(TheTrashCan,TextData);
  151.         if (TheScanner == NIL)
  152.             {
  153.              NoMemoryPoint2:
  154.                 DisposeTrashTracker(TheTrashCan);
  155.                 goto NoMemoryPoint1;
  156.             }
  157.         LoadKeywordsIntoScanner(TheScanner);
  158.  
  159.         TheSymbolTable = NewSymbolTable(TheTrashCan);
  160.         if (TheSymbolTable == NIL)
  161.             {
  162.                 goto NoMemoryPoint2;
  163.             }
  164.  
  165.         /* loop until there are no more things to parse */
  166.         LoopFlag = True;
  167.         while (LoopFlag)
  168.             {
  169.                 TokenRec*                Token;
  170.                 long                        InitialLineNumberOfForm;
  171.  
  172.                 Token = GetNextToken(TheScanner);
  173.                 if (Token == NIL)
  174.                     {
  175.                         goto NoMemoryPoint2;
  176.                     }
  177.                 InitialLineNumberOfForm = GetCurrentLineNumber(TheScanner);
  178.                 if (GetTokenType(Token) == eTokenEndOfInput)
  179.                     {
  180.                         /* no more functions to parse, so stop */
  181.                         LoopFlag = False;
  182.                     }
  183.                  else
  184.                     {
  185.                         CompileErrors                Error;
  186.                         SymbolRec*                    SymbolTableEntryForForm;
  187.                         ASTExpressionRec*        FunctionBodyRecord;
  188.  
  189.                         /* parse the function */
  190.                         UngetToken(TheScanner,Token);
  191.                         Error = ParseForm(&SymbolTableEntryForForm,&FunctionBodyRecord,
  192.                             TheScanner,TheSymbolTable,TheTrashCan,ErrorLineNumber);
  193.                         if (Error != eCompileNoError)
  194.                             {
  195.                                 ERROR(*ErrorLineNumber == 0x81818181,PRERR(AllowResume,
  196.                                     "CompileModule:  error line number not set properly"));
  197.                                 FinalErrorThing = Error;
  198.                                 goto ExitErrorPoint;
  199.                             }
  200.                         /* SymbolTableEntryForForm will be the symbol table entry that */
  201.                         /* was added to the symbol table.  FunctionBodyRecord is either */
  202.                         /* an expression for a function or NIL if it was a prototype */
  203.  
  204.                         /* if no error occurred, then generate code */
  205.                         if (FunctionBodyRecord != NIL)
  206.                             {
  207.                                 DataTypes                        ResultingType;
  208.                                 SymbolListRec*            FormalArgumentListScan;
  209.                                 long                                ArgumentIndex;
  210.                                 PcodeRec*                        TheFunctionCode;
  211.                                 long                                StackDepth;
  212.                                 FuncCodeRec*                TheWholeFunctionThing;
  213.                                 long                                ReturnValueLocation;
  214.  
  215.                                 /* only generate code for real functions */
  216.  
  217.                                 /* step 0:  make sure it hasn't been created yet */
  218.                                 if (CodeCenterHaveThisFunction(CodeCenter,GetSymbolName(
  219.                                     SymbolTableEntryForForm),PtrSize(GetSymbolName(
  220.                                     SymbolTableEntryForForm))))
  221.                                     {
  222.                                         *ErrorLineNumber = GetCurrentLineNumber(TheScanner);
  223.                                         FinalErrorThing = eCompileMultiplyDeclaredFunction;
  224.                                         goto ExitErrorPoint;
  225.                                     }
  226.  
  227.                                 /* step 1:  do type checking */
  228.                                 Error = TypeCheckExpression(&ResultingType,FunctionBodyRecord,
  229.                                     ErrorLineNumber,TheTrashCan);
  230.                                 if (Error != eCompileNoError)
  231.                                     {
  232.                                         ERROR(*ErrorLineNumber == 0x81818181,PRERR(AllowResume,
  233.                                             "CompileModule:  error line number not set properly"));
  234.                                         FinalErrorThing = Error;
  235.                                         goto ExitErrorPoint;
  236.                                     }
  237.                                 /* check to see that resulting type matches declared type */
  238.                                 if (!CanRightBeMadeToMatchLeft(GetSymbolFunctionReturnType(
  239.                                     SymbolTableEntryForForm),ResultingType))
  240.                                     {
  241.                                         *ErrorLineNumber = InitialLineNumberOfForm;
  242.                                         FinalErrorThing = eCompileTypeMismatch;
  243.                                         goto ExitErrorPoint;
  244.                                     }
  245.                                 /* if it has to be promoted, then promote it */
  246.                                 if (MustRightBePromotedToLeft(GetSymbolFunctionReturnType(
  247.                                     SymbolTableEntryForForm),ResultingType))
  248.                                     {
  249.                                         ASTExpressionRec*        ReplacementExpr;
  250.  
  251.                                         /* insert promotion operator above expression */
  252.                                         ReplacementExpr = PromoteTheExpression(ResultingType,
  253.                                             GetSymbolFunctionReturnType(SymbolTableEntryForForm),
  254.                                             FunctionBodyRecord,InitialLineNumberOfForm,TheTrashCan);
  255.                                         if (ReplacementExpr == NIL)
  256.                                             {
  257.                                                 *ErrorLineNumber = InitialLineNumberOfForm;
  258.                                                 FinalErrorThing = eCompileOutOfMemory;
  259.                                                 goto ExitErrorPoint;
  260.                                             }
  261.                                         FunctionBodyRecord = ReplacementExpr;
  262.                                         /* sanity check */
  263.                                         Error = TypeCheckExpression(&ResultingType,FunctionBodyRecord,
  264.                                             ErrorLineNumber,TheTrashCan);
  265.                                         ERROR((Error != eCompileNoError),PRERR(ForceAbort,
  266.                                             "CompileModule:  type promotion caused failure"));
  267.                                         ERROR(ResultingType != GetSymbolFunctionReturnType(
  268.                                             SymbolTableEntryForForm),PRERR(ForceAbort,"CompileModule:  "
  269.                                             "after type promotion, types are no longer the same"));
  270.                                     }
  271.  
  272.                                 /* step 2:  do code generation */
  273.                                 /* calling conventions:  */
  274.                                 /*  - leave a space for the return value */
  275.                                 /*  - push the arguments */
  276.                                 /*  - jsr pushes the return address */
  277.                                 /* thus, upon entry, Stack[0] will be the return address */
  278.                                 /* and Stack[-1] will be the rightmost argument */
  279.                                 StackDepth = 1;
  280.                                 ReturnValueLocation = StackDepth; /* remember return value location */
  281.                                 ArgumentIndex = 0;
  282.                                 FormalArgumentListScan = GetSymbolFunctionArgList(SymbolTableEntryForForm);
  283.                                 while (FormalArgumentListScan != NIL)
  284.                                     {
  285.                                         SymbolRec*                    TheFormalArg;
  286.  
  287.                                         TheFormalArg = GetFirstFromSymbolList(FormalArgumentListScan);
  288.                                         StackDepth += 1; /* allocate first */
  289.                                         SetSymbolVariableStackLocation(TheFormalArg,StackDepth); /* remember */
  290.                                         ArgumentIndex += 1;
  291.                                         FormalArgumentListScan = GetRestListFromSymbolList(
  292.                                             FormalArgumentListScan);
  293.                                     }
  294.                                 /* reserve return address spot */
  295.                                 StackDepth += 1;
  296.                                 /* allocate the function code */
  297.                                 TheFunctionCode = NewPcode();
  298.                                 if (TheFunctionCode == NIL)
  299.                                     {
  300.                                         goto NoMemoryPoint2;
  301.                                     }
  302.                                 if (!CodeGenExpression(TheFunctionCode,&StackDepth,FunctionBodyRecord))
  303.                                     {
  304.                                      NoMemoryPoint3:
  305.                                         DisposePcode(TheFunctionCode);
  306.                                         goto NoMemoryPoint2;
  307.                                     }
  308.                                 /* 3 extra words for retval, retaddr, and resultofexpr */
  309.                                 ERROR(StackDepth != ArgumentIndex + 1 + 1 + 1,PRERR(ForceAbort,
  310.                                     "CompileModule:  stack depth error after evaluating function"));
  311.                                 /* move the result to the return slot */
  312.                                 switch (GetExpressionsResultantType(FunctionBodyRecord))
  313.                                     {
  314.                                         default:
  315.                                             EXECUTE(PRERR(ForceAbort,"CompileModule:  unknown type"));
  316.                                             break;
  317.                                         case eBoolean:
  318.                                         case eInteger:
  319.                                         case eFixed:
  320.                                             if (!AddPcodeInstruction(TheFunctionCode,
  321.                                                 epStoreIntegerOnStack,NIL))
  322.                                                 {
  323.                                                     goto NoMemoryPoint3;
  324.                                                 }
  325.                                             break;
  326.                                         case eFloat:
  327.                                             if (!AddPcodeInstruction(TheFunctionCode,
  328.                                                 epStoreFloatOnStack,NIL))
  329.                                                 {
  330.                                                     goto NoMemoryPoint3;
  331.                                                 }
  332.                                             break;
  333.                                         case eDouble:
  334.                                             if (!AddPcodeInstruction(TheFunctionCode,
  335.                                                 epStoreDoubleOnStack,NIL))
  336.                                                 {
  337.                                                     goto NoMemoryPoint3;
  338.                                                 }
  339.                                             break;
  340.                                         case eArrayOfBoolean:
  341.                                         case eArrayOfInteger:
  342.                                         case eArrayOfFloat:
  343.                                         case eArrayOfDouble:
  344.                                         case eArrayOfFixed:
  345.                                             if (!AddPcodeInstruction(TheFunctionCode,
  346.                                                 epStoreArrayOnStack,NIL))
  347.                                                 {
  348.                                                     goto NoMemoryPoint3;
  349.                                                 }
  350.                                             break;
  351.                                     }
  352.                                 /* where to put it?  well, if there are no arguments, then */
  353.                                 /* Stack[0] = the value; Stack[-1] = return address, and */
  354.                                 /* Stack[-2] = the return value */
  355.                                 if (!AddPcodeOperandInteger(TheFunctionCode,
  356.                                     ReturnValueLocation - StackDepth))
  357.                                     {
  358.                                         goto NoMemoryPoint3;
  359.                                     }
  360.                                 /* now pop the result */
  361.                                 if (!AddPcodeInstruction(TheFunctionCode,epStackPop,NIL))
  362.                                     {
  363.                                         goto NoMemoryPoint3;
  364.                                     }
  365.                                 StackDepth -= 1;
  366.                                 /* now, drop all of the parameters from under return address */
  367.                                 if (ArgumentIndex > 0)
  368.                                     {
  369.                                         if (!AddPcodeInstruction(TheFunctionCode,epStackDeallocateUnder,NIL))
  370.                                             {
  371.                                                 goto NoMemoryPoint3;
  372.                                             }
  373.                                         if (!AddPcodeOperandInteger(TheFunctionCode,ArgumentIndex))
  374.                                             {
  375.                                                 goto NoMemoryPoint3;
  376.                                             }
  377.                                         StackDepth -= ArgumentIndex;
  378.                                     }
  379.                                 /* now put the return instruction */
  380.                                 if (!AddPcodeInstruction(TheFunctionCode,epReturnFromSubroutine,NIL))
  381.                                     {
  382.                                         goto NoMemoryPoint3;
  383.                                     }
  384.                                 StackDepth -= 1;
  385.                                 ERROR(StackDepth != 1,PRERR(ForceAbort,
  386.                                     "CompileModule:  stack depth is wrong at end of function"));
  387.  
  388.                                 /* step 2.5:  optimize the code */
  389.                                 OptimizePcode(TheFunctionCode);
  390.  
  391.                                 /* step 3:  create the function and save it away */
  392.                                 TheWholeFunctionThing = NewFunction(GetSymbolName(
  393.                                     SymbolTableEntryForForm),PtrSize(GetSymbolName(
  394.                                     SymbolTableEntryForForm)),GetSymbolFunctionArgList(
  395.                                     SymbolTableEntryForForm),TheFunctionCode,
  396.                                     GetSymbolFunctionReturnType(SymbolTableEntryForForm));
  397.                                 if (TheWholeFunctionThing == NIL)
  398.                                     {
  399.                                         goto NoMemoryPoint3;
  400.                                     }
  401.                                 /* add it to the code center */
  402.                                 if (!AddFunctionToCodeCenter(CodeCenter,TheWholeFunctionThing,Signature))
  403.                                     {
  404.                                      NoMemoryPoint4:
  405.                                         DisposeFunction(TheWholeFunctionThing);
  406.                                         goto NoMemoryPoint3;
  407.                                     }
  408.  
  409.                                 /* wow, all done!  on to the next one */
  410.                             }
  411.                     }
  412.             }
  413.  
  414.      ExitErrorPoint:
  415.         /* clean up the mess */
  416.         DisposeTrashTracker(TheTrashCan);
  417.  
  418.         if (FinalErrorThing != eCompileNoError)
  419.             {
  420.                 /* since we're aborting, dump any functions we've already created */
  421.                 FlushModulesCompiledFunctions(CodeCenter,Signature);
  422.             }
  423.  
  424.         return FinalErrorThing;
  425.     }
  426.  
  427.  
  428.  
  429.  
  430. /* return a null terminated static string describing the error. */
  431. char*                            GetCompileErrorString(CompileErrors Error)
  432.     {
  433.         char*                        S;
  434.  
  435.         switch (Error)
  436.             {
  437.                 default:
  438.                     EXECUTE(PRERR(ForceAbort,"GetCompileErrorString:  unknown error code"));
  439.                     break;
  440.                 case eCompileNoError:
  441.                     EXECUTE(PRERR(ForceAbort,"GetCompileErrorString:  eCompileNoError called"));
  442.                     break;
  443.                 case eCompileOutOfMemory:
  444.                     S = "Out of memory";
  445.                     break;
  446.                 case eCompileExpectedFuncOrProto:
  447.                     S = "Expected 'func' or 'proto'";
  448.                     break;
  449.                 case eCompileExpectedFunc:
  450.                     S = "Expected 'func'";
  451.                     break;
  452.                 case eCompileExpectedIdentifier:
  453.                     S = "Expected identifier";
  454.                     break;
  455.                 case eCompileExpectedOpenParen:
  456.                     S = "Expected '"OPAREN"'";
  457.                     break;
  458.                 case eCompileExpectedCloseParen:
  459.                     S = "Expected '"CPAREN"'";
  460.                     break;
  461.                 case eCompileExpectedColon:
  462.                     S = "Expected ':'";
  463.                     break;
  464.                 case eCompileExpectedSemicolon:
  465.                     S = "Expected ';'";
  466.                     break;
  467.                 case eCompileMultiplyDefinedIdentifier:
  468.                     S = "Identifier has already been used";
  469.                     break;
  470.                 case eCompileExpectedTypeSpecifier:
  471.                     S = "Expected type specification";
  472.                     break;
  473.                 case eCompileExpectedExpressionForm:
  474.                     S = "Expected expression";
  475.                     break;
  476.                 case eCompileExpectedColonEqual:
  477.                     S = "Expected ':='";
  478.                     break;
  479.                 case eCompileExpectedTo:
  480.                     S = "Expected 'to'";
  481.                     break;
  482.                 case eCompileExpectedStringLiteral:
  483.                     S = "Expected string literal";
  484.                     break;
  485.                 case eCompileExpectedResumable:
  486.                     S = "Expected 'resumable'";
  487.                     break;
  488.                 case eCompileExpectedWhile:
  489.                     S = "Expected 'while'";
  490.                     break;
  491.                 case eCompileExpectedDo:
  492.                     S = "Expected 'do'";
  493.                     break;
  494.                 case eCompileExpectedUntil:
  495.                     S = "Expected 'until'";
  496.                     break;
  497.                 case eCompileExpectedOpenParenOrEqual:
  498.                     S = "Expected '"OPAREN"' or '='";
  499.                     break;
  500.                 case eCompileExpectedThen:
  501.                     S = "Expected 'then'";
  502.                     break;
  503.                 case eCompileExpectedWhileOrUntil:
  504.                     S = "Expected 'while' or 'until'";
  505.                     break;
  506.                 case eCompileExpectedCommaOrCloseParen:
  507.                     S = "Expected ',' or '"CPAREN"'";
  508.                     break;
  509.                 case eCompileExpectedElseOrElseIf:
  510.                     S = "Expected 'else' or 'elseif'";
  511.                     break;
  512.                 case eCompileExpectedOperatorOrStatement:
  513.                     S = "Expected operator or statement";
  514.                     break;
  515.                 case eCompileExpectedOperand:
  516.                     S = "Expected operand";
  517.                     break;
  518.                 case eCompileIdentifierNotDeclared:
  519.                     S = "Identifier hasn't been declared";
  520.                     break;
  521.                 case eCompileExpectedRightAssociativeOperator:
  522.                     S = "Expected right associative operator";
  523.                     break;
  524.                 case eCompileExpectedOpenBracket:
  525.                     S = "Expected '"OBRACKET"'";
  526.                     break;
  527.                 case eCompileExpectedCloseBracket:
  528.                     S = "Expected '"CBRACKET"'";
  529.                     break;
  530.                 case eCompileExpectedVariable:
  531.                     S = "Expected variable";
  532.                     break;
  533.                 case eCompileExpectedArrayType:
  534.                     S = "Expected array type";
  535.                     break;
  536.                 case eCompileArraySizeSpecMustBeInteger:
  537.                     S = "Array size specifier must be integer";
  538.                     break;
  539.                 case eCompileTypeMismatch:
  540.                     S = "Type conflict";
  541.                     break;
  542.                 case eCompileInvalidLValue:
  543.                     S = "Invalid l-value";
  544.                     break;
  545.                 case eCompileOperandsMustBeScalar:
  546.                     S = "Operands must be scalar";
  547.                     break;
  548.                 case eCompileOperandsMustBeSequencedScalar:
  549.                     S = "Operands must be sequenced scalar";
  550.                     break;
  551.                 case eCompileOperandsMustBeIntegers:
  552.                     S = "Operands must be an integer";
  553.                     break;
  554.                 case eCompileRightOperandMustBeInteger:
  555.                     S = "Right operand must be an integer";
  556.                     break;
  557.                 case eCompileArraySubscriptMustBeInteger:
  558.                     S = "Array subscript must be an integer";
  559.                     break;
  560.                 case eCompileArrayRequiredForSubscription:
  561.                     S = "Array required for subscription";
  562.                     break;
  563.                 case eCompileDoubleRequiredForExponentiation:
  564.                     S = "Operands for exponentiation must be doubles";
  565.                     break;
  566.                 case eCompileArrayRequiredForResize:
  567.                     S = "Array required for resize";
  568.                     break;
  569.                 case eCompileIntegerRequiredForResize:
  570.                     S = "Integer required resize array size specifier";
  571.                     break;
  572.                 case eCompileConditionalMustBeBoolean:
  573.                     S = "Conditional expression must boolean";
  574.                     break;
  575.                 case eCompileTypeMismatchBetweenThenAndElse:
  576.                     S = "Type conflict between consequent and alternate arms of conditional";
  577.                     break;
  578.                 case eCompileErrorNeedsBooleanArg:
  579.                     S = "Error directive needs boolean argument";
  580.                     break;
  581.                 case eCompileFunctionIdentifierRequired:
  582.                     S = "Function identifier required";
  583.                     break;
  584.                 case eCompileArgumentTypeConflict:
  585.                     S = "Type conflict between formal and actual arguments";
  586.                     break;
  587.                 case eCompileWrongNumberOfArgsToFunction:
  588.                     S = "Wrong number of arguments to function";
  589.                     break;
  590.                 case eCompileCantHaveStringLiteralThere:
  591.                     S = "String literal is not allowed here";
  592.                     break;
  593.                 case eCompileMustBeAVariableIdentifier:
  594.                     S = "Variable identifier required";
  595.                     break;
  596.                 case eCompileOperandMustBeBooleanOrInteger:
  597.                     S = "Operands must be boolean or integer";
  598.                     break;
  599.                 case eCompileOperandMustBeDouble:
  600.                     S = "Operand must be double";
  601.                     break;
  602.                 case eCompileArrayRequiredForGetLength:
  603.                     S = "Array required for length operator";
  604.                     break;
  605.                 case eCompileTypeMismatchInAssignment:
  606.                     S = "Type conflict between l-value and argument";
  607.                     break;
  608.                 case eCompileVoidExpressionIsNotAllowed:
  609.                     S = "Void expression is not allowed";
  610.                     break;
  611.                 case eCompileMultiplyDeclaredFunction:
  612.                     S = "Function name has already been used";
  613.                     break;
  614.                 case eCompilePrototypeCantBeLastThingInExprList:
  615.                     S = "Prototype can't be the last expression in an expression sequence";
  616.                     break;
  617.                 case eCompileInputBeyondEndOfFunction:
  618.                     S = "Input beyond end of expression";
  619.                     break;
  620.                 case eCompileArrayConstructionOnScalarType:
  621.                     S = "Array constructor applied to scalar variable";
  622.                     break;
  623.             }
  624.         return S;
  625.     }
  626.  
  627.  
  628.  
  629.  
  630. /* compile a special function.  a special function has no function header, but is */
  631. /* simply some code to be executed.  the parameters the code is expecting are provided */
  632. /* in the FuncArray[] and NumParams.  the first parameter is deepest beneath the */
  633. /* top of stack.  the TextData is NOT altered.  if an error occurrs, *FunctionOut */
  634. /* will NOT contain a valid object */
  635. CompileErrors            CompileSpecialFunction(FunctionParamRec FuncArray[], long NumParams,
  636.                                         long* ErrorLineNumber, DataTypes* ReturnType, char* TextData,
  637.                                         struct PcodeRec** FunctionOut)
  638.     {
  639.         TrashTrackRec*        TheTrashCan;
  640.         ScannerRec*                TheScanner;
  641.         SymbolTableRec*        TheSymbolTable;
  642.         long                            StackDepth;
  643.         long                            ReturnAddressIndex;
  644.         CompileErrors            Error;
  645.         ASTExpressionRec*    TheExpressionThang;
  646.         ASTExprListRec*        ListOfExpressions;
  647.         PcodeRec*                    TheFunctionCode;
  648.         long                            Scan;
  649.         DataTypes                    ResultingType;
  650.         TokenRec*                    Token;
  651.  
  652.         EXECUTE(*ErrorLineNumber = 0x81818181;)
  653.         CheckPtrExistence(TextData);
  654.  
  655.         TheTrashCan = NewTrashTracker();
  656.         if (TheTrashCan == NIL)
  657.             {
  658.              NoMemoryPoint1:
  659.                 *ErrorLineNumber = 1;
  660.                 return eCompileOutOfMemory;
  661.             }
  662.  
  663.         TheScanner = NewScanner(TheTrashCan,TextData);
  664.         if (TheScanner == NIL)
  665.             {
  666.              NoMemoryPoint2:
  667.                 DisposeTrashTracker(TheTrashCan);
  668.                 goto NoMemoryPoint1;
  669.             }
  670.         LoadKeywordsIntoScanner(TheScanner);
  671.  
  672.         TheSymbolTable = NewSymbolTable(TheTrashCan);
  673.         if (TheSymbolTable == NIL)
  674.             {
  675.                 goto NoMemoryPoint2;
  676.             }
  677.  
  678.         /* build parameters into symbol table */
  679.         StackDepth = 1;
  680.         ReturnAddressIndex = StackDepth;
  681.         for (Scan = 0; Scan < NumParams; Scan += 1)
  682.             {
  683.                 SymbolRec*                TheParameter;
  684.  
  685.                 TheParameter = NewSymbol(TheTrashCan,FuncArray[Scan].ParameterName,
  686.                     StrLen(FuncArray[Scan].ParameterName));
  687.                 if (TheParameter == NIL)
  688.                     {
  689.                         goto NoMemoryPoint2;
  690.                     }
  691.                 SymbolBecomeVariable(TheParameter,FuncArray[Scan].ParameterType);
  692.                 /* allocate stack slot */
  693.                 StackDepth += 1;
  694.                 SetSymbolVariableStackLocation(TheParameter,StackDepth);
  695.                 switch (AddSymbolToTable(TheSymbolTable,TheParameter))
  696.                     {
  697.                         default:
  698.                             EXECUTE(PRERR(ForceAbort,"CompileSpecialFunction:  unknown "
  699.                                 "return code from AddSymbolToTable"));
  700.                             break;
  701.                         case eAddSymbolNoErr:
  702.                             break;
  703.                         case eAddSymbolAlreadyExists:
  704.                             EXECUTE(PRERR(ForceAbort,"CompileSpecialFunction:  "
  705.                                 "eAddSymbolAlreadyExists was returned from AddSymbolToTable"));
  706.                             break;
  707.                         case eAddSymbolNoMemory:
  708.                             goto NoMemoryPoint2;
  709.                     }
  710.             }
  711.         /* fence them off */
  712.         if (!IncrementSymbolTableLevel(TheSymbolTable))
  713.             {
  714.                 goto NoMemoryPoint2;
  715.             }
  716.  
  717.         /* save return address spot */
  718.         /* StackDepth += 1; NO RETURN ADDRESS! */
  719.  
  720.         Error = ParseExprList(&ListOfExpressions,TheScanner,TheSymbolTable,TheTrashCan,
  721.             ErrorLineNumber);
  722.         /* compile the thing */
  723.         if (Error != eCompileNoError)
  724.             {
  725.                 ERROR(*ErrorLineNumber == 0x81818181,PRERR(ForceAbort,
  726.                     "CompileSpecialFunction:  error line number wasn't set properly"));
  727.                 DisposeTrashTracker(TheTrashCan);
  728.                 return Error;
  729.             }
  730.         TheExpressionThang = NewExprSequence(ListOfExpressions,TheTrashCan,
  731.             GetCurrentLineNumber(TheScanner));
  732.         if (TheExpressionThang == NIL)
  733.             {
  734.                 *ErrorLineNumber = GetCurrentLineNumber(TheScanner);
  735.                 DisposeTrashTracker(TheTrashCan);
  736.                 return eCompileOutOfMemory;
  737.             }
  738.  
  739.         /* make sure there is nothing after it */
  740.         Token = GetNextToken(TheScanner);
  741.         if (Token == NIL)
  742.             {
  743.                 goto NoMemoryPoint2;
  744.             }
  745.         if (GetTokenType(Token) != eTokenEndOfInput)
  746.             {
  747.                 *ErrorLineNumber = GetCurrentLineNumber(TheScanner);
  748.                 DisposeTrashTracker(TheTrashCan);
  749.                 return eCompileInputBeyondEndOfFunction;
  750.             }
  751.  
  752.         Error = TypeCheckExpression(&ResultingType,TheExpressionThang,
  753.             ErrorLineNumber,TheTrashCan);
  754.         if (Error != eCompileNoError)
  755.             {
  756.                 ERROR(*ErrorLineNumber == 0x81818181,PRERR(ForceAbort,
  757.                     "CompileSpecialFunction:  error line number wasn't set properly"));
  758.                 DisposeTrashTracker(TheTrashCan);
  759.                 return Error;
  760.             }
  761.  
  762.         TheFunctionCode = NewPcode();
  763.         if (TheFunctionCode == NIL)
  764.             {
  765.                 goto NoMemoryPoint2;
  766.             }
  767.  
  768.         if (!CodeGenExpression(TheFunctionCode,&StackDepth,TheExpressionThang))
  769.             {
  770.              NoMemoryPoint3:
  771.                 DisposePcode(TheFunctionCode);
  772.                 goto NoMemoryPoint2;
  773.             }
  774.  
  775.         ERROR(ReturnType == NIL,PRERR(ForceAbort,
  776.             "CompileSpecialFunction:  ReturnType is NIL"));
  777.         *ReturnType = GetExpressionsResultantType(TheExpressionThang);
  778.  
  779.  
  780.         /* append epilogue */
  781.         /* 1. store result in return slot */
  782.         /* 2. pop result */
  783.         /* note that we do NOT pop the parameters!!! */
  784.  
  785.         /* 2 extra words for retval and resultofexpr */
  786.         ERROR(StackDepth != NumParams + 1 + 1,PRERR(ForceAbort,
  787.             "CompileSpecialFunction:  stack depth error after evaluating function"));
  788.         /* move the result to the return slot */
  789.         switch (GetExpressionsResultantType(TheExpressionThang))
  790.             {
  791.                 default:
  792.                     EXECUTE(PRERR(ForceAbort,"CompileSpecialFunction:  unknown type"));
  793.                     break;
  794.                 case eBoolean:
  795.                 case eInteger:
  796.                 case eFixed:
  797.                     if (!AddPcodeInstruction(TheFunctionCode,epStoreIntegerOnStack,NIL))
  798.                         {
  799.                             goto NoMemoryPoint3;
  800.                         }
  801.                     break;
  802.                 case eFloat:
  803.                     if (!AddPcodeInstruction(TheFunctionCode,epStoreFloatOnStack,NIL))
  804.                         {
  805.                             goto NoMemoryPoint3;
  806.                         }
  807.                     break;
  808.                 case eDouble:
  809.                     if (!AddPcodeInstruction(TheFunctionCode,epStoreDoubleOnStack,NIL))
  810.                         {
  811.                             goto NoMemoryPoint3;
  812.                         }
  813.                     break;
  814.                 case eArrayOfBoolean:
  815.                 case eArrayOfInteger:
  816.                 case eArrayOfFloat:
  817.                 case eArrayOfDouble:
  818.                 case eArrayOfFixed:
  819.                     if (!AddPcodeInstruction(TheFunctionCode,epStoreArrayOnStack,NIL))
  820.                         {
  821.                             goto NoMemoryPoint3;
  822.                         }
  823.                     break;
  824.             }
  825.         /* where to put it?  well, if there are no arguments, then */
  826.         /* Stack[0] = the value; Stack[-1] = return address, and */
  827.         /* Stack[-2] = the return value */
  828.         if (!AddPcodeOperandInteger(TheFunctionCode,ReturnAddressIndex - StackDepth))
  829.             {
  830.                 goto NoMemoryPoint3;
  831.             }
  832.         /* now pop the result */
  833.         if (!AddPcodeInstruction(TheFunctionCode,epStackPop,NIL))
  834.             {
  835.                 goto NoMemoryPoint3;
  836.             }
  837.         StackDepth -= 1;
  838.         /* now put the return instruction */
  839.         if (!AddPcodeInstruction(TheFunctionCode,epReturnFromSubroutine,NIL))
  840.             {
  841.                 goto NoMemoryPoint3;
  842.             }
  843.         /* magically, there is no return address, since the root function call */
  844.         /* is detected by the pcode evaluator and doesn't need a return address */
  845.         ERROR(StackDepth != NumParams + 1,PRERR(ForceAbort,
  846.             "CompileSpecialFunction:  stack depth is wrong at end of function"));
  847.  
  848.         /* optimize stupid things away */
  849.         OptimizePcode(TheFunctionCode);
  850.  
  851.  
  852.         /* it worked, so return the dang thing */
  853.         *FunctionOut = TheFunctionCode;
  854.         DisposeTrashTracker(TheTrashCan);
  855.         return eCompileNoError;
  856.     }
  857.