/// PAUSE keyword /// Pauses the program and outputs the given string. Waits for user /// input to continue. ParseNode KPause() { ExtCallParseNode node = new ExtCallParseNode("JComLib.Runtime,jcomlib", "PAUSE"); node.Parameters = new ParametersParseNode(); node.Parameters.Add(ParseStopPauseConstant()); return node; }
/// INQUIRE keyword /// Inquire of the state of a file. ParseNode KInquire() { ExtCallParseNode node = new ExtCallParseNode("JComLib.IO,jcomlib", "INQUIRE"); InitFunctionNodes(); ControlList cilist = ParseCIList(_inquireFunction.ParameterList); if (cilist == null) { SkipToEndOfLine(); return null; } node.Parameters = _inquireFunction.ParametersNode(cilist); // Wrap into a conditional if an ERR label is specified. if (cilist.Has("ERR")) { SwitchParseNode switchNode = new SwitchParseNode(); switchNode.CompareExpression = node; switchNode.Add(new NumberParseNode(-1), cilist["ERR"]); return switchNode; } return node; }
// Generic function that handles ENDFILE, BACKSPACE and REWIND since they // all take the exact same parameters. ParseNode PositionStatement(string keyword) { ExtCallParseNode node = new ExtCallParseNode("JComLib.IO,jcomlib", keyword); InitFunctionNodes(); ControlList cilist = ParseCIList(_posFunction.ParameterList); if (cilist == null) { SkipToEndOfLine(); return null; } if (cilist["UNIT"] == null) { _messages.Error(MessageCode.UNITREQUIRED, "UNIT specifier required for REWIND"); return null; } node.Parameters = _posFunction.ParametersNode(cilist); // Wrap into a conditional if an ERR label is specified. if (cilist.Has("ERR")) { SwitchParseNode switchNode = new SwitchParseNode(); switchNode.CompareExpression = node; switchNode.Add(new NumberParseNode(-1), cilist["ERR"]); return switchNode; } return node; }
// 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; }