Скачиваний:
12
Добавлен:
01.05.2014
Размер:
21.26 Кб
Скачать
{
C-like language compiler v0.1.0.485

12 november 2007

Copyright (C) 2006, 2007 Igor Krooshch
rheo.ikro@gmail.com

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This program 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
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
}

unit UCcSymbols;

interface

uses
SysUtils, Classes, IniFiles,
UCcSyntaxEntries, UCcCodeGenerator, UCcCodeGeneratorCommands, UCcBuffer;

type
TCcSymType = class;

TCcSymbolClass = class of TCcSymbol;
TCcSymbol = class(TCcSyntaxObject)
private
FName: string;
FIsFake: boolean;
FGenerated: boolean;
procedure SetGenerated(const AValue: boolean);
procedure SetName(const AName: string);
procedure SetIsFake(const AValue: boolean);
public
constructor Create(APosition: TCcPosition); reintroduce;

function Size: integer; virtual;

property IsFake: boolean read FIsFake write SetIsFake;
property Generated: boolean read FGenerated write SetGenerated;
property Name: string read FName write SetName;
end;


TCcSymTable = class
private
FSize: integer;
FList: THashedStringList;
FParent: TCcSymTable;

FSkipGenList: TStringList;

FGenerated: boolean;

FTokenizer: TObject; // for raising exceptions only
FIsParams: boolean;
FOffset: integer;

FRealSize: integer;
FRealCount: integer;

function GetSymbol(AIndex: integer): TCcSymbol;
public
constructor Create(
APosition: TCcPosition; AParent: TCcSymTable; ATokenizer: TObject;
const AIsParams: boolean = false);
destructor Destroy; override;

function Find(
const APosition: TCcPosition;
const AName: string;
const ASymClass: TCcSymbolClass;
const AGlobal: boolean = true;
const AShowError: boolean = true): TCcSymbol;
procedure Add(ASymbol: TCcSymbol; const AFake: boolean = false);

procedure AddSkipGenFunc(const AName: string);

function RealCount: integer;
function RealSize: integer;
function Count: integer;
function Size: integer;

procedure Generate(AGenerator: TObject);

property Generated: boolean read FGenerated write FGenerated;
property Offset: integer read FOffset;
property IsParams: boolean read FIsParams;
property Parent: TCcSymTable read FParent;
property Symbol[AIndex: integer]: TCcSymbol read GetSymbol; default;
end;


PCcSymTableStackRec = type Pointer;

TCcSymTableStack = class
private
FStack: TList;

FTopTable: TCcSymTable;
public
constructor Create(APosition: TCcPosition);
destructor Destroy; override;

procedure Push(ATable: TCcSymTable);
function Pop: TCcSymTable;

function SaveState: PCcSymTableStackRec;
procedure LoadState(AState: PCcSymTableStackRec);

function TopTable: TCcSymTable;
end;


TCcSymVariable = class(TCcSymbol)
private
FValType: TCcSymType;
FValue: TCcExpression;
FOffset: integer;
FTable: TCcSymTable;
public
constructor Create(
APosition: TCcPosition; const AName: string; AVal: TCcSymType;
AValue: TCcExpression = nil; ATable: TCcSymTable = nil);
property ValType: TCcSymType read FValType;
property Value: TCcExpression read FValue;

function Offset: integer;
function Size: integer; override;
function Table: TCcSymTable;

function GenerateLine: string;
end;


TCcSymTypeClass = class of TCcSymType;

TCcSymType = class(TCcSymbol)
public
function IsType(ATypeClass: TCcSymTypeClass): boolean; virtual;
function GetType: TCcSymType; virtual;

function GenerateTypeStr: string; virtual; abstract;
end;

TCcSymTypeScalar = class(TCcSymType);


TCcSymTypePointer = class(TCcSymType)
private
FPtrType: TCcSymType;
public
function GenerateTypeStr: string; override;

constructor Create(APosition: TCcPosition; AValType: TCcSymType);
function Size: Integer; override;

property PtrType: TCcSymType read FPtrType;
end;


TCcSymTypeStr = class(TCcSymTypeScalar)
public
function GenerateTypeStr: string; override;
end;


TCcSymTypeInt = class(TCcSymTypeScalar)
public
function Size: Integer; override;

function GenerateTypeStr: string; override;
end;


TCcSymTypeFloat = class(TCcSymTypeScalar)
public
function Size: Integer; override;
function GenerateTypeStr: string; override;
end;


TCcSymTypeVoid = class(TCcSymType)
public
function GenerateTypeStr: string; override;
end;


