DIRECTORY Ascii, Commander, CommandTool, Rope, IO, FS; MetaCedarImpl: CEDAR PROGRAM IMPORTS Commander, CommandTool, Rope, IO, FS = 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", IO.int[copiedTextStart], IO.int[copiedTextLength]]; }; copiedTextStart _ -1; copiedTextLength _ 0; }; CopyOut: PROC ~ { IF meta 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; }; StartPlain: PROC = { meta _ FALSE; }; startMetaCount: INT _ 0; StartMeta: PROC [eof: BOOLEAN _ FALSE] = { Flush[]; meta _ TRUE; }; MetaText: PROC [rope: ROPE] = { IF meta THEN ERROR; Flush[]; IO.PutRope[out, rope]; }; inxx: BOOLEAN _ FALSE; nestCount: NAT _ 0; beginStackTop: NAT _ 0; beginStack: ARRAY [0..50) OF NAT; GetToken[scanner]; IO.PutF[out, boilerPlateBegin, IO.rope[outputNameStem], IO.rope[outputNameStem], IO.rope[fileNameStem]]; WriteBindings[binding]; StartPlain[]; WHILE scanner.tokenKind # eof DO IF meta THEN { SELECT scanner.tokenKind FROM special => SELECT scanner.inputBuffer[scanner.tokenStart] FROM ' => StartPlain[]; ' => MetaError[scanner.locationOfBufferStart+scanner.tokenStart]; ENDCASE => CopyMetaOut[]; ENDCASE => CopyMetaOut[]; } ELSE { 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, "]; "]; }; 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[]; }; GetToken[scanner]; ENDLOOP; IF meta THEN StartPlain[]; StartMeta[eof: TRUE]; IO.PutRope[out, boilerPlateEnd]; IO.Close[in]; IO.Close[out]; }; boilerPlateBegin: ROPE = " DIRECTORY Ascii, Rope, RopeFile, IO, FS; MetaProgram: CEDAR PROGRAM IMPORTS Rope, RopeFile, IO, FS = { 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 ~ FS.StreamOpen[\"%g.mesa\", $create]; nest: NAT _ 0; Begin: PROC ~ {nest _ nest + 1}; End: PROC ~ {nest _ nest - 1}; PutInt: PROC [i: INT] ~ {IO.PutF[stream, IF i < 0 THEN \"(%%g)\" ELSE \"%%g\", IO.int[i]]}; metaSource: ROPE ~ RopeFile.Create[name: \"%g.meta\", raw: FALSE]; Ptxt: PROC [start, length: CARDINAL] ~ { s: INT _ start; FOR i: INT IN [start..start+length) DO SELECT metaSource.Fetch[i] FROM '{, '[, '( => Begin[]; '}, '], ') => End[]; Ascii.CR => { stream.PutRope[metaSource.Substr[s, i-s+1]]; FOR i: NAT IN [0..nest) DO stream.PutChar[Ascii.TAB] 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 ~ { c: IO.STREAM _ IO.RIS[cmd.commandLine]; stem: ROPE _ GetCmdToken[c]; outputStem: ROPE _ GetCmdToken[c]; binding: LIST OF RopePair _ NIL; IF outputStem = NIL THEN outputStem _ stem; cmd.out.PutF["Creating %g.mesa from %g.meta:\n", IO.rope[outputStem], IO.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", IO.rope[ropePair.name], IO.rope[ropePair.value]]; binding _ CONS[ropePair, binding]; ENDLOOP; result _ CommandTool.DoCommand[Rope.Cat["Copy MetaCedarTemp.meta _ ", stem, ".meta"], cmd]; IF result = $Failure THEN RETURN; result _ CommandTool.DoCommand["WriteMesaPlain MetaCedarTemp.meta", cmd]; IF result = $Failure THEN RETURN; cmd.out.PutRope["Writing "]; cmd.out.PutRope[outputStem]; cmd.out.PutRope[".MESA . . . " ]; Run["MetaCedarTemp", outputStem, binding ! MetaError => { result _ $Failure; msg _ IO.PutFR["Something fishy at position &g of MetaCedarTemp.meta\n", IO.int[sourceLoc]] } ]; IF result = $Failure THEN RETURN; cmd.out.PutRope["Done.\n"]; result _ CommandTool.DoCommand[Rope.Cat["Compile ", outputStem, ".MESA"], cmd]; IF result = $Failure THEN RETURN; result _ CommandTool.DoCommand[Rope.Cat["Run ", outputStem, ".bcd"], cmd]; IF result = $Failure THEN RETURN; result _ CommandTool.DoCommand[Rope.Cat["Compile ", outputStem, ".mesa"], cmd]; }; Commander.Register["MetaCedar", MetaCedarRunCommand, "Simpleton macro expander"]; END.  MetaCedarImpl.mesa Copyright (C) 1984, 1985, Xerox Corporation. All rights reserved. Michael Plass, September 27, 1985 5:17:13 pm PDT Gets the next token into inputBuffer[tokenStart] .. inputBuffer[tokenLength-1] Something funny about the way things match up. Κ –˜šœ™J™BJ™0J˜—JšΟk œ&œœ˜6J˜Jš Πln œœœœœ˜Išœ˜Jšœœœ˜Jšœ œœœ˜,Jšœ œœ ˜šœ œœ˜Jšœœœ˜Jšœ˜Jšœ œœ˜Jšœœ˜Jšœœœ˜Jšœ œ˜Jšœ ˜Jšœ˜J˜—Jšœœ˜Jšœœ˜!š Οn œœ œœœ˜Fšœ œ˜Jšœ˜Jšœ˜Jšœ œœ˜(Jšœœ˜+Jšœœœ˜4Jšœ˜Jšœ˜Jšœ˜—Jšœ˜J˜—Jšœœ3˜=šŸœœœœ ˜)šœ˜ Jšœ œ œœ˜AJš œœœœœ˜5Jšœœœ ˜Jšœœ ˜—Jšœ˜J˜—Jšœ œœœ˜šœ œ˜J˜—šŸœœ˜%JšœN™NJšœ<˜Jšœ˜JšœB˜BJšœ˜—Jšœ˜—Jšœ˜—šœ˜šœ˜šœ œ)˜>Jšœ˜JšœB˜BJšœ5˜5Jšœ5˜5šœ˜J˜Jšœ˜JšœΠbfœ˜Jšœ˜Jšœ œ˜Jšœ˜—Jšœ˜—Jšœ#œ˜)Jš œœ œœœ ˜4šœ˜Jšœ ˜ šœœ˜Jšœ˜Jšœ˜šœ˜Jšœ˜Jšœ&˜&Jšœ"˜"J˜—Jšœ˜Jšœ˜šœ˜Jšœ˜Jšœ"˜"šœ'œ=˜jJ™.—J˜—Jšœœ˜—Jšœ˜—Jšœ˜—Jšœ˜—Jšœ˜Jšœ˜—Jšœœ˜Jšœœ˜Jšœ˜ Jšœ ˜ Jšœ ˜J˜J˜—Jšœœ™˜―Jšœœ˜-šŸ œœ œœœœœ˜DJšœœœœ˜BJšœ˜J˜—šœ.˜.Jš œœœœœ˜'Jšœœ˜Jšœ œ˜"Jšœ œœ œ˜ Jšœœœ˜+Jšœ1œœ ˜Ušœ ˜JšœC˜CJš œœœœœœ˜9Jšœ"œœ˜SJšœ œ˜"Jšœ˜—Jšœ[˜[Jšœœœ˜!JšœI˜IJšœœœ˜!Jšœ[˜[šœ*˜*šœ˜Jšœ˜Jšœ[˜[Jšœ˜—Jšœ˜—Jšœœœ˜!Jšœ˜JšœO˜OJšœœœ˜!JšœJ˜JJšœœœ˜!JšœO˜OJšœ˜J˜—˜QJ˜——Jšœ˜—…—"΄.V