BravoToTioga.mesa, Jim Morris, July 12, 1982 3:35 pm
last written by Bill Paxton, November 30, 1982 9:20 am
Last Edited by: Plass, March 16, 1983 11:18 am
DIRECTORY
BtoT,
UserExec,
Rope,
FileIO,
IO,
SafeStorage,
TiogaFileOps;
BravoToTioga: CEDAR PROGRAM
IMPORTS R: Rope, FileIO, IO, T: TiogaFileOps, UserExec EXPORTS BtoT
= {
ROPE: TYPE = R.ROPE;
RCList: TYPE = LIST OF RECORD[coms: CList, span: INT];
CList: TYPE = LIST OF CHAR;
Font: ARRAY CHAR['1..'9] OF CHAR = ['s, , 'm, 'g, 'l, 'o, , 'f, 'x];
BtoTError: ERROR[c: CHAR, s1, s2: ROPE] = CODE;
Command: UserExec.CommandProc = {
in: IO.STREAMIO.CreateInputStreamFromRope[event.commandLine];
fileName: ROPE ← in.GetToken[];
outputName: ROPENIL;
outputName ← in.GetToken[! IO.EndOfStream => CONTINUE];
IF outputName.Equal["←"] THEN {
outputName ← fileName;
fileName ← in.GetToken[! IO.EndOfStream => CONTINUE];
};
msg ← IF fileName.Length[] > 0 THEN
IO.PutFToRope["%g written.\n", IO.rope[BravoToTioga[fileName, outputName]]]
ELSE "Empty file name.\n";
};
ParseLine: PROC [line: ROPE]
RETURNS [content: ROPE, paragraphData: ROPE, runCoding: ROPE] = {
contentEnd, pdStart, pEnd, rcStart: INT ← line.Length[];
State: TYPE = {inContent, inParagraphData, inRunCoding};
state: State ← inContent;
loc: INT ← 0;
Action: PROC [c: CHAR] RETURNS [BOOLFALSE] = {
SELECT state FROM
inContent => IF c=R.Control['Z] THEN {contentEnd ← loc; pdStart ← loc+1; state ← inParagraphData};
inParagraphData => IF c='\\ THEN {pEnd ← loc; rcStart ← loc+1; state ← inRunCoding};
inRunCoding => NULL;
ENDCASE => ERROR;
loc ← loc+1;
};
[] ← line.Map[action: Action];
content ← line.Substr[start: 0, len: contentEnd];
paragraphData ← line.Substr[start: pdStart, len: pEnd-pdStart];
runCoding ← line.Substr[start: rcStart];
};
GetInt: PROC[stream: IO.STREAM] RETURNS [value: INT ← 0] = {
WHILE NOT stream.EndOf[] AND stream.PeekChar[] IN ['0..'9] DO
value ← value * 10 + (stream.GetChar[] - '0);
ENDLOOP;
};
BravoToTioga: PUBLIC PROC[fileName: ROPE, outputName: ROPENIL]
RETURNS[actualOutputName: ROPE] = {
st: IO.Handle;
ParentStack: ARRAY [0..10) OF RECORD[node: T.Ref];
psp: [0..10) ← 0;
root: T.Ref;
node: T.Ref;
rootName: ROPE;
DotPos: INT = fileName.SkipTo[0, "."];
IF DotPos=fileName.Length[] THEN {rootName ← fileName; fileName ← fileName.Cat[".bravo"]}
ELSE rootName ← fileName.Substr[0, DotPos];
actualOutputName ← IF outputName=NIL THEN rootName.Cat[".tioga"] ELSE outputName;
st ← FileIO.Open[fileName, read];
root ← T.CreateRoot[]; T.SetStyle[root, "Cedar"];
node ← root;
ParentStack[0] ← [root];
UNTIL st.EndOf[] DO
newIndent: INT;
GetNum: PROC [keyChar: CHAR, default: INT ← 0] RETURNS [INT] = {
FOR j: INT IN [0..p.Length) DO
IF p.Fetch[j] = keyChar THEN {
value: INT ← 0;
FOR k: INT IN [j+1..p.Length) DO
digit: CHAR ← p.Fetch[k];
IF digit IN ['0..'9] THEN value ← value * 10 + (digit-'0) ELSE EXIT;
ENDLOOP;
RETURN[value];
};
ENDLOOP;
RETURN[default]
};
c, p, r: ROPE;
[content: c, paragraphData: p, runCoding: r] ← ParseLine[IO.GetSequence[st]];
newIndent ← MIN[psp+1, GetNum['l, 3000]/(2540/2)];
Force to be even half inches
and at most one indent greater than parent
IF st.PeekChar[] = IO.CR THEN [] ← st.GetChar[];
UNTIL psp<=1 OR newIndent >= psp DO psp ← psp-1 ENDLOOP;
IF newIndent>psp THEN {
psp ← psp+1;
ParentStack[psp] ← [node ← T.InsertNode[ParentStack[psp-1].node, TRUE]]
}
ELSE {
ParentStack[psp].node ← node ← T.InsertNode[ParentStack[psp].node, FALSE]
};
T.SetContents[node, c];
T.SetFormat[node, "indent"];
{here: INT ← 0;
FOR l: RCList ← ParseRC[r, c.Length[]], l.rest UNTIL l=NIL DO
c: CList ← l.first.coms;
UNTIL c=NIL DO
SELECT c.first FROM
'f => {d: CHAR = c.rest.first;
c ← c.rest;
IF d='2 THEN {T.SetFormat[node, "logo"]}
ELSE IF d='7 THEN {x: INT = ComputeRun[l, 'f];
T.AddLooks[node, here, x, 'o, root];
T.AddLooks[node, here, x, 's, root]}
ELSE IF d#'0 THEN
{T.AddLooks[node, here, ComputeRun[l, 'f], Font[d], root]}};
't, 'o => c ← c.rest;
'b, 'i, 'z => {T.AddLooks[node, here, ComputeRun[l, R.Upper[c.first]], c.first, root]};
'u, 'd => {T.AddLooks[node, here, ComputeRun[l, 'D], c.first, root]};
ENDCASE;
c ← c.rest;
ENDLOOP;
here ← here + l.first.span;
ENDLOOP};
ENDLOOP;
{T.Store[root, actualOutputName]};
st.Close[];
};
ParseRC: PROC[r: ROPE, l: INT] RETURNS[RCList] =
{ms: IO.STREAMIO.CreateInputStreamFromRope[r];
P: PROC RETURNS [RCList] =
{IF ms.EndOf[] THEN RETURN [NIL];
{c: CList = GetComs[];
i: INT = GetSpan[];
RETURN[CONS[[c, i], P[]]]}};
GetComs: PROC RETURNS [CList] =
{IF ms.EndOf[] THEN RETURN[NIL];
SELECT ms.PeekChar[] FROM
'o => {[] ← ms.GetChar[];
{n: INT = GetInt[ms]; -- n>128 implies subscript, n=0 implies neither
RETURN[CONS[(IF n=0 THEN 'D ELSE IF n>128 THEN 'd ELSE 'u), GetComs[]]]}};
'f, 't=> {RETURN[CONS[ms.GetChar[], CONS[ms.GetChar[], GetComs[]]]]};
'b, 'i, 'B, 'I, 'v, 'V, 'g, 'G, 's, 'S => {RETURN[CONS[ms.GetChar[], GetComs[]]]};
'u => {[] ← ms.GetChar[]; RETURN[CONS['z, GetComs[]]]};
'U => {[] ← ms.GetChar[]; RETURN[CONS['Z, GetComs[]]]};
' => {[] ← ms.GetChar[]; RETURN[NIL]};
IN ['0..'9] => RETURN[NIL];
ENDCASE => ERROR BtoTError[ms.PeekChar[], " unexpected in trailer ", r]};
GetSpan: PROC RETURNS[n: INT] =
{IF ms.EndOf[] THEN RETURN[l];
n ← GetInt[ms];
l ← l-n};
RETURN[P[]]};
ComputeRun: PROC[l: RCList, stop: CHAR] RETURNS [i: INT] =
{i ← l.first.span;
FOR x: RCList ← l.rest, x.rest UNTIL x=NIL DO
FOR t: CList ← x.first.coms, t.rest UNTIL t=NIL DO
IF t.first=stop THEN RETURN;
ENDLOOP;
i ← i+x.first.span;
ENDLOOP};
UserExec.RegisterCommand["BravoToTioga", Command, "Conversion program"];
}..