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.STREAM ← IO.CreateInputStreamFromRope[event.commandLine];
fileName:
ROPE ← in.GetToken[];
outputName: ROPE ← NIL;
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 [
BOOL←
FALSE] = {
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:
ROPE ←
NIL]
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]};
ParseRC:
PROC[r:
ROPE, l:
INT]
RETURNS[RCList] =
{ms:
IO.
STREAM ←
IO.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"];