MODULE CompilerInterface;
IMPORT
KernelLog, Streams, Commands, Strings, Texts, Diagnostics;
CONST
ModuleName = "CompilerInterface";
TYPE
Name* = ARRAY 16 OF CHAR;
Description* = ARRAY 128 OF CHAR;
FileExtension* = ARRAY 16 OF CHAR;
CompileTextProc* = PROCEDURE {DELEGATE} (t : Texts.Text; CONST source: ARRAY OF CHAR; pos: LONGINT; CONST pc,opt: ARRAY OF CHAR;
log: Streams.Writer; diagnostics : Diagnostics.Diagnostics; VAR error: BOOLEAN);
TYPE
Compiler* = OBJECT
VAR
name- : Name;
description- : Description;
fileExtension- : FileExtension;
compileText : CompileTextProc;
next : Compiler;
PROCEDURE CompileText*(t : Texts.Text; CONST source: ARRAY OF CHAR; pos: LONGINT; CONST pc,opt: ARRAY OF CHAR;
log: Streams.Writer; diagnostics : Diagnostics.Diagnostics; VAR error: BOOLEAN);
VAR
trap : BOOLEAN;
BEGIN
trap := FALSE;
IF (compileText # NIL) THEN
compileText(t, source, pos, pc, opt, log, diagnostics, error);
ELSIF (diagnostics # NIL) THEN
diagnostics.Error(source, Diagnostics.Invalid, Diagnostics.Invalid, "Text compile procedure not set");
END;
FINALLY
IF trap THEN
error := TRUE;
diagnostics.Error(source, Diagnostics.Invalid, Diagnostics.Invalid, "COMPILER TRAPPED");
log.String("COMPILER TRAPPED!!!"); log.Update;
END;
END CompileText;
PROCEDURE Show(out : Streams.Writer);
BEGIN
out.String(name);
out.String(" ("); out.String(description); out.String(") ");
out.String("File Extension: "); out.String(fileExtension);
out.Ln;
END Show;
PROCEDURE &Init*(
CONST name : Name;
CONST description : Description;
CONST fileExtension : FileExtension;
compileText : CompileTextProc
);
BEGIN
SELF.name := name; SELF.description := description; SELF.fileExtension := fileExtension;
SELF.compileText := compileText;
END Init;
END Compiler;
VAR
compilers : Compiler;
PROCEDURE FindCompilerByName(CONST name : ARRAY OF CHAR) : Compiler;
VAR c : Compiler;
BEGIN
c := compilers;
WHILE (c # NIL) & (c.name # name) DO c := c.next; END;
RETURN c;
END FindCompilerByName;
PROCEDURE GetCompiler*(fileExtension : FileExtension) : Compiler;
VAR c : Compiler;
BEGIN {EXCLUSIVE}
Strings.UpperCase(fileExtension);
c := compilers;
WHILE (c # NIL) & (c.fileExtension # fileExtension) DO c := c.next; END;
RETURN c;
END GetCompiler;
PROCEDURE GetCompilerByName*(CONST name : ARRAY OF CHAR) : Compiler;
BEGIN {EXCLUSIVE}
RETURN FindCompilerByName(name);
END GetCompilerByName;
PROCEDURE GetCompilerByFilename*(filename : ARRAY OF CHAR) : Compiler;
VAR c : Compiler; pos : LONGINT;
BEGIN {EXCLUSIVE}
Strings.UpperCase(filename);
c := compilers;
LOOP
IF (c = NIL) THEN EXIT; END;
pos := Strings.Pos(c.fileExtension, filename);
IF (pos > 0) & (filename[pos-1] = ".") THEN
EXIT;
END;
c := c.next;
END;
RETURN c;
END GetCompilerByFilename;
PROCEDURE Show*(context : Commands.Context);
VAR c : Compiler;
BEGIN {EXCLUSIVE}
IF (compilers = NIL) THEN
context.out.String("No compilers registered."); context.out.Ln;
ELSE
c := compilers;
WHILE (c # NIL) DO c.Show(context.out); c := c.next; END;
END;
END Show;
PROCEDURE Register*(
CONST name : Name;
CONST description : Description;
fileExtension : FileExtension;
compileText : CompileTextProc);
VAR
c : Compiler;
BEGIN {EXCLUSIVE}
ASSERT(compileText # NIL);
c := FindCompilerByName(name);
IF (c = NIL) THEN
Strings.UpperCase(fileExtension);
NEW(c, name, description, fileExtension, compileText);
c.next := compilers; compilers := c;
ELSE
KernelLog.Enter;
KernelLog.String(ModuleName); KernelLog.String(": Cannot register compiler '");
KernelLog.String(name); KernelLog.String("': Name is already in use.");
KernelLog.Exit;
END;
END Register;
PROCEDURE Unregister*(CONST name : Name);
VAR prev : Compiler;
BEGIN {EXCLUSIVE}
IF (compilers = NIL) THEN RETURN; END;
IF (compilers.name = name) THEN
compilers := compilers.next;
ELSE
prev := compilers;
WHILE(prev.next # NIL) & (prev.next.name # name) DO prev := prev.next; END;
IF (prev.next # NIL) THEN
prev.next := prev.next.next;
END;
END;
END Unregister;
BEGIN
compilers := NIL;
END CompilerInterface.
CompilerInterface.Show ~
SystemTools.Free CompilerInterface ~