-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCompilerUnit.pas
168 lines (129 loc) · 5.69 KB
/
CompilerUnit.pas
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
unit CompilerUnit;
//TODO: Ñäåëàòü íîðìàëüíî try..except, try..finally
//TODO: Ñäåëàòü çíàêè + äëÿ char è string
//TODO: Ðåàëèçîâàòü ïåðå÷èñëèìûé òèï
// type Months = (January,February,March,April,May,June,July,August,September,October,November,December);
uses
PABCSystem,
System,
System.IO,
System.Collections,
System.Collections.Generic,
ASemanticTree,
ASyntaxTree,
ScannerUnit,
SyntaxAnalyze,
TreeConverter,
CodeGen,
CommonUnit;
const
LibSource = 'LibSource';
var
Scanner: GScanner;
Parser: GParser;
Converter: GConverter;
CodeGenerator: GCodeGenerator;
type
Compiler = class
private
procedure CompilerMessage(msg: string);
function GetSyntaxTree(UnitName: string; Dir: string): UnitTree;
public
function Compile(OutputProc: MessageProc): boolean;
end;
procedure Compiler.CompilerMessage(msg: string);
begin
OutputProc(new MessageInfo(msg));
end;
/// ôóíêöèÿ êîòîðóþ âûçûâàåò ñåìàíòè÷åñêèé àíàëèçàòîð äëÿ çàãðóçêè â íåãî ñèíòàêñè÷åñêîãî äåðåâî íóæíîãî ìîäóëÿ
function Compiler.GetSyntaxTree(UnitName: string; Dir: string): UnitTree;
begin
// Ãäå áóäåì èñêàòü Unit
var UnitSearchPaths := new List<string>;
UnitSearchPaths.Add(Dir); // Ïàïêà ãäå ëåæèò ôàéë â êîòîðîì âêëþ÷åí äàííûé Unit
UnitSearchPaths.Add(Path.Combine(Path.GetDirectoryName(GetEXEFilename), LibSource));
UnitSearchPaths.Add(Environment.CurrentDirectory); // òåêóùàÿ ïàïêà
UnitSearchPaths.Add(Path.GetDirectoryName(GetEXEFilename)); // ãäå íàõîäèòñÿ ñàì êîìïèëÿòîð
foreach s: string in UnitSearchPaths do
begin
var fname := Path.Combine(s, UnitName + '.pas');
if &File.Exists(fname) then
begin
var scan := new GScanner(fname, Options.DefineList);
var pars := new GParser(scan.Tokens, fname);
Result := (pars.SyntaxTree as UnitTree);
end;
end;
if not (Result is UnitTree) then Result := nil;
end;
function Compiler.Compile(OutputProc: MessageProc): boolean;
begin
{$UNDEF NOTDEBUG}
{$IFDEF NOTDEBUG}
// try
{$ENDIF}
Result := true;
CommonUnit.OutputProc := OutputProc;
&File.Delete(Options.OutFile);
CompilerMessage(Format('Ñòàðò êîìïèëÿöèè "{0}"...', Path.GetFileName(Options.SourceFile)));
// Êîìïèëÿòîð ðàáîòàåò â 4 ïðîõîäà:
// Ëåêñè÷åñêèé àíàëèç. Íà ýòîì ýòàïå ïîñëåäîâàòåëüíîñòü ñèìâîëîâ èñõîäíîãî ôàéëà ïðåîáðàçóåòñÿ â ïîñëåäîâàòåëüíîñòü ëåêñåì.
// Âûïîëíÿåò åù¸ ôóíêöèè ïðåïðîöåññîðà
var startCompileTime := Milliseconds;
Scanner := new GScanner(Options.SourceFile, Options.DefineList);
var ScanTime := Milliseconds - startCompileTime;
// Ñèíòàêñè÷åñêèé (ãðàììàòè÷åñêèé) àíàëèç. Ïîñëåäîâàòåëüíîñòü ëåêñåì ïðåîáðàçóåòñÿ â äåðåâî ðàçáîðà.
Parser := new GParser(Scanner.Tokens, Options.SourceFile);
var ParsTime := Milliseconds - (ScanTime + startCompileTime);
// Ñåìàíòè÷åñêèé àíàëèç. Äåðåâî ðàçáîðà îáðàáàòûâàåòñÿ ñ öåëüþ óñòàíîâëåíèÿ åãî ñåìàíòèêè (ñìûñëà)
Converter := new GConverter(Parser.SyntaxTree, GetSyntaxTree);
var TreeConvertTime := Milliseconds - (ScanTime + startCompileTime + ParsTime);
// Ãåíåðàöèÿ êîäà. Èç ñåìàíòè÷åñêîãî äåðåâà ïîðîæäàåòñÿ MSIL êîä.
if (Converter.SemanticTree is SUnitTree) then raise new Exception('îæèäàëàñü ïðîãðàììà èëè áèáëèîòåêà, à íå ìîäóëü.');
CodeGenerator := new GCodeGenerator(Options.OutFile, Converter.SemanticTree);
var CodeGenTime := Milliseconds - (ScanTime + startCompileTime + ParsTime + TreeConvertTime);
var CompileTime := Milliseconds - startCompileTime;
// ===========================================================================
CompilerMessage(Format('Êîìïèëÿöèÿ "{0}" çàâåðøåíà óñïåøíî.', Path.GetFileName(Options.SourceFile)));
CompilerMessage(' ÂÐÅÌß ÐÀÁÎÒÛ ');
CompilerMessage(Format('1.Ñêàíèðîâàíèå è ïðåïðîöåññîð :{0} ìñ ({1:f2}%)', ScanTime, (ScanTime / CompileTime) * 100));
CompilerMessage(Format('2.Ïàðñèíã :{0} ìñ ({1:f2}%)', ParsTime, (ParsTime / CompileTime) * 100));
CompilerMessage(Format('3.Êîíâåðòèðîâàíèå äåðåâà è îïòèìèçàöèÿ :{0} ìñ ({1:f2}%)', TreeConvertTime, (TreeConvertTime / CompileTime) * 100));
CompilerMessage(Format('4.Êîäîãåíåðàöèÿ :{0} ìñ ({1:f2}%)', CodeGenTime, (CodeGenTime / CompileTime) * 100));
CompilerMessage(Format(' Îáùåå âðåìÿ ðàáîòû ïðîãðàììû :{0} ìñ', CompileTime));
{$IFDEF NOTDEBUG}
{* except
on e: Exception do
begin
Result := False;
if e is ScannerException then
begin
var exp := (e as ScannerException);
OutputProc(new MessageInfo( string.Format('[{0},{1}] SCANNER_ERROR: {2}: {3}', exp.Loc.BeginLine, exp.Loc.BeginColumn, exp.Loc.FileName, exp.Message), Error, exp.Loc));
end
else
if e is ParserException then
begin
var exp := (e as ParserException);
OutputProc( new MessageInfo( string.Format('[{0},{1}] PARSER_ERROR: {2}', exp.Loc.BeginLine, exp.Loc.BeginColumn, exp.Message), Error, exp.Loc));
end
else
if e is SemanticException then
begin
var exp := (e as SemanticException);
OutputProc( new MessageInfo( string.Format('[{0},{1}] SEMANTIC_ERROR: {2}', exp.Loc.BeginLine, exp.Loc.BeginColumn, exp.Message), Error, exp.Loc));
end
else
if e is CodeGenException then
begin
var exp := (e as CodeGenException);
OutputProc( new MessageInfo( string.Format('[{0},{1}] CODEGEN_ERROR: {2}', exp.Loc.BeginLine, exp.Loc.BeginColumn, exp.Message), Error, exp.Loc));
end
else OutputProc( new MessageInfo( string.Format('UNKNOWN_ERROR: {0}', e.Message)));
end;
end;
*}
{$ENDIF}
end;
begin
end.