{
Компилятор языка программирования
Объектно-ориентированный продвинутый векторный транслятор
Copyright © 2021, 2024, 2026 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Стандартной
общественной лицензии GNU.
Вы должны были получить копию Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
}
program avtc;
{$MODE OBJFPC}
{%region} uses
pascalx.lang,
pascalx.lang.locale,
pascalx.lang.locale.rtlang,
pascalx.lang.math.avo,
pascalx.lang.math.vcoverage,
pascalx.io,
pascalx.io.bytearray,
pascalx.io.charset,
pascalx.io.charset.basiclatin,
pascalx.io.charset.eightbit,
pascalx.io.charset.rtlang,
pascalx.io.charset.unicode,
pascalx.io.extension,
platform.independent.filesystem,
platform.independent.osservices,
platform.independent.streamformat,
platform.independent.streamformat.compression.zlib,
platform.independent.streamformat.text,
platform.independent.streamformat.text.plain,
ru.malik.elaborarer.avtoo.lang,
ru.malik.elaborarer.avtoo.compiler,
ru.malik.elaborarer.avtoo.generator,
ru.malik.elaborarer.avtoo.avtc;
{%endregion}
{$R *.res}
{$R *.icons.res}
{$IFDEF WINDOWS}{$R *@windows.res}{$ELSE}{$R *@unix.res}{$ENDIF}
function loadParametersFrom(stream: ByteReader): UnicodeString_Array1d;
var
text: UnicodeString;
decoder: PlainCodec;
begin
decoder := PlainCodec.create();
try
decoder.loadFromInputStream(stream);
text := decoder.getText();
finally
decoder.free();
end;
if text.startsWith(#$feff) then text := text.substring(2);
result := text.split();
end;
function loadParametersFrom(fileSystem: FileSystem; const fileName: UnicodeString): UnicodeString_Array1d;
var
stream: ByteReader;
begin
stream := fileSystem.openFileForRead(fileName);
try
result := loadParametersFrom(stream);
finally
stream.close();
end;
end;
function main(const arguments: UnicodeString_Array1d): int;
var
isLibrary: boolean;
isReflect: boolean;
isProjectDirectorySet: boolean;
level: int;
debug: int;
index: int;
chpos: int;
time: long;
stdStreamCharsetName: AnsiString;
arg: UnicodeString;
low: UnicodeString;
value: UnicodeString;
prefix: UnicodeString;
parameter: UnicodeString;
overwritten: UnicodeString;
classpathName: UnicodeString;
projectRootPath: UnicodeString;
workingDirectory: UnicodeString;
processDirectory: UnicodeString;
projectDirectory: UnicodeString;
libraryDirectory: UnicodeString;
parameters: UnicodeString_Array1d;
stdOut: PrintStream;
stdErr: PrintStream;
lexThread: PrintThread;
codeThread: PrintThread;
currentProcess: Process;
programme: CodeGenerator;
projectLibrary: &Library;
projectFileSystem: FileSystem;
libraryFileSystem: FileSystem;
monitor: pascalx.lang.Monitor;
excludes: ru.malik.elaborarer.avtoo.compiler.UnicodeStringArray;
libraries: ru.malik.elaborarer.avtoo.compiler.UnicodeStringArray;
begin
result := 0;
stdOut := nil;
stdErr := nil;
try
{ стандартный вывод }
currentProcess := Process.current();
stdStreamCharsetName := Charset.getConsoleOutput().name;
stdOut := PrintStream.create(currentProcess.standardOutput, stdStreamCharsetName);
stdErr := PrintStream.create(currentProcess.standardError, stdStreamCharsetName);
{ проверка поддержки AVX-512 }
if not Vector.isAVX512SupportedByCPU() then begin
stdErr.println(AResource.readUnitResourceAsAnsiString(pascalx.lang.math.avo.UNIT_NAME, 'noavx.cpu'));
result := 207;
exit;
end;
if not Vector.isAVX512SupportedByOS() then begin
stdErr.println(AResource.readUnitResourceAsAnsiString(pascalx.lang.math.avo.UNIT_NAME, 'noavx.os'));
result := 207;
exit;
end;
{ переменные для хранения аргументов командной строки }
isProjectDirectorySet := false;
level := BinarySourceGenerator.LEVEL_CLASS;
debug := 0;
classpathName := '';
projectDirectory := '';
{ чтение аргументов командной строки }
for index := 1 to system.length(arguments) - 1 do begin
arg := arguments[index];
low := arg.toLowerCase();
prefix := '--level=';
if low.startsWith(prefix) then begin
value := low.substring(prefix.length + 1);
if value = 'pack' then begin
level := BinarySourceGenerator.LEVEL_PACKAGE;
continue;
end;
if value = 'lib' then begin
level := BinarySourceGenerator.LEVEL_LIBRARY;
end;
continue;
end;
prefix := '--debug=';
if low.startsWith(prefix) then begin
value := low.substring(prefix.length + 1);
if value = 'code' then begin
debug := 1;
continue;
end;
if value = 'lexemes' then begin
debug := 2;
continue;
end;
if value = 'both' then begin
debug := 3;
continue;
end;
if value = 'trace' then begin
debug := 4;
continue;
end;
if (value = 'code+trace') or (value = 'trace+code') then begin
debug := 5;
continue;
end;
if (value = 'lexemes+trace') or (value = 'trace+lexemes') then begin
debug := 6;
continue;
end;
if (value = 'both+trace') or (value = 'trace+both') then begin
debug := 7;
end;
continue;
end;
if not isProjectDirectorySet then begin
isProjectDirectorySet := true;
projectDirectory := arg;
continue;
end;
classpathName := arg;
end;
try
{ папки процесса }
workingDirectory := currentProcess.workingDirectory;
processDirectory := FileSystemRoot.toObjectPath(arguments[0]);
processDirectory := processDirectory.substring(1, processDirectory.lastIndexOf('/') + 1);
{ вывод приветствия }
stdOut.printlnf(AResource.readUnitResourceAsAnsiString('', 'title'), [ CoAnsiString.create(AVTOOConstants.getVersion()) ]);
{ папка проекта }
if not isProjectDirectorySet then begin
stdOut.println(AResource.readUnitResourceAsAnsiString('', 'help'));
result := 1;
exit;
end;
if FileSystemRoot.isInternalPathFull(projectDirectory) then begin
projectDirectory := FileSystemRoot.toObjectPath(projectDirectory);
end else begin
projectDirectory := workingDirectory + FileSystemRoot.get(workingDirectory).fileSystem.toObjectName(projectDirectory);
end;
if not projectDirectory.endsWith('/') then begin
projectDirectory := projectDirectory + '/';
end;
with FileSystemRoot.get(projectDirectory) do begin
projectRootPath := path;
projectDirectory := projectDirectory.substring(projectRootPath.length + 1);
projectFileSystem := fileSystem;
end;
{ файл параметров проекта }
if classpathName.length > 0 then begin
classpathName := projectFileSystem.toObjectName(classpathName);
end;
{ процесс компиляции }
{ время компиляции }
time := TimeBase.currentTimeInMillis();
{ параметры компиляции }
parameters := loadParametersFrom(projectFileSystem, projectDirectory + classpathName + '.classpath');
{ переменные для хранения параметров компиляции }
isLibrary := false;
isReflect := false;
excludes := nil;
libraries := nil;
programme := nil;
try
try
excludes := ru.malik.elaborarer.avtoo.compiler.UnicodeStringArray.create();
libraries := ru.malik.elaborarer.avtoo.compiler.UnicodeStringArray.create();
{ чтение параметров компиляции }
for index := 0 to system.length(parameters) - 1 do begin
parameter := parameters[index];
{ комментарии }
chpos := parameter.indexOf(';');
if chpos > 0 then begin
parameter := parameter.substring(1, chpos);
end;
{ параметры компиляции }
chpos := parameter.indexOf('=');
if chpos > 0 then begin
prefix := parameter.substring(1, chpos).trim();
value := parameter.substring(1 + chpos).trim();
if prefix = 'pointer-size' then begin
{ устаревший параметр }
continue;
end;
if prefix = 'library' then begin
isLibrary := (value <> '0') and (value.length > 0);
continue;
end;
if prefix = 'reflect' then begin
isReflect := (value <> '0') and (value.length > 0);
continue;
end;
end;
{ исключаемые из обработки файлы исходного кода }
prefix := '-';
parameter := parameter.trim();
if parameter.startsWith(prefix) then begin
excludes.append(parameter.substring(prefix.length + 1).trim());
continue;
end;
{ используемые проектом библиотеки }
if parameter.length > 0 then begin
libraries.append(parameter);
end;
end;
{ создание экземпляра компилятора }
if isLibrary then begin
programme := BinarySourceGenerator.create();
BinarySourceGenerator(programme).level := level;
end else begin
programme := AssemblerSourceGenerator.create(isReflect, classpathName.replaceAll('/', '.'));
end;
programme.documentationEnabled := (debug and 2) <> 0;
{ исключаемые из обработки файлы исходного кода }
with programme.excludes do for index := 0 to excludes.getLength() - 1 do begin
append(excludes.readComponent(index).asUnicodeString());
end;
{ используемые проектом библиотеки }
for index := 0 to libraries.getLength() - 1 do begin
libraryDirectory := libraries.readComponent(index).asUnicodeString();
if not libraryDirectory.startsWith('/') then libraryDirectory := processDirectory + libraryDirectory;
if not libraryDirectory.endsWith('/') then libraryDirectory := libraryDirectory + '/';
with FileSystemRoot.get(libraryDirectory) do begin
libraryDirectory := libraryDirectory.substring(path.length + 1);
libraryFileSystem := fileSystem;
end;
programme.createLibrary(libraryFileSystem, libraryDirectory, false);
end;
finally
excludes.free();
libraries.free();
end;
{ создание библиотеки проекта }
projectLibrary := programme.createLibrary(projectFileSystem, projectDirectory, not isLibrary);
try
{ компиляция проекта }
programme.compile();
except
on exc: RuntimeException do begin
exc.printStackTrace();
result := 4;
end;
on exc: Exception do begin
if (debug and 4) <> 0 then begin
exc.printStackTrace();
end else begin
stdErr.println(exc);
end;
if exc is CompilerException then begin
result := 2;
end else begin
result := 3;
end;
end;
end;
{ вывод времени и результатов компиляции }
time := (TimeBase.currentTimeInMillis() - time) div 100;
overwritten := programme.overwritten;
if (result <> 0) or (overwritten.length <= 0) then begin
stdOut.printlnf(AResource.readUnitResourceAsAnsiString('', 'time.only'), [
CoAnsiString.create(CoLong.toString(time div 10)),
CoAnsiString.create(CoLong.toString(time mod 10))
]);
end else begin
stdOut.printlnf(AResource.readUnitResourceAsAnsiString('', 'time.overwritten'), [
CoAnsiString.create(CoLong.toString(time div 10)),
CoAnsiString.create(CoLong.toString(time mod 10)),
CoUnicodeString.create(FileSystemRoot.toInternalPath(projectRootPath) + projectFileSystem.toInternalName(overwritten))
]);
end;
{ отладочная печать }
if (debug and 3) <> 0 then begin
monitor := pascalx.lang.Monitor.create();
try
lexThread := nil;
codeThread := nil;
if (debug and 1) <> 0 then begin
codeThread := PrintCodeThread.create(monitor, projectFileSystem, projectDirectory + 'debug.code.txt', programme);
codeThread.start();
end;
if (debug and 2) <> 0 then begin
lexThread := PrintLexemesThread.create(monitor, projectFileSystem, projectDirectory + 'debug.lexemes.txt', projectLibrary);
lexThread.start();
end;
monitor.beginSynchronized();
try
repeat
monitor.wait();
until ((codeThread = nil) or codeThread.isTerminated()) and ((lexThread = nil) or lexThread.isTerminated());
finally
monitor.endSynchronized();
end;
finally
monitor.free();
end;
end;
finally
programme.free();
end;
except
on exc: IOException do begin
exc.printStackTrace();
result := 3;
end;
on exc: Exception do begin
exc.printStackTrace();
result := 4;
end;
end;
finally
stdOut.free();
stdErr.free();
end;
end;
begin
exitCode := main(Process.current().commandLine);
end.