2024-04-20 22:23:29 +08:00
|
|
|
|
using Canon.Console.Models;
|
|
|
|
|
using Canon.Core.Abstractions;
|
|
|
|
|
using Canon.Core.LexicalParser;
|
2024-04-30 15:04:58 +08:00
|
|
|
|
using Canon.Core.SemanticParser;
|
2024-04-20 22:23:29 +08:00
|
|
|
|
using Canon.Core.SyntaxNodes;
|
|
|
|
|
using Microsoft.Extensions.Hosting;
|
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
|
|
|
|
|
|
namespace Canon.Console.Services;
|
|
|
|
|
|
|
|
|
|
public class Compiler(
|
|
|
|
|
CompilerOption compilerOption,
|
|
|
|
|
ILexer lexer,
|
|
|
|
|
IGrammarParser grammarParser,
|
2024-04-30 15:04:58 +08:00
|
|
|
|
SyntaxTreeTraveller traveller,
|
2024-04-20 22:23:29 +08:00
|
|
|
|
IHostApplicationLifetime applicationLifetime,
|
|
|
|
|
ILogger<Compiler> logger) : IHostedService
|
|
|
|
|
{
|
|
|
|
|
public async Task StartAsync(CancellationToken cancellationToken)
|
|
|
|
|
{
|
|
|
|
|
IEnumerable<SemanticToken> tokens = lexer.Tokenize(await CreateSourceReader());
|
|
|
|
|
ProgramStruct root = grammarParser.Analyse(tokens);
|
|
|
|
|
|
2024-04-30 15:04:58 +08:00
|
|
|
|
CCodeGenerateVisitor visitor = new();
|
|
|
|
|
traveller.Travel(root, visitor);
|
2024-04-20 22:23:29 +08:00
|
|
|
|
|
2024-04-30 15:04:58 +08:00
|
|
|
|
await WriteToOutputFile(visitor.Builder.Build());
|
2024-04-20 22:23:29 +08:00
|
|
|
|
applicationLifetime.StopApplication();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task StopAsync(CancellationToken cancellationToken)
|
|
|
|
|
{
|
|
|
|
|
return Task.CompletedTask;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task<ISourceReader> CreateSourceReader()
|
|
|
|
|
{
|
|
|
|
|
if (!Path.IsPathRooted(compilerOption.SourceFilename))
|
|
|
|
|
{
|
|
|
|
|
compilerOption.SourceFilename = Path.Combine(Environment.CurrentDirectory, compilerOption.SourceFilename);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
logger.LogDebug("Select source file: '{}'.", compilerOption.SourceFilename);
|
|
|
|
|
|
|
|
|
|
FileInfo sourceFile = new(compilerOption.SourceFilename);
|
|
|
|
|
using StreamReader reader = sourceFile.OpenText();
|
|
|
|
|
|
|
|
|
|
return new StringSourceReader(await reader.ReadToEndAsync());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task WriteToOutputFile(string compiledCode)
|
|
|
|
|
{
|
2024-04-30 15:04:58 +08:00
|
|
|
|
FileInfo outputFile = new(Path.Combine(Path.GetDirectoryName(compilerOption.SourceFilename)!,
|
2024-04-20 22:23:29 +08:00
|
|
|
|
Path.GetFileNameWithoutExtension(compilerOption.SourceFilename) + ".c"));
|
|
|
|
|
logger.LogDebug("Select output file: '{}'.", outputFile.Name);
|
|
|
|
|
|
|
|
|
|
if (outputFile.Exists)
|
|
|
|
|
{
|
|
|
|
|
logger.LogWarning("Rewrite output file : '{}'", outputFile.Name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await using StreamWriter writer = outputFile.CreateText();
|
|
|
|
|
await writer.WriteAsync(compiledCode);
|
|
|
|
|
}
|
|
|
|
|
}
|