/// <summary> /// スニペット変数を追加する /// </summary> /// <param name="id">変数名</param> /// <param name="toolTip">説明</param> /// <param name="_default">デフォルト値</param> /// <param name="function">適用する関数</param> public void AddDeclaration(string id, string toolTip, string _default, Function?function) { if (Declarations is null) { Declarations = new List <Literal>(); } Declarations.Add(new Literal(id, toolTip, _default, function)); }
/// <summary> /// Parses arguments for a function call. If <paramref name="usingParentheses"/> /// is true, assumes opening parenthesis has been read and reads up to and /// including the closing parenthesis. Returns false on error. /// </summary> /// <param name="function">Function being called. May be null for user /// functions. Used to verify argument count for intrinsic functions.</param> private bool ParseFunctionArguments(Function?function, bool usingParentheses) { Token token; int count = 0; // Save position and write placeholder for argument count int argumentCountIP = Writer.Write(0); if (ParseExpression(false)) { count++; token = Lexer.GetNext(); while (token.Type == TokenType.Comma) { if (!ParseExpression()) { return(false); } count++; token = Lexer.GetNext(); } } else { token = Lexer.GetNext(); } if (usingParentheses) { if (token.Type != TokenType.RightParen) { Error(ErrorCode.ExpectedRightParen, token); return(false); } } else { Lexer.UngetToken(token); } // Enforce argument count for intrinsic functions // (May be null for user functions not yet defined) if (function is IntrinsicFunction intrinsicFunction) { if (!intrinsicFunction.IsParameterCountValid(count, out string?error)) { Error(ErrorCode.WrongNumberOfArguments, error); return(false); } } // Fixup argument count Writer.WriteAt(argumentCountIP, count); return(true); }
/// <summary> /// Function.ClassName以外対応 /// </summary> /// <param name="id"></param> /// <param name="function">Function.ClassName以外を指定すること</param> public Literal(string id, Function?function, string functionValue) { string _default = null; if (function == MinteaCore.SnippetGenerator.Function.GenerateSwitchCases) { _default = ":default"; } Initialize(id, null, _default); Function = function; FunctionValue = functionValue; }
public Function?FindFunction(int address) { var idx = Search(_functions, new Function(address, 0), FunctionAddressComparer); Function?result = null; if (idx >= 0 && idx < _functions.Count) { result = _functions[idx]; } return(result); }
/// <summary> /// Creates a new function with the given name /// </summary> /// <param name="functionName">The function's name. If null will get random name</param> /// <param name="setting">The settings for how to write the file</param> /// <returns>The newly created function</returns> public Function Function(string?functionName = null, BaseFile.WriteSetting setting = BaseFile.WriteSetting.LockedAuto) { if (string.IsNullOrWhiteSpace(functionName)) { return(new Function(this, null, setting)); } Function?returnFunction = (Function?)GetFile("function", functionName); if (returnFunction is null) { return(new Function(this, functionName, setting)); } else { return(returnFunction); } }
/// <summary> /// Parses a symbol. Expected to be either a label, an assignment, a function /// definition, or function call. /// </summary> private void ParseSymbol(Token token) { Token nextToken = Lexer.GetNext(); switch (nextToken.Type) { case TokenType.Colon: // Label definition if (!InFunction) { Error(ErrorCode.CodeOutsideFunction, token); NextLine(); return; } AddLabel(token.Value, Writer.IP); // Allow another statement on same line break; case TokenType.LeftBracket: // Assignment to list item if (!InFunction) { Error(ErrorCode.CodeOutsideFunction, token); NextLine(); return; } Writer.Write(ByteCode.AssignListVariableMulti, GetVariableId(token.Value)); int subscriptsIP = Writer.Write(0); // int subscripts = 0; do { // Parse list index if (!ParseExpression()) { return; } token = Lexer.GetNext(); if (token.Type != TokenType.RightBracket) { Error(ErrorCode.ExpectedRightBracket, token); NextLine(); return; } subscripts++; // Get next token token = Lexer.GetNext(); } while (token.Type == TokenType.LeftBracket); // Set index count Writer.WriteAt(subscriptsIP, subscripts); if (token.Type != TokenType.Equal) { Error(ErrorCode.ExpectedEquals, token); NextLine(); return; } // Parse expression if (!ParseExpression()) { return; } VerifyEndOfLine(); break; case TokenType.Equal: // Assignment if (!InFunction) { Error(ErrorCode.CodeOutsideFunction, token); NextLine(); return; } // Test for read-only int varId = GetVariableId(token.Value); if (IsReadOnly(varId)) { Error(ErrorCode.AssignToReadOnlyVariable, token); NextLine(); return; } Writer.Write(ByteCode.Assign, varId); if (!ParseExpression()) { return; } VerifyEndOfLine(); break; default: if (InFunction) { // Function call int functionId = GetFunctionId(token.Value); Function?function = Functions[functionId]; Writer.Write(ByteCode.ExecFunction, functionId); // Next token might be part of argument expression Lexer.UngetToken(nextToken); if (!ParseFunctionArguments(function, false)) { return; } VerifyEndOfLine(); } else { // Function definition requires parentheses if (nextToken.Type != TokenType.LeftParen) { Error(ErrorCode.ExpectedLeftParen, nextToken); break; } // Create function var function = new CompileTimeUserFunction(token.Value, Writer.IP); // Parse and add parameters if (!ParseFunctionParameters(function)) { return; } // Add user function AddUserFunction(token.Value, function); InHeader = false; CurrentFunction = function; token = Lexer.GetNextSkipNewLines(); if (token.Type != TokenType.LeftBrace) { Error(ErrorCode.ExpectedLeftBrace, token); return; } // Parse statements in function while (ParseStatement()) { ; } token = Lexer.GetNext(); if (token.Type != TokenType.RightBrace) { Error(ErrorCode.ExpectedRightBrace); return; } // Write return (no return expression) Writer.Write(ByteCode.Return, 0); // Check for undefined labels foreach (var labelInfo in function.Labels.GetKeyValuePairs()) { if (labelInfo.Value.IP == null) { Error(ErrorCode.LabelNotDefined, labelInfo.Key.MakeQuoted()); return; } } CurrentFunction = null; } break; } }
// defaultはリファレンスに説明が書いてないので書かない /// <summary> /// Function.ClassNameのみ対応 /// </summary> /// <param name="id"></param> /// <param name="toolTip"></param> /// <param name="_default"></param> /// <param name="function">Function.ClassNameを指定すること</param> public Literal(string id, string toolTip, string _default, Function?function = MinteaCore.SnippetGenerator.Function.ClassName) { Initialize(id, toolTip, _default); Function = function; FunctionValue = string.Empty; }
protected Message(FrameHeader header, MessageType?type = null, Function?function = null) { Header = header; Type = type; Function = function; }
public void Execute(string function) { // get the current function Function?currentFunction = null; foreach (Function f in _functions) { if (f.Name == function) { currentFunction = f; break; } } if (currentFunction.HasValue == false) { throw new ArgumentException("Function not found: " + function); } int instructionPtr = 0; byte[] code = currentFunction.Value.Code; uint codeOffset = currentFunction.Value.CodeOffset; while (instructionPtr < code.Length) { byte op = code[instructionPtr++]; int param; Parameter[] functionParams; switch (op) { case 0x00: // SitnSpin // do nothing break; case 0x02: // CallSysFunctionV param = getIntFromBytes(code, ref instructionPtr); functionParams = buildParameterArray(); SheepMachine.CallVoidSystemFunction(Imports[param].Name, functionParams); _state.PushStack(0); break; case 0x03: // CallSysFunctionI param = getIntFromBytes(code, ref instructionPtr); functionParams = buildParameterArray(); _state.PushStack(SheepMachine.CallIntSystemFunction(Imports[param].Name, functionParams)); break; case 0x05: // CallSysFunctionS param = getIntFromBytes(code, ref instructionPtr); functionParams = buildParameterArray(); SheepMachine.CallStringSystemFunction(Imports[param].Name, functionParams); _state.PushString(0); break; case 0x06: // Branch param = getIntFromBytes(code, ref instructionPtr); instructionPtr = param - (int)codeOffset; break; case 0x08: // BranchIfZero param = getIntFromBytes(code, ref instructionPtr); if (_state.PeekStack().Type != ParameterType.Integer) { throw new InvalidOperationException("stack is bad"); } if (_state.PopStack().Integer == 0) { instructionPtr = param - (int)codeOffset; } break; case 0x09: // BeginWait // do nothing break; case 0x0A: // EndWait // do nothing break; case 0x0B: // ReturnV return; case 0x13: // PushI param = getIntFromBytes(code, ref instructionPtr); _state.PushStack(param); break; case 0x15: // PushS param = getIntFromBytes(code, ref instructionPtr); _state.PushString(param); break; case 0x16: // Pop _state.PopStack(); break; case 0x21: // IsEqualI if (_state.PeekStack().Type != ParameterType.Integer || _state.PeekStack().Type != ParameterType.Integer) { throw new InvalidOperationException("IsLessI found two non-integers on the stack"); } if (_state.PopStack().Integer == _state.PopStack().Integer) { _state.PushStack(1); } else { _state.PushStack(0); } break; case 0x27: // IsLessI if (_state.PeekStack().Type != ParameterType.Integer || _state.PeekStack().Type != ParameterType.Integer) { throw new InvalidOperationException("IsLessI found two non-integers on the stack"); } if (_state.PopStack().Integer >= _state.PopStack().Integer) { _state.PushStack(1); } else { _state.PushStack(0); } break; case 0x2D: param = getIntFromBytes(code, ref instructionPtr); _state.PushStack((float)param); break; case 0x30: // do nothing break; case 0x31: // do nothing break; case 0x33: // GetString { if (_state.PeekStack().Type != ParameterType.String) { throw new InvalidOperationException("GetString failed because value on stack isn't a string"); } param = _state.PopStack().Integer; Parameter p = new Parameter(); p.Type = ParameterType.String; p.Integer = param; p.String = Constants[_constantOffsetIndexMap[param]]; _state.PushStack(p); } break; default: throw new NotImplementedException("Instruction " + op.ToString("X") + " not implemented"); } } return; }