using System.Diagnostics; using System.Reflection; using CLI; using Generation.QBE; using Syntax; using Syntax.Parsing; using Syntax.Tokenization; using Syntax.Typing; const string BIN_DIR = "bin"; const string BIN_INT_DIR = "bin-int"; if (Directory.Exists(BIN_DIR)) { Directory.Delete(BIN_DIR, true); } if (Directory.Exists(BIN_INT_DIR)) { Directory.Delete(BIN_INT_DIR, true); } Directory.CreateDirectory(BIN_DIR); Directory.CreateDirectory(BIN_INT_DIR); var error = false; var compilationUnits = new List(); var sourceTexts = new Dictionary(); foreach (var file in args) { if (!File.Exists(file)) { Console.Error.WriteLine($"File '{file}' does not exist"); return 1; } var content = File.ReadAllText(file); var sourceText = new SourceText(file, content); var tokenizeResult = Tokenizer.Tokenize(sourceText); tokenizeResult.PrintAllDiagnostics(); error = error || tokenizeResult.HasErrors; var parseResult = Parser.ParseFile(tokenizeResult.Value); parseResult.PrintAllDiagnostics(); error = error || parseResult.HasErrors; if (parseResult.Value != null) { compilationUnits.Add(parseResult.Value); sourceTexts[parseResult.Value] = sourceText; } } if (error) { return 1; } var definitionTable = new DefinitionTable(compilationUnits); foreach (var compilationUnit in compilationUnits) { var typeCheckResult = TypeChecker.Check(compilationUnit, definitionTable); typeCheckResult.PrintAllDiagnostics(); error = error || typeCheckResult.HasErrors; } if (error) { return 1; } var objectFiles = new List(); foreach (var compilationUnit in compilationUnits) { var relativeFilePath = Path.GetRelativePath(Environment.CurrentDirectory, sourceTexts[compilationUnit].Path); var outputPath = Path.Combine(BIN_INT_DIR, "program", relativeFilePath); var outputDirectory = Path.GetDirectoryName(outputPath); Debug.Assert(!string.IsNullOrWhiteSpace(outputDirectory)); Directory.CreateDirectory(outputDirectory); var ssa = QBEGenerator.Emit(compilationUnit, definitionTable); var ssaPath = Path.ChangeExtension(outputPath, "ssa"); File.WriteAllText(ssaPath, ssa); var asm = await QBE.Invoke(ssa); if (asm == null) { return 1; } var asmPath = Path.ChangeExtension(outputPath, "s"); await File.WriteAllTextAsync(asmPath, asm); var objPath = Path.ChangeExtension(outputPath, "o"); var asmSuccess = await GCC.Assemble(asmPath, objPath); if (!asmSuccess) { return 1; } objectFiles.Add(objPath); } var assembly = Assembly.GetExecutingAssembly(); var runtimeResources = assembly .GetManifestResourceNames() .Where(name => name.EndsWith(".s", StringComparison.OrdinalIgnoreCase)); foreach (var resourceName in runtimeResources) { await using var stream = assembly.GetManifestResourceStream(resourceName); if (stream == null) { Console.Error.WriteLine($"Could not load embedded resource {resourceName}"); return 1; } using var reader = new StreamReader(stream); var asm = await reader.ReadToEndAsync(); var outputDirectory = Path.Combine(BIN_INT_DIR, "runtime"); Directory.CreateDirectory(outputDirectory); var fileName = resourceName.Split('.').Reverse().Skip(1).First(); var asmPath = Path.Combine(outputDirectory, fileName + ".s"); await File.WriteAllTextAsync(asmPath, asm); var objPath = Path.Combine(outputDirectory, fileName + ".o"); var asmSuccess = await GCC.Assemble(asmPath, objPath); if (!asmSuccess) { return 1; } objectFiles.Add(objPath); } var linkSuccess = await GCC.Link(objectFiles, Path.Combine(BIN_DIR, "out")); return linkSuccess ? 0 : 1;