示例#1
0
文件: Compiler.cs 项目: Ciastex/Silk
        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);
        }
示例#2
0
文件: Compiler.cs 项目: Ciastex/Silk
        /// <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;
            }
        }