C2COnlyImpl.mesa
Copyright Ó 1987, 1988, 1989, 1990, 1991 by Xerox Corporation. All rights reserved.
Christian Jacobi, February 23, 1987 11:58:50 am PST
Christian Jacobi, October 8, 1990 6:01:17 pm PDT
Russ Atkinson (RRA) March 23, 1989 6:13:00 am PST
JKF August 2, 1988 7:10:08 am PDT
A way of calling C2C directly without explicite Mimosa front end.
Useful for debugging C2C.
Michael Plass, September 27, 1991 11:24 am PDT
DIRECTORY
Ascii,
CardTab,
C2CAccess,
Commander,
CommanderOps,
FileNames,
FS,
IntCodeDefs,
IO,
ParseIntCode,
Process,
ProcessProps,
RefText,
Rope,
SymTab,
UserProfile;
C2COnlyImpl: CEDAR PROGRAM
IMPORTS CardTab, C2CAccess, Commander, CommanderOps, FileNames, FS, IO, ParseIntCode, Process, ProcessProps, RefText, Rope, UserProfile =
BEGIN
failedAndMessaged: ERROR = CODE;
icdExtension: Rope.ROPE ¬ ".icd";
namesExtension: Rope.ROPE ¬ ".names";
outputExtension: Rope.ROPE ¬ ".c2c.c";
externProcsExtension: Rope.ROPE ¬ ".externProcs";
defaultSwitches: Rope.ROPE ¬ "-";
documentation: Rope.ROPE ¬ "Cedar To C (IntCode to C translator) debugging mode";
globalErrorStream: IO.STREAM ¬ NIL;
ScanNames: PROC [namesStream: IO.STREAM, names, labels: CardTab.Ref] = {
ScanLine: PROC [line: REF TEXT] = {
ENABLE {
IO.Error => GOTO Oops;
IO.EndOfStream => GOTO Oops;
};
usedTable: CardTab.Ref ¬ names;
id: INT;
name: Rope.ROPE;
st: IO.STREAM ¬ IO.TIS[line];
--read id number
DO
[] ¬ IO.SkipWhitespace[st];
SELECT IO.PeekChar[st] FROM
'- => RETURN; --comment line ?? no negative id's?
'% => {[] ¬ IO.GetChar[st]; usedTable ¬ labels; LOOP};
IN ['0..'9] => id ¬ IO.GetInt[st];
ENDCASE => RETURN; --error
EXIT;
ENDLOOP;
--read colon (separator)
[] ¬ IO.SkipWhitespace[st];
SELECT IO.PeekChar[st] FROM
': => [] ¬ IO.GetChar[st];
ENDCASE => RETURN; --error
--read id name
DO
[] ¬ IO.SkipWhitespace[st];
SELECT IO.PeekChar[st] FROM
IN ['a..'z], IN ['A..'Z] => name ¬ IO.GetID[st];
'& => {[] ¬ IO.GetChar[st]; LOOP};
ENDCASE => RETURN; --error;
EXIT;
ENDLOOP;
IF usedTable#NIL THEN [] ¬ CardTab.Insert[usedTable, LOOPHOLE[id], name];
EXITS Oops => NULL;
};
IF namesStream#NIL THEN {
line: REF TEXT ¬ RefText.ObtainScratch[200];
DO
line ¬ IO.GetLine[namesStream, line
! IO.EndOfStream => {RefText.ReleaseScratch[line]; GOTO done}
];
ScanLine[line];
ENDLOOP;
};
EXITS done => NULL;
};
DefineSwitch: PROC [switch: Rope.ROPE, sense: BOOL, doc: Rope.ROPE ¬ NIL] = {
--for c2conly command; not for Mimosa
IF ~sense THEN defaultSwitches ¬ Rope.Concat[defaultSwitches, "~"];
defaultSwitches ¬ Rope.Concat[defaultSwitches, switch];
IF doc#NIL THEN {
documentation ¬ IO.PutFLR["%g\n%g-%g: %g [%g]", LIST[IO.rope[documentation], IO.char[Ascii.TAB], IO.rope[switch], IO.rope[doc], IO.char[IF sense THEN 'T ELSE 'F]]];
};
};
CreateErrStream: PROC [] RETURNS [err: IO.STREAM] = {
err ¬ globalErrorStream;
IF err=NIL THEN {
WITH ProcessProps.GetProp[$ErrOut] SELECT FROM
s: IO.STREAM => err ¬ s;
ENDCASE => err ¬ IO.noWhereStream;
globalErrorStream ¬ err
};
};
GenCCommand: Commander.CommandProc = {
searchRules: REF ANY ¬ CommanderOps.GetProp[cmd, $SearchRules];
filePattern: Rope.ROPE ¬ NIL;
floatInlineSwitch: BOOL ¬ FALSE;
referenceCountSwitch: BOOL ¬ FALSE;
debugSwitch: BOOL ¬ TRUE;
externProcSwitch: BOOL ¬ FALSE;
minKeep: INT ¬ MAX[UserProfile.Number[key: "C2C.MinKeep", default: 2], 1];
CreateOutput: PROC [outputName: Rope.ROPE] RETURNS [output: IO.STREAM] = {
keep: INT ¬ minKeep;
keep ¬ FS.FileInfo[name: outputName, remoteCheck: FALSE ! FS.Error => CONTINUE].keep;
IF keep<minKeep THEN {
keep ¬ minKeep;
FS.SetKeep[name: outputName, keep: keep ! FS.Error => CONTINUE]
};
output ¬ FS.StreamOpen[fileName: outputName, accessOptions: $create, keep: keep];
IF output=NIL THEN {
IO.PutRope[cmd.out, "== output file not created\n"];
ERROR failedAndMessaged
};
};
OpenInput: PROC [pattern, ext, purpose: Rope.ROPE] RETURNS [input: IO.STREAM, name: Rope.ROPE] = {
FindInputName: PROC [pattern: Rope.ROPE, ext: Rope.ROPE] RETURNS [fileName: Rope.ROPE] = {
fileName ¬ FileNames.FileWithSearchRules[
root: pattern,
defaultExtension: ext,
requireExtension: TRUE, requireExact: TRUE,
searchRules: searchRules].fullPath;
};
Open: PROC [name, purpose: Rope.ROPE] RETURNS [input: IO.STREAM] = {
input ¬ FS.StreamOpen[name, $read
! FS.Error => {
IO.PutRope[cmd.out, "== "];
IO.PutRope[cmd.out, purpose];
IO.PutRope[cmd.out, " "];
IO.PutRope[cmd.out, error.explanation];
IO.PutRope[cmd.out, "\n"];
ERROR failedAndMessaged
}];
};
IF pattern=NIL THEN {
IO.PutRope[cmd.out, "== "];
IO.PutRope[cmd.out, purpose];
IO.PutRope[cmd.out, " no name\n"];
ERROR failedAndMessaged
};
name ¬ FindInputName[pattern, ext];
IF Rope.IsEmpty[name] THEN {
IO.PutRope[cmd.out, "== "];
IO.PutRope[cmd.out, purpose];
IO.PutRope[cmd.out, " not found\n"];
ERROR failedAndMessaged
};
input ¬ Open[name, purpose];
IF input=NIL THEN {
IO.PutRope[cmd.out, "== "];
IO.PutRope[cmd.out, purpose];
IO.PutRope[cmd.out, " not found\n"];
ERROR failedAndMessaged
};
};
MyClose: PROC [stream: IO.STREAM] = {
IF stream#NIL THEN IO.Close[stream]
};
ProcessSwitches: PROC [arg: Rope.ROPE] = {
sense: BOOL ¬ TRUE;
FOR index: INT IN [0..Rope.Length[arg]) DO
SELECT Rope.Fetch[arg, index] FROM
'~ => {sense ¬ NOT sense; LOOP};
'd, 'D => debugSwitch ¬ sense;
'f, 'F => floatInlineSwitch ¬ sense;
'x, 'X => externProcSwitch ¬ sense;
'q, 'Q => referenceCountSwitch ¬ sense;
ENDCASE;
sense ¬ TRUE;
ENDLOOP;
};
CompileOneFile: PROC [filePattern: Rope.ROPE ¬ NIL] = {
regularNamesStream: IO.STREAM;
icdStream: IO.STREAM;
icdName: Rope.ROPE;
pleaseDestroyWhenFinished: IntCodeDefs.Node¬NIL;
params: C2CAccess.InputParameters;
ok: BOOL;
OutputName: PROC [] RETURNS [outputName: Rope.ROPE ¬ NIL] = {
shortName: Rope.ROPE ¬ FileNames.GetShortName[icdName];
outputName ¬ Rope.Replace[
base: shortName,
start: Rope.Length[shortName]-Rope.Length[icdExtension],
with: outputExtension];
};
innerFailed: BOOL ¬ FALSE;
Inner: PROC [] = {
names: CardTab.Ref ¬ CardTab.Create[];
labels: CardTab.Ref ¬ CardTab.Create[];
nodes: IntCodeDefs.NodeList;
externProcs: SymTab.Ref ¬ NIL;
synopsis: Rope.ROPE;
ScanNames[regularNamesStream, names, labels];
nodes ¬ ParseIntCode.FromStream[icdStream
! ParseIntCode.SyntaxError => {
IO.PutRope[cmd.out, " ==failed parsing intcode "]; IO.PutRope[cmd.out, why];
GOTO Oops
}
];
IF nodes=NIL OR nodes.rest#NIL THEN GOTO Oops;
params.root ¬ nodes.first;
params.supportInlineFloatingPoint ¬ floatInlineSwitch;
params.supportReferenceCounting ¬ referenceCountSwitch;
params.debuggingMode ¬ debugSwitch;
params.destroyRoot ¬ FALSE;
params.names ¬ names;
params.labels ¬ labels;
params.lineTerminationChar ¬ Ascii.LF;
BEGIN
outputName: Rope.ROPE ¬ OutputName[];
params.outputStream ¬ CreateOutput[outputName ! failedAndMessaged => GOTO Oops];
END;
globalErrorStream ¬ NIL;
[ok, synopsis] ¬ C2CAccess.CallC2C[params];
MyClose[params.outputStream ! failedAndMessaged => GOTO Oops];
IF ~ok THEN GOTO Oops;
EXITS Oops => {
innerFailed ¬ TRUE;
result ¬ $Failure
};
};
params.getErrorStream ¬ CreateErrStream;
params.versionStamp ¬ "";
innerFailed ¬ FALSE;
IO.PutRope[cmd.out, "C2C "]; IO.PutRope[cmd.out, filePattern]; IO.PutRope[cmd.out, " "];
[icdStream, icdName] ¬ OpenInput[filePattern, icdExtension, "intermediate code file" ! failedAndMessaged => GOTO Oops];
params.fileName ¬ icdName;
regularNamesStream ¬ OpenInput[filePattern, namesExtension, "names file" ! failedAndMessaged => GOTO Oops].input;
IF externProcSwitch THEN {
params.namesStream ¬ OpenInput[filePattern, externProcsExtension, "extern procs file" ! failedAndMessaged => GOTO Oops].input;
};
C2CAccess.ExcludeReEntry[Inner];
MyClose[regularNamesStream ! failedAndMessaged => GOTO Oops];
MyClose[icdStream ! failedAndMessaged => GOTO Oops];
IF innerFailed
THEN IO.PutRope[cmd.out, "\n"]
ELSE IO.PutRope[cmd.out, "done\n"];
EXITS Oops => result ¬ $Failure
};
argv: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd: cmd
! CommanderOps.Failed => {msg ¬ errorMsg; GO TO Oops}
];
Process.SetPriority[Process.priorityBackground];
ProcessSwitches[defaultSwitches];
result ¬ NIL;
FOR i: NAT IN [1..argv.argc) DO
arg: Rope.ROPE = argv[i];
IF Rope.Length[arg] = 0 THEN LOOP;
IF Rope.Fetch[arg, 0] = '- THEN {
This argument sets switches for the remaining patterns
ProcessSwitches[arg];
LOOP;
};
Now the argument is assumed to be a file pattern.
CompileOneFile[arg];
ENDLOOP;
IO.PutRope[cmd.out, "End of compilation\n"];
IF result=NIL THEN result ¬ $Success;
IO.PutRope[cmd.out, IF result=$Success THEN "S\n" ELSE "F\n"];
EXITS Oops => result ¬ $Failure
};
--these switches are defined for c2c command
DefineSwitch["d", TRUE, "Debugging the compiler"];
DefineSwitch["f", FALSE, "inline Floating point"];
DefineSwitch["r", FALSE, "exteRnProc file used"];
DefineSwitch["q", FALSE, "support reference counting"];
Commander.Register[key: "C2COnly", proc: GenCCommand, doc: documentation];
END.