{
Этот исходный код является частью проекта ПВТ-ОО.
Copyright © 2021 Малик Разработчик
Это свободная программа: вы можете перераспространять её и/или
изменять её на условиях Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она может быть полезна,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЁННЫХ ЦЕЛЕЙ. Подробнее см. в Стандартной
общественной лицензии GNU.
Вы должны были получить копию Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<http://www.gnu.org/licenses/>.
}
unit ru.malik.elaborarer.avt.generator;
{$MODE DELPHI}
interface
uses
pascalx.lang,
pascalx.io,
pascalx.io.vfs,
pascalx.osapi,
pascalx.utils,
ru.malik.elaborarer.avt.programme,
ru.malik.elaborarer.avt.tree;
{$ASMMODE INTEL,CALLING REGISTER,TYPEINFO ON}
{%region pulic }
type
AVTCodePrinter = class;
AVTCodeGenerator = class;
AVTCodePrinter = class(_Object, Closeable, Output)
private
class function spaces(count: int): AnsiString; static;
private
isLabelPrinted: boolean;
stream: Output;
procedure writeString(const data: AnsiString);
public
constructor create(stream: Output);
procedure close();
procedure flush();
procedure write(data: int); overload;
procedure write(const src: byte_Array1d); overload;
procedure write(const src: byte_Array1d; offset, length: int); overload;
procedure print(const data: AnsiString);
{ На будущее: добавить возможность вывода данных с произвольным отступом слева (сейчас этот отступ фиксирован). }
{ (Отступ измеряется в пробелах) }
procedure printLabel(const name: AnsiString);
procedure printHeader(const data: AnsiString);
procedure printInstruction(const data: AnsiString); overload;
procedure printInstruction(const instr: AnsiString; const operands: array of AnsiString); overload;
procedure printContinuation(const data: AnsiString);
procedure println(); overload;
procedure println(const data: AnsiString); overload;
procedure printlnHeader(const data: AnsiString);
procedure printlnSourceLine(const data: AnsiString);
procedure printlnInstruction(const data: AnsiString); overload;
procedure printlnInstruction(const instr: AnsiString; const operands: array of AnsiString); overload;
procedure printlnContinuation(const data: AnsiString);
end;
AVTCodeGenerator = class(AVTCodeBuilder)
private
class procedure clearDirectory(vfs: WriteableVirtualFileSystem; const dir: UnicodeString); static;
class procedure copyFile(vfs: WriteableVirtualFileSystem; const srcFile, dstFile: UnicodeString); static;
class procedure copyFilesOnly(vfs: WriteableVirtualFileSystem; const srcDir, dstDir: UnicodeString); static;
class procedure copyData(src: Input; dst: Output); static;
class procedure compileImplementors(typeRef, serviceRef: AVTTypeStructured; printer: AVTCodePrinter); static;
class procedure listResourcesInDir(vfs: WriteableVirtualFileSystem; const dir, subDir: UnicodeString; table: Hashtable); static;
class function listResources(vfs: WriteableVirtualFileSystem; const dir: UnicodeString): Hashtable; static;
class function resourceDirToDir(const dir: UnicodeString): UnicodeString; static;
class function resourceDirToPath(const dir: UnicodeString): AnsiString; static;
class function labelNumberToString(prefix: char; labelNumber: int): AnsiString; overload; static;
class function labelNumberToString(labelNumber: int): AnsiString; overload; static;
class function typeNameToSourceName(typeRef: AVTType): AnsiString; static;
class function typeReturnSuffix(typeRef: AVTType): AnsiString; static;
class function avtBooleanValueToString(value: boolean): AnsiString; static;
class function avtIntValueToString(value: int): AnsiString; static;
class function avtByteToString(value: int): AnsiString; static;
class function avtShortToString(value: int): AnsiString; static;
class function avtIntToString(value: int): AnsiString; static;
class function avtLongToString(value: long): AnsiString; static;
class function typeToInstructionName(typeRef: AVTType): AnsiString; static;
class function getImplementorsVector(typeRef: AVTTypeStructured): Vector; static;
private
i2: AVTInt2Storage;
i4: AVTInt4Storage;
i8: AVTInt8Storage;
l: AVTLongStorage;
l2: AVTLong2Storage;
l4: AVTLong4Storage;
l8: AVTLong8Storage;
f: AVTFloatStorage;
f2: AVTFloat2Storage;
f4: AVTFloat4Storage;
f8: AVTFloat8Storage;
d: AVTDoubleStorage;
d2: AVTDouble2Storage;
d4: AVTDouble4Storage;
d8: AVTDouble8Storage;
b2: AVTByte2Storage;
b4: AVTByte4Storage;
b8: AVTByte8Storage;
s2: AVTShort2Storage;
s4: AVTShort4Storage;
s8: AVTShort8Storage;
x: AVTRealStorage;
strings: AVTStringStorage;
debugInfoSources: AVTStringStorage;
debugInfoStrings: AVTStringStorage;
procedure compileProgramme(vfs: WriteableVirtualFileSystem; const progFile: UnicodeString; packList: Vector; resList: Hashtable);
procedure compileProgrammeConstants(vfs: WriteableVirtualFileSystem; const constFile: UnicodeString);
procedure compileProgrammeDebugInfo(vfs: WriteableVirtualFileSystem; const dbinfDir: UnicodeString);
procedure compilePackage(currPackRef, nextPackRef: AVTPackage; vfs: WriteableVirtualFileSystem; const codeDir, dataDir, nativesDir: UnicodeString);
procedure compilePackageData(currPackRef, nextPackRef: AVTPackage; vfs: WriteableVirtualFileSystem; const dataFile: UnicodeString);
procedure compilePrimitiveData(typeRef: AVTTypePrimitive; vfs: WriteableVirtualFileSystem; const dataFile: UnicodeString);
procedure compileClassCode(typeRef: AVTTypeStructured; vfs: WriteableVirtualFileSystem; const codeFile, nativesFile: UnicodeString);
procedure compileClassData(typeRef: AVTTypeStructured; vfs: WriteableVirtualFileSystem; const dataFile: UnicodeString);
procedure compileMethod(methodRef: AVTMethod; printer: AVTCodePrinter);
procedure compileInstructionNode(node: AVTNode; methodRef: AVTMethod; printer: AVTCodePrinter);
function nonStackableTypeToStackable(typeRef: AVTType): AVTType;
public
constructor create(programme: AVTProgramme);
destructor destroy; override;
function generate(vfs: WriteableVirtualFileSystem; const directory: UnicodeString): UnicodeString;
end;
{%endregion}
implementation
{%region AVTCodePrinter }
class function AVTCodePrinter.spaces(count: int): AnsiString;
var
i: int;
s: AnsiString;
begin
s := AnsiString_create(count);
for i := 0 to count - 1 do begin
s[i + 1] := #$20;
end;
result := s;
end;
procedure AVTCodePrinter.writeString(const data: AnsiString);
begin
stream.write(stringToByteArray(data));
end;
constructor AVTCodePrinter.create(stream: Output);
begin
inherited create();
self.stream := stream;
end;
procedure AVTCodePrinter.close();
begin
stream.close();
free();
end;
procedure AVTCodePrinter.flush();
begin
stream.flush();
end;
procedure AVTCodePrinter.write(data: int);
begin
stream.write(data);
end;
procedure AVTCodePrinter.write(const src: byte_Array1d);
begin
stream.write(src);
end;
procedure AVTCodePrinter.write(const src: byte_Array1d; offset, length: int);
begin
stream.write(src, offset, length);
end;
procedure AVTCodePrinter.print(const data: AnsiString);
begin
isLabelPrinted := false;
writeString(data);
end;
procedure AVTCodePrinter.printLabel(const name: AnsiString);
begin
if isLabelPrinted then begin
writeString(LINE_ENDING + ' ' + name + ':' + spaces(intMax(7 - length(name), 1)));
exit;
end;
isLabelPrinted := true;
writeString(' ' + name + ':' + spaces(intMax(7 - length(name), 1)));
end;
procedure AVTCodePrinter.printHeader(const data: AnsiString);
begin
if isLabelPrinted then begin
isLabelPrinted := false;
writeString(LINE_ENDING + ' ' + data + LINE_ENDING);
exit;
end;
writeString(' ' + data);
end;
procedure AVTCodePrinter.printInstruction(const data: AnsiString);
begin
if isLabelPrinted then begin
isLabelPrinted := false;
writeString(data);
exit;
end;
writeString(' ' + data);
end;
procedure AVTCodePrinter.printInstruction(const instr: AnsiString; const operands: array of AnsiString);
var
i: int;
lim: int;
data: AnsiString;
begin
lim := length(operands) - 1;
if lim < 0 then begin
data := instr;
end else begin
data := instr + spaces(intMax(8 - length(instr), 1));
end;
for i := 0 to lim do begin
data := data + operands[i];
if i < lim then data := data + ', ';
end;
printInstruction(data);
end;
procedure AVTCodePrinter.printContinuation(const data: AnsiString);
begin
isLabelPrinted := false;
writeString(' ' + data);
end;
procedure AVTCodePrinter.println();
begin
isLabelPrinted := false;
writeString(LINE_ENDING);
end;
procedure AVTCodePrinter.println(const data: AnsiString);
begin
isLabelPrinted := false;
writeString(data + LINE_ENDING);
end;
procedure AVTCodePrinter.printlnHeader(const data: AnsiString);
begin
if isLabelPrinted then begin
isLabelPrinted := false;
writeString(LINE_ENDING + ' ' + data + LINE_ENDING);
exit;
end;
writeString(' ' + data + LINE_ENDING);
end;
procedure AVTCodePrinter.printlnSourceLine(const data: AnsiString);
begin
if isLabelPrinted then begin
isLabelPrinted := false;
writeString(LINE_ENDING + ' ; ' + data + LINE_ENDING);
exit;
end;
writeString(' ; ' + data + LINE_ENDING);
end;
procedure AVTCodePrinter.printlnInstruction(const data: AnsiString);
begin
if isLabelPrinted then begin
isLabelPrinted := false;
writeString(data + LINE_ENDING);
exit;
end;
writeString(' ' + data + LINE_ENDING);
end;
procedure AVTCodePrinter.printlnInstruction(const instr: AnsiString; const operands: array of AnsiString);
var
i: int;
lim: int;
data: AnsiString;
begin
lim := length(operands) - 1;
if lim < 0 then begin
data := instr;
end else begin
data := instr + spaces(intMax(8 - length(instr), 1));
end;
for i := 0 to lim do begin
data := data + operands[i];
if i < lim then data := data + ', ';
end;
printlnInstruction(data);
end;
procedure AVTCodePrinter.printlnContinuation(const data: AnsiString);
begin
isLabelPrinted := false;
writeString(' ' + data + LINE_ENDING);
end;
{%endregion}
{%region AVTCodeGenerator }
class procedure AVTCodeGenerator.clearDirectory(vfs: WriteableVirtualFileSystem; const dir: UnicodeString);
var
dirs: Vector;
files: Vector;
enum: FileEnumeration;
name: UnicodeString;
begin
dirs := nil;
files := nil;
try
enum := vfs.findFirst(dir);
if enum <> nil then begin
try
repeat
if enum.isDirectory() then begin
if dirs = nil then dirs := Vector.create();
dirs.append(ValueOfUnicodeString.create(enum.getName()));
end else begin
if files = nil then files := Vector.create();
files.append(ValueOfUnicodeString.create(enum.getName()));
end;
until not enum.findNext();
finally
enum.close();
end;
if files <> nil then with files.elements() do while hasMoreElements() do begin
vfs.deleteFile(dir + nextElement().unicodeStringValue());
end;
if dirs <> nil then with dirs.elements() do while hasMoreElements() do begin
name := dir + nextElement().unicodeStringValue();
clearDirectory(vfs, name + '/');
vfs.deleteDirectory(name);
end;
end;
finally
dirs.free();
files.free();
end;
end;
class procedure AVTCodeGenerator.copyFile(vfs: WriteableVirtualFileSystem; const srcFile, dstFile: UnicodeString);
var
src: Input;
dst: Output;
begin
src := vfs.openFileForReading(srcFile);
try
dst := vfs.createFile(dstFile);
try
copyData(src, dst);
finally
dst.close();
end;
finally
src.close();
end;
end;
class procedure AVTCodeGenerator.copyFilesOnly(vfs: WriteableVirtualFileSystem; const srcDir, dstDir: UnicodeString);
var
name: UnicodeString;
enum: FileEnumeration;
begin
enum := vfs.findFirst(srcDir);
if enum <> nil then begin
try
repeat
if not enum.isDirectory() then begin
name := enum.getName();
copyFile(vfs, srcDir + name, dstDir + name);
end;
until not enum.findNext();
finally
enum.close();
end;
end;
end;
class procedure AVTCodeGenerator.copyData(src: Input; dst: Output);
var
length: int;
buffer: byte_Array1d;
begin
buffer := byte_Array1d_create($0800);
repeat
length := src.read(buffer);
if length <= 0 then break;
dst.write(buffer, 0, length);
until false;
end;
class procedure AVTCodeGenerator.compileImplementors(typeRef, serviceRef: AVTTypeStructured; printer: AVTCodePrinter);
label
label0;
var
i: int;
vindex: int;
methodName: AnsiString;
classMethod: AVTMethod;
serviceMethod: AVTMethod;
classRef: AVTTypeStructured;
found: TObject;
begin
printer.println();
printer.printlnHeader('impl ' + typeRef.fasmArgumentName + ', ' + serviceRef.fasmArgumentName + ' ; <fold ' + serviceRef.fullName + '>');
for i := 0 to serviceRef.serviceMethodsCount - 1 do begin
classMethod := nil;
serviceMethod := serviceRef.serviceMethod[i];
methodName := serviceMethod.simpleName;
classRef := typeRef;
repeat
with classRef.members(methodName) do while hasMoreElements() do begin
found := nextElement().objectValue();
if (found is AVTMethod) and ((found = serviceMethod) or AVTMethod(found).isOverride(serviceMethod)) then begin
classMethod := AVTMethod(found);
goto label0;
end;
end;
classRef := classRef.extends();
until classRef = nil;
with typeRef.implements() do while hasMoreElements() do begin
classRef := nextElement().objectValue() as AVTTypeStructured;
with classRef.members(methodName) do while hasMoreElements() do begin
found := nextElement().objectValue();
if (found is AVTMethod) and ((found = serviceMethod) or AVTMethod(found).isOverride(serviceMethod)) then begin
classMethod := AVTMethod(found);
goto label0;
end;
end;
end;
label0:
vindex := classMethod.virtualIndex;
if vindex >= 0 then begin
printer.printlnInstruction('jumpvirtual', [classMethod.fasmFullName, avtIntToString(vindex)]);
end else begin
printer.printlnInstruction('jumpspecial', [classMethod.fasmFullName]);
end;
end;
printer.printlnHeader('; </fold>');
end;
class procedure AVTCodeGenerator.listResourcesInDir(vfs: WriteableVirtualFileSystem; const dir, subDir: UnicodeString; table: Hashtable);
var
name: UnicodeString;
list: Vector;
enum: FileEnumeration;
begin
list := nil;
enum := vfs.findFirst(dir + subDir);
if enum <> nil then begin
try
repeat
name := enum.getName();
if enum.isDirectory() then begin
listResourcesInDir(vfs, dir, subDir + name + '/', table);
end else
if not stringEndsWith(UnicodeString('.avt'), stringToLowerCase(name)) then begin
if list = nil then begin
list := Vector.create();
table.put(ValueOfUnicodeString.create(subDir), ValueOfObject.create(list));
end;
list.append(ValueOfUnicodeString.create(name));
end;
until not enum.findNext();
finally
enum.close();
end;
end;
end;
class function AVTCodeGenerator.listResources(vfs: WriteableVirtualFileSystem; const dir: UnicodeString): Hashtable;
var
table: Hashtable;
begin
table := Hashtable.create();
listResourcesInDir(vfs, dir, '', table);
result := table;
end;
class function AVTCodeGenerator.resourceDirToDir(const dir: UnicodeString): UnicodeString;
var
len: int;
begin
len := length(dir);
if len <= 0 then begin
result := '';
exit;
end;
result := stringReplace(stringCopy(dir, 1, len), '/', '.');
end;
class function AVTCodeGenerator.resourceDirToPath(const dir: UnicodeString): AnsiString;
begin
result := stringToUTF8(UnicodeString('/') + stringReplace(dir, '.', '/'));
end;
class function AVTCodeGenerator.labelNumberToString(prefix: char; labelNumber: int): AnsiString;
begin
if (labelNumber >= 0) and (labelNumber <= $0fff) then begin
result := '.' + prefix + '.' + stringToUpperCase(intToHexString((labelNumber shr 8) and $0f) + intToHexString((labelNumber shr 4) and $0f) + intToHexString(labelNumber and $0f));
exit;
end;
result := '.' + prefix + '.' + stringToUpperCase(intToHexString(labelNumber));
end;
class function AVTCodeGenerator.labelNumberToString(labelNumber: int): AnsiString;
begin
result := labelNumberToString('L', labelNumber);
end;
class function AVTCodeGenerator.typeNameToSourceName(typeRef: AVTType): AnsiString;
var
dim: int;
begin
if typeRef is AVTTypeArray then begin
dim := AVTTypeArray(typeRef).dimensionsCount;
result := AVTTypeArray(typeRef).cellType.simpleName + '.' + char(int('0') + (dim div 10)) + char(int('0') + (dim mod 10)) + 'd.inc';
exit;
end;
result := typeRef.simpleName + '.inc';
end;
class function AVTCodeGenerator.typeReturnSuffix(typeRef: AVTType): AnsiString;
begin
if typeRef.isVoid() then begin
result := '';
exit;
end;
if typeRef.isDword() then begin
result := 'd';
exit;
end;
if typeRef.isQword() then begin
result := 'q';
exit;
end;
if typeRef.isTword() then begin
result := 't';
exit;
end;
if typeRef.isXword() then begin
result := 'x';
exit;
end;
if typeRef.isYword() then begin
result := 'y';
exit;
end;
if typeRef.isZword() then begin
result := 'z';
exit;
end;
result := 'r';
end;
class function AVTCodeGenerator.avtBooleanValueToString(value: boolean): AnsiString;
begin
if value then begin
result := 'true';
exit;
end;
result := 'false';
end;
class function AVTCodeGenerator.avtIntValueToString(value: int): AnsiString;
begin
if value >= 0 then begin
result := avtIntToString(value);
exit;
end;
result := '-' + avtIntToString(-value);
end;
class function AVTCodeGenerator.avtByteToString(value: int): AnsiString;
var
i: int;
s: AnsiString;
begin
s := intToHexString(value and $ff);
for i := length(s) + 1 to 2 do s := '0' + s;
result := '$' + s;
end;
class function AVTCodeGenerator.avtShortToString(value: int): AnsiString;
var
i: int;
s: AnsiString;
begin
s := intToHexString(value and $ffff);
for i := length(s) + 1 to 4 do s := '0' + s;
result := '$' + s;
end;
class function AVTCodeGenerator.avtIntToString(value: int): AnsiString;
var
i: int;
s: AnsiString;
begin
s := intToHexString(value);
for i := length(s) + 1 to 8 do s := '0' + s;
result := '$' + s;
end;
class function AVTCodeGenerator.avtLongToString(value: long): AnsiString;
var
i: int;
s: AnsiString;
begin
s := longToHexString(value);
for i := length(s) + 1 to 16 do s := '0' + s;
result := '$' + s;
end;
class function AVTCodeGenerator.typeToInstructionName(typeRef: AVTType): AnsiString;
begin
if typeRef is AVTTypeStructured then begin
result := 'r';
exit;
end;
if typeRef is AVTTypePrimitive then begin
case AVTTypePrimitive(typeRef).primitiveKind of
AVT_CHAR: result := 'c';
AVT_REAL: result := 'x';
AVT_BOOLEAN,
AVT_BYTE: result := 'b';
AVT_BYTE2: result := 'b2';
AVT_BYTE4: result := 'b4';
AVT_BYTE8: result := 'b8';
AVT_SHORT: result := 's';
AVT_SHORT2: result := 's2';
AVT_SHORT4: result := 's4';
AVT_SHORT8: result := 's8';
AVT_INT: result := 'i';
AVT_INT2: result := 'i2';
AVT_INT4: result := 'i4';
AVT_INT8: result := 'i8';
AVT_LONG: result := 'l';
AVT_LONG2: result := 'l2';
AVT_LONG4: result := 'l4';
AVT_LONG8: result := 'l8';
AVT_FLOAT: result := 'f';
AVT_FLOAT2: result := 'f2';
AVT_FLOAT4: result := 'f4';
AVT_FLOAT8: result := 'f8';
AVT_DOUBLE: result := 'd';
AVT_DOUBLE2: result := 'd2';
AVT_DOUBLE4: result := 'd4';
AVT_DOUBLE8: result := 'd8';
end;
exit;
end;
result := '';
end;
class function AVTCodeGenerator.getImplementorsVector(typeRef: AVTTypeStructured): Vector;
var
v: Vector;
begin
v := Vector.create();
if typeRef.isClass() or typeRef.isService() and not typeRef.isAbstract() then begin
if typeRef.isService() then begin
v.append(ValueOfObject.create(typeRef, false));
end;
with typeRef.implements() do while hasMoreElements() do begin
v.append(ValueOfObject.create(nextElement().objectValue(), false));
end;
end;
result := v;
end;
procedure AVTCodeGenerator.compileProgramme(vfs: WriteableVirtualFileSystem; const progFile: UnicodeString; packList: Vector; resList: Hashtable);
var
resFold: UnicodeString;
resPath: AnsiString;
resDir: AnsiString;
resName: AnsiString;
packName: AnsiString;
packRef: AVTPackage;
typeRef: AVTType;
printer: AVTCodePrinter;
resKey: Value;
begin
printer := AVTCodePrinter.create(vfs.createFile(progFile));
try
printer.println('include "format.inc"');
printer.println();
printer.println('include "macro.inc"');
printer.println();
printer.println('include "chapter.code.inc"');
printer.println();
printer.printlnHeader('code$begin: ; <fold code>');
printer.printlnInstruction('call', ['ctx$createMainContext']);
printer.printlnInstruction('call', ['platform.dependent.Startup$main$']);
printer.printlnInstruction('call', ['ctx$destroyMainContext']);
printer.printlnInstruction('include', ['"code/context.inc"']);
printer.printlnInstruction('include', ['"code/subject.inc"']);
printer.printlnInstruction('include', ['"code/instruction.inc"']);
with packList.elements() do while hasMoreElements() do begin
packRef := nextElement().objectValue() as AVTPackage;
packName := packRef.fullName;
if length(packName) <= 0 then begin
packName := 'system.package';
end;
with packRef.types() do while hasMoreElements() do begin
typeRef := nextElement().objectValue() as AVTType;
if typeRef is AVTTypeStructured then begin
printer.printlnInstruction('include', ['"code/' + packName + '/' + typeNameToSourceName(typeRef) + '"']);
end;
end;
end;
printer.printlnHeader('code$end: ; </fold>');
printer.println();
printer.println('include "chapter.data.inc"');
printer.println();
printer.printlnHeader('data$begin: ; <fold data>');
with packList.elements() do while hasMoreElements() do begin
packRef := nextElement().objectValue() as AVTPackage;
packName := packRef.fullName;
if length(packName) <= 0 then begin
packName := 'system.package';
end;
printer.printlnInstruction('include', ['"data/' + packName + '/$package.inc"']);
with packRef.types() do while hasMoreElements() do begin
printer.printlnInstruction('include', ['"data/' + packName + '/' + typeNameToSourceName(nextElement().objectValue() as AVTType) + '"']);
end;
end;
printer.printlnHeader('data$end: ; </fold>');
printer.println();
printer.println('include "chapter.debuginfo.inc"');
printer.println();
printer.printlnHeader('debuginfo$begin: ; <fold debug info>');
printer.printlnInstruction('dbinfob', ['"AVTC ' + AVTC_VERSION + ' [' + stringReplace({$I %DATE%}, '/', '-') + ']"']);
printer.printlnInstruction('include', ['"dbinf/strings.inc"']);
printer.printlnInstruction('include', ['"dbinf/sources.inc"']);
printer.printlnInstruction('include', ['"dbinf/entries.inc"']);
printer.printlnHeader('debuginfo$end: ; </fold>');
printer.println();
printer.println('include "chapter.resource.inc"');
printer.println();
printer.printlnHeader('resources$begin: ; <fold resources>');
with resList.keys() do while hasMoreElements() do begin
resKey := nextElement();
resFold := resKey.unicodeStringValue();
resPath := resourceDirToPath(resFold);
resDir := stringToUTF8(resourceDirToDir(resFold));
if length(resFold) > 0 then begin
resDir := resDir + '/';
end;
with (resList.get(resKey).objectValue() as Vector).elements() do while hasMoreElements() do begin
resName := nextElement().ansiStringValue();
printer.printlnInstruction('avtresource', ['"' + resPath + resName + '"', '"rsrc/' + resDir + resName + '"']);
end;
end;
printer.printlnInstruction('endresource');
printer.printlnHeader('resources$end: ; </fold>');
printer.println();
printer.println('include "chapter.const.inc"');
printer.println();
printer.printlnHeader('; <fold constants>');
printer.printlnInstruction('include', ['"const/instruction.inc"']);
printer.printlnInstruction('include', ['"const/programme.inc"']);
printer.printlnInstruction('include', ['"const/context.inc"']);
printer.printlnHeader('; </fold>');
printer.println();
printer.println('include "chapter.end.inc"');
finally
printer.close();
end;
end;
procedure AVTCodeGenerator.compileProgrammeConstants(vfs: WriteableVirtualFileSystem; const constFile: UnicodeString);
var
i: int;
j: int;
count: int;
value: AVTValue;
printer: AVTCodePrinter;
begin
printer := AVTCodePrinter.create(vfs.createFile(constFile));
try
printer.println('; <fold programme''s constants>');
with value do begin
printer.printlnHeader('; <fold int2>');
printer.printlnInstruction('dalign', [avtByteToString($10)]);
printer.printLabel('i2');
with i2 do begin
count := length;
for i := 0 to count - 1 do begin
asInt2 := itemAt(i);
printer.printlnInstruction('dd', [avtIntToString(asInt8[0]), avtIntToString(asInt8[1])]);
end;
end;
if count <= 0 then printer.println();
printer.printlnHeader('; </fold>');
printer.println();
printer.printlnHeader('; <fold int4>');
printer.printlnInstruction('dalign', [avtByteToString($10)]);
printer.printLabel('i4');
with i4 do begin
count := length;
for i := 0 to count - 1 do begin
asInt4 := itemAt(i);
printer.printlnInstruction('dd', [
avtIntToString(asInt8[0]), avtIntToString(asInt8[1]), avtIntToString(asInt8[2]), avtIntToString(asInt8[3])
]);
end;
end;
if count <= 0 then printer.println();
printer.printlnHeader('; </fold>');
printer.println();
printer.printlnHeader('; <fold int8>');
printer.printlnInstruction('dalign', [avtByteToString($20)]);
printer.printLabel('i8');
with i8 do begin
count := length;
for i := 0 to count - 1 do begin
asInt8 := itemAt(i);
printer.printlnInstruction('dd', [
avtIntToString(asInt8[0]), avtIntToString(asInt8[1]), avtIntToString(asInt8[2]), avtIntToString(asInt8[3]),
avtIntToString(asInt8[4]), avtIntToString(asInt8[5]), avtIntToString(asInt8[6]), avtIntToString(asInt8[7])
]);
end;
end;
if count <= 0 then printer.println();
printer.printlnHeader('; </fold>');
printer.println();
printer.printlnHeader('; <fold long>');
printer.printlnInstruction('dalign', [avtByteToString($10)]);
printer.printLabel('l');
with l do begin
count := length;
for i := 0 to count - 1 do begin
asLong := itemAt(i);
printer.printlnInstruction('dq', [avtLongToString(asLong8[0])]);
end;
end;
if count <= 0 then printer.println();
printer.printlnHeader('; </fold>');
printer.println();
printer.printlnHeader('; <fold long2>');
printer.printlnInstruction('dalign', [avtByteToString($10)]);
printer.printLabel('l2');
with l2 do begin
count := length;
for i := 0 to count - 1 do begin
asLong2 := itemAt(i);
printer.printlnInstruction('dq', [avtLongToString(asLong8[0]), avtLongToString(asLong8[1])]);
end;
end;
if count <= 0 then printer.println();
printer.printlnHeader('; </fold>');
printer.println();
printer.printlnHeader('; <fold long4>');
printer.printlnInstruction('dalign', [avtByteToString($20)]);
printer.printLabel('l4');
with l4 do begin
count := length;
for i := 0 to count - 1 do begin
asLong4 := itemAt(i);
printer.printlnInstruction('dq', [
avtLongToString(asLong8[0]), avtLongToString(asLong8[1]), avtLongToString(asLong8[2]), avtLongToString(asLong8[3])
]);
end;
end;
if count <= 0 then printer.println();
printer.printlnHeader('; </fold>');
printer.println();
printer.printlnHeader('; <fold long8>');
printer.printlnInstruction('dalign', [avtByteToString($40)]);
printer.printLabel('l8');
with l8 do begin
count := length;
for i := 0 to count - 1 do begin
asLong8 := itemAt(i);
printer.printlnInstruction('dq', [
avtLongToString(asLong8[0]), avtLongToString(asLong8[1]), avtLongToString(asLong8[2]), avtLongToString(asLong8[3]),
avtLongToString(asLong8[4]), avtLongToString(asLong8[5]), avtLongToString(asLong8[6]), avtLongToString(asLong8[7])
]);
end;
end;
if count <= 0 then printer.println();
printer.printlnHeader('; </fold>');
printer.println();
printer.printlnHeader('; <fold float>');
printer.printlnInstruction('dalign', [avtByteToString($10)]);
printer.printLabel('f');
with f do begin
count := length;
for i := 0 to count - 1 do begin
asFloat := itemAt(i);
printer.printlnInstruction('dd', [avtIntToString(asInt8[0])]);
end;
end;
if count <= 0 then printer.println();
printer.printlnHeader('; </fold>');
printer.println();
printer.printlnHeader('; <fold float2>');
printer.printlnInstruction('dalign', [avtByteToString($10)]);
printer.printLabel('f2');
with f2 do begin
count := length;
for i := 0 to count - 1 do begin
asFloat2 := itemAt(i);
printer.printlnInstruction('dd', [avtIntToString(asInt8[0]), avtIntToString(asInt8[1])]);
end;
end;
if count <= 0 then printer.println();
printer.printlnHeader('; </fold>');
printer.println();
printer.printlnHeader('; <fold float4>');
printer.printlnInstruction('dalign', [avtByteToString($10)]);
printer.printLabel('f4');
with f4 do begin
count := length;
for i := 0 to count - 1 do begin
asFloat4 := itemAt(i);
printer.printlnInstruction('dd', [
avtIntToString(asInt8[0]), avtIntToString(asInt8[1]), avtIntToString(asInt8[2]), avtIntToString(asInt8[3])
]);
end;
end;
if count <= 0 then printer.println();
printer.printlnHeader('; </fold>');
printer.println();
printer.printlnHeader('; <fold float8>');
printer.printlnInstruction('dalign', [avtByteToString($20)]);
printer.printLabel('f8');
with f8 do begin
count := length;
for i := 0 to count - 1 do begin
asFloat8 := itemAt(i);
printer.printlnInstruction('dd', [
avtIntToString(asInt8[0]), avtIntToString(asInt8[1]), avtIntToString(asInt8[2]), avtIntToString(asInt8[3]),
avtIntToString(asInt8[4]), avtIntToString(asInt8[5]), avtIntToString(asInt8[6]), avtIntToString(asInt8[7])
]);
end;
end;
if count <= 0 then printer.println();
printer.printlnHeader('; </fold>');
printer.println();
printer.printlnHeader('; <fold double>');
printer.printlnInstruction('dalign', [avtByteToString($10)]);
printer.printLabel('d');
with d do begin
count := length;
for i := 0 to count - 1 do begin
asDouble := itemAt(i);
printer.printlnInstruction('dq', [avtLongToString(asLong8[0])]);
end;
end;
if count <= 0 then printer.println();
printer.printlnHeader('; </fold>');
printer.println();
printer.printlnHeader('; <fold double2>');
printer.printlnInstruction('dalign', [avtByteToString($10)]);
printer.printLabel('d2');
with d2 do begin
count := length;
for i := 0 to count - 1 do begin
asDouble2 := itemAt(i);
printer.printlnInstruction('dq', [avtLongToString(asLong8[0]), avtLongToString(asLong8[1])]);
end;
end;
if count <= 0 then printer.println();
printer.printlnHeader('; </fold>');
printer.println();
printer.printlnHeader('; <fold double4>');
printer.printlnInstruction('dalign', [avtByteToString($20)]);
printer.printLabel('d4');
with d4 do begin
count := length;
for i := 0 to count - 1 do begin
asDouble4 := itemAt(i);
printer.printlnInstruction('dq', [
avtLongToString(asLong8[0]), avtLongToString(asLong8[1]), avtLongToString(asLong8[2]), avtLongToString(asLong8[3])
]);
end;
end;
if count <= 0 then printer.println();
printer.printlnHeader('; </fold>');
printer.println();
printer.printlnHeader('; <fold double8>');
printer.printlnInstruction('dalign', [avtByteToString($40)]);
printer.printLabel('d8');
with d8 do begin
count := length;
for i := 0 to count - 1 do begin
asDouble8 := itemAt(i);
printer.printlnInstruction('dq', [
avtLongToString(asLong8[0]), avtLongToString(asLong8[1]), avtLongToString(asLong8[2]), avtLongToString(asLong8[3]),
avtLongToString(asLong8[4]), avtLongToString(asLong8[5]), avtLongToString(asLong8[6]), avtLongToString(asLong8[7])
]);
end;
end;
if count <= 0 then printer.println();
printer.printlnHeader('; </fold>');
printer.println();
printer.printlnHeader('; <fold byte2>');
printer.printlnInstruction('dalign', [avtByteToString($10)]);
printer.printLabel('b2');
with b2 do begin
count := length;
for i := 0 to count - 1 do begin
asByte2 := itemAt(i);
printer.printlnInstruction('db', [avtByteToString(asByte8[0]), avtByteToString(asByte8[1])]);
end;
end;
if count <= 0 then printer.println();
printer.printlnHeader('; </fold>');
printer.println();
printer.printlnHeader('; <fold byte4>');
printer.printlnInstruction('dalign', [avtByteToString($10)]);
printer.printLabel('b4');
with b4 do begin
count := length;
for i := 0 to count - 1 do begin
asByte4 := itemAt(i);
printer.printlnInstruction('db', [
avtByteToString(asByte8[0]), avtByteToString(asByte8[1]), avtByteToString(asByte8[2]), avtByteToString(asByte8[3])
]);
end;
end;
if count <= 0 then printer.println();
printer.printlnHeader('; </fold>');
printer.println();
printer.printlnHeader('; <fold byte8>');
printer.printlnInstruction('dalign', [avtByteToString($10)]);
printer.printLabel('b8');
with b8 do begin
count := length;
for i := 0 to count - 1 do begin
asByte8 := itemAt(i);
printer.printlnInstruction('db', [
avtByteToString(asByte8[0]), avtByteToString(asByte8[1]), avtByteToString(asByte8[2]), avtByteToString(asByte8[3]),
avtByteToString(asByte8[4]), avtByteToString(asByte8[5]), avtByteToString(asByte8[6]), avtByteToString(asByte8[7])
]);
end;
end;
if count <= 0 then printer.println();
printer.printlnHeader('; </fold>');
printer.println();
printer.printlnHeader('; <fold short2>');
printer.printlnInstruction('dalign', [avtByteToString($10)]);
printer.printLabel('s2');
with s2 do begin
count := length;
for i := 0 to count - 1 do begin
asShort2 := itemAt(i);
printer.printlnInstruction('dw', [avtShortToString(asShort8[0]), avtShortToString(asShort8[1])]);
end;
end;
if count <= 0 then printer.println();
printer.printlnHeader('; </fold>');
printer.println();
printer.printlnHeader('; <fold short4>');
printer.printlnInstruction('dalign', [avtByteToString($10)]);
printer.printLabel('s4');
with s4 do begin
count := length;
for i := 0 to count - 1 do begin
asShort4 := itemAt(i);
printer.printlnInstruction('dw', [
avtShortToString(asShort8[0]), avtShortToString(asShort8[1]), avtShortToString(asShort8[2]), avtShortToString(asShort8[3])
]);
end;
end;
if count <= 0 then printer.println();
printer.printlnHeader('; </fold>');
printer.println();
printer.printlnHeader('; <fold short8>');
printer.printlnInstruction('dalign', [avtByteToString($10)]);
printer.printLabel('s8');
with s8 do begin
count := length;
for i := 0 to count - 1 do begin
asShort8 := itemAt(i);
printer.printlnInstruction('dw', [
avtShortToString(asShort8[0]), avtShortToString(asShort8[1]), avtShortToString(asShort8[2]), avtShortToString(asShort8[3]),
avtShortToString(asShort8[4]), avtShortToString(asShort8[5]), avtShortToString(asShort8[6]), avtShortToString(asShort8[7])
]);
end;
end;
if count <= 0 then printer.println();
printer.printlnHeader('; </fold>');
printer.println();
printer.printlnHeader('; <fold real>');
printer.printlnInstruction('dalign', [avtByteToString($10)]);
printer.printLabel('x');
with x do begin
count := length;
for i := 0 to count - 1 do begin
asReal := itemAt(i);
printer.printlnInstruction('dw', [
avtShortToString(asShort8[0]), avtShortToString(asShort8[1]), avtShortToString(asShort8[2]), avtShortToString(asShort8[3]),
avtShortToString(asShort8[4])
]);
end;
end;
if count <= 0 then printer.println();
printer.printlnHeader('; </fold>');
printer.println();
printer.printlnHeader('; <fold string descriptor>');
printer.printlnInstruction('dalign', [avtByteToString($10)]);
printer.printLabel('string');
with strings do begin
count := length;
for i := 0 to count - 1 do begin
asString := itemAt(i);
printer.printlnInstruction('dd', [avtIntToString(system.length(asString)), 'st' + avtIntToString(i) + '-($-$04)']);
end;
if count <= 0 then printer.println();
printer.printlnHeader('; </fold>');
printer.println();
printer.printlnHeader('; <fold string content>');
printer.printlnInstruction('dalign', [avtByteToString($10)]);
for i := 0 to count - 1 do begin
asString := itemAt(i);
printer.printLabel('st' + avtIntToString(i));
for j := 0 to system.length(asString) - 1 do begin
if (j and $0f) = 0 then begin
printer.println();
printer.printInstruction('dw', [avtShortToString(int(asString[j + 1]))]);
end else begin
printer.print(', ' + avtShortToString(int(asString[j + 1])));
end;
end;
printer.println();
end;
end;
printer.printlnHeader('; </fold>');
end;
printer.println('; </fold>');
finally
printer.close();
end;
end;
procedure AVTCodeGenerator.compileProgrammeDebugInfo(vfs: WriteableVirtualFileSystem; const dbinfDir: UnicodeString);
var
i: int;
j: int;
len: int;
inst: AnsiString;
typn: AnsiString;
meth: AnsiString;
srcn: AnsiString;
astr: AnsiString;
ustr: UnicodeString;
printer: AVTCodePrinter;
strings: AVTStringStorage;
typeRef: AVTType;
memberRef: TObject;
methodRef: AVTMethod;
source: AVTSource;
begin
printer := AVTCodePrinter.create(vfs.createFile(dbinfDir + 'strings.inc'));
try
strings := debugInfoStrings;
printer.println('; <fold programme''s debug info>');
printer.printlnHeader('; <fold strings>');
printer.printLabel('debuginfo$string');
printer.println();
for i := 0 to strings.length - 1 do begin
astr := stringToUTF8(strings[i]);
if not stringStartsWith('<', astr) or not stringEndsWith('>', astr) then begin
printer.printlnInstruction('dstr', [astr]);
end else begin
printer.printlnInstruction('dstrs', [stringCopy(astr, 2, length(astr))]);
end;
end;
printer.printLabel('.end');
printer.printlnHeader('; </fold>');
printer.println('; </fold>');
finally
printer.close();
end;
printer := AVTCodePrinter.create(vfs.createFile(dbinfDir + 'sources.inc'));
try
strings := debugInfoSources;
printer.println('; <fold programme''s debug info>');
printer.printlnHeader('; <fold sources>');
printer.printlnInstruction('dalign', [avtByteToString($02)]);
printer.printLabel('debuginfo$source');
printer.println();
for i := 0 to strings.length - 1 do begin
astr := 'avt' + avtIntToString(i);
ustr := strings[i];
len := length(ustr);
printer.printInstruction('dsrc', [astr]);
for j := 0 to len - 1 do begin
if (j and 7) > 0 then begin
printer.print(', ');
end else begin
printer.println(', \');
printer.printContinuation('');
end;
printer.print(avtShortToString(int(ustr[j + 1])));
end;
printer.println();
end;
printer.printLabel('.end');
printer.printlnHeader('; </fold>');
printer.println('; </fold>');
finally
printer.close();
end;
printer := AVTCodePrinter.create(vfs.createFile(dbinfDir + 'entries.inc'));
try
printer.println('; <fold programme''s debug info>');
printer.printlnHeader('; <fold code regions>');
printer.printlnInstruction('dalign', [avtByteToString($20)]);
printer.printLabel('debuginfo$entry');
printer.println();
with programme.packages() do while hasMoreElements() do with (nextElement().objectValue() as AVTPackage).types() do while hasMoreElements() do begin
typeRef := nextElement().objectValue() as AVTType;
typn := typeRef.fasmFullName;
source := typeRef.source;
if typeRef is AVTTypeStructured then with AVTTypeStructured(typeRef).members() do while hasMoreElements() do begin
memberRef := nextElement().objectValue();
if not(memberRef is AVTMethod) then continue;
methodRef := AVTMethod(memberRef);
if methodRef.isAbstract() then continue;
astr := methodRef.simpleName;
meth := methodRef.fasmFullName;
if source = nil then begin
ustr := '';
end else begin
ustr := source.simpleName;
end;
if not stringStartsWith('<', astr) or not stringEndsWith('>', astr) then begin
inst := 'dent';
end else begin
inst := 'dents';
astr := stringCopy(astr, 2, length(astr));
end;
srcn := avtIntToString(strings.indexOf(ustr));
len := methodRef.getDebugInfoLength();
if len <= 0 then begin
printer.printlnInstruction(inst, [meth, meth + '.D.END', 'avt' + srcn, '0', typn, astr]);
continue;
end;
j := 1;
for i := 0 to len - 1 do begin
if j < len then begin
printer.printlnInstruction(inst, [meth + labelNumberToString('D', i), meth + labelNumberToString('D', j), 'avt' + srcn, intToString(methodRef.getDebugInfoLineNumber(i)), typn, astr]);
end else begin
printer.printlnInstruction(inst, [meth + labelNumberToString('D', i), meth + '.D.END', 'avt' + srcn, intToString(methodRef.getDebugInfoLineNumber(i)), typn, astr]);
end;
inc(j);
end;
end;
end;
printer.printLabel('.end');
printer.printlnHeader('; </fold>');
printer.println('; </fold>');
finally
printer.close();
end;
end;
procedure AVTCodeGenerator.compilePackage(currPackRef, nextPackRef: AVTPackage; vfs: WriteableVirtualFileSystem; const codeDir, dataDir, nativesDir: UnicodeString);
var
typ: AVTType;
fileName: UnicodeString;
begin
with currPackRef.types() do while hasMoreElements() do begin
typ := nextElement().objectValue() as AVTType;
fileName := stringToUTF16(typeNameToSourceName(typ));
if typ is AVTTypeStructured then begin
compileClassCode(AVTTypeStructured(typ), vfs, codeDir + fileName, nativesDir + fileName);
compileClassData(AVTTypeStructured(typ), vfs, dataDir + fileName);
end else
if typ is AVTTypePrimitive then begin
compilePrimitiveData(AVTTypePrimitive(typ), vfs, dataDir + fileName);
end;
end;
compilePackageData(currPackRef, nextPackRef, vfs, dataDir + '$package.inc');
end;
procedure AVTCodeGenerator.compilePackageData(currPackRef, nextPackRef: AVTPackage; vfs: WriteableVirtualFileSystem; const dataFile: UnicodeString);
var
fullName: AnsiString;
packName: AnsiString;
types: Vector;
printer: AVTCodePrinter;
begin
fullName := currPackRef.fullName;
if length(fullName) <= 0 then begin
packName := 'system.package';
end else begin
packName := fullName;
end;
types := nil;
printer := AVTCodePrinter.create(vfs.createFile(dataFile));
try
types := Vector.create();
with currPackRef.types() do while hasMoreElements() do begin
types.append(ValueOfObject.create(nextElement().objectValue(), false));
end;
printer.println('; package ' + packName + ' (data)');
printer.println();
printer.printlnHeader('package ' + packName);
printer.printlnInstruction('dd', [avtIntToString(FLAG_PUBLIC) + ' ; modifiers']);
printer.printlnInstruction('dd', [avtIntToString(strings.indexAcquire(fullName)) + ' ; full name index']);
printer.printlnInstruction('dd', [avtIntToString(0) + ' ; reserved field']);
printer.printlnInstruction('dd', [avtIntToString(0) + ' ; reserved field']);
printer.printlnInstruction('dd', [avtIntToString(types.size()) + ' ; types quantity']);
printer.printlnInstruction('dd', [avtIntToString(0) + ' ; reserved field']);
printer.printlnInstruction('dd', [avtIntToString(0) + ' ; reserved field']);
printer.printlnInstruction('dd', [avtIntToString(0) + ' ; reserved field']);
printer.printlnInstruction('dd', ['-.package+.this', avtIntToString(0), avtIntToString(0), avtIntToString(0)]);
if nextPackRef <> nil then begin
printer.printlnInstruction('dq', ['-.package+' + nextPackRef.fullName + ' ; next package']);
end else begin
printer.printlnInstruction('dq', [avtLongToString(0) + ' ; next package']);
end;
printer.printlnInstruction('dq', [avtLongToString(0) + ' ; reserved field']);
printer.printlnInstruction('dq', [avtLongToString(0) + ' ; reserved field']);
printer.printlnInstruction('dq', [avtLongToString(0) + ' ; reserved field']);
printer.printLabel('.this');
with types.elements() do while hasMoreElements() do begin
printer.printlnInstruction('dq', ['-.this+' + (nextElement().objectValue() as AVTType).fasmFullName]);
end;
finally
printer.close();
types.free();
end;
end;
procedure AVTCodeGenerator.compilePrimitiveData(typeRef: AVTTypePrimitive; vfs: WriteableVirtualFileSystem; const dataFile: UnicodeString);
var
printer: AVTCodePrinter;
begin
printer := AVTCodePrinter.create(vfs.createFile(dataFile));
try
printer.println('; ' + typeRef.fullName + ' (data)');
printer.println();
printer.printlnHeader('class ' + typeRef.fasmFullName);
printer.printlnInstruction('dd', [avtIntToString(typeRef.flags) + ' ; modifiers']);
printer.printlnInstruction('dd', [avtIntToString(strings.indexAcquire(typeRef.fullName)) + ' ; simple name index']);
printer.printlnInstruction('dd', [avtIntToString(typeRef.fieldWidth) + ' ; instance size']);
printer.printlnInstruction('dd', [avtIntToString(typeRef.primitiveKind) + ' ; structure size']);
printer.printlnInstruction('dd', [avtIntToString(0) + ' ; reference fields quantity']);
printer.printlnInstruction('dd', [avtIntToString(0) + ' ; virtual methods quantity']);
printer.printlnInstruction('dd', [avtIntToString(0) + ' ; implementors quantity']);
printer.printlnInstruction('dd', [avtIntToString(0) + ' ; services quantity']);
printer.printlnInstruction('dd', [avtIntToString(0) + ' ; struct reference fields quantity ']);
printer.printlnInstruction('dd', [avtIntToString(0) + ' ; reserved field']);
printer.printlnInstruction('dd', [avtIntToString(0) + ' ; reserved field']);
printer.printlnInstruction('dd', [avtIntToString(0) + ' ; reserved field']);
printer.printlnInstruction('dd', [avtIntToString(0), avtIntToString(0), avtIntToString(0), avtIntToString(0)]);
printer.printlnInstruction('dd', [avtIntToString(0), avtIntToString(0), avtIntToString(0), avtIntToString(0)]);
printer.printlnInstruction('dq', [avtLongToString(0) + ' ; super type']);
printer.printlnInstruction('dq', [avtLongToString(0) + ' ; component type']);
printer.printlnInstruction('dq', ['-.class+system.package ; owned package']);
printer.printlnInstruction('dq', [avtLongToString(0) + ' ; main constructor']);
printer.printlnInstruction('dd', [avtIntToString(0) + ' ; source simple name offset']);
printer.printlnInstruction('dd', [avtIntToString(0) + ' ; reserved field']);
printer.printlnInstruction('dq', [avtLongToString(0) + ' ; reserved field']);
printer.printlnInstruction('dq', [avtLongToString(0) + ' ; reserved field']);
printer.printlnInstruction('dq', [avtLongToString(0) + ' ; reserved field']);
printer.printlnInstruction('dq', [avtLongToString(0) + ' ; reserved field']);
printer.printlnInstruction('dq', [avtLongToString(0) + ' ; reserved field']);
finally
printer.close();
end;
end;
procedure AVTCodeGenerator.compileClassCode(typeRef: AVTTypeStructured; vfs: WriteableVirtualFileSystem; const codeFile, nativesFile: UnicodeString);
var
natives: Input;
printer: AVTCodePrinter;
memberRef: TObject;
methodRef: AVTMethod;
begin
printer := AVTCodePrinter.create(vfs.createFile(codeFile));
try
{ код методов на fasm }
with typeRef.members() do while hasMoreElements() do begin
memberRef := nextElement().objectValue();
if (memberRef is AVTMethod) and ((AVTMethod(memberRef).flags and FLAG_NATIVE) <> 0) then begin
natives := vfs.openFileForReading(nativesFile);
try
copyData(natives, printer);
printer.println();
finally
natives.close();
end;
break;
end;
end;
{ код методов на ПВТ }
printer.println('; <fold ' + typeRef.fullName + ' (code)>');
with typeRef.members() do while hasMoreElements() do begin
memberRef := nextElement().objectValue();
if not(memberRef is AVTMethod) then continue;
methodRef := AVTMethod(memberRef);
if (methodRef.code = nil) and not methodRef.isAbstract() then begin
debugInfoStrings.indexAcquire(methodRef.simpleName);
end;
if (methodRef.flags and FLAG_NATIVE) = 0 then begin
compileMethod(methodRef, printer);
end;
end;
printer.println('; </fold>');
printer.println();
{ реализации сервисов }
with getImplementorsVector(typeRef) do begin
try
printer.println('; <fold ' + typeRef.fullName + ' (implementors)>');
with elements() do while hasMoreElements() do begin
compileImplementors(typeRef, nextElement().objectValue() as AVTTypeStructured, printer);
end;
printer.println('; </fold>');
finally
free();
end;
end;
finally
printer.close();
end;
end;
procedure AVTCodeGenerator.compileClassData(typeRef: AVTTypeStructured; vfs: WriteableVirtualFileSystem; const dataFile: UnicodeString);
var
index: int;
srcName: UnicodeString;
packName: AnsiString;
implName: AnsiString;
services: Vector;
implementors: Vector;
objectReferenceFields: Vector;
structReferenceFields: Vector;
mainConstructor: AVTInstInit;
printer: AVTCodePrinter;
classRef: AVTTypeStructured;
memberRef: AVTMember;
fieldValue: Value;
startValue: AVTConstant;
constType: AVTType;
source: AVTSource;
begin
packName := typeRef.package.fullName;
if length(packName) <= 0 then begin
packName := 'system.package';
end;
implName := '-.impl+' + typeRef.fasmArgumentName + '$$impl$$';
services := nil;
implementors := nil;
objectReferenceFields := nil;
structReferenceFields := nil;
printer := AVTCodePrinter.create(vfs.createFile(dataFile));
try
services := Vector.create();
implementors := getImplementorsVector(typeRef);
objectReferenceFields := Vector.create();
structReferenceFields := Vector.create();
mainConstructor := nil;
with typeRef.implements() do while hasMoreElements() do begin
services.append(ValueOfObject.create(nextElement().objectValue(), false));
end;
classRef := typeRef;
repeat
index := 0;
with classRef.members() do while hasMoreElements() do begin
memberRef := nextElement().objectValue() as AVTMember;
if (mainConstructor = nil) and ((classRef = typeRef) or (typeRef.isService() and (classRef = typeRef.extends()))) and (memberRef.visibility >= AVT_PUBLIC) and (memberRef is AVTInstInit) and (AVTInstInit(memberRef).getArgumentsCount() = 0) then begin
mainConstructor := AVTInstInit(memberRef);
end;
if not memberRef.isStatic() and (length(memberRef.simpleName) > 0) and (memberRef is AVTField) then with AVTField(memberRef) do if valueType is AVTTypeStructured then begin
fieldValue := ValueOfObject.create(memberRef, false);
objectReferenceFields.insert(index, fieldValue);
if classRef.isStruct() then begin
structReferenceFields.insert(index, fieldValue);
end;
inc(index);
end;
end;
classRef := classRef.extends();
until classRef = nil;
printer.println('; ' + typeRef.fullName + ' (data)');
printer.println();
printer.printlnHeader('class ' + typeRef.fasmFullName);
printer.printlnInstruction('dd', [avtIntToString(typeRef.flags) + ' ; modifiers']);
printer.printlnInstruction('dd', [avtIntToString(strings.indexAcquire(typeRef.simpleName)) + ' ; simple name index']);
printer.printlnInstruction('dd', [avtIntToString(typeRef.instanceSize) + ' ; instance size']);
printer.printlnInstruction('dd', [avtIntToString(typeRef.structureSize) + ' ; structure size']);
printer.printlnInstruction('dd', [avtIntToString(objectReferenceFields.size()) + ' ; reference fields quantity']);
printer.printlnInstruction('dd', [avtIntToString(typeRef.virtualMethodsCount) + ' ; virtual methods quantity']);
printer.printlnInstruction('dd', [avtIntToString(implementors.size()) + ' ; implementors quantity']);
printer.printlnInstruction('dd', [avtIntToString(services.size()) + ' ; services quantity']);
printer.printlnInstruction('dd', [avtIntToString(structReferenceFields.size()) + ' ; struct reference fields quantity ']);
printer.printlnInstruction('dd', [avtIntToString(0) + ' ; reserved field']);
printer.printlnInstruction('dd', [avtIntToString(0) + ' ; reserved field']);
printer.printlnInstruction('dd', [avtIntToString(0) + ' ; reserved field']);
printer.printlnInstruction('dd', ['-.class+.refs', '-.class+.virt', '-.class+.impl', '-.class+.serv']);
if typeRef.isStruct() then begin
printer.printlnInstruction('dd', ['-.class+.stru', avtIntToString(0), avtIntToString(0), avtIntToString(0)]);
end else begin
printer.printlnInstruction('dd', [avtIntToString(0), avtIntToString(0), avtIntToString(0), avtIntToString(0)]);
end;
classRef := typeRef.extends();
if classRef <> nil then begin
printer.printlnInstruction('dq', ['-.class+' + classRef.fasmFullName + ' ; super type']);
end else begin
printer.printlnInstruction('dq', [avtLongToString(0) + ' ; super type']);
end;
if typeRef is AVTTypeArray then begin
printer.printlnInstruction('dq', ['-.class+' + AVTTypeArray(typeRef).elementType.fasmFullName + ' ; component type']);
end else begin
printer.printlnInstruction('dq', [avtLongToString(0) + ' ; component type']);
end;
printer.printlnInstruction('dq', ['-.class+' + packName + ' ; owned package']);
if mainConstructor <> nil then begin
printer.printlnInstruction('dq', ['-.class+' + mainConstructor.fasmFullName + ' ; main constructor']);
end else begin
printer.printlnInstruction('dq', [avtLongToString(0) + ' ; main constructor']);
end;
source := typeRef.source;
if source = nil then begin
srcName := '';
end else begin
srcName := source.simpleName;
end;
printer.printlnInstruction('dd', ['-.class+debuginfo$source.avt' + avtIntToString(debugInfoSources.indexAcquire(srcName)) + ' ; source simple name offset']);
printer.printlnInstruction('dd', [avtIntToString(0) + ' ; reserved field']);
printer.printlnInstruction('dq', [avtLongToString(0) + ' ; reserved field']);
printer.printlnInstruction('dq', [avtLongToString(0) + ' ; reserved field']);
printer.printlnInstruction('dq', [avtLongToString(0) + ' ; reserved field']);
printer.printlnInstruction('dq', [avtLongToString(0) + ' ; reserved field']);
printer.printlnInstruction('dq', [avtLongToString(0) + ' ; reserved field']);
printer.printLabel('.refs');
with objectReferenceFields.elements() do while hasMoreElements() do with nextElement().objectValue() as AVTField do begin
printer.printlnInstruction('dd', [fasmFullName]);
end;
printer.printlnInstruction('dalign', [avtByteToString($08)]);
printer.printLabel('.virt');
with typeRef.virtualMethods() do while hasMoreElements() do begin
printer.printlnInstruction('dq', ['-.virt+' + (nextElement().objectValue() as AVTMember).fasmFullName]);
end;
printer.printlnInstruction('dalign', [avtByteToString($10)]);
printer.printLabel('.impl');
with implementors.elements() do while hasMoreElements() do with nextElement().objectValue() as AVTTypeStructured do begin
printer.printlnInstruction('dq', [implName + fasmArgumentName, '-.impl+' + fasmFullName]);
end;
printer.printLabel('.serv');
with services.elements() do while hasMoreElements() do begin
printer.printlnInstruction('dq', ['-.serv+' + (nextElement().objectValue() as AVTTypeStructured).fasmFullName]);
end;
if typeRef.isStruct() then begin
printer.printlnInstruction('dalign', [avtByteToString($10)]);
printer.printLabel('.stru');
with structReferenceFields.elements() do while hasMoreElements() do with nextElement().objectValue() as AVTField do begin
printer.printlnInstruction('dd', [fasmFullName, fasmStructName, '-.stru+' + valueType.fasmFullName, avtIntToString(length)]);
end;
end;
printer.println(LINE_ENDING);
with typeRef.members() do while hasMoreElements() do begin
memberRef := nextElement().objectValue() as AVTMember;
if (memberRef is AVTField) and memberRef.isStatic() then with AVTField(memberRef) do begin
startValue := valueConst;
if (startValue <> nil) and memberRef.isFinal() then begin
constType := startValue.valueType;
if constType is AVTTypePrimitive then with startValue.value do begin
case AVTTypePrimitive(constType).primitiveKind of
AVT_BOOLEAN: printer.printlnHeader(fasmFullName + ' = ' + avtBooleanValueToString(asBoolean));
AVT_CHAR: printer.printlnHeader(fasmFullName + ' = ' + avtIntValueToString(int(asChar)));
AVT_REAL: printer.printlnHeader('label ' + fasmFullName + ' at x+' + intToString(x.indexAcquire(asReal) * 10));
AVT_BYTE: printer.printlnHeader(fasmFullName + ' = ' + avtIntValueToString(asByte));
AVT_BYTE2: printer.printlnHeader('label ' + fasmFullName + ' at b2+' + avtIntToString(b2.indexAcquire(asByte2) * 2));
AVT_BYTE4: printer.printlnHeader('label ' + fasmFullName + ' at b4+' + avtIntToString(b4.indexAcquire(asByte4) * 4));
AVT_BYTE8: printer.printlnHeader('label ' + fasmFullName + ' at b8+' + avtIntToString(b8.indexAcquire(asByte8) * 8));
AVT_SHORT: printer.printlnHeader(fasmFullName + ' = ' + avtIntValueToString(asShort));
AVT_SHORT2: printer.printlnHeader('label ' + fasmFullName + ' at s2+' + avtIntToString(s2.indexAcquire(asShort2) * 4));
AVT_SHORT4: printer.printlnHeader('label ' + fasmFullName + ' at s4+' + avtIntToString(s4.indexAcquire(asShort4) * 8));
AVT_SHORT8: printer.printlnHeader('label ' + fasmFullName + ' at s8+' + avtIntToString(s8.indexAcquire(asShort8) * 16));
AVT_INT: printer.printlnHeader(fasmFullName + ' = ' + avtIntValueToString(asInt));
AVT_INT2: printer.printlnHeader('label ' + fasmFullName + ' at i2+' + avtIntToString(i2.indexAcquire(asInt2) * 8));
AVT_INT4: printer.printlnHeader('label ' + fasmFullName + ' at i4+' + avtIntToString(i4.indexAcquire(asInt4) * 16));
AVT_INT8: printer.printlnHeader('label ' + fasmFullName + ' at i8+' + avtIntToString(i8.indexAcquire(asInt8) * 32));
AVT_LONG: printer.printlnHeader('label ' + fasmFullName + ' at l+' + avtIntToString(l.indexAcquire(asLong) * 8));
AVT_LONG2: printer.printlnHeader('label ' + fasmFullName + ' at l2+' + avtIntToString(l2.indexAcquire(asLong2) * 16));
AVT_LONG4: printer.printlnHeader('label ' + fasmFullName + ' at l4+' + avtIntToString(l4.indexAcquire(asLong4) * 32));
AVT_LONG8: printer.printlnHeader('label ' + fasmFullName + ' at l8+' + avtIntToString(l8.indexAcquire(asLong8) * 64));
AVT_FLOAT: printer.printlnHeader('label ' + fasmFullName + ' at f+' + avtIntToString(f.indexAcquire(asFloat) * 4));
AVT_FLOAT2: printer.printlnHeader('label ' + fasmFullName + ' at f2+' + avtIntToString(f2.indexAcquire(asFloat2) * 8));
AVT_FLOAT4: printer.printlnHeader('label ' + fasmFullName + ' at f4+' + avtIntToString(f4.indexAcquire(asFloat4) * 16));
AVT_FLOAT8: printer.printlnHeader('label ' + fasmFullName + ' at f8+' + avtIntToString(f8.indexAcquire(asFloat8) * 32));
AVT_DOUBLE: printer.printlnHeader('label ' + fasmFullName + ' at d+' + avtIntToString(d.indexAcquire(asDouble) * 8));
AVT_DOUBLE2: printer.printlnHeader('label ' + fasmFullName + ' at d2+' + avtIntToString(d2.indexAcquire(asDouble2) * 16));
AVT_DOUBLE4: printer.printlnHeader('label ' + fasmFullName + ' at d4+' + avtIntToString(d4.indexAcquire(asDouble4) * 32));
AVT_DOUBLE8: printer.printlnHeader('label ' + fasmFullName + ' at d8+' + avtIntToString(d8.indexAcquire(asDouble8) * 64));
end;
end;
end else begin
printer.printlnHeader('glob ' + fasmFullName);
if startValue = nil then begin
case valueType.fieldWidth of
$01..$10:
printer.printlnInstruction('dq', ['0', '0']);
$11..$20:
printer.printlnInstruction('dq', ['0', '0', '0', '0']);
$21..$40:
printer.printlnInstruction('dq', ['0', '0', '0', '0', '0', '0', '0', '0']);
end;
end else with startValue.value do begin
case valueType.fieldWidth of
$01..$10: begin
printer.printlnInstruction('dq', [avtLongToString(asLong8[0]), avtLongToString(asLong8[1])]);
end;
$11..$20: begin
printer.printlnInstruction('dq', [avtLongToString(asLong8[0]), avtLongToString(asLong8[1])]);
printer.printlnInstruction('dq', [avtLongToString(asLong8[2]), avtLongToString(asLong8[3])]);
end;
$21..$40: begin
printer.printlnInstruction('dq', [avtLongToString(asLong8[0]), avtLongToString(asLong8[1])]);
printer.printlnInstruction('dq', [avtLongToString(asLong8[2]), avtLongToString(asLong8[3])]);
printer.printlnInstruction('dq', [avtLongToString(asLong8[4]), avtLongToString(asLong8[5])]);
printer.printlnInstruction('dq', [avtLongToString(asLong8[6]), avtLongToString(asLong8[7])]);
end;
end;
end;
end;
end;
end;
with typeRef.members() do while hasMoreElements() do begin
memberRef := nextElement().objectValue() as AVTMember;
if not memberRef.isStatic() and (length(memberRef.simpleName) > 0) and (memberRef is AVTField) then with AVTField(memberRef) do if not typeRef.isStruct() or (valueType is AVTTypeStructured) then begin
printer.printlnHeader('field ' + avtIntToString(instanceOffset) + ', ' + fasmFullName);
end;
end;
if typeRef.isStruct() then begin
printer.println();
with typeRef.members() do while hasMoreElements() do begin
memberRef := nextElement().objectValue() as AVTMember;
if not memberRef.isStatic() and (length(memberRef.simpleName) > 0) and (memberRef is AVTField) then with AVTField(memberRef) do begin
printer.printlnHeader('field ' + avtIntToString(structureOffset) + ', ' + fasmStructName);
end;
end;
end;
finally
printer.close();
services.free();
implementors.free();
objectReferenceFields.free();
structReferenceFields.free();
end;
end;
procedure AVTCodeGenerator.compileMethod(methodRef: AVTMethod; printer: AVTCodePrinter);
var
isVoid: boolean;
ehEmpty: boolean;
i: int;
j: int;
lim: int;
lastLine: int;
currLine: int;
locsList: Vector;
locsTable: Hashtable;
local: AVTVariable;
element: Value;
key: Value;
code: AVTCode;
node: AVTNode;
returnTypeRef: AVTType;
source: AVTSource;
begin
locsTable := nil;
locsList := Vector.create();
try
{ заголовок }
if not methodRef.isStatic() then begin
locsList.append(ValueOfObject.create(methodRef.argumentThis, false));
end;
with methodRef.arguments() do while hasMoreElements() do begin
locsList.append(ValueOfObject.create(nextElement().objectValue(), false));
end;
printer.println();
lim := locsList.size() - 1;
if lim >= 0 then begin
printer.printlnHeader('method ' + methodRef.fasmFullName + ', \');
end else begin
printer.printHeader('method ' + methodRef.fasmFullName + ' ;');
end;
for i := 0 to lim do begin
local := locsList.elementAt(i).objectValue() as AVTVariable;
if i < lim then begin
printer.printlnInstruction(local.fasmShortName + ', ' + local.valueType.fasmArgumentName + ', \');
end else begin
printer.printInstruction(local.fasmShortName + ', ' + local.valueType.fasmArgumentName + ' ;');
end;
end;
returnTypeRef := methodRef.returnType;
isVoid := returnTypeRef.isVoid();
if not isVoid then begin
printer.print(' returns ' + returnTypeRef.fullName);
end;
with methodRef.throws() do if hasMoreElements() then begin
if isVoid then begin
printer.print(' throws ');
end else begin
printer.print('; throws ');
end;
repeat
printer.print((nextElement().objectValue() as AVTType).fullName);
if not hasMoreElements() then break;
printer.print(', ');
until false;
end;
code := methodRef.code;
if code = nil then begin
printer.println();
exit;
end;
printer.println(' <fold >');
{ локальные переменные }
locsList.clear();
locsTable := Hashtable.create();
with code.instructions() do while hasMoreElements() do with nextElement().objectValue() as AVTNode do begin
case instruction of
DECLARE_VARIABLE, AVT_CATCH: begin
local := operand1 as AVTVariable;
key := ValueOfAnsiString.create(local.simpleName);
element := locsTable.get(key);
if element = nil then begin
locsList.append(key);
locsTable.put(key, ValueOfObject.create(local, false));
end else
if local.valueType.fieldWidth > (element.objectValue() as AVTVariable).valueType.fieldWidth then begin
locsTable.put(key, ValueOfObject.create(local, false));
end;
end;
end;
end;
with locsList.elements() do while hasMoreElements() do with locsTable.get(nextElement()).objectValue() as AVTVariable do begin
printer.printlnInstruction('loc', [fasmShortName, valueType.fasmArgumentName]);
end;
finally
locsTable.free();
locsList.free();
end;
{ код метода }
isVoid := true;
lastLine := -1;
source := methodRef.source;
if source = nil then begin
debugInfoSources.indexAcquire('');
end else begin
debugInfoSources.indexAcquire(source.simpleName);
end;
debugInfoStrings.indexAcquire(methodRef.simpleName);
with code.instructions() do while hasMoreElements() do if (nextElement().objectValue() as AVTNode).lineIndex >= 0 then begin
isVoid := false;
break;
end;
if isVoid then begin
printer.printLabel(labelNumberToString('D', methodRef.addDebugInfoLineNumber(0)));
end;
with code.instructions() do while hasMoreElements() do begin
node := nextElement().objectValue() as AVTNode;
currLine := node.lineIndex;
if (currLine <> -1) and (currLine <> lastLine) then begin
printer.printlnSourceLine(stringToUTF8(source.fileName) + '[' + intToString(currLine + 1) + ']: ' + stringToUTF8(stringTrim(source[currLine])));
printer.printLabel(labelNumberToString('D', methodRef.addDebugInfoLineNumber(currLine + 1)));
lastLine := currLine;
end;
compileInstructionNode(node, methodRef, printer);
end;
{ код обработчика исключений }
ehEmpty := true;
for i := code.length - 1 downto 0 do with code[i] do if instruction = AVT_TRY_BEGIN then begin
if ehEmpty then begin
printer.printlnInstruction('eenter');
end else begin
printer.printLabel('@@');
end;
ehEmpty := false;
printer.printlnInstruction('tryblock', [labelNumberToString(labelNumber), labelNumberToString(child[1].labelNumber), '@F']);
for j := 3 to length - 1 do with child[j] do begin
case instruction of
AVT_CATCH: printer.printlnInstruction('catchblock', [(operand1 as AVTVariable).valueType.fasmFullName, labelNumberToString(labelNumber)]);
AVT_FINALLY: printer.printlnInstruction('finallyblock', [labelNumberToString(labelNumber)]);
end;
end;
end;
if not ehEmpty then begin
printer.printLabel('@@');
end;
printer.printlnInstruction('eleave');
{ закрытие свёртывания }
printer.printlnHeader('; </fold>');
end;
procedure AVTCodeGenerator.compileInstructionNode(node: AVTNode; methodRef: AVTMethod; printer: AVTCodePrinter);
var
a: int;
b: int;
i: int;
kind: int;
vindex: int;
sindex: int;
nextOrder: int;
labelNumber: int;
caseCurVal: int;
caseMinVal: int;
caseMaxVal: int;
caseCountLookup: int;
caseCountTable: long;
caseValues: Vector;
caseEnum: Enumeration;
jumpCase: AVTNode;
jumpDefault: AVTNode;
jumpIsTrue: AVTNode;
jumpIsFalse: AVTNode;
typ: AVTType;
prim: AVTTypePrimitive;
typeOldRef: AVTType;
typeNewRef: AVTType;
primOldRef: AVTTypePrimitive;
primImmRef: AVTTypePrimitive;
primNewRef: AVTTypePrimitive;
interactMember: _Object;
begin
labelNumber := node.labelNumber;
if labelNumber >= 0 then begin
printer.printLabel(labelNumberToString(labelNumber));
end;
jumpIsFalse := node.jumpIsFalse;
jumpIsTrue := node.jumpIsTrue;
nextOrder := node.order + 1;
case node.instruction of
AVT_INSTANCEOF: begin
printer.printlnInstruction('rinstanceof', [(node.operand1 as AVTType).fasmFullName]);
end;
AVT_SWITCH: begin
caseEnum := node.jumpCaseValues();
if not caseEnum.hasMoreElements() then begin
printer.printlnInstruction('pop1');
exit;
end;
caseValues := Vector.create();
try
repeat
caseValues.append(caseEnum.nextElement());
until not caseEnum.hasMoreElements();
caseCountLookup := caseValues.size();
caseMaxVal := caseValues.firstElement().intValue();
caseMinVal := caseMaxVal;
for i := 1 to caseCountLookup - 1 do begin
caseCurVal := caseValues.elementAt(i).intValue();
if caseMinVal > caseCurVal then caseMinVal := caseCurVal;
if caseMaxVal < caseCurVal then caseMaxVal := caseCurVal;
end;
jumpDefault := node.jumpDefault;
caseCountTable := long(caseMaxVal) - long(caseMinVal) + 1;
if (caseCountTable shl 2) + 48 <= (long(caseCountLookup) + 1) * 10 then begin
{ itableswitch }
printer.printlnInstruction('itableswitch', [labelNumberToString(jumpDefault.labelNumber), avtIntToString(caseMinVal), '\']);
for i := 0 to int(caseCountTable) - 1 do begin
jumpCase := node.jumpCaseGetNode(caseMinVal + i);
if jumpCase = nil then jumpCase := jumpDefault;
if i = 0 then begin
printer.printContinuation(labelNumberToString(jumpCase.labelNumber));
end else
if (i and 7) > 0 then begin
printer.print(', ' + labelNumberToString(jumpCase.labelNumber));
end else begin
printer.println(', \');
printer.printContinuation(labelNumberToString(jumpCase.labelNumber));
end;
end;
end else begin
{ ilookupswitch }
dec(caseCountLookup);
printer.printlnInstruction('ilookupswitch', [labelNumberToString(jumpDefault.labelNumber), '\']);
for i := 0 to caseCountLookup do begin
caseCurVal := caseValues.elementAt(i).intValue();
printer.printContinuation(avtIntToString(caseCurVal) + ', ' + labelNumberToString(node.jumpCaseGetNode(caseCurVal).labelNumber));
if i < caseCountLookup then printer.println(', \');
end;
end;
printer.println();
finally
caseValues.free();
end;
end;
AVT_CASE, AVT_DEFAULT, AVT_TRY_BEGIN, AVT_TRY_END: begin
{ нет инструкций, только метка }
end;
AVT_RETURN, JUMP: begin
printer.printlnInstruction('jmp', [labelNumberToString(node.jumpDefault.labelNumber)]);
end;
AVT_THROW: begin
printer.printlnInstruction('rthrow');
end;
AVT_CATCH, DECLARE_VARIABLE, STORE_VARIABLE: begin
with node.operand1 as AVTVariable do begin
printer.printlnInstruction(typeToInstructionName(nonStackableTypeToStackable(valueType)) + 'storeloc', [fasmShortName]);
end;
end;
AVT_FINALLY: begin
printer.printlnInstruction('fenter');
end;
AVT_FINALLY_RETURN: begin
printer.printlnInstruction('fleave');
end;
AVT_FINALLY_INVOKE: begin
printer.printlnInstruction('invokefinally', [labelNumberToString((node.operand1 as AVTNode).labelNumber)]);
end;
AVT_CLINIT_TRY_LOCK: begin
printer.printlnInstruction('statictrylock', [(node.operand1 as AVTTypeStructured).fasmFullName]);
end;
AVT_CLINIT_UNLOCK: begin
printer.printlnInstruction('staticunlock');
end;
AVT_MONITOR_ENTER: begin
printer.printlnInstruction('rmonitorenter');
end;
AVT_MONITOR_LEAVE: begin
printer.printlnInstruction('rmonitorleave');
end;
AVT_ENTER: begin
if (methodRef.flags and FLAG_INTERRUPT) <> 0 then begin
printer.printlnInstruction('ienter');
end else begin
printer.printlnInstruction('menter');
end;
end;
AVT_LEAVE: begin
if (methodRef.flags and FLAG_INTERRUPT) <> 0 then begin
printer.printlnInstruction('ileave');
end else begin
printer.printlnInstruction('mleave' + typeReturnSuffix(node.operand1 as AVTType));
end;
end;
LOAD_VARIABLE: begin
with node.operand1 as AVTVariable do begin
printer.printlnInstruction(typeToInstructionName(nonStackableTypeToStackable(valueType)) + 'loadloc', [fasmShortName]);
end;
end;
LOAD_STATIC: begin
with node.operand1 as AVTField do begin
printer.printlnInstruction(typeToInstructionName(valueType) + 'load', ['[' + fasmFullName + ']']);
end;
end;
LOAD_CONST: begin
with node.operand1 as AVTConstant, value do begin
typ := valueType;
if (typ = nil) or (typ is AVTTypeStructured) then begin
typ := asClass;
if isNull then begin
printer.printlnInstruction('rloadnull');
end else
if typ <> nil then begin
printer.printlnInstruction('rloadclass', [typ.fasmFullName]);
end else begin
printer.printlnInstruction('rloadstring', [avtIntToString(strings.indexAcquire(asString))]);
end;
end else
if typ is AVTTypePrimitive then begin
case AVTTypePrimitive(typ).primitiveKind of
AVT_BOOLEAN: begin
if asBoolean then begin
printer.printlnInstruction('bloadt');
end else begin
printer.printlnInstruction('bloadf');
end;
end;
AVT_CHAR: printer.printlnInstruction('cload', [avtShortToString(int(asChar))]);
AVT_REAL: printer.printlnInstruction('xload', ['[x+' + intToString(x.indexAcquire(asReal) * 10) + ']']);
AVT_BYTE: printer.printlnInstruction('bload', [avtByteToString(asByte)]);
AVT_BYTE2: printer.printlnInstruction('b2load', ['[b2+' + avtIntToString(b2.indexAcquire(asByte2) * 2) + ']']);
AVT_BYTE4: printer.printlnInstruction('b4load', ['[b4+' + avtIntToString(b4.indexAcquire(asByte4) * 4) + ']']);
AVT_BYTE8: printer.printlnInstruction('b8load', ['[b8+' + avtIntToString(b8.indexAcquire(asByte8) * 8) + ']']);
AVT_SHORT: printer.printlnInstruction('sload', [avtShortToString(asShort)]);
AVT_SHORT2: printer.printlnInstruction('s2load', ['[s2+' + avtIntToString(s2.indexAcquire(asShort2) * 4) + ']']);
AVT_SHORT4: printer.printlnInstruction('s4load', ['[s4+' + avtIntToString(s4.indexAcquire(asShort4) * 8) + ']']);
AVT_SHORT8: printer.printlnInstruction('s8load', ['[s8+' + avtIntToString(s8.indexAcquire(asShort8) * 16) + ']']);
AVT_INT: printer.printlnInstruction('iload', [avtIntToString(asInt)]);
AVT_INT2: printer.printlnInstruction('i2load', ['[i2+' + avtIntToString(i2.indexAcquire(asInt2) * 8) + ']']);
AVT_INT4: printer.printlnInstruction('i4load', ['[i4+' + avtIntToString(i4.indexAcquire(asInt4) * 16) + ']']);
AVT_INT8: printer.printlnInstruction('i8load', ['[i8+' + avtIntToString(i8.indexAcquire(asInt8) * 32) + ']']);
AVT_LONG: printer.printlnInstruction('lload', ['[l+' + avtIntToString(l.indexAcquire(asLong) * 8) + ']']);
AVT_LONG2: printer.printlnInstruction('l2load', ['[l2+' + avtIntToString(l2.indexAcquire(asLong2) * 16) + ']']);
AVT_LONG4: printer.printlnInstruction('l4load', ['[l4+' + avtIntToString(l4.indexAcquire(asLong4) * 32) + ']']);
AVT_LONG8: printer.printlnInstruction('l8load', ['[l8+' + avtIntToString(l8.indexAcquire(asLong8) * 64) + ']']);
AVT_FLOAT: printer.printlnInstruction('fload', ['[f+' + avtIntToString(f.indexAcquire(asFloat) * 4) + ']']);
AVT_FLOAT2: printer.printlnInstruction('f2load', ['[f2+' + avtIntToString(f2.indexAcquire(asFloat2) * 8) + ']']);
AVT_FLOAT4: printer.printlnInstruction('f4load', ['[f4+' + avtIntToString(f4.indexAcquire(asFloat4) * 16) + ']']);
AVT_FLOAT8: printer.printlnInstruction('f8load', ['[f8+' + avtIntToString(f8.indexAcquire(asFloat8) * 32) + ']']);
AVT_DOUBLE: printer.printlnInstruction('dload', ['[d+' + avtIntToString(d.indexAcquire(asDouble) * 8) + ']']);
AVT_DOUBLE2: printer.printlnInstruction('d2load', ['[d2+' + avtIntToString(d2.indexAcquire(asDouble2) * 16) + ']']);
AVT_DOUBLE4: printer.printlnInstruction('d4load', ['[d4+' + avtIntToString(d4.indexAcquire(asDouble4) * 32) + ']']);
AVT_DOUBLE8: printer.printlnInstruction('d8load', ['[d8+' + avtIntToString(d8.indexAcquire(asDouble8) * 64) + ']']);
end;
end;
end;
end;
GET_FIELD: begin
with node.operand1 as AVTField do begin
if parentType.isStruct() and valueType.isPrimitive() then begin
printer.printlnInstruction('getstructfield' + typeToInstructionName(valueType), [fasmStructName]);
end else begin
printer.printlnInstruction('getfield' + typeToInstructionName(valueType), [fasmFullName]);
end;
end;
end;
GET_PROPERTY: begin
with node.operand1 as AVTProperty do begin
interactMember := readMember;
if isOverridden() or hasIndex or (interactMember = nil) or (interactMember is AVTConstant) then with readSynthetic do begin
vindex := virtualIndex;
sindex := serviceIndex;
if sindex >= 0 then begin
printer.printlnInstruction('invokeservice' + typeReturnSuffix(returnType), [parentType.fasmFullName, fasmShortName, avtIntToString(sindex)]);
end else
if vindex >= 0 then begin
printer.printlnInstruction('invokevirtual' + typeReturnSuffix(returnType), [fasmFullName, avtIntToString(vindex)]);
end else begin
printer.printlnInstruction('invokespecial' + typeReturnSuffix(returnType), [fasmFullName]);
end;
end else
if interactMember is AVTMethod then with AVTMethod(interactMember) do begin
vindex := virtualIndex;
sindex := serviceIndex;
if sindex >= 0 then begin
printer.printlnInstruction('invokeservice' + typeReturnSuffix(returnType), [parentType.fasmFullName, fasmShortName, avtIntToString(sindex)]);
end else
if vindex >= 0 then begin
printer.printlnInstruction('invokevirtual' + typeReturnSuffix(returnType), [fasmFullName, avtIntToString(vindex)]);
end else begin
printer.printlnInstruction('invokespecial' + typeReturnSuffix(returnType), [fasmFullName]);
end;
end else
if interactMember is AVTField then with AVTField(interactMember) do begin
printer.printlnInstruction('getfield' + typeToInstructionName(valueType), [fasmFullName]);
end;
end;
end;
GET_ARRAY_ELEMENT: begin
printer.printlnInstruction('getarrayelement' + typeToInstructionName(node.operand1 as AVTType));
end;
GET_VECTOR_ELEMENT: begin
printer.printlnInstruction('getvectorelement' + typeToInstructionName(node.operand1 as AVTType));
end;
DUP1: begin
printer.printlnInstruction('dup1');
end;
DUP2: begin
printer.printlnInstruction('dup2');
end;
DUP1X1: begin
printer.printlnInstruction('dup1x1');
end;
DUP1X2: begin
printer.printlnInstruction('dup1x2');
end;
POP1: begin
printer.printlnInstruction('pop1');
end;
INVOKE_STATIC: begin
with node.operand1 as AVTMethod do begin
printer.printlnInstruction('invokestatic' + typeReturnSuffix(returnType), [fasmFullName]);
end;
end;
INVOKE_SPECIAL: begin
with node.operand1 as AVTMethod do begin
printer.printlnInstruction('invokespecial' + typeReturnSuffix(returnType), [fasmFullName]);
end;
end;
INVOKE_VIRTUAL: begin
with node.operand1 as AVTMethod do begin
vindex := virtualIndex;
if vindex < 0 then begin
printer.printlnInstruction('invokespecial' + typeReturnSuffix(returnType), [fasmFullName]);
end else begin
printer.printlnInstruction('invokevirtual' + typeReturnSuffix(returnType), [fasmFullName, avtIntToString(vindex)]);
end;
end;
end;
INVOKE_SERVICE: begin
with node.operand1 as AVTMethod do begin
printer.printlnInstruction('invokeservice' + typeReturnSuffix(returnType), [parentType.fasmFullName, fasmShortName, avtIntToString(serviceIndex)]);
end;
end;
NEW_ARRAY_BY_LENGTH: begin
printer.printlnInstruction('newarray', [(node.operand1 as AVTType).fasmFullName]);
end;
NEW_MULTI_ARRAY: begin
printer.printlnInstruction('newmultiarray', [(node.operand1 as AVTType).fasmFullName]);
end;
NEW_ARRAY_BY_ELEMENTS: begin
with node.operand1 as AVTType, node.operand2 as AVTConstant, value do begin
case (valueType as AVTTypePrimitive).primitiveKind of
AVT_BYTE: printer.printlnInstruction('bload', [avtByteToString(asByte)]);
AVT_SHORT: printer.printlnInstruction('sload', [avtShortToString(asShort)]);
else printer.printlnInstruction('iload', [avtIntToString(asInt)]);
end;
printer.printlnInstruction('newarray', [fasmFullName]);
end;
end;
NEW_VECTOR: begin
printer.printlnInstruction('newvector' + typeToInstructionName(node.operand1 as AVTType));
end;
NEW_CLASS, NEW_STRUCT, NEW_SERVICE: begin
printer.printlnInstruction('newclass', [(node.operand1 as AVTType).fasmFullName]);
end;
OPER_INCREMENT: begin
with node.operand1 as AVTVariable do begin
printer.printlnInstruction(typeToInstructionName(valueType) + 'inc', [fasmShortName]);
end;
end;
OPER_DECREMENT: begin
with node.operand1 as AVTVariable do begin
printer.printlnInstruction(typeToInstructionName(valueType) + 'dec', [fasmShortName]);
end;
end;
OPER_INC_POST: begin
with node.operand1 as AVTVariable do begin
printer.printlnInstruction(typeToInstructionName(valueType) + 'incpost', [fasmShortName]);
end;
end;
OPER_DEC_POST: begin
with node.operand1 as AVTVariable do begin
printer.printlnInstruction(typeToInstructionName(valueType) + 'decpost', [fasmShortName]);
end;
end;
OPER_INC_PRED: begin
with node.operand1 as AVTVariable do begin
printer.printlnInstruction(typeToInstructionName(valueType) + 'incpred', [fasmShortName]);
end;
end;
OPER_DEC_PRED: begin
with node.operand1 as AVTVariable do begin
printer.printlnInstruction(typeToInstructionName(valueType) + 'decpred', [fasmShortName]);
end;
end;
OPER_TYPE_CAST: begin
{ На будущее: улучшить конверсию примитивных типов.
Сейчас: сперва изменяется количество элементов вектора, а затем – тип элементов
Необходимо: если количество элементов вектора понижается, то сделать как сейчас, иначе – наоборот (сперва изменяется тип элементов, а затем – их количество). }
typeOldRef := node.operand2 as AVTType;
typeNewRef := node.operand1 as AVTType;
if (typeOldRef is AVTTypePrimitive) and (typeNewRef is AVTTypePrimitive) then begin
primOldRef := AVTTypePrimitive(nonStackableTypeToStackable(typeOldRef));
primNewRef := AVTTypePrimitive(typeNewRef);
if primOldRef <> primNewRef then begin
a := primOldRef.compoundBase;
b := primNewRef.compoundBase;
if a = AVT_REAL then begin
if (b = AVT_BYTE) or (b = AVT_SHORT) or (b = AVT_CHAR) then begin
printer.printlnInstruction('xtoi');
primOldRef := getPrimitiveType(AVT_INT);
a := AVT_INT;
end;
if (b <> a) and (b <> AVT_BYTE) and (b <> AVT_SHORT) and (b <> AVT_CHAR) then begin
primImmRef := getPrimitiveType(b);
printer.printlnInstruction(typeToInstructionName(primOldRef) + 'to' + typeToInstructionName(primImmRef));
primOldRef := AVTTypePrimitive(nonStackableTypeToStackable(primImmRef));
a := primOldRef.compoundBase;
end;
end;
if primOldRef.compoundLength <> primNewRef.compoundLength then begin
if b < AVT_BYTE then begin
primImmRef := getPrimitiveType(a);
end else begin
primImmRef := getPrimitiveType(a + (primNewRef.primitiveKind and 3));
end;
printer.printlnInstruction(typeToInstructionName(primOldRef) + 'to' + typeToInstructionName(primImmRef));
primOldRef := AVTTypePrimitive(nonStackableTypeToStackable(primImmRef));
a := primOldRef.compoundBase;
end;
if a <> b then begin
case b of
AVT_REAL: begin
printer.printlnInstruction(typeToInstructionName(primOldRef) + 'tox');
end;
AVT_CHAR: begin
if a <> AVT_INT then begin
printer.printlnInstruction(typeToInstructionName(primOldRef) + 'toi');
end;
printer.printlnInstruction('itoc');
end
else
if ((a = AVT_BYTE) or (a = AVT_SHORT)) and ((b = AVT_FLOAT) or (b = AVT_DOUBLE)) or ((a = AVT_FLOAT) or (a = AVT_DOUBLE)) and ((b = AVT_BYTE) or (b = AVT_SHORT)) then begin
primImmRef := getPrimitiveType(AVT_INT + (primNewRef.primitiveKind and 3));
printer.printlnInstruction(typeToInstructionName(primOldRef) + 'to' + typeToInstructionName(primImmRef));
primOldRef := primImmRef;
end;
printer.printlnInstruction(typeToInstructionName(primOldRef) + 'to' + typeToInstructionName(primNewRef));
end;
end;
end;
end else
if (typeOldRef is AVTTypeStructured) and (typeNewRef is AVTTypeStructured) and not typeNewRef.isAssignableFrom(typeOldRef) then begin
printer.printlnInstruction('rcast', [typeNewRef.fasmFullName]);
end;
end;
OPER_BIT_NOT: begin
printer.printlnInstruction(typeToInstructionName(node.operand1 as AVTType) + 'not');
end;
OPER_BIT_AND: begin
printer.printlnInstruction(typeToInstructionName(node.operand1 as AVTType) + 'and');
end;
OPER_BIT_OR: begin
printer.printlnInstruction(typeToInstructionName(node.operand1 as AVTType) + 'or');
end;
OPER_BIT_XOR: begin
printer.printlnInstruction(typeToInstructionName(node.operand1 as AVTType) + 'xor');
end;
OPER_SCAL_MINUS: begin
printer.printlnInstruction(typeToInstructionName(nonStackableTypeToStackable(node.operand1 as AVTType)) + 'sneg');
end;
OPER_SCAL_MUL: begin
printer.printlnInstruction(typeToInstructionName(nonStackableTypeToStackable(node.operand1 as AVTType)) + 'smul');
end;
OPER_SCAL_DIV: begin
printer.printlnInstruction(typeToInstructionName(nonStackableTypeToStackable(node.operand1 as AVTType)) + 'sdiv');
end;
OPER_SCAL_DIVU: begin
printer.printlnInstruction(typeToInstructionName(nonStackableTypeToStackable(node.operand1 as AVTType)) + 'sdivu');
end;
OPER_SCAL_REM: begin
printer.printlnInstruction(typeToInstructionName(nonStackableTypeToStackable(node.operand1 as AVTType)) + 'srem');
end;
OPER_SCAL_REMU: begin
printer.printlnInstruction(typeToInstructionName(nonStackableTypeToStackable(node.operand1 as AVTType)) + 'sremu');
end;
OPER_SCAL_ADD: begin
printer.printlnInstruction(typeToInstructionName(nonStackableTypeToStackable(node.operand1 as AVTType)) + 'sadd');
end;
OPER_SCAL_SUB: begin
printer.printlnInstruction(typeToInstructionName(nonStackableTypeToStackable(node.operand1 as AVTType)) + 'ssub');
end;
OPER_SCAL_SAR: begin
printer.printlnInstruction(typeToInstructionName(nonStackableTypeToStackable(node.operand1 as AVTType)) + 'ssar');
end;
OPER_SCAL_SAL: begin
printer.printlnInstruction(typeToInstructionName(nonStackableTypeToStackable(node.operand1 as AVTType)) + 'ssal');
end;
OPER_SCAL_SHR: begin
printer.printlnInstruction(typeToInstructionName(nonStackableTypeToStackable(node.operand1 as AVTType)) + 'sshr');
end;
OPER_SCAL_G: begin
prim := node.operand1 as AVTTypePrimitive;
kind := prim.compoundBase;
if (kind = AVT_FLOAT) or (kind = AVT_DOUBLE) or (kind = AVT_REAL) then begin
printer.printlnInstruction(typeToInstructionName(prim) + 'cmpl');
end else begin
printer.printlnInstruction(typeToInstructionName(nonStackableTypeToStackable(prim)) + 'cmp');
end;
if (jumpIsTrue = nil) or (jumpIsFalse = nil) then begin
printer.printlnInstruction('isetg');
exit;
end;
if jumpIsFalse.order = nextOrder then begin
printer.printlnInstruction('ijmpg', [labelNumberToString(jumpIsTrue.labelNumber)]);
exit;
end;
if jumpIsTrue.order = nextOrder then begin
printer.printlnInstruction('ijmpng', [labelNumberToString(jumpIsFalse.labelNumber)]);
exit;
end;
printer.printlnInstruction('ijmpg', [labelNumberToString(jumpIsTrue.labelNumber)]);
printer.printlnInstruction('jmp', [labelNumberToString(jumpIsFalse.labelNumber)]);
exit;
end;
OPER_SCAL_GE: begin
prim := node.operand1 as AVTTypePrimitive;
kind := prim.compoundBase;
if (kind = AVT_FLOAT) or (kind = AVT_DOUBLE) or (kind = AVT_REAL) then begin
printer.printlnInstruction(typeToInstructionName(prim) + 'cmpl');
end else begin
printer.printlnInstruction(typeToInstructionName(nonStackableTypeToStackable(prim)) + 'cmp');
end;
if (jumpIsTrue = nil) or (jumpIsFalse = nil) then begin
printer.printlnInstruction('isetge');
exit;
end;
if jumpIsFalse.order = nextOrder then begin
printer.printlnInstruction('ijmpge', [labelNumberToString(jumpIsTrue.labelNumber)]);
exit;
end;
if jumpIsTrue.order = nextOrder then begin
printer.printlnInstruction('ijmpnge', [labelNumberToString(jumpIsFalse.labelNumber)]);
exit;
end;
printer.printlnInstruction('ijmpge', [labelNumberToString(jumpIsTrue.labelNumber)]);
printer.printlnInstruction('jmp', [labelNumberToString(jumpIsFalse.labelNumber)]);
exit;
end;
OPER_SCAL_L: begin
prim := node.operand1 as AVTTypePrimitive;
kind := prim.compoundBase;
if (kind = AVT_FLOAT) or (kind = AVT_DOUBLE) or (kind = AVT_REAL) then begin
printer.printlnInstruction(typeToInstructionName(prim) + 'cmpg');
end else begin
printer.printlnInstruction(typeToInstructionName(nonStackableTypeToStackable(prim)) + 'cmp');
end;
if (jumpIsTrue = nil) or (jumpIsFalse = nil) then begin
printer.printlnInstruction('isetl');
exit;
end;
if jumpIsFalse.order = nextOrder then begin
printer.printlnInstruction('ijmpl', [labelNumberToString(jumpIsTrue.labelNumber)]);
exit;
end;
if jumpIsTrue.order = nextOrder then begin
printer.printlnInstruction('ijmpnl', [labelNumberToString(jumpIsFalse.labelNumber)]);
exit;
end;
printer.printlnInstruction('ijmpl', [labelNumberToString(jumpIsTrue.labelNumber)]);
printer.printlnInstruction('jmp', [labelNumberToString(jumpIsFalse.labelNumber)]);
exit;
end;
OPER_SCAL_LE: begin
prim := node.operand1 as AVTTypePrimitive;
kind := prim.compoundBase;
if (kind = AVT_FLOAT) or (kind = AVT_DOUBLE) or (kind = AVT_REAL) then begin
printer.printlnInstruction(typeToInstructionName(prim) + 'cmpg');
end else begin
printer.printlnInstruction(typeToInstructionName(nonStackableTypeToStackable(prim)) + 'cmp');
end;
if (jumpIsTrue = nil) or (jumpIsFalse = nil) then begin
printer.printlnInstruction('isetle');
exit;
end;
if jumpIsFalse.order = nextOrder then begin
printer.printlnInstruction('ijmple', [labelNumberToString(jumpIsTrue.labelNumber)]);
exit;
end;
if jumpIsTrue.order = nextOrder then begin
printer.printlnInstruction('ijmpnle', [labelNumberToString(jumpIsFalse.labelNumber)]);
exit;
end;
printer.printlnInstruction('ijmple', [labelNumberToString(jumpIsTrue.labelNumber)]);
printer.printlnInstruction('jmp', [labelNumberToString(jumpIsFalse.labelNumber)]);
exit;
end;
OPER_SCAL_E: begin
typ := node.operand1 as AVTType;
if typ is AVTTypeStructured then begin
if node[0].isLoadNull() or node[1].isLoadNull() then begin
printer.printlnInstruction('risnull');
end else begin
printer.printlnInstruction('re');
end;
end else
if typ.isCompound() then begin
printer.printlnInstruction(typeToInstructionName(typ) + 'se');
end else begin
prim := node.operand1 as AVTTypePrimitive;
kind := prim.compoundBase;
if (kind = AVT_FLOAT) or (kind = AVT_DOUBLE) or (kind = AVT_REAL) then begin
printer.printlnInstruction(typeToInstructionName(prim) + 'cmpl');
end else begin
printer.printlnInstruction(typeToInstructionName(nonStackableTypeToStackable(prim)) + 'cmp');
end;
if (jumpIsTrue = nil) or (jumpIsFalse = nil) then begin
printer.printlnInstruction('isete');
exit;
end;
if jumpIsFalse.order = nextOrder then begin
printer.printlnInstruction('ijmpe', [labelNumberToString(jumpIsTrue.labelNumber)]);
exit;
end;
if jumpIsTrue.order = nextOrder then begin
printer.printlnInstruction('ijmpne', [labelNumberToString(jumpIsFalse.labelNumber)]);
exit;
end;
printer.printlnInstruction('ijmpe', [labelNumberToString(jumpIsTrue.labelNumber)]);
printer.printlnInstruction('jmp', [labelNumberToString(jumpIsFalse.labelNumber)]);
exit;
end;
end;
OPER_SCAL_NE: begin
typ := node.operand1 as AVTType;
if typ is AVTTypeStructured then begin
if node[0].isLoadNull() or node[1].isLoadNull() then begin
printer.printlnInstruction('risnotnull');
end else begin
printer.printlnInstruction('rne');
end;
end else
if typ.isCompound() then begin
printer.printlnInstruction(typeToInstructionName(typ) + 'sne');
end else begin
prim := node.operand1 as AVTTypePrimitive;
kind := prim.compoundBase;
if (kind = AVT_FLOAT) or (kind = AVT_DOUBLE) or (kind = AVT_REAL) then begin
printer.printlnInstruction(typeToInstructionName(prim) + 'cmpl');
end else begin
printer.printlnInstruction(typeToInstructionName(nonStackableTypeToStackable(prim)) + 'cmp');
end;
if (jumpIsTrue = nil) or (jumpIsFalse = nil) then begin
printer.printlnInstruction('isetne');
exit;
end;
if jumpIsFalse.order = nextOrder then begin
printer.printlnInstruction('ijmpne', [labelNumberToString(jumpIsTrue.labelNumber)]);
exit;
end;
if jumpIsTrue.order = nextOrder then begin
printer.printlnInstruction('ijmpe', [labelNumberToString(jumpIsFalse.labelNumber)]);
exit;
end;
printer.printlnInstruction('ijmpne', [labelNumberToString(jumpIsTrue.labelNumber)]);
printer.printlnInstruction('jmp', [labelNumberToString(jumpIsFalse.labelNumber)]);
exit;
end;
end;
OPER_VECT_PACK: begin
printer.printlnInstruction(typeToInstructionName(node.operand1 as AVTType) + 'vpack');
end;
OPER_VECT_UNPCKL: begin
printer.printlnInstruction(typeToInstructionName(node.operand1 as AVTType) + 'vunpckl');
end;
OPER_VECT_UNPCKU: begin
printer.printlnInstruction(typeToInstructionName(node.operand1 as AVTType) + 'vunpcku');
end;
OPER_VECT_MINUS: begin
printer.printlnInstruction(typeToInstructionName(node.operand1 as AVTType) + 'vneg');
end;
OPER_VECT_MUL: begin
printer.printlnInstruction(typeToInstructionName(node.operand1 as AVTType) + 'vmul');
end;
OPER_VECT_DIV: begin
printer.printlnInstruction(typeToInstructionName(node.operand1 as AVTType) + 'vdiv');
end;
OPER_VECT_ADD: begin
printer.printlnInstruction(typeToInstructionName(node.operand1 as AVTType) + 'vadd');
end;
OPER_VECT_SUB: begin
printer.printlnInstruction(typeToInstructionName(node.operand1 as AVTType) + 'vsub');
end;
OPER_VECT_SAR: begin
printer.printlnInstruction(typeToInstructionName(node.operand1 as AVTType) + 'vsar');
end;
OPER_VECT_SAL: begin
printer.printlnInstruction(typeToInstructionName(node.operand1 as AVTType) + 'vsal');
end;
OPER_VECT_SHR: begin
printer.printlnInstruction(typeToInstructionName(node.operand1 as AVTType) + 'vshr');
end;
OPER_VECT_G: begin
printer.printlnInstruction(typeToInstructionName(node.operand1 as AVTType) + 'vg');
end;
OPER_VECT_GE: begin
printer.printlnInstruction(typeToInstructionName(node.operand1 as AVTType) + 'vge');
end;
OPER_VECT_L: begin
printer.printlnInstruction(typeToInstructionName(node.operand1 as AVTType) + 'vl');
end;
OPER_VECT_LE: begin
printer.printlnInstruction(typeToInstructionName(node.operand1 as AVTType) + 'vle');
end;
OPER_VECT_E: begin
printer.printlnInstruction(typeToInstructionName(node.operand1 as AVTType) + 've');
end;
OPER_VECT_NE: begin
printer.printlnInstruction(typeToInstructionName(node.operand1 as AVTType) + 'vne');
end;
OPER_VECT_MULS: begin
printer.printlnInstruction(typeToInstructionName(node.operand1 as AVTType) + 'vmuls');
end;
OPER_VECT_ADDS: begin
printer.printlnInstruction(typeToInstructionName(node.operand1 as AVTType) + 'vadds');
end;
OPER_VECT_SUBS: begin
printer.printlnInstruction(typeToInstructionName(node.operand1 as AVTType) + 'vsubs');
end;
OPER_VECT_MULU: begin
printer.printlnInstruction(typeToInstructionName(node.operand1 as AVTType) + 'vmulu');
end;
OPER_VECT_ADDU: begin
printer.printlnInstruction(typeToInstructionName(node.operand1 as AVTType) + 'vaddu');
end;
OPER_VECT_SUBU: begin
printer.printlnInstruction(typeToInstructionName(node.operand1 as AVTType) + 'vsubu');
end;
STORE_STATIC: begin
with node.operand1 as AVTField do begin
printer.printlnInstruction(typeToInstructionName(valueType) + 'store', ['[' + fasmFullName + ']']);
end;
end;
SET_FIELD: begin
with node.operand1 as AVTField do begin
if parentType.isStruct() and valueType.isPrimitive() then begin
printer.printlnInstruction('setstructfield' + typeToInstructionName(valueType), [fasmStructName]);
end else begin
printer.printlnInstruction('setfield' + typeToInstructionName(valueType), [fasmFullName]);
end;
end;
end;
SET_PROPERTY: begin
with node.operand1 as AVTProperty do begin
interactMember := writeMember;
if isOverridden() or hasIndex or (interactMember = nil) then with writeSynthetic do begin
vindex := virtualIndex;
sindex := serviceIndex;
if sindex >= 0 then begin
printer.printlnInstruction('invokeservice', [parentType.fasmFullName, fasmShortName, avtIntToString(sindex)]);
end else
if vindex >= 0 then begin
printer.printlnInstruction('invokevirtual', [fasmFullName, avtIntToString(vindex)]);
end else begin
printer.printlnInstruction('invokespecial', [fasmFullName]);
end;
end else
if interactMember is AVTMethod then with AVTMethod(interactMember) do begin
vindex := virtualIndex;
sindex := serviceIndex;
if sindex >= 0 then begin
printer.printlnInstruction('invokeservice', [parentType.fasmFullName, fasmShortName, avtIntToString(sindex)]);
end else
if vindex >= 0 then begin
printer.printlnInstruction('invokevirtual', [fasmFullName, avtIntToString(vindex)]);
end else begin
printer.printlnInstruction('invokespecial', [fasmFullName]);
end;
end else
if interactMember is AVTField then with AVTField(interactMember) do begin
printer.printlnInstruction('setfield' + typeToInstructionName(valueType), [fasmFullName]);
end;
end;
end;
SET_ARRAY_ELEMENT: begin
printer.printlnInstruction('setarrayelement' + typeToInstructionName(node.operand1 as AVTType));
end
else
printer.printlnInstruction('; <invalid>');
end;
typ := node.dataType;
if (typ <> nil) and typ.isBoolean() and (jumpIsTrue <> nil) and (jumpIsFalse <> nil) then begin
if jumpIsFalse.order = nextOrder then begin
printer.printlnInstruction('ijmpt', [labelNumberToString(jumpIsTrue.labelNumber)]);
end else
if jumpIsTrue.order = nextOrder then begin
printer.printlnInstruction('ijmpf', [labelNumberToString(jumpIsFalse.labelNumber)]);
end else begin
printer.printlnInstruction('ijmpt', [labelNumberToString(jumpIsTrue.labelNumber)]);
printer.printlnInstruction('jmp', [labelNumberToString(jumpIsFalse.labelNumber)]);
end;
end;
end;
function AVTCodeGenerator.nonStackableTypeToStackable(typeRef: AVTType): AVTType;
var
kind: int;
begin
if typeRef is AVTTypePrimitive then begin
kind := AVTTypePrimitive(typeRef).primitiveKind;
if (kind = AVT_BOOLEAN) or (kind = AVT_CHAR) or (kind = AVT_BYTE) or (kind = AVT_SHORT) then begin
typeRef := getPrimitiveType(AVT_INT);
end;
end;
result := typeRef;
end;
constructor AVTCodeGenerator.create(programme: AVTProgramme);
begin
inherited create(programme);
self.i2 := AVTInt2Storage.create();
self.i4 := AVTInt4Storage.create();
self.i8 := AVTInt8Storage.create();
self.l := AVTLongStorage.create();
self.l2 := AVTLong2Storage.create();
self.l4 := AVTLong4Storage.create();
self.l8 := AVTLong8Storage.create();
self.f := AVTFloatStorage.create();
self.f2 := AVTFloat2Storage.create();
self.f4 := AVTFloat4Storage.create();
self.f8 := AVTFloat8Storage.create();
self.d := AVTDoubleStorage.create();
self.d2 := AVTDouble2Storage.create();
self.d4 := AVTDouble4Storage.create();
self.d8 := AVTDouble8Storage.create();
self.b2 := AVTByte2Storage.create();
self.b4 := AVTByte4Storage.create();
self.b8 := AVTByte8Storage.create();
self.s2 := AVTShort2Storage.create();
self.s4 := AVTShort4Storage.create();
self.s8 := AVTShort8Storage.create();
self.x := AVTRealStorage.create();
self.strings := AVTStringStorage.create();
self.debugInfoSources := AVTStringStorage.create();
self.debugInfoStrings := AVTStringStorage.create();
end;
destructor AVTCodeGenerator.destroy;
begin
i2.free();
i4.free();
i8.free();
l.free();
l2.free();
l4.free();
l8.free();
f.free();
f2.free();
f4.free();
f8.free();
d.free();
d2.free();
d4.free();
d8.free();
b2.free();
b4.free();
b8.free();
s2.free();
s4.free();
s8.free();
x.free();
strings.free();
debugInfoSources.free();
debugInfoStrings.free();
inherited destroy;
end;
function AVTCodeGenerator.generate(vfs: WriteableVirtualFileSystem; const directory: UnicodeString): UnicodeString;
var
isDir: boolean;
i: int;
lim: int;
dstDir: UnicodeString;
asmDir: UnicodeString;
avtDir: UnicodeString;
dstCodeDir: UnicodeString;
dstConstDir: UnicodeString;
dstDataDir: UnicodeString;
dstDbinfDir: UnicodeString;
dstResDir: UnicodeString;
dstResPath: UnicodeString;
asmCodeDir: UnicodeString;
asmConstDir: UnicodeString;
asmDataDir: UnicodeString;
asmResDir: UnicodeString;
avtResPath: UnicodeString;
codeDir: UnicodeString;
dataDir: UnicodeString;
progFile: UnicodeString;
name: UnicodeString;
resList: Hashtable;
packList: Vector;
pack: AVTPackage;
next: AVTPackage;
enum: FileEnumeration;
begin
dstDir := directory + 'dst';
asmDir := directory + 'src.asm/';
avtDir := directory + 'src.avt/';
{ 1. Подготовка папки dst }
enum := vfs.findFirst(dstDir);
if enum = nil then begin
vfs.createDirectory(dstDir);
end else begin
isDir := enum.isDirectory();
enum.close();
if isDir then begin
clearDirectory(vfs, dstDir + '/');
end else begin
vfs.deleteFile(dstDir); { На будущее: файл dst нужно переименовывать, а не удалять. }
vfs.createDirectory(dstDir);
end;
end;
dstDir := dstDir + '/';
dstCodeDir := dstDir + 'code';
dstConstDir := dstDir + 'const';
dstDataDir := dstDir + 'data';
dstDbinfDir := dstDir + 'dbinf';
dstResDir := dstDir + 'rsrc';
asmCodeDir := asmDir + 'code/';
asmConstDir := asmDir + 'const/';
asmDataDir := asmDir + 'data/';
asmResDir := asmDir + 'rsrc/';
{ 2. Создание подпапок }
vfs.createDirectory(dstCodeDir);
vfs.createDirectory(dstConstDir);
vfs.createDirectory(dstDataDir);
vfs.createDirectory(dstDbinfDir);
vfs.createDirectory(dstResDir);
dstCodeDir := dstCodeDir + '/';
dstConstDir := dstConstDir + '/';
dstDataDir := dstDataDir + '/';
dstDbinfDir := dstDbinfDir + '/';
dstResDir := dstResDir + '/';
{ 3. Копирование файлов }
copyFilesOnly(vfs, asmDir, dstDir);
copyFilesOnly(vfs, asmCodeDir, dstCodeDir);
copyFilesOnly(vfs, asmConstDir, dstConstDir);
copyFilesOnly(vfs, asmDataDir, dstDataDir);
copyFilesOnly(vfs, asmResDir, dstResDir);
{ 4. Компиляция пакетов }
progFile := dstDir + 'programme.asm';
resList := nil;
packList := Vector.create();
try
with programme.packages() do while hasMoreElements() do begin
pack := nextElement().objectValue() as AVTPackage;
if pack.types().hasMoreElements() then begin
if length(pack.fullName) <= 0 then begin
packList.insert(0, ValueOfObject.create(pack, false));
end else begin
packList.append(ValueOfObject.create(pack, false));
end;
end;
end;
next := packList.firstElement().objectValue() as AVTPackage;
lim := packList.size() - 1;
for i := 0 to lim do begin
pack := next;
if i >= lim then begin
next := nil;
end else begin
next := packList.elementAt(i + 1).objectValue() as AVTPackage;
end;
name := stringToUTF16(pack.fullName);
if length(name) <= 0 then begin
name := 'system.package';
end;
codeDir := dstCodeDir + name;
dataDir := dstDataDir + name;
vfs.createDirectory(codeDir);
vfs.createDirectory(dataDir);
compilePackage(pack, next, vfs, codeDir + '/', dataDir + '/', asmCodeDir + name + '/');
end;
{ 5. Генерация файла const/programme.inc }
compileProgrammeConstants(vfs, dstConstDir + 'programme.inc');
{ 6. Генерация отладочной информации }
compileProgrammeDebugInfo(vfs, dstDbinfDir);
{ 7. Копирование ресурсов }
resList := listResources(vfs, avtDir);
with resList.keys() do while hasMoreElements() do begin
name := nextElement().unicodeStringValue();
avtResPath := avtDir + name;
dstResPath := dstResDir + resourceDirToDir(name);
if length(name) > 0 then begin
enum := vfs.findFirst(dstResPath);
if enum = nil then begin
vfs.createDirectory(dstResPath);
end else begin
enum.close();
end;
dstResPath := dstResPath + '/';
end;
with (resList.get(ValueOfUnicodeString.create(name)).objectValue() as Vector).elements() do while hasMoreElements() do begin
name := nextElement().unicodeStringValue();
copyFile(vfs, avtResPath + name, dstResPath + name);
end;
end;
{ 8. Генерация файла programme.asm }
compileProgramme(vfs, progFile, packList, resList);
finally
packList.free();
resList.free();
end;
result := progFile;
end;
{%endregion}
end.