This commit is contained in:
nub31
2025-06-27 15:55:32 +02:00
parent d9027d6751
commit 19c309c494
20 changed files with 159 additions and 232 deletions

View File

@@ -1,6 +1,4 @@
using System.Diagnostics;
using System.Reflection;
using CLI;
using CLI;
using Generation.QBE;
using Syntax;
using Syntax.Diagnostics;
@@ -9,40 +7,22 @@ using Syntax.Tokenization;
using Syntax.Typing;
using Binder = Syntax.Typing.Binder;
const string BIN_DIR = "bin";
const string BIN_INT_DIR = "bin-int";
const string OUT_DIR = "bin-int";
if (Directory.Exists(BIN_DIR))
if (Directory.Exists(OUT_DIR))
{
Directory.Delete(BIN_DIR, true);
Directory.Delete(OUT_DIR, true);
}
if (Directory.Exists(BIN_INT_DIR))
{
Directory.Delete(BIN_INT_DIR, true);
}
Directory.CreateDirectory(BIN_DIR);
Directory.CreateDirectory(BIN_INT_DIR);
var files = new List<string>();
string? runtimePath = null;
foreach (var arg in args)
{
if (arg.StartsWith("-r="))
{
runtimePath = arg.Substring("-r=".Length);
}
else
{
files.Add(arg);
}
files.Add(arg);
}
var diagnostics = new List<Diagnostic>();
var syntaxTrees = new List<SyntaxTree>();
var syntaxTrees = new Dictionary<string, SyntaxTree>();
foreach (var file in files)
{
@@ -61,29 +41,27 @@ foreach (var file in files)
var tokenizeResult = Tokenizer.Tokenize(sourceText, out var tokenizerDiagnostics);
diagnostics.AddRange(tokenizerDiagnostics);
var syntaxTree = Parser.ParseFile(tokenizeResult, file, out var parseDiagnostics);
var syntaxTree = Parser.ParseFile(tokenizeResult, out var parseDiagnostics);
diagnostics.AddRange(parseDiagnostics);
if (syntaxTree != null)
{
syntaxTrees.Add(syntaxTree);
}
else
{
throw new Exception();
syntaxTrees[file] = syntaxTree;
}
}
var definitionTable = new DefinitionTable(syntaxTrees);
var definitionTable = new DefinitionTable(syntaxTrees.Values);
var boundSyntaxTrees = new List<BoundSyntaxTree>();
var boundSyntaxTrees = new Dictionary<string, BoundSyntaxTree>();
foreach (var syntaxTree in syntaxTrees)
foreach (var (file, syntaxTree) in syntaxTrees)
{
boundSyntaxTrees.Add(Binder.Bind(syntaxTree, definitionTable));
var boundSyntaxTree = Binder.Bind(syntaxTree, definitionTable, out var binderDiagnostics);
diagnostics.AddRange(binderDiagnostics);
boundSyntaxTrees[file] = boundSyntaxTree;
}
var boundDefinitionTable = new BoundDefinitionTable(boundSyntaxTrees);
var boundDefinitionTable = new BoundDefinitionTable(boundSyntaxTrees.Values);
foreach (var diagnostic in diagnostics)
{
@@ -97,48 +75,18 @@ if (diagnostics.Any(diagnostic => diagnostic.Severity == DiagnosticSeverity.Erro
var objectFiles = new List<string>();
if (runtimePath == null)
foreach (var file in files)
{
const string RUNTIME_NAME = "libruntime_x64";
await using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(RUNTIME_NAME);
if (stream == null)
{
throw new Exception("Runtime stream is null");
}
var tmpDir = Directory.CreateTempSubdirectory("nub");
runtimePath = Path.Combine(tmpDir.FullName, RUNTIME_NAME + ".a");
await using var writer = new FileStream(runtimePath, FileMode.Create, FileAccess.Write);
await stream.CopyToAsync(writer);
}
objectFiles.Add(runtimePath);
foreach (var boundSyntaxTree in boundSyntaxTrees)
{
var relativeFilePath = Path.GetRelativePath(Environment.CurrentDirectory, boundSyntaxTree.FilePath);
var outputPath = Path.Combine(BIN_INT_DIR, relativeFilePath);
var outputDirectory = Path.GetDirectoryName(outputPath);
Debug.Assert(!string.IsNullOrWhiteSpace(outputDirectory));
Directory.CreateDirectory(outputDirectory);
var ssa = QBEGenerator.Emit(boundSyntaxTree, boundDefinitionTable);
var ssaPath = Path.ChangeExtension(outputPath, "ssa");
File.WriteAllText(ssaPath, ssa);
var ssa = QBEGenerator.Emit(boundSyntaxTrees[file], boundDefinitionTable);
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);
var fileName = $"{Path.GetFileNameWithoutExtension(file)}_{StringRandomizer.GenerateUniqueHexString(8)}.o";
var objPath = Path.Combine(OUT_DIR, fileName);
var asmSuccess = await GCC.Assemble(asm, objPath);
if (!asmSuccess)
{
return 1;
@@ -147,5 +95,28 @@ foreach (var boundSyntaxTree in boundSyntaxTrees)
objectFiles.Add(objPath);
}
var linkSuccess = await GCC.Link(objectFiles, Path.Combine(BIN_DIR, "out"));
return linkSuccess ? 0 : 1;
foreach (var objectFile in objectFiles)
{
Console.Out.WriteLine(objectFile);
}
return 0;
internal static class StringRandomizer
{
private static readonly char[] StringChars = "0123456789abcdef".ToArray();
public static string GenerateUniqueHexString(int length)
{
var rand = new Random();
var hexString = "";
for (var i = 0; i < length; i++)
{
var randIndex = rand.Next(0, StringChars.Length);
hexString += StringChars[randIndex];
}
return hexString;
}
}