public bool Compile(string path, out CompiledProgram program) { Functions = new OrderedDictionary <string, Function>(StringComparer.OrdinalIgnoreCase); Variables = new OrderedDictionary <string, Variable>(StringComparer.OrdinalIgnoreCase); Literals = new List <Variable>(); Lexer = new LexicalAnalyzer(); Lexer.Error += Lexer_Error; Writer = new ByteCodeWriter(Lexer); InHeader = true; CurrentFunction = null; Errors = new List <Error>(); program = null; // Add intrinsic functions to function collection foreach (var function in IntrinsicFunctions.Values) { Functions.Add(function.Name, function); } // Add intrinsic variables to variable collection foreach (var pair in IntrinsicVariables.GetKeyValuePairs()) { Variables.Add(pair.Key, pair.Value); } // Add internal functions and variables if (EnableInternalFunctions) { InternalFunctions.AddInternalFunctionsAndVariables(Functions, Variables); } try { // Load file and initialize lexer Lexer.Reset(File.ReadAllText(path)); // Write bytecodes to call function main. // Also causes error if main function is not defined Writer.Write(OpCode.ExecFunction, GetFunctionId(Function.Main)); // Parse statements while (ParseStatement()) { } // Verify end of file Token token = Lexer.GetNext(); if (token.Type != TokenType.EndOfFile) { Error(ErrorCode.UnexpectedToken, token); } // Check for undefined functions foreach (var funcInfo in Functions.GetKeyValuePairs()) { if (funcInfo.Value == null) { if (funcInfo.Key.Equals(Function.Main, StringComparison.CurrentCultureIgnoreCase)) { Error(ErrorCode.MainNotDefined, Function.Main.MakeQuoted()); } else { Error(ErrorCode.FunctionNotDefined, funcInfo.Key.MakeQuoted()); } } } } catch (TooManyErrorsException) { // Already handled } catch (Exception ex) { Error(ErrorCode.InternalError, ex.Message, ErrorLevel.FatalError); } // Done if compile failed if (Errors.Count > 0) { return(false); } // Implement logging if (CreateLogFile) { Writer.WriteLogFile(path, Path.ChangeExtension(path, "log")); } // Return compiled data program = new CompiledProgram { ByteCodes = Writer.GetBytecodes(), Functions = Functions.Values.Select(f => (f is CompileTimeUserFunction userFunction) ? new UserFunction(userFunction) : f).ToArray(), Variables = Variables.Values.ToArray(), Literals = Literals.ToArray(), LineNumbers = EnableLineNumbers ? Writer.GetLineNumbers() : null, }; return(true); }
/// <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(OpCode.AssignListVariable, GetVariableId(token.Value)); // Parse list index if (!ParseExpression()) { return; } token = Lexer.GetNext(); if (token.Type != TokenType.RightBracket) { Error(ErrorCode.ExpectedRightBracket, token); NextLine(); return; } // Parse equal sign token = Lexer.GetNext(); 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; } Writer.Write(OpCode.Assign, GetVariableId(token.Value)); if (!ParseExpression()) { return; } VerifyEndOfLine(); break; default: if (InFunction) { // Function call int functionId = GetFunctionId(token.Value); Function function = Functions[functionId]; Writer.Write(OpCode.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(OpCode.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; } }