/// <summary> /// Emit code that loads a value from an array. There are some special cases here. /// </summary> /// <param name="identNode">Ident parse node</param> /// <param name="useRef">If set to <c>true</c> load the element address</param> /// <returns>The symbol type of the array element</returns> public SymType GenerateLoadFromArray(IdentifierParseNode identNode, bool useRef) { if (identNode == null) { throw new ArgumentNullException("identNode"); } Symbol sym = identNode.Symbol; // Handle loading the base array as opposed to an element Debug.Assert(sym.IsArray); if (identNode.IsArrayBase) { return GenerateLoadArray(identNode, useRef); } // OK, we're loading an array element. GenerateLoadArrayAddress(identNode); if (useRef) { _em.LoadArrayElementReference(sym); } else { _em.LoadArrayElement(sym); } return sym.Type; }
/// <summary> /// Emit the load of an address of full symbol. This may either be /// the address of a local object or the address of an array element. /// </summary> /// <param name="identNode">An IdentifierParseNode representing the variable /// or array element whose address should be emitted.</param> public void LoadAddress(IdentifierParseNode identNode) { if (identNode == null) { throw new ArgumentNullException("identNode"); } Symbol sym = identNode.Symbol; if (sym.IsArray) { GenerateLoadFromArray(identNode, true); } else { GenerateLoadAddress(sym); } }
/// <summary> /// Emit the code that loads an entire array. This is generally /// emitting the base address of the array if useRef is specified, or /// the array itself otherwise. /// </summary> /// <returns>The type of the array</returns> /// <param name="identNode">An IdentifierParseNode object representing /// the array variable.</param> /// <param name="useRef">If set to <c>true</c> use emit the address of /// the array</param> public SymType GenerateLoadArray(IdentifierParseNode identNode, bool useRef) { if (identNode == null) { throw new ArgumentNullException("identNode"); } Symbol sym = identNode.Symbol; if (useRef) { GenerateLoadAddress(sym); } else if (sym.IsLocal) { LoadLocal(sym); } else { GenerateLoadArgument(sym); } return SymType.REF; }
/// <summary> /// Emit the code that loads the base array and the offset of the /// indexed element to the top of the stack.. /// </summary> /// <param name="identNode">Parse node for array identifier</param> public void GenerateLoadArrayAddress(IdentifierParseNode identNode) { if (identNode == null) { throw new ArgumentNullException("identNode"); } Symbol sym = identNode.Symbol; if (sym.IsLocal) { LoadLocal(sym); } else { GenerateLoadArgument(sym); } for (int c = 0; c < identNode.Indexes.Count; ++c) { ParseNode indexNode = identNode.Indexes[c]; if (indexNode.IsConstant) { NumberParseNode intNode = (NumberParseNode)indexNode; if (sym.Dimensions[c].LowerBound.IsConstant) { _em.LoadInteger((0 - sym.Dimensions[c].LowerBound.Value.IntValue) + intNode.Value.IntValue); } else { _em.LoadInteger(0); GenerateExpression(SymType.INTEGER, sym.Dimensions[c].LowerBound); _em.Sub(SymType.INTEGER); _em.LoadInteger(intNode.Value.IntValue); _em.Add(SymType.INTEGER); } } else { GenerateExpression(SymType.INTEGER, indexNode); if (sym.Dimensions[c].LowerBound.IsConstant) { int lowBound = sym.Dimensions [c].LowerBound.Value.IntValue; if (lowBound != 0) { _em.LoadInteger((0 - lowBound)); _em.Add(SymType.INTEGER); } } else { _em.LoadInteger(0); GenerateExpression(SymType.INTEGER, sym.Dimensions[c].LowerBound); _em.Sub(SymType.INTEGER); _em.Add(SymType.INTEGER); } } if (sym.IsFlatArray && c > 0) { for (int m = c - 1; m >= 0; --m) { int arraySize = sym.Dimensions[m].Size; if (arraySize >= 0) { _em.LoadInteger(arraySize); } else { GenerateExpression(SymType.INTEGER, sym.Dimensions[m].UpperBound); GenerateExpression(SymType.INTEGER, sym.Dimensions[m].LowerBound); _em.Sub(SymType.INTEGER); _em.LoadInteger(1); _em.Add(SymType.INTEGER); } _em.Mul(SymType.INTEGER); } _em.Add(SymType.INTEGER); } } }
// Emit the code that loads part of an entire array by making a copy of // the array to the destination array dimensions and copying from the // given offset. void GenerateLoadSubArray(CodeGenerator cg, IdentifierParseNode identNode, Symbol symParam, Temporaries locals) { if (!identNode.HasIndexes) { cg.GenerateLoadArray(identNode, false); return; } LocalDescriptor index = locals.New(symParam.SystemType); cg.GenerateLoadArrayAddress(identNode); cg.Emitter.CreateSimpleArray(symParam.ArraySize, Symbol.SymTypeToSystemType(symParam.Type)); cg.Emitter.Dup(); cg.Emitter.StoreLocal(index); cg.Emitter.LoadInteger(0); cg.Emitter.LoadInteger(symParam.ArraySize); cg.Emitter.Call(typeof(Array).GetMethod("Copy", new [] { typeof(Array), typeof(int), typeof(Array), typeof(int), typeof(int) })); cg.Emitter.LoadLocal(index); }
// Parse an intrinsic function call ParseNode IntrinsicOperand(string name, IdentifierParseNode node) { ExtCallParseNode tokenNode = new ExtCallParseNode("JComLib.Intrinsics,jcomlib", name); IntrDefinition intrDefinition = Intrinsics.IntrinsicDefinition(name); Debug.Assert(intrDefinition != null); SymType argType = SymType.NONE; int countOfParams = 0; bool isVarArg = (intrDefinition.Count == ArgCount.TwoOrMore); ParametersParseNode paramsNode = new ParametersParseNode(); VarArgParseNode argList = new VarArgParseNode(); // Parameters to inlined instrinsics are always passed by value. bool useByRef = !(_opts.Inline) || !tokenNode.CanInline(); if (!intrDefinition.IsPermittedInIntrinsic) { useByRef = false; } for (int c = 0; c < node.Indexes.Count; ++c) { ParseNode exprNode = node.Indexes[c]; if (c > 0 && !ValidateAssignmentTypes(exprNode.Type, argType)) { _messages.Error(MessageCode.TYPEMISMATCH, string.Format("All arguments to {0} must be of the same type", name)); } argType = exprNode.Type; if (!intrDefinition.IsValidArgType(argType)) { _messages.Error(MessageCode.TYPEMISMATCH, String.Format("Invalid argument type for {0}", name)); } if (intrDefinition.RequiredType != SymType.GENERIC) { exprNode.Type = intrDefinition.RequiredType; } if (isVarArg) { argList.Add(exprNode); } else { paramsNode.Add(exprNode, useByRef); } ++countOfParams; } if (isVarArg) { paramsNode.Add(argList, useByRef); } tokenNode.Parameters = paramsNode; // Make sure actual and expected arguments match bool match = false; switch (intrDefinition.Count) { case ArgCount.One: match = (countOfParams == 1); break; case ArgCount.OneOrTwo: match = (countOfParams == 1 || countOfParams == 2); break; case ArgCount.Two: match = (countOfParams == 2); break; case ArgCount.TwoOrMore: match = (countOfParams >= 2); break; default: Debug.Assert(false, "Unhandled ArgCount!"); break; } if (!match) { _messages.Error(MessageCode.WRONGNUMBEROFARGUMENTS, String.Format("Wrong number of arguments for {0}", name)); } // Set return type. GENERIC means use the type of the argument Debug.Assert(!(intrDefinition.ReturnType == SymType.GENERIC && argType == SymType.NONE), "argType cannot be null here!"); tokenNode.Type = (intrDefinition.ReturnType == SymType.GENERIC) ? argType : intrDefinition.ReturnType; tokenNode.Inline = _opts.Inline; return tokenNode; }
// Parse a function call operand ParseNode FunctionOperand(string name, IdentifierParseNode identNode) { Symbol sym = GetSymbolForCurrentScope(name); SymType type = SymType.NONE; // Look for this symbol name in the local table which means its type // was predefined. Symbol symLocal = _localSymbols.Get(name); if (symLocal != null && symLocal.Scope != SymScope.PARAMETER && symLocal.Class != SymClass.FUNCTION && !symLocal.IsIntrinsic) { type = symLocal.Type; _localSymbols.Remove(symLocal); sym = _globalSymbols.Get(name); } if (sym == null) { sym = _globalSymbols.Add(name, new SymFullType(type), SymClass.FUNCTION, null, _ls.LineNumber); } // If this was a parameter now being used as a function, change its // class and type. if (sym.Class != SymClass.FUNCTION) { sym.Class = SymClass.FUNCTION; sym.Defined = true; sym.Linkage = SymLinkage.BYVAL; } sym.IsReferenced = true; CallParseNode node = new CallParseNode(); node.ProcName = new IdentifierParseNode(sym); node.Parameters = new ParametersParseNode(); node.Type = sym.Type; foreach (ParseNode t in identNode.Indexes) { node.Parameters.Add(t, true); } return node; }
// Parse an identifier parse node from the specified token. IdentifierParseNode ParseIdentifierParseNode() { IdentifierParseNode node = new IdentifierParseNode(null); Collection<ParseNode> indices = null; SimpleToken token = _ls.GetToken(); bool isSubstring = false; while (token.ID == TokenID.LPAREN) { if (indices == null) { indices = new Collection<ParseNode>(); } if (_ls.PeekToken().ID != TokenID.RPAREN) { do { ParseNode item = null; if (_ls.PeekToken().ID == TokenID.RPAREN) { SkipToken(TokenID.RPAREN); break; } if (_ls.PeekToken().ID != TokenID.COLON) { item = Expression(); } token = _ls.GetToken(); if (token.ID == TokenID.COLON) { isSubstring = true; if (item == null) { item = new NumberParseNode(1); } node.SubstringStart = item; token = new SimpleToken(TokenID.COMMA); continue; } if (isSubstring) { node.SubstringEnd = item; break; } indices.Add(item); } while (token.ID == TokenID.COMMA); _ls.BackToken(); } ExpectToken(TokenID.RPAREN); token = _ls.GetToken(); } node.Indexes = indices; _ls.BackToken(); return node; }
/// Parse an identifier with no subscript. IdentifierParseNode ParseBasicIdentifier() { IdentifierToken identToken = ExpectIdentifierToken(); if (identToken != null) { Symbol sym = GetMakeSymbolForCurrentScope(identToken.Name); if (sym == null) { _messages.Error(MessageCode.UNDEFINEDVARIABLE, String.Format("Undefined identifier {0}", identToken.Name)); return null; } IdentifierParseNode node = new IdentifierParseNode(sym); sym.IsReferenced = true; return node; } return null; }