TCcSymAlias = class(TCcSymType)
private
FSrcType: TCcSymType;
public
constructor Create(ASrcType: TCcSymType; APosition: TCcPosition); reintroduce;

function IsType(ATypeClass: TCcSymTypeClass): Boolean; override;
function GetType: TCcSymType; override;

function Size: Integer; override;

function GenerateTypeStr: string; override;

property SrcType: TCcSymType read FSrcType;
end;


TCcSymArray = class(TCcSymType)
private
FLength: integer;
FValType: TCcSymType;
FDimension: integer;
FDimSize: integer;

FMaxDim: integer;
public
constructor Create(
APosition: TCcPosition; AValType: TCcSymType; ALength: integer);

function Size: integer; override;

function DimensionSize(ADim: integer): integer;

function GenerateTypeStr: string; override;

property Dimension: integer read FDimension write FDimension;
property Length: integer read FLength;
property ValType: TCcSymType read FValType;

property MaxDim: integer read FMaxDim;
end;


TCcSymStruct = class(TCcSymType)
private
FFields: TCcSymTable;
public
constructor Create(APosition: TCcPosition; AFields: TCcSymTable);
destructor Destroy; override;

function GenerateTypeStr: string; override;
function Size: Integer; override;

property Fields: TCcSymTable read FFields;
end;


TCcSymProc = class(TCcSymbol)
private
FTable: TCcSymTable;
FParams: TCcSymTable;
FBlock: TCcBlockStatement;
public
constructor Create(
APosition: TCcPosition; AParentTable: TCcSymTable;
ATokenizer: TObject); virtual;
destructor Destroy; override;

procedure Generate(AGenerator: TCcCodeGenerator); override;

procedure AddParam(AVar: TCcSymVariable; const AFake: boolean = false);
procedure SetBlock(ABlock: TCcBlockStatement);

property Block: TCcBlockStatement read FBlock;

property Params: TCcSymTable read FParams;
property Table: TCcSymTable read FTable;
end;


TCcSymFunc = class(TCcSymProc)
private
FReturn: TCcSymType;
public
constructor Create(
APosition: TCcPosition; AParentTable: TCcSymTable;
ATokenizer: TObject); override;

procedure SetReturn(AReturn: TCcSymType);

property Return: TCcSymType read FReturn;
end;

var
SymInt: TCcSymTypeInt = nil;
SymFloat: TCcSymTypeFloat = nil;
SymVoid: TCcSymTypeVoid = nil;
SymStr: TCcSymTypeStr = nil;

implementation

uses
UCcTokenizer,
UCcParserConsts, UCcSymanticConsts;


const
POINTER_SIZE = 4;
FUNC_STACK_OFFSET = 8;


{ TCcSymTable }

procedure TCcSymTable.Add(ASymbol: TCcSymbol; const AFake: boolean);
var
s: TCcSymbol;
begin
s := Find(ASymbol.Position, ASymbol.Name, nil, false, false);
if (s <> nil) then
(FTokenizer as TCcTokenizer).ErrorFmt(
SCcParserRedefinitionFmt, [ASymbol.Name]);
if (ASymbol is TCcSymVariable) then begin
TCcSymVariable(ASymbol).FOffset := FSize;
Inc(FSize, TCcSymVariable(ASymbol).Size);
if TCcSymVariable(ASymbol).ValType.IsType(TCcSymTypePointer) then
Inc(FRealSize, 4)
else
Inc(FRealSize, TCcSymVariable(ASymbol).Size);
end;

FList.AddObject(ASymbol.Name, ASymbol);
if not AFake then
Inc(FRealCount)
else
ASymbol.IsFake := true;
end;


procedure TCcSymTable.AddSkipGenFunc(const AName: string);
begin
FSkipGenList.Add(AName);
end;


function TCcSymTable.Count: integer;
begin
Result := FList.Count;
end;


constructor TCcSymTable.Create(
APosition: TCcPosition; AParent: TCcSymTable; ATokenizer: TObject;
const AIsParams: boolean);
begin
inherited Create;
FRealSize := 0;
FRealCount := 0;
FGenerated := false;
FSkipGenList := TStringList.Create;
FSkipGenList.Sorted := true;
FParent := AParent;
FTokenizer := ATokenizer;
FList := THashedStringList.Create;
FList.CaseSensitive := true;
FIsParams := AIsParams;
FOffset := 0;
if
(not IsParams) and (AParent <> nil) and
(not AParent.IsParams) and (AParent.Parent <> nil)
then
FOffset := AParent.Size + AParent.Offset
else if IsParams then
FOffset := FUNC_STACK_OFFSET;
end;


