DIRECTORY Ascii, Commander, CommanderOps, Convert, Rope, IO, PFS; MetaCedarImpl: CEDAR PROGRAM IMPORTS Commander, CommanderOps, Convert, Rope, IO, PFS = BEGIN ROPE: TYPE ~ Rope.ROPE; RopePair: TYPE ~ RECORD [name, value: ROPE]; Scanner: TYPE ~ REF ScannerRep; ScannerRep: TYPE ~ RECORD [ stream: IO.STREAM, tokenKind: Kind, inputBuffer: REF TEXT, locationOfBufferStart: INT, identifierScratch: REF TEXT, tokenStart: NAT, tokenLength: NAT ]; inputBufferSize: NAT ¬ 1024; identifierScratchSize: NAT ¬ 120; CreateScanner: PROC [stream: IO.STREAM] RETURNS [scanner: Scanner] ~ { scanner ¬ NEW[ScannerRep ¬ [ stream: stream, tokenKind: whitespace, inputBuffer: NEW[TEXT[inputBufferSize]], locationOfBufferStart: IO.GetIndex[stream], identifierScratch: NEW[TEXT[identifierScratchSize]], tokenStart: 0, tokenLength: 0 ]]; }; Kind: TYPE ~ {identifier, special, whitespace, newline, eof}; KindOf: PROC [c: CHAR] RETURNS [Kind] ~ { SELECT c FROM IN ['a..'z], IN ['A..'Z], IN ['0..'9], '$ => RETURN [identifier]; Ascii.SP, Ascii.TAB, Ascii.LF => RETURN [whitespace]; Ascii.CR => RETURN [newline]; ENDCASE => RETURN [special]; }; breakLoc: INT ¬ LAST[INT]; breakCount: INT ¬ 0; GetToken: PROC [scanner: Scanner] ~ { scanner.tokenStart ¬ scanner.tokenStart+scanner.tokenLength; scanner.tokenLength ¬ 0; IF scanner.tokenStart>=scanner.inputBuffer.length THEN RefillBuffer[scanner]; IF scanner.inputBuffer.length = 0 THEN {scanner.tokenKind ¬ eof; RETURN}; scanner.tokenKind ¬ KindOf[scanner.inputBuffer[scanner.tokenStart]]; IF scanner.tokenKind = special THEN { scanner.tokenLength ¬ 1; RETURN; }; WHILE scanner.tokenStart+scanner.tokenLength 0 THEN { IO.PutF[out, "Ptxt[%g, %g];\n", [integer[copiedTextStart]], [integer[copiedTextLength]]]; }; copiedTextStart ¬ -1; copiedTextLength ¬ 0; }; CopyOut: PROC ~ { IF mode#text THEN ERROR; IF copiedTextStart+copiedTextLength = scanner.locationOfBufferStart+scanner.tokenStart THEN copiedTextLength ¬ copiedTextLength + scanner.tokenLength ELSE IF scanner.tokenLength > 0 THEN { Flush[]; copiedTextStart ¬ scanner.locationOfBufferStart+scanner.tokenStart; copiedTextLength ¬ scanner.tokenLength; }; lineStart ¬ FALSE; }; CopyMetaOut: PROC ~ { IF scanner.tokenLength > 0 THEN { Flush[]; IO.PutBlock[out, scanner.inputBuffer, scanner.tokenStart, scanner.tokenLength]; }; lineStart ¬ FALSE; }; arg: ROPE ¬ NIL; unquoted: ROPE ¬ NIL; CopyQuotedOut: PROC ~ { arg ¬ Rope.Concat[arg, Rope.FromRefText[s: scanner.inputBuffer, start: scanner.tokenStart, len: scanner.tokenLength]]; }; CopyUnquotedOut: PROC [type: ROPE] ~ { id: ROPE ~ Rope.FromRefText[s: scanner.inputBuffer, start: scanner.tokenStart, len: scanner.tokenLength]; arg ¬ Rope.Concat[arg, "%g"]; IF unquoted # NIL THEN unquoted ¬ Rope.Concat[unquoted, ", "]; unquoted ¬ Rope.Concat[unquoted, IO.PutFR["[%g[%g]]", [rope[type]], [rope[id]]]]; }; QFlush: PROC ~ { Flush[]; IF unquoted # NIL THEN IO.PutRope[out, "IO.PutFLR["]; IF arg#NIL THEN IO.PutRope[out, Convert.RopeFromRope[arg]]; IF unquoted # NIL THEN { IO.PutRope[out, ", LIST["]; IO.PutRope[out, unquoted]; IO.PutRope[out, "]]"]; }; unquoted ¬ arg ¬ NIL; }; StartPlain: PROC = { mode ¬ text; }; startMetaCount: INT ¬ 0; StartMeta: PROC [eof: BOOL ¬ FALSE] = { Flush[]; mode ¬ meta; }; MetaText: PROC [rope: ROPE] = { IF mode#text THEN ERROR; Flush[]; IO.PutRope[out, rope]; }; inxx: BOOL ¬ FALSE; nestCount: NAT ¬ 0; qnest: INT ¬ 0; beginStackTop: NAT ¬ 0; beginStack: ARRAY [0..50) OF NAT; GetToken[scanner]; IO.PutF[out, boilerPlateBegin, [rope[outputNameStem]], [rope[outputNameStem]], [rope[fileNameStem]]]; WriteBindings[binding]; StartPlain[]; WHILE scanner.tokenKind # eof DO SELECT mode FROM meta => { SELECT scanner.tokenKind FROM special => SELECT scanner.inputBuffer[scanner.tokenStart] FROM ' => StartPlain[]; ' => MetaError[scanner.locationOfBufferStart+scanner.tokenStart]; ENDCASE => CopyMetaOut[]; ENDCASE => CopyMetaOut[]; }; quoteargs => { SELECT scanner.tokenKind FROM special => SELECT scanner.inputBuffer[scanner.tokenStart] FROM ', => { IF qnest = 0 THEN {QFlush[]; IO.PutRope[out, ", "]} ELSE CopyQuotedOut[] }; '(, '{, '[ => {qnest ¬ qnest + 1; CopyQuotedOut[]}; '), '} => { qnest ¬ qnest - 1; IF qnest < 0 THEN MetaError[scanner.locationOfBufferStart+scanner.tokenStart] ELSE CopyQuotedOut[] }; '] => { qnest ¬ qnest - 1; IF qnest < 0 THEN {mode ¬ text; QFlush[]; IO.PutRope[out, "]; "]} ELSE CopyQuotedOut[] }; '& => { GetToken[scanner]; CopyUnquotedOut["integer"]; }; '% => { GetToken[scanner]; CopyUnquotedOut["rope"]; }; '?, ', ' => { MetaError[scanner.locationOfBufferStart+scanner.tokenStart]; }; ENDCASE => CopyQuotedOut[]; ENDCASE => CopyQuotedOut[]; }; text => { SELECT scanner.tokenKind FROM special => SELECT scanner.inputBuffer[scanner.tokenStart] FROM ' => StartMeta[]; ' => MetaError[scanner.locationOfBufferStart+scanner.tokenStart]; '(, '{, '[ => {nestCount ¬ nestCount + 1; CopyOut[]}; '), '}, '] => {nestCount ¬ nestCount - 1; CopyOut[]}; '& => { Flush[]; GetToken[scanner]; IO.PutRope[out, "PutInt["]; CopyMetaOut[]; IO.PutRope[out, "]; "]; }; '% => { Flush[]; GetToken[scanner]; IO.PutRope[out, "stream.PutRope["]; CopyMetaOut[]; IO.PutRope[out, "]; "]; }; '? => { Flush[]; GetToken[scanner]; CopyMetaOut[]; GetToken[scanner]; IF scanner.inputBuffer[scanner.tokenStart] # '[ THEN MetaError[scanner.locationOfBufferStart+scanner.tokenStart]; IO.PutRope[out, "["]; qnest ¬ 0; mode ¬ quoteargs; }; ENDCASE => CopyOut[]; newline => {CopyOut[]; lineStart ¬ TRUE}; whitespace => IF lineStart THEN NULL ELSE CopyOut[]; identifier => { CopyOut[]; SELECT TRUE FROM Match[scanner, "DO"], Match[scanner, "FROM"], Match[scanner, "BEGIN"] => { MetaText["Begin[];"]; beginStack[beginStackTop] ¬ nestCount; beginStackTop ¬ beginStackTop + 1; }; Match[scanner, "ENDLOOP"], Match[scanner, "ENDCASE"], Match[scanner, "END"] => { MetaText["End[];"]; beginStackTop ¬ beginStackTop - 1; IF beginStack[beginStackTop] # nestCount THEN MetaError[scanner.locationOfBufferStart+scanner.tokenStart]; }; ENDCASE => NULL; }; ENDCASE => CopyOut[]; }; ENDCASE => ERROR; GetToken[scanner]; ENDLOOP; IF mode=meta THEN StartPlain[]; StartMeta[eof: TRUE]; IO.PutRope[out, boilerPlateEnd]; IO.Close[in]; IO.Close[out]; }; boilerPlateBegin: ROPE = " DIRECTORY Rope, IO, PFS; MetaProgram: CEDAR PROGRAM IMPORTS Rope, IO, PFS = { ROPE: TYPE ~ Rope.ROPE; TwoToThe: PROC [a: INT] RETURNS [b: INT] ~ { IF a < 0 THEN RETURN [0]; b _ 1; THROUGH [0..a) DO b _ b+b ENDLOOP; }; ModuleName: PROC ~ {IO.PutRope[stream, \"%g\"]}; stream: IO.STREAM ~ PFS.StreamOpen[PFS.PathFromRope[\"%g.mesa\"], $create]; nest: NAT _ 0; Begin: PROC ~ {nest _ nest + 1}; End: PROC ~ {nest _ nest - 1}; PutInt: PROC [i: INT] ~ { IO.PutF1[stream, IF i < 0 THEN \"(%%g)\" ELSE \"%%g\", [integer[i]]]}; metaSource: ROPE ~ PFS.RopeOpen[PFS.PathFromRope[\"%g.meta\"]].rope; Ptxt: PROC [start, length: CARDINAL] ~ { s: INT _ start; FOR i: INT IN [start..start+length) DO SELECT metaSource.Fetch[i] FROM '{, '[, '( => Begin[]; '}, '], ') => End[]; '\r => { stream.PutRope[metaSource.Substr[s, i-s+1]]; FOR i: NAT IN [0..nest) DO stream.PutChar['\t] ENDLOOP; s _ i+1; }; ENDCASE => NULL; ENDLOOP; stream.PutRope[metaSource.Substr[s, start+length-s]]; }; "; boilerPlateEnd: ROPE = "IO.Close[stream]}."; GetCmdToken: PROC [stream: IO.STREAM] RETURNS [rope: ROPE ¬ NIL] ~ { rope ¬ IO.GetTokenRope[stream ! IO.EndOfStream => CONTINUE].token; }; MetaCedarRunCommand: Commander.CommandProc ~ { ENABLE PFS.Error => CommanderOps.Failed[error.explanation]; c: IO.STREAM ¬ IO.RIS[cmd.commandLine]; stem: ROPE ¬ GetCmdToken[c]; outputStem: ROPE ¬ GetCmdToken[c]; binding: LIST OF RopePair ¬ NIL; out: IO.STREAM ¬ cmd.out; tmpDir: ROPE ~ Rope.Cat["/tmp/meta-", stem, "/"]; IF outputStem = NIL THEN outputStem ¬ stem; out.PutF["Creating %g.mesa from %g.meta:\n", [rope[outputStem]], [rope[stem]]]; UNTIL c.EndOf DO ropePair: RopePair ¬ [name: GetCmdToken[c], value: GetCmdToken[c]]; IF ropePair.name = NIL OR ropePair.value = NIL THEN EXIT; cmd.out.PutF[" %g: INT ~ %g;\n", [rope[ropePair.name]], [rope[ropePair.value]]]; binding ¬ CONS[ropePair, binding]; ENDLOOP; result ¬ CommanderOps.DoCommand[Rope.Concat["mkdir /tmp/meta-", stem], cmd]; result ¬ CommanderOps.DoCommand[ Rope.Cat["Copy ", tmpDir, "MetaCedarTemp.meta _ ", stem, ".meta"], cmd]; IF result = $Failure THEN RETURN; BEGIN InTmp: PROC ~ { result ¬ CommanderOps.DoCommand["WriteMesaPlain MetaCedarTemp.meta", cmd]; IF result = $Failure THEN RETURN; IO.PutRope[out, "Writing MetaProgram.mesa . . . "]; Run["MetaCedarTemp", outputStem, binding ! MetaError => { result ¬ $Failure; msg ¬ IO.PutFR1["Something fishy at position &g of MetaCedarTemp.meta\n", [integer[sourceLoc]]] } ]; IF result = $Failure THEN RETURN; out.PutRope["Done.\n"]; result ¬ CommanderOps.DoCommand["bringover -o BasicTime.mob Rope.mob IO.mob PFS.mob /Cedar/Top/PFS.df", cmd]; result ¬ CommanderOps.DoCommand["mkdir sun4", cmd]; result ¬ CommanderOps.DoCommand["Mako -~o MetaProgram.mesa", cmd]; IF result = $Failure THEN RETURN; result ¬ CommanderOps.DoCommand["Run -a MetaProgram", cmd]; IF result = $Failure THEN RETURN; result ¬ CommanderOps.DoCommand[Rope.Cat["TiogaMesa ", outputStem, ".mesa"], cmd]; }; PFS.DoInWDir[PFS.PathFromRope[tmpDir], InTmp]; END; IF result = $Failure THEN RETURN; result ¬ CommanderOps.DoCommand[Rope.Cat["Copy ", tmpDir, outputStem, ".mesa"], cmd]; IF result = $Failure THEN RETURN; }; Commander.Register["MetaCedar", MetaCedarRunCommand, "Simpleton macro expander"]; END. ž MetaCedarImpl.mesa Copyright Σ 1984, 1985, 1987, 1990, 1991, 1992 Xerox Corporation. All rights reserved. Michael Plass, November 23, 1992 7:30:56 pm PST Russ Atkinson (RRA) May 11, 1987 6:19:05 pm PDT Gets the next token into inputBuffer[tokenStart] .. inputBuffer[tokenLength-1] Something funny about the way things match up. result ¬ CommanderOps.DoCommand[Rope.Cat["Mako ", outputStem, ".mesa"], cmd]; Κ›•NewlineDelimiter –(cedarcode) style™codešœ™Kšœ ΟeœL™WK™/K™/K˜—KšΟk œ0žœžœ˜AK˜KšΟn œžœž˜Kšžœ)žœž˜7šœž˜K˜Kšžœžœžœ˜Kšœ žœžœžœ˜,Kšœ žœžœ ˜šœ žœžœ˜Kšœžœžœ˜Kšœ˜Kšœ žœžœ˜Kšœžœ˜Kšœžœžœ˜Kšœ žœ˜Kšœ ž˜Kšœ˜K˜—Kšœžœ˜Kšœžœ˜!š Ÿ œžœ žœžœžœ˜Fšœ žœ˜Kšœ˜Kšœ˜Kšœ žœžœ˜(Kšœžœ˜+Kšœžœžœ˜4Kšœ˜Kšœ˜Kšœ˜—Kšœ˜K˜—Kšœžœ3˜=šŸœžœžœžœ ˜)šžœž˜ Kšžœ žœ žœžœ˜AKš œžœžœžœžœ˜5Kšœžœžœ ˜Kšžœžœ ˜—Kšœ˜K˜—Kšœ žœžœžœ˜šœ žœ˜K˜—šŸœžœ˜%KšœN™NKšœ<˜[s: REF READONLY TEXT, start: NAT _ 0, len: NAT _ 32767]šœv˜vKšœ˜—šŸœžœžœ˜&K–>[s: REF READONLY TEXT, start: NAT _ 0, len: NAT _ 32767]šœžœa˜iKšœ˜K–>[s: REF READONLY TEXT, start: NAT _ 0, len: NAT _ 32767]šžœ žœžœ(˜>Kšœ!žœ.˜QKšœ˜—šŸœžœ˜Kšœ˜Kšžœ žœžœžœ˜5Kšžœžœžœžœ)˜;šžœ žœžœ˜Kšžœ˜Kšžœ˜Kšžœ˜K˜—Kšœžœ˜Kšœ˜—šŸ œžœ˜Kšœ ˜ Kšœ˜—Kšœžœ˜šŸ œžœžœžœ˜'K˜Kšœ ˜ Kšœ˜—šŸœžœžœ˜Kšžœ žœžœ˜K˜Kšžœ˜Kšœ˜—Kšœžœžœ˜Kšœ žœ˜Kšœžœ˜Kšœžœ˜Kšœ žœ žœžœ˜!Kšœ˜Kšžœc˜eKšœ˜Kšœ ˜ šžœž˜ šžœž˜šœ ˜ šžœž˜šœ žœ)ž˜>Kšœ˜KšœB˜BKšžœ˜—Kšžœ˜—Kšœ˜—˜šžœž˜šœ žœ)ž˜>šœ˜šžœ ˜ Kšžœ žœ˜&Kšžœ˜—Kšœ˜—Kšœ3˜3šœ ˜ Kšœ˜šžœ ˜ Kšžœ<˜@Kšžœ˜—Kšœ˜—šœ˜Kšœ˜šžœ ˜ Kšžœžœ˜4Kšžœ˜—Kšœ˜—šœ˜Kšœ˜K˜Kšœ˜—šœ˜Kšœ˜K˜Kšœ˜—šœ˜Kšœ<˜Kšœ˜KšœB˜BKšœ5˜5Kšœ5˜5šœ˜K˜Kšœ˜Kšžœ˜Kšœ˜Kšžœ˜Kšœ˜—šœ˜K˜Kšœ˜Kšžœ!˜#Kšœ˜Kšžœ˜Kšœ˜—šœ˜K˜Kšœ˜Kšœ˜Kšœ˜Kšžœ.žœ=˜qKšžœ˜K˜ K˜Kšœ˜—Kšžœ˜—Kšœ#žœ˜)Kš œžœ žœžœžœ ˜4šœ˜Kšœ ˜ šžœžœž˜Kšœ˜Kšœ˜šœ˜Kšœ˜Kšœ&˜&Kšœ"˜"K˜—Kšœ˜Kšœ˜šœ˜Kšœ˜Kšœ"˜"šžœ'žœ=˜jK™.—K˜—Kšžœžœ˜—Kšœ˜—Kšžœ˜—K˜—Kšžœžœ˜—Kšœ˜Kšžœ˜—Kšžœ žœ˜Kšœžœ˜Kšžœ˜ Kšžœ ˜ Kšžœ ˜K˜K˜—Kšœžœž œžœžœŸ œžœžœžœžœžœžœžœžœŸœžœžœžœžœ žœžœžœžœžœ žœ Ÿ œžœžœ%žœžœžœ žœ.žœŸœžœŸœžœŸœžœžœ žœžœžœ žœ(žœžœ žœ$Ÿœžœžœ žœžœžœžœžœžœžœžœžœžœ žœžœ*žœžœžœG˜πKšœžœžœ˜-šŸ œžœ žœžœžœžœžœ˜DKšœžœžœžœ˜BKšœ˜K˜—šŸœ˜.Kšžœžœ1˜;Kš œžœžœžœžœ˜'Kšœžœ˜Kšœ žœ˜"Kšœ žœžœ žœ˜ Kšœžœžœ ˜Kšœžœ%˜1Kšžœžœžœ˜+KšœO˜Ošžœ ž˜KšœC˜CKš žœžœžœžœžœžœ˜9Kšœžœ:˜QKšœ žœ˜"Kšžœ˜—K˜LK˜iKšžœžœžœ˜!šž˜šŸœžœ˜K˜JKšžœžœžœ˜!Kšžœ1˜3šœ*˜*šœ˜Kšœ˜KšœžœW˜_Kšœ˜—Kšœ˜—Kšžœžœžœ˜!Kšœ˜K˜mK˜3K˜BKšžœžœžœ˜!Kšœ;˜;Kšžœžœžœ˜!KšœR˜RK˜—Kšžœ žœ˜.Kšžœ˜—Kšžœžœžœ˜!K˜UKšžœžœžœ˜!K™MKšœ˜K˜—˜QK˜——Kšžœ˜—…—,θ>!