// Parse an assignment statement. // Fairly straightforward. ParseNode KAssignment() { AssignmentParseNode node = new AssignmentParseNode(); _ls.BackToken(); IdentifierToken identToken = ExpectIdentifierToken(); if (identToken == null) { SkipToEndOfLine(); return null; } // Do a little work to see if this is a possible statement function. The logic // is: if the symbol is not already declared or it is but it isn't an array // then we're a statement function. Array element assignments here MUST have been // predefined. Symbol sym = _localSymbols.Get(identToken.Name); if (_ls.PeekToken().ID == TokenID.LPAREN && (sym == null || !sym.IsArray)) { return KStatementFunction(identToken); } IdentifierParseNode identNode = (IdentifierParseNode)ParseIdentifierFromToken(identToken); if (identNode != null) { // Can never assign to a constant if (identNode.Symbol.IsConstant) { _messages.Error(MessageCode.CANNOTASSIGNTOCONST, "Cannot assign a value to a constant"); SkipToEndOfLine(); return null; } node.Identifier = identNode; ExpectToken(TokenID.EQUOP); ParseNode exprNode = Expression(); if (exprNode != null) { bool valid = ValidateAssignmentTypes(identNode.Type, exprNode.Type); if (!valid) { _messages.Error(MessageCode.TYPEMISMATCH, "Type mismatch in assignment"); } node.ValueExpression = exprNode; } } else { SkipToEndOfLine(); } return node; }
/// WRITE keyword ParseNode KWrite() { WriteParseNode node = new WriteParseNode(); InitFunctionNodes(); ControlList cilist = ParseCIList(_writeFunctions.ParameterList); if (cilist == null) { SkipToEndOfLine(); return null; } node.ArgList = ParseVarargList(); node.ErrLabel = (SymbolParseNode)cilist["ERR"]; // First column is special for F77 only node.FirstColumnSpecial = (_opts.F77); // If this is internal storage, create an expression that // assigns the result to the character string ParseNode unit = cilist["UNIT"]; if (unit != null && unit.ID == ParseID.IDENT && Symbol.IsCharType(unit.Type)) { node.WriteParamsNode = _ioCoreFunctions.ParametersNode(cilist); node.WriteManagerParamsNode = _writeFunctionString.ParametersNode(cilist); AssignmentParseNode assignNode = new AssignmentParseNode(); assignNode.Identifier = (IdentifierParseNode)unit; assignNode.ValueExpression = node; return assignNode; } if (unit == null) { cilist["UNIT"] = new NumberParseNode(new Variant(IOConstant.Stdout)); } node.WriteParamsNode = _ioCoreFunctions.ParametersNode(cilist); node.WriteManagerParamsNode = _writeFunctions.ParametersNode(cilist); return node; }
// ASSIGN keyword. // This is a straight assignment of a label to an identifier. The // code generator will differentiate and construct the right code // to perform the assignment of the label's internal ID. ParseNode KAssign() { AssignmentParseNode assignNode = new AssignmentParseNode(); SymbolParseNode label = ParseLabel(); ExpectToken(TokenID.KTO); int index; for (index = 0; index < _currentProcedure.LabelList.Count; ++index) { SymbolParseNode thisLabel = (SymbolParseNode)_currentProcedure.LabelList[index]; if (thisLabel.Symbol == label.Symbol) { break; } } if (index == _currentProcedure.LabelList.Count) { _currentProcedure.LabelList.Add(label); } assignNode.Identifier = ParseBasicIdentifier(); assignNode.ValueExpression = new NumberParseNode(index); return assignNode; }
// DATA keyword // Syntax: DATA list-of-vars/values/ ParseNode KData() { SimpleToken token; do { List<ParseNode> idList = new List<ParseNode>(); List<Variant> valueList = new List<Variant>(); do { // BUGBUG: Check for duplicate identifier in ANY data // statement. Need to set a symbol flag. ParseNode node = ParseIdentifierWithImpliedDo(); if (node == null) { SkipToEndOfLine(); return null; } idList.Add(node); token = _ls.GetToken(); } while(token.ID == TokenID.COMMA); _ls.BackToken(); Variant repeatNode; Variant valueNode; ExpectToken(TokenID.DIVIDE); do { valueNode = ParseConstant(); repeatNode = new Variant(1); token = _ls.GetToken(); if (token.ID == TokenID.STAR) { if (valueNode.IntValue < 1) { _messages.Error(MessageCode.BADREPEATCOUNT, "Repeat count must be positive and non-zero"); } else { repeatNode = valueNode; } valueNode = ParseConstant(); token = _ls.GetToken(); } valueList.Add(repeatNode); valueList.Add(valueNode); } while(token.ID == TokenID.COMMA); _ls.BackToken(); ExpectToken(TokenID.DIVIDE); IdentifierParseNode idNode = null; int idIndex = 0; int valueIndex = 0; int repeatCount = 0; int offset = 0; while (idIndex < idList.Count || valueIndex < valueList.Count) { if (idIndex < idList.Count) { ParseNode parseNode = idList[idIndex++]; if (parseNode.ID == ParseID.LOOP) { LoopParseNode loopNode = (LoopParseNode)parseNode; // Make sure the loop range evaluates to a constant. int loopCount = loopNode.IterationCount(); if (loopCount == -1) { _messages.Error(MessageCode.NONCONSTANTDATALOOP, "Implied DO loop in DATA must be a constant"); SkipToEndOfLine(); return null; } // Also make sure that the loop control is an identifier. It should be an // array identifier but we don't particularly check for this. Maybe we should? if (loopNode.LoopValue.ID != ParseID.IDENT) { _messages.Error(MessageCode.NONCONSTANTDATALOOP, "Implied DO loop in DATA must be an identifier"); SkipToEndOfLine(); return null; } // Generate the implied DO loop as a sequence of assignment statements that are // executed during the procedure initialisation phase. All the different value // representations should be handled here. // // 1. If the value is a sequence, then there should be as many values as // required by the loop count. If there are less, the remainder of the loop // is ignored. // 2. If the value has a repeat count, we expand the value by the repeat count // and use subsequent values if there are still iterations left in the loop // counter. // 3. Values beyond the end of the loop count are assigned to the other identifiers // specified in the DATA statement, if any. // IdentifierParseNode loopIdent = (IdentifierParseNode)loopNode.LoopValue; Symbol loopSymbol = loopIdent.Symbol; int loopIndex = loopNode.StartExpression.Value.IntValue; while (loopCount > 0) { if (repeatCount == 0 && valueIndex < valueList.Count) { repeatNode = valueList[valueIndex++]; valueNode = valueList[valueIndex++]; } AssignmentParseNode assignNode = new AssignmentParseNode(); assignNode.Identifier = new IdentifierParseNode(loopSymbol, loopIndex); assignNode.ValueExpression = new NumberParseNode(valueNode); AddInit(assignNode); if (repeatCount > 0) { --repeatCount; } loopIndex += loopNode.StepExpression.Value.IntValue; --loopCount; } continue; } Debug.Assert(parseNode.ID == ParseID.IDENT); idNode = (IdentifierParseNode)parseNode; offset = 0; } if (repeatCount == 0 && valueIndex < valueList.Count) { repeatNode = valueList[valueIndex++]; valueNode = valueList[valueIndex++]; repeatCount = repeatNode.IntValue; } Debug.Assert(idNode != null); Symbol sym = idNode.Symbol; if (sym.IsArray) { ArrayParseNode arrayNode = new ArrayParseNode(); arrayNode.Identifier = idNode; if (idNode.Indexes != null) { arrayNode.StartRange = 0; arrayNode.EndRange = 0; arrayNode.RangeValue = valueNode; AddInit(arrayNode); } else { arrayNode.StartRange = offset; arrayNode.EndRange = offset + (repeatCount - 1); arrayNode.RangeValue = valueNode; AddInit(arrayNode); offset += repeatCount; repeatCount = 1; } } else if (idNode.HasSubstring) { AssignmentParseNode assignNode = new AssignmentParseNode(); assignNode.Identifier = idNode; assignNode.ValueExpression = new StringParseNode(valueNode.StringValue); AddInit(assignNode); } else { sym.Value = valueNode; } --repeatCount; } token = _ls.GetToken(); } while (token.ID == TokenID.COMMA); _ls.BackToken(); return null; }