destructor TCcSymTable.Destroy;
var
i: integer;
begin
for i := 0 to FList.Count - 1 do
TObject(FList.Objects[i]).Free;
FList.Free;
FSkipGenList.Free;
inherited;
end;


function TCcSymTable.Find(
const APosition: TCcPosition; const AName: string;
const ASymClass: TCcSymbolClass; const AGlobal: boolean;
const AShowError: boolean): TCcSymbol;
var
i: integer;
begin
Result := nil;
i := FList.IndexOf(AName);
if (i > -1) then begin
Result := TCcSymbol(FList.Objects[i]);
if (ASymClass <> nil) and not (Result is ASymClass) then
if AShowError then
SymanticError(APosition, SCcSymanticIncompatibleTypes)
else begin
Result := nil;
Exit;
end;
end
else
if AGlobal and (Parent <> nil) then
Result := Parent.Find(APosition, AName, ASymClass, true, AShowError);
if (Result = nil) and AShowError then
SymanticError(APosition, SCcSymanticUndefinedType);
end;


procedure TCcSymTable.Generate(AGenerator: TObject);
var
gen: TCcCodeGenerator;
i: integer;
symVar: TCcSymVariable;
sym: TCcSymbol;
ofs: integer;
begin
gen := AGenerator as TCcCodeGenerator;
if Parent = nil then begin
for i := 0 to FList.Count - 1 do begin
sym := TCcSymbol(FList.Objects[i]);
if not sym.Generated then begin
if (sym is TCcSymVariable) then
gen.Gen(TCcSymVariable(sym).GenerateLine, Parent = nil)
else if (sym is TCcSymFunc) then
if FSkipGenList.IndexOf(TCcSymFunc(sym).Name) = -1 then
TCcSymFunc(sym).Generate(gen);
sym.Generated := true;
end;
end;
end
else if not IsParams then begin
if not Generated then begin
(AGenerator as TCcCodeGenerator).Gen(ctSub, 'esp', IntToStr(Size));
Generated := true;
end;
for i := 0 to FList.Count - 1 do begin
sym := TCcSymbol(FList.Objects[i]);
if not sym.Generated then begin
sym.Generated := true;
if FList.Objects[i] is TCcSymVariable then begin
symVar := TCcSymVariable(FList.Objects[i]);
ofs := Offset + symVar.Offset + symVar.Size;
if symVar.Value is TCcSyntaxConstInteger then begin
gen.Gen(ctMov, 'eax', 'ebp');
gen.Gen(ctSub, 'eax', IntToStr(ofs));
gen.Gen(
ctMov, '[eax]',
'dword ptr ' +
IntToStr(TCcSyntaxConstInteger(symVar.Value).Value));
end
else if symVar.Value is TCcSyntaxConstFloat then begin
gen.Gen(ctMov, 'eax', 'ebp');
gen.Gen(ctSub, 'eax', IntToStr(ofs));
symVar.Value.Generate(gen);
gen.Gen(ctPop, 'ebx');
gen.Gen(ctMov, '[eax]', 'ebx');
end;
end;
end;
end;
end;
end;


function TCcSymTable.GetSymbol(AIndex: integer): TCcSymbol;
var
i, ci: integer;
sym: TCcSymbol;
begin
if (AIndex < 0) or (AIndex > RealCount - 1) then
SymanticError(
TCcTokenizer(FTokenizer).Position, SCcSymanticIndexOutOfBounds);
Result := nil;
ci := 0;
for i := 0 to FList.Count - 1 do begin
sym := FList.Objects[i] as TCcSymbol;
if sym.IsFake then
Continue;
if (AIndex = ci) then begin
Result := sym;
Exit;
end
else
Inc(ci);
end;
end;


function TCcSymTable.RealCount: integer;
begin
Result := FRealCount;
end;


function TCcSymTable.RealSize: integer;
begin
Result := FRealSize;
end;


function TCcSymTable.Size: integer;
begin
Result := FSize;
end;


{ TCcSymTableStack }

constructor TCcSymTableStack.Create(APosition: TCcPosition);
begin
FStack := TList.Create;
FTopTable := nil;
end;


destructor TCcSymTableStack.Destroy;
begin
while (FStack.Count > 0) do
Pop;
FStack.Free;
inherited;
end;


