| 1 | unit ProducerGCC;
|
|---|
| 2 |
|
|---|
| 3 | interface
|
|---|
| 4 |
|
|---|
| 5 | uses
|
|---|
| 6 | SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls,
|
|---|
| 7 | SourceCodePascal, Producer, StrUtils;
|
|---|
| 8 |
|
|---|
| 9 | type
|
|---|
| 10 |
|
|---|
| 11 | { TProducerGCCC }
|
|---|
| 12 |
|
|---|
| 13 | TProducerGCCC = class(TProducer)
|
|---|
| 14 | private
|
|---|
| 15 | function TranslateType(Name: string): string;
|
|---|
| 16 | function TranslateOperator(Name: string): string;
|
|---|
| 17 | procedure Emit(AText: string);
|
|---|
| 18 | procedure EmitLn(AText: string = '');
|
|---|
| 19 | procedure GenerateUses(UsedModules: TUsedModules);
|
|---|
| 20 | procedure GenerateModule(Module: TSourceModule);
|
|---|
| 21 | procedure GenerateCommonBlock(CommonBlock: TCommonBlock;
|
|---|
| 22 | LabelPrefix: string);
|
|---|
| 23 | procedure GenerateType(AType: TType);
|
|---|
| 24 | procedure GenerateTypes(Types: TTypes);
|
|---|
| 25 | procedure GenerateProgram(ProgramBlock: TProgram);
|
|---|
| 26 | procedure GenerateFunctions(Functions: TFunctions;
|
|---|
| 27 | Prefix: string = '');
|
|---|
| 28 | procedure GenerateBeginEnd(BeginEnd: TBeginEnd);
|
|---|
| 29 | procedure GenerateVariableList(VariableList: TVariables);
|
|---|
| 30 | procedure GenerateVariable(Variable: TVariable);
|
|---|
| 31 | procedure GenerateCommand(Command: TCommand);
|
|---|
| 32 | procedure GenerateWhileDo(WhileDo: TWhileDo);
|
|---|
| 33 | procedure GenerateForToDo(ForToDo: TForToDo);
|
|---|
| 34 | procedure GenerateIfThenElse(IfThenElse: TIfThenElse);
|
|---|
| 35 | procedure GenerateAssignment(Assignment: TAssignment);
|
|---|
| 36 | procedure GenerateFunctionCall(FunctionCall: TFunctionCall);
|
|---|
| 37 | function GenerateExpression(Expression: TExpression): string;
|
|---|
| 38 | public
|
|---|
| 39 | TextSource: TStringList;
|
|---|
| 40 | IndentationLength: Integer;
|
|---|
| 41 | Indetation: Integer;
|
|---|
| 42 | procedure AssignToStringList(Target: TStringList); override;
|
|---|
| 43 | procedure Produce(Module: TSourceModule); override;
|
|---|
| 44 | constructor Create;
|
|---|
| 45 | destructor Destroy; override;
|
|---|
| 46 | end;
|
|---|
| 47 |
|
|---|
| 48 |
|
|---|
| 49 | implementation
|
|---|
| 50 |
|
|---|
| 51 | { TProducerGCCC }
|
|---|
| 52 |
|
|---|
| 53 | constructor TProducerGCCC.Create;
|
|---|
| 54 | begin
|
|---|
| 55 | TextSource := TStringList.Create;
|
|---|
| 56 | IndentationLength := 2;
|
|---|
| 57 | {$IFDEF Windows}
|
|---|
| 58 | CompilerPath := 'c:\Program Files\MinGW\bin\gcc.exe -o %1:s';
|
|---|
| 59 | {$ENDIF}
|
|---|
| 60 | {$IFDEF Linux}
|
|---|
| 61 | CompilerPath := '/usr/bin/gcc';
|
|---|
| 62 | {$ENDIF}
|
|---|
| 63 | end;
|
|---|
| 64 |
|
|---|
| 65 | destructor TProducerGCCC.Destroy;
|
|---|
| 66 | begin
|
|---|
| 67 | FreeAndNil(TextSource);
|
|---|
| 68 | inherited;
|
|---|
| 69 | end;
|
|---|
| 70 |
|
|---|
| 71 | function TProducerGCCC.TranslateType(Name: string): string;
|
|---|
| 72 | begin
|
|---|
| 73 | if Name = 'Byte' then Result := 'uint8'
|
|---|
| 74 | else if Name = 'ShortInt' then Result := 'int8'
|
|---|
| 75 | else if Name = 'Word' then Result := 'int16'
|
|---|
| 76 | else if Name = 'SmallInt' then Result := 'int16'
|
|---|
| 77 | else if Name = 'Cardinal' then Result := 'uint32'
|
|---|
| 78 | else if Name = 'Integer' then Result := 'int32'
|
|---|
| 79 | else if Name = 'Void' then Result := 'void'
|
|---|
| 80 | else Result := Name;
|
|---|
| 81 | end;
|
|---|
| 82 |
|
|---|
| 83 | function TProducerGCCC.TranslateOperator(Name: string): string;
|
|---|
| 84 | begin
|
|---|
| 85 | if Name = '=' then Result := '=='
|
|---|
| 86 | else if Name = 'shl' then Result := '<<'
|
|---|
| 87 | else if Name = 'shr' then Result := '>>'
|
|---|
| 88 | else if Name = 'not' then Result := '!'
|
|---|
| 89 | else if Name = 'mod' then Result := '^'
|
|---|
| 90 | else if Name = ':=' then Result := '='
|
|---|
| 91 | else if Name = '@' then Result := '*'
|
|---|
| 92 | else if Name = 'and' then Result := '&'
|
|---|
| 93 | else if Name = 'or' then Result := '|'
|
|---|
| 94 | else if Name = 'xor' then Result := '^'
|
|---|
| 95 | else Result := Name;
|
|---|
| 96 | end;
|
|---|
| 97 |
|
|---|
| 98 | procedure TProducerGCCC.EmitLn(AText: string = '');
|
|---|
| 99 | begin
|
|---|
| 100 | Emit(AText);
|
|---|
| 101 | TextSource.Add('');
|
|---|
| 102 | end;
|
|---|
| 103 |
|
|---|
| 104 | procedure TProducerGCCC.Emit(AText: string);
|
|---|
| 105 | begin
|
|---|
| 106 | with TextSource do begin
|
|---|
| 107 | if Count = 0 then Add('');
|
|---|
| 108 | if Strings[Count - 1] = '' then
|
|---|
| 109 | Strings[Count - 1] := Strings[Count - 1] + DupeString(' ', IndentationLength * Indetation);
|
|---|
| 110 | Strings[Count - 1] := Strings[Count - 1] + AText;
|
|---|
| 111 | end;
|
|---|
| 112 | end;
|
|---|
| 113 |
|
|---|
| 114 | procedure TProducerGCCC.GenerateUses(UsedModules: TUsedModules);
|
|---|
| 115 | var
|
|---|
| 116 | I: Integer;
|
|---|
| 117 | begin
|
|---|
| 118 | for I := 0 to UsedModules.Count - 1 do
|
|---|
| 119 | EmitLn('#include "' + TUsedModule(UsedModules[I]).Name + '.h"');
|
|---|
| 120 | EmitLn;
|
|---|
| 121 | end;
|
|---|
| 122 |
|
|---|
| 123 | procedure TProducerGCCC.GenerateModule(Module: TSourceModule);
|
|---|
| 124 | begin
|
|---|
| 125 | Module.TargetFile := Module.Name + '.c';
|
|---|
| 126 | EmitLn('#include "platform.h"');
|
|---|
| 127 | EmitLn;
|
|---|
| 128 | if Module is TModuleProgram then begin
|
|---|
| 129 | TModuleProgram(Module).Body.Name := 'main';
|
|---|
| 130 | GenerateUses(TModuleProgram(Module).UsedModules);
|
|---|
| 131 | GenerateCommonBlock(TModuleProgram(Module).Body, '');
|
|---|
| 132 | end else
|
|---|
| 133 | if Module is TModuleUnit then begin
|
|---|
| 134 | GenerateUses(TModuleProgram(Module).UsedModules);
|
|---|
| 135 | GenerateCommonBlock(TModuleUnit(Module).Body, '');
|
|---|
| 136 | end;
|
|---|
| 137 | end;
|
|---|
| 138 |
|
|---|
| 139 | procedure TProducerGCCC.Produce(Module: TSourceModule);
|
|---|
| 140 | begin
|
|---|
| 141 | inherited;
|
|---|
| 142 | TextSource.Clear;
|
|---|
| 143 | GenerateModule(Module);
|
|---|
| 144 | end;
|
|---|
| 145 |
|
|---|
| 146 | procedure TProducerGCCC.GenerateProgram(ProgramBlock: TProgram);
|
|---|
| 147 | var
|
|---|
| 148 | I: Integer;
|
|---|
| 149 | begin
|
|---|
| 150 | Indetation := 0;
|
|---|
| 151 | with ProgramBlock do
|
|---|
| 152 | for I := 0 to Modules.Count - 1 do
|
|---|
| 153 | GenerateModule(TSourceModule(Modules[I]));
|
|---|
| 154 | end;
|
|---|
| 155 |
|
|---|
| 156 | procedure TProducerGCCC.GenerateFunctions(Functions: TFunctions;
|
|---|
| 157 | Prefix: string = '');
|
|---|
| 158 | var
|
|---|
| 159 | I: Integer;
|
|---|
| 160 | J: Integer;
|
|---|
| 161 | Line: string;
|
|---|
| 162 | begin
|
|---|
| 163 | for I := 0 to Functions.Count - 1 do
|
|---|
| 164 | with TFunction(Functions[I]) do
|
|---|
| 165 | if not Internal then begin
|
|---|
| 166 | if (FunctionType = ftFunction) and Assigned(ResultType) then
|
|---|
| 167 | Line := TranslateType(ResultType.Name) + ' '
|
|---|
| 168 | else Line := 'void ';
|
|---|
| 169 | Line := Line + Prefix + Name + '(';
|
|---|
| 170 | if Parameters.Count > 0 then
|
|---|
| 171 | for J := 0 to Parameters.Count - 1 do begin
|
|---|
| 172 | Line := Line + TranslateType(TParameter(Parameters[J]).ValueType.Name) +
|
|---|
| 173 | ' ' + TParameter(Parameters[J]).Name;
|
|---|
| 174 | if J < Parameters.Count - 1 then Line := Line + ', ';
|
|---|
| 175 | end;
|
|---|
| 176 | Line := Line + ')';
|
|---|
| 177 | EmitLn(Line);
|
|---|
| 178 | GenerateBeginEnd(Code);
|
|---|
| 179 | EmitLn;
|
|---|
| 180 | end;
|
|---|
| 181 | end;
|
|---|
| 182 |
|
|---|
| 183 | procedure TProducerGCCC.GenerateBeginEnd(BeginEnd: TBeginEnd);
|
|---|
| 184 | var
|
|---|
| 185 | I: Integer;
|
|---|
| 186 | begin
|
|---|
| 187 | EmitLn('{');
|
|---|
| 188 | Inc(Indetation);
|
|---|
| 189 |
|
|---|
| 190 | // Variables
|
|---|
| 191 | if BeginEnd.Parent is TCommonBlock then begin
|
|---|
| 192 | GenerateVariableList(BeginEnd.CommonBlock.Variables);
|
|---|
| 193 | end;
|
|---|
| 194 |
|
|---|
| 195 | // Commands
|
|---|
| 196 | for I := 0 to BeginEnd.Commands.Count - 1 do
|
|---|
| 197 | GenerateCommand(TCommand(BeginEnd.Commands[I]));
|
|---|
| 198 |
|
|---|
| 199 | Dec(Indetation);
|
|---|
| 200 | EmitLn('}');
|
|---|
| 201 | end;
|
|---|
| 202 |
|
|---|
| 203 | procedure TProducerGCCC.GenerateVariableList(VariableList: TVariables);
|
|---|
| 204 | var
|
|---|
| 205 | I: Integer;
|
|---|
| 206 | begin
|
|---|
| 207 | for I := 0 to VariableList.Count - 1 do
|
|---|
| 208 | GenerateVariable(TVariable(VariableList[I]));
|
|---|
| 209 | // EmitLn;
|
|---|
| 210 | end;
|
|---|
| 211 |
|
|---|
| 212 | procedure TProducerGCCC.GenerateVariable(Variable: TVariable);
|
|---|
| 213 | begin
|
|---|
| 214 | with Variable do
|
|---|
| 215 | EmitLn(TranslateType(ValueType.Name) + ' ' + Name + ';');
|
|---|
| 216 | end;
|
|---|
| 217 |
|
|---|
| 218 | procedure TProducerGCCC.GenerateCommand(Command: TCommand);
|
|---|
| 219 | begin
|
|---|
| 220 | if Command is TBeginEnd then GenerateBeginEnd(TBeginEnd(Command))
|
|---|
| 221 | else if Command is TWhileDo then GenerateWhileDo(TWhileDo(Command))
|
|---|
| 222 | else if Command is TForToDo then GenerateForToDo(TForToDo(Command))
|
|---|
| 223 | else if Command is TIfThenElse then GenerateIfThenElse(TIfThenElse(Command))
|
|---|
| 224 | else if Command is TAssignment then GenerateAssignment(TAssignment(Command))
|
|---|
| 225 | else if Command is TFunctionCall then GenerateFunctionCall(TFunctionCall(Command));
|
|---|
| 226 | end;
|
|---|
| 227 |
|
|---|
| 228 | procedure TProducerGCCC.GenerateWhileDo(WhileDo: TWhileDo);
|
|---|
| 229 | begin
|
|---|
| 230 | EmitLn('while (' + GenerateExpression(WhileDo.Condition) + ')');
|
|---|
| 231 | if Assigned(WhileDo.Command) then GenerateCommand(WhileDo.Command);
|
|---|
| 232 | end;
|
|---|
| 233 |
|
|---|
| 234 | procedure TProducerGCCC.GenerateForToDo(ForToDo: TForToDo);
|
|---|
| 235 | begin
|
|---|
| 236 | with ForToDo do begin
|
|---|
| 237 | if Assigned(ControlVariable) then
|
|---|
| 238 | EmitLn('for(' + ControlVariable.Name + ' = ' +
|
|---|
| 239 | GenerateExpression(Start) + '; ' + ControlVariable.Name + ' < ' +
|
|---|
| 240 | GenerateExpression(Stop) + '; ' + ControlVariable.Name + '++)');
|
|---|
| 241 | GenerateCommand(Command);
|
|---|
| 242 | end;
|
|---|
| 243 | end;
|
|---|
| 244 |
|
|---|
| 245 | procedure TProducerGCCC.GenerateIfThenElse(IfThenElse: TIfThenElse);
|
|---|
| 246 | begin
|
|---|
| 247 | EmitLn('if(' + GenerateExpression(IfThenElse.Condition) + ')');
|
|---|
| 248 | GenerateCommand(IfThenElse.Command);
|
|---|
| 249 | if Assigned(IfThenElse.ElseCommand) then begin
|
|---|
| 250 | EmitLn('else ');
|
|---|
| 251 | GenerateCommand(IfThenElse.ElseCommand);
|
|---|
| 252 | end;
|
|---|
| 253 | end;
|
|---|
| 254 |
|
|---|
| 255 | procedure TProducerGCCC.GenerateAssignment(Assignment: TAssignment);
|
|---|
| 256 | begin
|
|---|
| 257 | if Assignment.Target.Name = 'Result' then EmitLn('return(' + GenerateExpression(Assignment.Source) + ');')
|
|---|
| 258 | else EmitLn(Assignment.Target.Name + ' = ' + GenerateExpression(Assignment.Source) + ';');
|
|---|
| 259 | end;
|
|---|
| 260 |
|
|---|
| 261 | procedure TProducerGCCC.GenerateFunctionCall(FunctionCall: TFunctionCall);
|
|---|
| 262 | var
|
|---|
| 263 | Line: string;
|
|---|
| 264 | I: Integer;
|
|---|
| 265 | begin
|
|---|
| 266 | with FunctionCall do begin
|
|---|
| 267 | Line := FunctionRef.Name + '(';
|
|---|
| 268 | if ParameterExpression.Count > 0 then begin
|
|---|
| 269 | for I := 0 to ParameterExpression.Count - 1 do begin
|
|---|
| 270 | Line := Line + GenerateExpression(TExpression(ParameterExpression[I]));
|
|---|
| 271 | if I < ParameterExpression.Count - 1 then Line := Line + ', ';
|
|---|
| 272 | end;
|
|---|
| 273 | end;
|
|---|
| 274 | Line := Line + ');';
|
|---|
| 275 | EmitLn(Line);
|
|---|
| 276 | end;
|
|---|
| 277 | end;
|
|---|
| 278 |
|
|---|
| 279 | function TProducerGCCC.GenerateExpression(Expression: TExpression): string;
|
|---|
| 280 | begin
|
|---|
| 281 | case Expression.NodeType of
|
|---|
| 282 | ntConstant: begin
|
|---|
| 283 | if VarType(Expression.Value) = varString then
|
|---|
| 284 | Result := '"' + Expression.Value + '"'
|
|---|
| 285 | else Result := Expression.Value;
|
|---|
| 286 | end;
|
|---|
| 287 | ntVariable: Result := Expression.Variable.Name;
|
|---|
| 288 | ntFunction: Result := Expression.FunctionCall.FunctionRef.Name;
|
|---|
| 289 | ntOperator: begin
|
|---|
| 290 | Result := GenerateExpression(TExpression(Expression.SubItems.First))
|
|---|
| 291 | + ' ' + TranslateOperator(Expression.OperatorName) + ' ' +
|
|---|
| 292 | GenerateExpression(TExpression(Expression.SubItems.Last));
|
|---|
| 293 | end;
|
|---|
| 294 | ntNone: ;
|
|---|
| 295 | end;
|
|---|
| 296 | end;
|
|---|
| 297 |
|
|---|
| 298 | procedure TProducerGCCC.AssignToStringList(Target: TStringList);
|
|---|
| 299 | begin
|
|---|
| 300 | Target.Assign(TextSource);
|
|---|
| 301 | end;
|
|---|
| 302 |
|
|---|
| 303 | procedure TProducerGCCC.GenerateCommonBlock(CommonBlock: TCommonBlock; LabelPrefix: string);
|
|---|
| 304 | var
|
|---|
| 305 | I: Integer;
|
|---|
| 306 | LabelName: string;
|
|---|
| 307 | begin
|
|---|
| 308 | with CommonBlock do begin
|
|---|
| 309 | GenerateTypes(Types);
|
|---|
| 310 | GenerateFunctions(Functions);
|
|---|
| 311 | EmitLn('void ' + Name + '()');
|
|---|
| 312 | GenerateBeginEnd(Code);
|
|---|
| 313 | end;
|
|---|
| 314 | end;
|
|---|
| 315 |
|
|---|
| 316 | procedure TProducerGCCC.GenerateType(AType: TType);
|
|---|
| 317 | var
|
|---|
| 318 | I: Integer;
|
|---|
| 319 | begin
|
|---|
| 320 | if Assigned(AType) then begin
|
|---|
| 321 | if AType is TTypeRecord then begin
|
|---|
| 322 | EmitLn('struct');
|
|---|
| 323 | EmitLn('{');
|
|---|
| 324 | Inc(Indetation);
|
|---|
| 325 | GenerateVariableList(TTypeRecord(AType).CommonBlock.Variables);
|
|---|
| 326 | Dec(Indetation);
|
|---|
| 327 | EmitLn('} ' + TranslateType(AType.Name) + ';');
|
|---|
| 328 | EmitLn;
|
|---|
| 329 | GenerateFunctions(TTypeRecord(AType).CommonBlock.Functions, AType.Name + '_');
|
|---|
| 330 | end else
|
|---|
| 331 | if AType is TTypeArray then begin
|
|---|
| 332 | GenerateType(TTypeArray(AType).ItemType);
|
|---|
| 333 | EmitLn('* ');
|
|---|
| 334 |
|
|---|
| 335 | (* if Assigned(TTypeArray(AType).IndexType) then begin
|
|---|
| 336 | Emit(AType.Name + '[');
|
|---|
| 337 | Emit('[');
|
|---|
| 338 | GenerateType(TTypeArray(AType).IndexType);
|
|---|
| 339 | Emit(']');
|
|---|
| 340 | end;
|
|---|
| 341 | Emit(' of ');
|
|---|
| 342 | if Assigned(TTypeArray(AType).ItemType) then*)
|
|---|
| 343 | Emit(TranslateType(AType.Name));
|
|---|
| 344 | end else
|
|---|
| 345 | if AType is TTypePointer then begin
|
|---|
| 346 | if Assigned(AType.UsedType) then begin
|
|---|
| 347 | Emit(AType.UsedType.Name);
|
|---|
| 348 | Emit(' *');
|
|---|
| 349 | end;
|
|---|
| 350 | Emit(TranslateType(AType.Name));
|
|---|
| 351 | end else begin
|
|---|
| 352 | if Assigned(AType.UsedType) then begin
|
|---|
| 353 | //GenerateType(AType.UsedType);
|
|---|
| 354 | Emit(AType.UsedType.Name);
|
|---|
| 355 | Emit(' ');
|
|---|
| 356 | end;
|
|---|
| 357 | Emit(TranslateType(AType.Name));
|
|---|
| 358 | end;
|
|---|
| 359 | end;
|
|---|
| 360 | end;
|
|---|
| 361 |
|
|---|
| 362 | procedure TProducerGCCC.GenerateTypes(Types: TTypes);
|
|---|
| 363 | var
|
|---|
| 364 | I: Integer;
|
|---|
| 365 | begin
|
|---|
| 366 | if Types.Count > 0 then begin
|
|---|
| 367 | Inc(Indetation);
|
|---|
| 368 | for I := 0 to Types.Count - 1 do
|
|---|
| 369 | with TType(Types[I]) do
|
|---|
| 370 | if (not Internal) then begin
|
|---|
| 371 | Emit('typedef ');
|
|---|
| 372 | GenerateType(TType(Types[I]));
|
|---|
| 373 | EmitLn(';');
|
|---|
| 374 | end;
|
|---|
| 375 | Dec(Indetation);
|
|---|
| 376 | EmitLn('');
|
|---|
| 377 | end;
|
|---|
| 378 | end;
|
|---|
| 379 |
|
|---|
| 380 | end.
|
|---|