-
Notifications
You must be signed in to change notification settings - Fork 21
/
Program.cs
129 lines (106 loc) · 4.57 KB
/
Program.cs
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/* Copyright 2022 Xingyu Xie
This file is part of CMinor.
CMinor is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
CMinor is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with CMinor. If not, see <https://www.gnu.org/licenses/>. */
using System;
using System.IO;
using System.Collections.Generic;
using Antlr4.Runtime;
using Antlr4.Runtime.Misc;
using CommandLine;
using CommandLine.Text;
namespace cminor
{
/// <summary> 整个验证工具的入口类 </summary>
class Program
{
class Options
{
[Option("source",
Required = true,
HelpText = "The source file of CMinor language (recommended with filename extension '.c').")]
public string sourcePath { get; set; } = default!;
[Option("printCFG",
Required = false,
HelpText = "The file (or 'console') to which the control flow graph is printed.")]
public string? CFGFile { get; set; } = null;
[Usage(ApplicationAlias = "cminor")]
public static IEnumerable<Example> Examples
{
get
{
return new List<Example>()
{
new Example("The simplest usage to compile and verify a pi source file", new Options
{
sourcePath = "<path>"
})
};
}
}
}
/// <summary> 整个验证工具的入口函数 </summary>
static void Main(string[] args)
{
CommandLine.Parser.Default.ParseArguments<Options>(args)
.WithParsed(RunOptions);
}
/// <summary> 整个验证工具的主驱动函数 </summary>
/// <remarks>
/// 返回码的设计是这样的:
/// <list type="bullet">
/// <item> 0 表示验证成功 </item>
/// <item> 1 表示验证失败 </item>
/// <item> 2 表示语义错误 </item>
/// <item> 3 表示语法错误 </item>
/// </list>
/// </remarks>
static void RunOptions(Options opts)
{
try
{
// 首先,我们要生成 cfg!
StreamReader reader = File.OpenText(opts.sourcePath);
AntlrInputStream stream = new AntlrInputStream(reader);
ITokenSource lexer = new CMinorLexer(stream);
ITokenStream tokens = new CommonTokenStream(lexer);
CMinorParser parser = new CMinorParser(tokens);
// 由于现有的 error listener 或者 handler,
// 要么不会终止 parse,要么连行号都不会打印出来……
// 所以我们需要写一个新的 listener!
parser.RemoveErrorListeners();
parser.AddErrorListener(new ThrowingErrorListener());
CMinorParser.MainContext tree = parser.main();
CFGGenerator generator = new CFGGenerator();
IRMain cfg = generator.Apply(tree);
if (opts.CFGFile != null)
{
// 输出 cfg
using (TextWriter writer = opts.CFGFile == "console"
? Console.Out
: new StreamWriter(opts.CFGFile))
{
cfg.Print(writer);
}
}
Verifier verifier = new Verifier(Console.Out);
int result = verifier.Apply(cfg);
if (result > 0) Console.WriteLine("VERIFIED");
else if (result == 0) Console.WriteLine("UNKNOWN");
else if (result < 0) Console.WriteLine("UNVERIFIED");
Environment.Exit(0);
}
catch (ParsingException e)
{
Console.Error.WriteLine($"semantic error: {e.Message}");
Environment.Exit(1);
}
catch (ParseCanceledException e)
{
Console.Error.WriteLine($"syntax error: {e.Message}");
Environment.Exit(1);
}
}
}
}