procedure TCcSymTableStack.LoadState(AState: PCcSymTableStackRec);
begin
if Integer(AState) > FStack.Count then
SymanticErrorFmt(
CcPosition(0, 0), SCcSymanticInternalErrorFmt, [SCcInternalTS01]);
while (FStack.Count <> Integer(AState)) do
Pop;
end;


function TCcSymTableStack.Pop: TCcSymTable;
begin
if FStack.Count = 0 then
SymanticError(CcPosition(0, 0), SCcSymanticTableStackEmpty);
Result := FStack[FStack.Count - 1];
FStack.Delete(FStack.Count - 1);
if (FStack.Count = 0) then
FTopTable := nil
else
FTopTable := FStack[FStack.Count - 1];
end;


procedure TCcSymTableStack.Push(ATable: TCcSymTable);
begin
FStack.Add(ATable);
FTopTable := ATable;
end;


function TCcSymTableStack.SaveState: PCcSymTableStackRec;
begin
Result := PCcSymTableStackRec(FStack.Count);
end;


function TCcSymTableStack.TopTable: TCcSymTable;
begin
Result := FTopTable;
end;


{ TCcSymArray }

constructor TCcSymArray.Create(
APosition: TCcPosition; AValType: TCcSymType; ALength: integer);
begin
inherited Create(APosition);
FDimension := 0;
FValType := AValType;
if FValType.IsType(TCcSymArray) then
FDimension := TCcSymArray(FValType.GetType).Dimension + 1;
FLength := ALength;
FDimSize := FValType.Size * Length;
FMaxDim := FDimension;
end;


function TCcSymArray.DimensionSize(ADim: integer): integer;
var
vt: TCcSymType;
a: integer;
begin
Result := 0;
if (ADim > Dimension) then
SymanticError(Position, SCcSymanticDimension);

vt := ValType.GetType;
if ValType.IsType(TCcSymTypeScalar) then begin
if (ADim < 1) then
Result := ValType.Size
else
SymanticErrorFmt(
Position, SCcSymanticInternalErrorFmt, [SCcInternalDS01]);

if ADim = 0 then
Result := Result * Length;
end
else begin
a := ADim;
if (a = -1) then
a := 0;
while (TCcSymArray(vt).Dimension > a) do
vt := TCcSymArray(vt).ValType.GetType;
if (ADim > -1) then
Result := TCcSymArray(vt).Size
else
Result := TCcSymArray(vt).ValType.Size;
end;
end;


function TCcSymArray.GenerateTypeStr: string;
begin
Result := Format('db %d dup (?)', [Size]);
end;


function TCcSymArray.Size: Integer;
begin
if (FLength = -1) then
Result := POINTER_SIZE
else
Result := Length * ValType.Size;
end;


{ TCcSymVariable }

constructor TCcSymVariable.Create(
APosition: TCcPosition; const AName: string; AVal: TCcSymType;
AValue: TCcExpression; ATable: TCcSymTable);
begin
FValType := AVal;
FValue := AValue;
FTable := ATable;
SetName(AName);
end;


function TCcSymVariable.GenerateLine: string;
var
s: string;
i: ^LongWord;
f: real;
begin
if (Value <> nil) then begin
if not (Value is TCcSyntaxConst) then
SymanticError(Position, SCcSymanticInitialization);

if (Value is TCcSyntaxConstInteger) then
s := IntToStr((Value as TCcSyntaxConstInteger).Value)
else begin
f := (Value as TCcSyntaxConstFloat).Value;
i := @f;
s := Format('0%sh', [IntToHex(i^, 8)]);
end;
end
else
s := '?';

if ValType.IsType(TCcSymArray) or ValType.IsType(TCcSymStruct) then
Result := Format('%s %s', [FormatVarName(Name), ValType.GenerateTypeStr])
else
Result :=
Format('%s %s %s', [FormatVarName(Name), ValType.GenerateTypeStr, s]);
end;


function TCcSymVariable.Offset: integer;
begin
Result := FOffset;
end;


function TCcSymVariable.Size: Integer;
begin
Result := ValType.Size;
end;


function TCcSymVariable.Table: TCcSymTable;
begin
Result := FTable;
end;


{ TCcSymbol }

constructor TCcSymbol.Create(APosition: TCcPosition);
begin
inherited Create(APosition);
FIsFake := false;
FGenerated := false;
end;


procedure TCcSymbol.SetGenerated(const AValue: boolean);
begin
FGenerated := AValue;
end;


procedure TCcSymbol.SetIsFake(const AValue: boolean);
begin
FIsFake := AValue;
end;


