public Result Parse(List <Token> tokens, Compiler.Settings settings = null) { if (settings == null) { settings = new Compiler.Settings(); } this.Tokens = tokens; this.CurrentIndex = 0; this.CurrentLine = 0; Result result = new Result(); this.Errors = result.Messages; while (!IsAtEnd()) { SkipWhitespace(); try { if (ConsumeIfType(out Token classToken, TokenType.KeywordClass)) { SkipWhitespace(); result.Classes.Add(ParseClassStatement(classToken)); } else if (ConsumeIfType(out Token functionKeyword, TokenType.KeywordFunction)) { SkipWhitespace(); result.Functions.Add(ParseSubroutineStatement(functionKeyword)); } else if (ConsumeIfType(out Token globalKeyword, TokenType.KeywordGlobal)) { SkipWhitespace(); Token globalName = ConsumeType(TokenType.Symbol, "Expected a name for the global.", "LSS007"); result.Globals.Add(new GlobalStatement(globalKeyword.Span + globalName.Span, globalName)); ConsumeType(TokenType.Semicolon, "Expected a semicolon after global name.", "LSS008"); } else { Token extra = Consume(); if (extra.Type != TokenType.Whitespace && extra.Type != TokenType.Comment && extra.Type != TokenType.MultilineComment && extra.Type != TokenType.EndOfStream) { Panic("Expected global, class, or function", "LSS009", extra.Span); } } } catch (StatementPanicException) { SynchronizeToStatement(); } SkipWhitespace(); } return(result); }
private static int DoCompile(CLIOptions options) { List <CompileMessage> messages = new List <CompileMessage>(); // Translate CLIOptions into compiler options Compiler.Settings settings = new Compiler.Settings(); settings.EmitLineNumbers = options.EmitLineNumbers; string[] versionNumberParts = options.OSIVersion.Split('.'); if (versionNumberParts.Length == 2) { settings.VersionMajor = Int32.Parse(versionNumberParts[0]); settings.VersionMinor = Int32.Parse(versionNumberParts[1]); } else { messages.Add(new CompileMessage("Invalid OSI version. Version number should be specified like '4.1'.", "LSSC001", CompileMessage.MessageSeverity.Warning, new SourceSpan("", 0, null, 0))); } // Check options.Inputs for directory names, and replace them with the files they contain, considering the option to be recursive List <string> inputs = new List <string>(); foreach (string input in options.Inputs) { if (System.IO.Directory.Exists(input)) { EnumerateDirectory(input, inputs, options.RecurseDirectories); } else if (System.IO.File.Exists(input)) { inputs.Add(input); } } Compiler.Result result = Compiler.CompileFiles(inputs); messages.AddRange(result.Messages); int errorCount = 0; foreach (CompileMessage message in messages) { Console.WriteLine(message.ToString()); if (message.Severity >= CompileMessage.MessageSeverity.Error) { errorCount++; } } if (errorCount > 0) { Console.WriteLine("Finished with " + errorCount + " errors."); return(EXIT_SYNTAX_ERROR); } else { string outputFilename = System.IO.Path.GetFullPath(options.Output == "" ? "./base.osi" : options.Output); if (System.IO.File.Exists(outputFilename) && !options.AllowOverwrite) { Console.WriteLine("Aborted - file '" + outputFilename + "' already exists. (Specify -y to overwrite.)"); return(EXIT_OUTPUT_EXISTS); } else { try { using (System.IO.FileStream stream = new System.IO.FileStream(outputFilename, System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.Read)) using (System.IO.BinaryWriter writer = new System.IO.BinaryWriter(stream)) { result.OSI.Write(writer); } Console.WriteLine("Compiled into '" + outputFilename + "'."); return(EXIT_SUCCESS); } catch (System.IO.IOException exception) { Console.WriteLine("Failed to write result to '" + outputFilename + "': " + exception.ToString()); return(EXIT_IO_ERROR); } } } }