summaryrefslogtreecommitdiff
path: root/Compiler/Preprocessor.cs
blob: 01c14abd0b115edb3d01155c7fa103f2969bf331 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
namespace Q1.Compiler;

using System.Text.RegularExpressions;

public static class Preprocessor
{
    private static readonly Dictionary<string, string> Defines = new();

    public static string Process(string filePath)
    {
        List<string> lines = [];
        ProcessFile(filePath, lines, []);
        return string.Join(Environment.NewLine, lines);
    }

    private static void ProcessFile(string filePath, List<string> output, HashSet<string> includeGuard)
    {
        if (includeGuard.Contains(Path.GetFullPath(filePath)))
            return; // prevent recursive includes
        
        includeGuard.Add(Path.GetFullPath(filePath));

        foreach (string rawLine in File.ReadAllLines(filePath))
        {
            string line = rawLine.Trim();

            if (line.StartsWith("#include"))
            {
                // simple format: #include "file"
                Match match = Regex.Match(line, "#include\\s+\"([^\"]+)\"");
                if (match.Success)
                {
                    string includePath = Path.Combine(Path.GetDirectoryName(filePath)!, match.Groups[1].Value);
                    ProcessFile(includePath, output, includeGuard);
                }
                continue;
            }
            else if (line.StartsWith("#define"))
            {
                // simple format: #define NAME VALUE
                Match match = Regex.Match(line, "#define\\s+(\\w+)\\s+(.*)");
                if (match.Success)
                    Defines[match.Groups[1].Value] = match.Groups[2].Value;
                continue;
            }
            else if (line.StartsWith("#load"))
            {
                output.Add(line.Replace("#load", "#.include"));
                continue;
            }

            // expand macros
            foreach (KeyValuePair<string, string> kvp in Defines)
                line = line.Replace(kvp.Key, kvp.Value);

            output.Add(line);
        }
    }
}