-
Notifications
You must be signed in to change notification settings - Fork 5
/
ProcDeclaration.pas
186 lines (164 loc) · 5.16 KB
/
ProcDeclaration.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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
unit ProcDeclaration;
interface
uses
Classes, Types, CodeElement, DataType, VarDeclaration, Generics.Collections, WriterIntf;
type
TArguments = array of TVarDeclaration;
TProcDeclaration = class(TCodeElement)
private
FResultType: TDataType;
FParameters: TObjectList<TCodeElement>;
FLocals: TObjectList<TCodeElement>;
FStartLine: Integer;
FEndLine: Integer;
FIsDummy: Boolean;
function GetIsFunction: Boolean;
public
constructor Create(const AName: string);
procedure AddResultValue();
procedure AddLocal(AVar: TVarDeclaration);
procedure GetDCPUSource(AWriter: IWriter); override;
function GetElement(AName: string; AType: TCodeElementClass): TCodeElement;
function GetCurrentWordSpaceOfLocals(): Integer;
function ParameterMatches(AProc: TProcDeclaration): Boolean;
function DeclarationMatches(AProc: TProcDeclaration): Boolean;
property IsFunction: Boolean read GetIsFunction;
property ResultType: TDataType read FResultType write FResultType;
property Parameters: TObjectList<TCodeElement> read FParameters;
property Locals: TObjectList<TCodeElement> read FLocals;
property StartLine: Integer read FStartLine write FStartLine;
property EndLine: Integer read FEndLine write FEndLine;
property IsDummy: Boolean read FIsDummy write FIsDummy;
end;
implementation
uses
SysUtils, Optimizer;
{ TProcDeclaration }
{ TProcDeclaration }
procedure TProcDeclaration.AddLocal(AVar: TVarDeclaration);
var
LElement: TCodeElement;
begin
for LElement in FParameters do
begin
if TVarDeclaration(LElement).ParamIndex > 3 then
begin
TVarDeclaration(LElement).ParamIndex := TVarDeclaration(LElement).ParamIndex +1;
end;
end;
for LElement in FLocals do
begin
TVarDeclaration(LElement).ParamIndex := TVarDeclaration(LElement).ParamIndex - AVar.DataType.GetRamWordSize();
end;
AVar.ParamIndex := -1;
FLocals.Add(AVar);
end;
procedure TProcDeclaration.AddResultValue;
begin
AddLocal(TVarDeclaration.Create('Result', ResultType));
end;
constructor TProcDeclaration.Create(const AName: string);
begin
inherited Create(AName);
FParameters := TObjectList<TCodeElement>.Create();
FLocals := TObjectList<TCodeElement>.Create();
FIsDummy := False;
end;
function TProcDeclaration.DeclarationMatches(AProc: TProcDeclaration): Boolean;
begin
Result := SameText(Name, AProc.Name) and (IsFunction = AProc.IsFunction);
if Result then
begin
Result := ParameterMatches(AProc);
end;
end;
function TProcDeclaration.GetCurrentWordSpaceOfLocals: Integer;
var
LElement: TCodeElement;
begin
Result := 0;
for LElement in FLocals do
begin
Result := Result + TVarDeclaration(LElement).DataType.GetRamWordSize();
end;
end;
procedure TProcDeclaration.GetDCPUSource;
begin
if Self.IsDummy then Exit; // a dummy NEVER produces source, but is used by the compiler for ahead declaration
AWriter.Write(':' + Name);
if (FParameters.Count > 3) or (FLocals.Count > 0) then
begin
AWriter.AddMapping(Self, StartLine - Line, False);//mark the entryline of prolog
AWriter.Write('set push, j');
if FLocals.Count > 0 then
begin
AWriter.Write('sub sp, ' + IntToStr(GetCurrentWordSpaceOfLocals()));
end;
AWriter.Write('set j, sp');
end;
inherited GetDCPUSource(AWriter);
AWriter.AddMapping(Self, EndLine - Line, True);//mark the entryline of epilog
if IsFunction and (FLocals.Count > 0) then
begin
AWriter.Write('set a, [' +
TVarDeclaration(GetElement('Result', TVarDeclaration)).GetAccessIdentifier() + ']');
end;
if (FParameters.Count > 3) or (FLocals.Count > 0) then
begin
AWriter.Write('set sp, j');
if FLocals.Count > 0 then
begin
AWriter.Write('add sp, ' + IntToStr(GetCurrentWordSpaceOfLocals()));
end;
AWriter.Write('set j, pop');
end;
AWriter.Write('set pc, pop');
//Result := SimpleOptimizeDCPUCode(Result);
end;
function TProcDeclaration.GetElement(AName: string;
AType: TCodeElementClass): TCodeElement;
var
LElement: TCodeElement;
begin
Result := nil;
for LElement in FParameters do
begin
if SameText(LElement.Name, AName) and LElement.InheritsFrom(AType) then
begin
Result := LElement;
Exit;
end;
end;
for LElement in FLocals do
begin
if SameText(LElement.Name, AName) and LElement.InheritsFrom(AType) then
begin
Result := LElement;
Exit;
end;
end;
if not Assigned(Result) then
begin
Result := inherited;
end;
end;
function TProcDeclaration.GetIsFunction: Boolean;
begin
Result := Assigned(FResultType);
end;
function TProcDeclaration.ParameterMatches(AProc: TProcDeclaration): Boolean;
var
i: Integer;
begin
Result := Parameters.Count = AProc.Parameters.Count;
if Result then
begin
for i := 0 to Parameters.Count - 1 do
begin
Result := SameText(Parameters[i].Name, AProc.Parameters[i].Name)
and (TVarDeclaration(Parameters[i]).DataType = TVarDeclaration(AProc.Parameters[i]).DataType);
if not Result then Break;
end;
end;
end;
end.