procedure TCcSymbol.SetName(const AName: string);
begin
FName := AName;
end;


function TCcSymbol.Size: integer;
begin
Result := 0;
end;


{ TCcSymProc }

procedure TCcSymProc.AddParam(AVar: TCcSymVariable; const AFake: boolean);
begin
Params.Add(AVar, AFake);
end;


constructor TCcSymProc.Create(
APosition: TCcPosition; AParentTable: TCcSymTable; ATokenizer: TObject);
begin
FParams :=
TCcSymTable.Create(
APosition, AParentTable, ATokenizer as TCcTokenizer, true);
FTable := TCcSymTable.Create(APosition, FParams, ATokenizer as TCcTokenizer);
end;


destructor TCcSymProc.Destroy;
begin
FTable.Free;
FParams.Free;
inherited;
end;


procedure TCcSymProc.Generate(AGenerator: TCcCodeGenerator);
begin
AGenerator.StartProc(Name, Table);
Block.Generate(AGenerator);
AGenerator.EndProc;
end;


procedure TCcSymProc.SetBlock(ABlock: TCcBlockStatement);
begin
FBlock := ABlock;
end;


{ TCcSymTypeInt }

function TCcSymTypeInt.GenerateTypeStr: string;
begin
Result := 'dd ';
end;


function TCcSymTypeInt.Size: Integer;
begin
Result := 4;
end;


{ TCcSymTypeFloat }

function TCcSymTypeFloat.GenerateTypeStr: string;
begin
Result := 'dd ';
end;


function TCcSymTypeFloat.Size: Integer;
begin
Result := 4;
end;


{ TCcSymTypeVoid }

function TCcSymTypeVoid.GenerateTypeStr: string;
begin
Result := '';
end;


{ TCcSymAlias }

constructor TCcSymAlias.Create(ASrcType: TCcSymType; APosition: TCcPosition);
begin
inherited Create(APosition);
FSrcType := ASrcType;
end;


function TCcSymAlias.GenerateTypeStr: string;
begin
Result := SrcType.GenerateTypeStr;
end;


function TCcSymAlias.GetType: TCcSymType;
begin
Result := SrcType;
end;


function TCcSymAlias.IsType(ATypeClass: TCcSymTypeClass): Boolean;
begin
Result := SrcType.IsType(ATypeClass);
end;


function TCcSymAlias.Size: Integer;
begin
Result := SrcType.Size;
end;


{ TCcSymStruct }

constructor TCcSymStruct.Create(APosition: TCcPosition; AFields: TCcSymTable);
begin
FFields := AFields;
end;


destructor TCcSymStruct.Destroy;
begin
FFields.Free;
inherited;
end;


function TCcSymStruct.GenerateTypeStr: string;
begin
Result := Format('db %d dup (?)', [Fields.Size]);
end;


function TCcSymStruct.Size: Integer;
begin
Result := Fields.Size;
end;


{ TCcSymFunc }

constructor TCcSymFunc.Create(
APosition: TCcPosition; AParentTable: TCcSymTable; ATokenizer: TObject);
begin
inherited;
FReturn := SymVoid;
end;


procedure TCcSymFunc.SetReturn(AReturn: TCcSymType);
begin
FReturn := AReturn;
end;


{ TCcSymTypePointer }

constructor TCcSymTypePointer.Create(
APosition: TCcPosition; AValType: TCcSymType);
begin
FPtrType := AValType;
end;


function TCcSymTypePointer.GenerateTypeStr: string;
begin
Result := '';
end;


function TCcSymTypePointer.Size: Integer;
begin
Result := PtrType.Size;
end;


{ TCcSymTypeStr }

function TCcSymTypeStr.GenerateTypeStr: string;
begin
Result := '';
end;


{ TCcSymType }

function TCcSymType.GetType: TCcSymType;
begin
Result := Self;
end;


function TCcSymType.IsType(ATypeClass: TCcSymTypeClass): boolean;
begin
Result := Self is ATypeClass;
end;


initialization
SymInt := TCcSymTypeInt.Create(CcPosition(0, 0));
SymInt.Name := 'int';

SymFloat := TCcSymTypeFloat.Create(CcPosition(0, 0));
SymFloat.Name := 'float';

SymVoid := TCcSymTypeVoid.Create(CcPosition(0, 0));
SymStr := TCcSymTypeStr.Create(CcPosition(0, 0));

finalization
SymStr.Free;
SymVoid.Free;
SymFloat.Free;
SymInt.Free;

end.
Соседние файлы в папке Parser