private static SymbolRec ArgListTypesToSymbol( string functionName, DataTypes[] argsTypes, DataTypes returnType) { SymbolListRec head = null; for (int i = argsTypes.Length - 1; i >= 0; i--) { SymbolRec symbolArg = new SymbolRec(null); symbolArg.SymbolBecomeVariable(argsTypes[i]); SymbolListRec node = new SymbolListRec(symbolArg, head); head = node; } SymbolRec symbol = new SymbolRec(functionName); symbol.SymbolBecomeFunction(head, returnType); return(symbol); }
/* compile a special function. a special function has no function header, but is */ /* simply some code to be executed. the parameters the code is expecting are provided */ /* in the FuncArray[] and NumParams. the first parameter is deepest beneath the */ /* top of stack. the TextData is NOT altered. if an error occurrs, *FunctionOut */ /* will NOT contain a valid object */ public static CompileErrors CompileSpecialFunction( CodeCenterRec CodeCenter, FunctionParamRec[] FuncArray, out int ErrorLineNumber, out DataTypes ReturnTypeOut, string TextData, bool suppressCILEmission, out PcodeRec FunctionOut, out ASTExpression ASTOut) { CompileErrors Error; ErrorLineNumber = -1; ASTOut = null; FunctionOut = null; ReturnTypeOut = DataTypes.eInvalidDataType; ScannerRec <KeywordsType> TheScanner = new ScannerRec <KeywordsType>(TextData, KeywordTable); SymbolTableRec TheSymbolTable = new SymbolTableRec(); // reconstitute function prototypes for (int i = 0; i < CodeCenter.RetainedFunctionSignatures.Length; i++) { SymbolRec functionSignature = ArgListTypesToSymbol( CodeCenter.RetainedFunctionSignatures[i].Key, CodeCenter.RetainedFunctionSignatures[i].Value.ArgsTypes, CodeCenter.RetainedFunctionSignatures[i].Value.ReturnType); bool f = TheSymbolTable.Add(functionSignature); Debug.Assert(f); // should never fail (due to duplicate) since CodeCenter.RetainedFunctionSignatures is unique-keyed } /* build parameters into symbol table */ int StackDepth = 0; int MaxStackDepth = 0; int ReturnAddressIndex = StackDepth; for (int i = 0; i < FuncArray.Length; i += 1) { SymbolRec TheParameter = new SymbolRec(FuncArray[i].ParameterName); TheParameter.SymbolBecomeVariable(FuncArray[i].ParameterType); /* allocate stack slot */ StackDepth++; MaxStackDepth = Math.Max(MaxStackDepth, StackDepth); TheParameter.SymbolVariableStackLocation = StackDepth; if (!TheSymbolTable.Add(TheParameter)) // our own code should never pass in a formal arg list with duplicates { Debug.Assert(false); throw new InvalidOperationException(); } } /* fence them off */ TheSymbolTable.IncrementSymbolTableLevel(); /* reserve spot for fake return address (so we have uniform calling convention everywhere) */ StackDepth++; MaxStackDepth = Math.Max(MaxStackDepth, StackDepth); if (StackDepth != FuncArray.Length + 1) { // stack depth error before evaluating function Debug.Assert(false); throw new InvalidOperationException(); } ASTExpressionList ListOfExpressions; Error = ParseExprList( out ListOfExpressions, new ParserContext( TheScanner, TheSymbolTable), out ErrorLineNumber); /* compile the thing */ if (Error != CompileErrors.eCompileNoError) { return(Error); } ASTExpression TheExpressionThang = new ASTExpression( ListOfExpressions, TheScanner.GetCurrentLineNumber()); /* make sure there is nothing after it */ TokenRec <KeywordsType> Token = TheScanner.GetNextToken(); if (Token.GetTokenType() != TokenTypes.eTokenEndOfInput) { ErrorLineNumber = TheScanner.GetCurrentLineNumber(); return(CompileErrors.eCompileInputBeyondEndOfFunction); } DataTypes ResultingType; Error = TheExpressionThang.TypeCheck(out ResultingType, out ErrorLineNumber); if (Error != CompileErrors.eCompileNoError) { return(Error); } OptimizeAST(ref TheExpressionThang); PcodeRec TheFunctionCode = new PcodeRec(); TheExpressionThang.PcodeGen( TheFunctionCode, ref StackDepth, ref MaxStackDepth); Debug.Assert(StackDepth <= MaxStackDepth); ReturnTypeOut = TheExpressionThang.ResultType; /* 2 extra words for retaddr, resultofexpr */ if (StackDepth != FuncArray.Length + 1 /*retaddr*/ + 1 /*result*/) { // stack depth error after evaluating function Debug.Assert(false); throw new InvalidOperationException(); } /* now put the return instruction */ int unused; TheFunctionCode.AddPcodeInstruction(Pcodes.epReturnFromSubroutine, out unused, TheScanner.GetCurrentLineNumber()); // special function returns without popping args -- so that args can be have in/out behavior TheFunctionCode.AddPcodeOperandInteger(0); StackDepth -= 1; /* pop retaddr */ Debug.Assert(StackDepth <= MaxStackDepth); if (StackDepth != 1 + FuncArray.Length) { // stack depth is wrong at end of function Debug.Assert(false); throw new InvalidOperationException(); } TheFunctionCode.MaxStackDepth = MaxStackDepth; /* optimize stupid things away */ TheFunctionCode.OptimizePcode(); if (CILObject.EnableCIL && !suppressCILEmission) { DataTypes[] argsTypes = new DataTypes[FuncArray.Length]; string[] argsNames = new string[FuncArray.Length]; for (int i = 0; i < argsTypes.Length; i++) { argsTypes[i] = FuncArray[i].ParameterType; argsNames[i] = FuncArray[i].ParameterName; } CILAssembly cilAssembly = new CILAssembly(); CILObject cilObject = new CILObject( CodeCenter.ManagedFunctionLinker, argsTypes, argsNames, TheExpressionThang.ResultType, TheExpressionThang, cilAssembly, true /*argsByRef*/); // args by ref true for special functions to permit multiple return values TheFunctionCode.cilObject = cilObject; cilAssembly.Finish(); } /* it worked, so return the dang thing */ FunctionOut = TheFunctionCode; ASTOut = TheExpressionThang; return(CompileErrors.eCompileNoError); }