DIRECTORY Basics, Atom USING [MakeAtom--, GetPName--], ISMessage, ISBinding, ISNode, ISScan, ISToken, ISTiogaIntern, Rope USING [ROPE--, Fetch, Length, Concat, Substr--], IO USING [STREAM, RIS, ROS, EndOfStream, RopeFromROS, CR, GetChar, PeekChar, PutChar, GetIndex, SetIndex--, atom--]; ISScanImpl: CEDAR PROGRAM IMPORTS Atom, ISBinding, ISNode, IO, --Rope, --ISTiogaIntern EXPORTS ISBinding, ISScan = BEGIN OPEN ISToken, ISScan; ParseFailure: PUBLIC SIGNAL [s: ISScan.ScanHandle, r: ISScan.ParseFailureReason] = CODE; BindingFailure: PUBLIC SIGNAL [r: ISBinding.BindingFailureReason] = CODE; currentEnvironment: ISBinding.EnvironmentHandle _ NIL; environmentAnchor: ISBinding.Handle _ NIL; notACharacter: CARDINAL = LAST[CARDINAL]; bufferWords: CARDINAL = ISScan.bufferBytes / 2; -- all must be power of two -- CreateScan: PUBLIC PROCEDURE [ base: Rope.ROPE, index: INT, bindingStack: ISBinding.StackHandle _ NIL, family: ATOM _ NIL ] RETURNS [ScanHandle] = BEGIN newScanner: CharactersScanner _ NEW[ScanStream.characters]; new: ScanHandle _ NEW[ScanObject]; newScanner^ _ [name: NIL, body: characters [cstream: IO.RIS[base]]]; IO.SetIndex[newScanner.cstream, index]; new^ _ [ stream: newScanner, family: family--,-- --allocateWith: allocateWith--]; IF bindingStack#NIL THEN {new.bindingStack _ bindingStack; new.stackIsScans _ FALSE} ELSE {new.bindingStack _ ISBinding.CreateStack[]; new.stackIsScans _ TRUE}; RETURN [new]; END; InitializeScan: PUBLIC PROCEDURE [s: ScanHandle] = BEGIN WITH s.stream SELECT FROM ss: CharactersScanner => IF ss.cstream=NIL THEN ERROR; ENDCASE => ERROR; RETURN; END; InitializeScanThroughCurly: PUBLIC PROCEDURE [s: ScanHandle] = BEGIN InitializeScan [s]; WITH s.stream SELECT FROM ss: CharactersScanner => BEGIN THROUGH [0..100) DO IF IO.PeekChar[ss.cstream]='{ THEN {[] _ AdvanceScan[s]; RETURN}; [] _ IO.GetChar[ss.cstream]; ENDLOOP; END; ENDCASE => ERROR; SIGNAL ParseFailure [s, spare]; RETURN; END; UseUpPeek: PROC [s: IO.STREAM] ~ { [] _ IO.GetChar[s]; }; PeelInteger: PROCEDURE [stream: IO.STREAM, startCharacter: CHAR _ '0] RETURNS [LONG INTEGER] = BEGIN li: LONG INTEGER _ startCharacter - '0; a: ARRAY [0..10] OF NAT; count: NAT _ 0; radix: NAT _ 10; peek: CHAR; WHILE (peek_IO.PeekChar[stream]) IN ['0..'9] DO a[count] _ IO.GetChar[stream] - '0; count _ MIN[count+1,10]; ENDLOOP; IF peek='B OR peek='b THEN { radix _ 8; UseUpPeek[stream] }; FOR z: NAT IN [0..count) DO li _ li*radix + a[z]; ENDLOOP; RETURN [li]; END; AdvanceScan: PUBLIC PROCEDURE [s: ScanHandle] = BEGIN DO -- so we can repeatedly pop -- WITH s.stream SELECT FROM ss: TokensScanner => s.stream.token _ TokenFromTokensScanner [ss]; ss: CharactersScanner => s.stream.token _ TokenFromCharactersScanner [ss]; ENDCASE => ERROR; -- not tokens or characters -- BEGIN type: TVType _ s.stream.token.type; IF (type = endOfString OR type = endOfStream) AND s.stream.pushed#NIL THEN BEGIN -- pop the scan -- old: REF ScanStream _ s.stream.pushed; s.stream _ old; type _ s.stream.token.type; IF type#endOfStream AND type#endOfString AND type3null THEN RETURN; END ELSE RETURN; END; ENDLOOP; END; TokenFromTokensScanner: PROCEDURE [ts: TokensSca~ner] RETURNS [obj: TVHandle] = BEGIN IF ts.tokenList=NIL THEN obj _ NEW[TVObject.endOfStream] ELSE {obj _ ts.tokenList; 43.tokenList _ ts.tokenList.next}; obj.streamName _ ts.name; --<>-- RETURN; END; TokenFromCharactersScanner: PROCEDURE [cs: CharactersScanner] RETURNS [tr: TVHandle] = BEGIN byte: CHAR; inComment: BOOLEAN _ FALSE; ios: IO.STREAM _ cs.cstream; DO -- skip noise bytes and comments -- byte _ IO.GetChar[ios ! IO.EndOfStream => GOTO PopInputScanner]; IF inComment THEN SELECT byte FROM '- => IF IO.PeekChar[ios]='- THEN {UseUpPeek[ios]; inComment _ FALSE}; IO.CR => inComment _ FALSE; -- comment ended by cr or eos -- ENDCASE => NULL ELSE SELECT VAL[byte] FROM IN [1B..40B] => LOOP; VAL['-] => IF IO.PeekChar[ios]='- THEN -- comment -- {UseUpPeek[ios]; inComment _ TRUE} ELSE EXIT; ENDCASE => EXIT; REPEAT PopInputScanner => RETURN[NEW[TVObject.endOfStream]]; ENDLOOP; SELECT byte FROM --<>-- IN ['A..'Z], IN ['a..'z] => BEGIN -- atom or dollar -- --<>-- rope: IO.STREAM _ IO.ROS[]; peek: CHAR; IO.PutChar[rope, byte]; WHILE (peek_IO.PeekChar[ios]) IN ['A..'Z] OR peek IN ['a..'z] OR peek IN ['0..'9] -- Allow non-leading digits -- OR peek='. DO -- current (feb85) separator, e.g. 'FONT.Points' -- IO.PutChar[rope, IO.GetChar[ios]]; ENDLOOP; IF peek='$ OR VAL[peek]=244B THEN BEGIN -- the dollar used to be in the atom .. but no more .. rma feb85 -- UseUpPeek[ios]; tr _ NEW[TVObject _ [body: dollar[value: Atom.MakeAtom[IO.RopeFromROS[rope, TRUE]]]] ]; END ELSE tr _ NEW[TVObject _ [body: atom[value: Atom.MakeAtom[IO.RopeFromROS[rope, TRUE]]]] ]; END; '< => BEGIN -- characters -- startIndex: INT = IO.GetIndex[ios]; cs0: BOOLEAN _ TRUE; DO --<< See comment above 'Get' >>-- char: CHAR _ IO.GetChar[ios]; IF cs0 AND char='> THEN IF IO.PeekChar[ios]#'> THEN EXIT ELSE [] _ IO.GetChar[ios]; IF VAL[char]=377B THEN cs0 _ VAL[IO.GetChar[ios]]=0; ENDLOOP; tr _ NEW[TVObject _ [body: characters [stream: ios, startIndex: startIndex, length: IO.GetIndex[ios]-startIndex-1]] ]; END; IN ['0..'9] => BEGIN -- number -- t: integer TVObject _ [body: integer[value: 0]]; t.value _ PeelInteger [stream: ios, startCharacter: byte]; tr _ NEW[TVObject _ t ]; END; '_ => {tr _ NEW[TVObject _ [body: gets[]] ]}; VAL[254B] => {tr _ NEW[TVObject _ [body: gets[]] ]}; '= => {tr _ NEW[TVObject _ [body: gets[]] ]}; '{ => {tr _ NEW[TVObject _ [body: leftCurly[]] ]}; '} => {tr _ NEW[TVObject _ [body: rightCurly[]] ]}; '+ => {tr _ NEW[TVObject _ [body: plus[]] ]}; '- => {tr _ NEW[TVObject _ [body: minus[]] ]}; '* => {tr _ NEW[TVObject _ [body: times[]] ]}; '^ => {tr _ NEW[TVObject _ [body: open[]] ]}; VAL[255B] => {tr _ NEW[TVObject _ [body: open[]] ]}; '! => {tr _ NEW[TVObject _ [body: open[]] ]}; '| => {tr _ NEW[TVObject _ [body: open[]] ]}; '" => -- string .. Interscript string-constant -- BEGIN IF cs.inString THEN {tr _ NEW[TVObject _ [body: endOfString[]] ]; cs.inString _ FALSE} ELSE BEGIN stringToken: StringTVHandle _ NEW[string TVObject _ [body: string[]]]; stringToken.tail _ stringToken; cs.inString _ TRUE; DO to: TVHandle _ TokenFromCharactersScanner [cs]; IF to.type=endOfString THEN {tr _ NEW[TVObject _ stringToken^ ]; GOTO FoundEndOfString} ELSE BEGIN new: TVHandle _ CopyOneTV [to]; new.next _ NIL; stringToken.tail.next _ new; stringToken.tail _ new; END; ENDLOOP; END; -- of else -- EXITS FoundEndOfString => NULL; END; -- of Interscript string-constant -- '/ => {tr _ NEW[TVObject _ [body: divide[]] ]}; '[ => {tr _ NEW[TVObject _ [body: push[]] ]}; '] => {tr _ NEW[TVObject _ [body: pop[]] ]}; ENDCASE => SIGNAL ParseFailure [NIL, unsupportedConstruct]; tr.streamName _ cs.name; RETURN; END; CreateStack: PUBLIC PROCEDURE [useEnvironment: BOOLEAN _ TRUE] RETURNS [ISBinding.StackHandle] = BEGIN sh: ISBinding.StackHandle _ NEW [ISBinding.StackObject]; sh^ _ [top: IF useEnvironment THEN environmentAnchor ELSE NIL]; RETURN [sh]; END; DestroyStack: PUBLIC PROCEDURE [atStack: REF ISBinding.StackHandle] = BEGIN atStack^ _ NIL; END; AnchorBindings: PUBLIC PROCEDURE [stack: ISBinding.StackHandle] RETURNS [ISBinding.Anchor] = {RETURN [stack^]}; CreateEnvironment: PUBLIC PROCEDURE [stack: ISBinding.StackHandle] RETURNS [ISBinding.EnvironmentHandle] = BEGIN eh: ISBinding.EnvironmentHandle _ NEW[ISBinding.EnvironmentObject]; eh^ _ [stack: stack]; environmentAnchor _ stack.top; RETURN [eh]; END; UseEnvironment: PUBLIC PROCEDURE [environment: ISBinding.EnvironmentHandle] = BEGIN currentEnvironment _ environment; environmentAnchor _ environment.stack.top; --<>-- END; UnuseEnvironment: PUBLIC PROCEDURE RETURNS [ISBinding.EnvironmentHandle] = BEGIN eh: ISBinding.EnvironmentHandle _ currentEnvironment; currentEnvironment _ NIL; environmentAnchor _ NIL; --<>-- RETURN [eh]; END; PruneBindings: PUBLIC PROCEDURE [ stack: ISBinding.StackHandle, anchor: ISBinding.Anchor] = BEGIN stack^ _ anchor; --<>-- RETURN; END; AugmentBindings: PUBLIC PROCEDURE [ name: ATOM, value: TVHandle, stack: ISBinding.StackHandle] = BEGIN temp: ISBinding.Handle _ NEW[ISBinding.Object]; temp^ _ [ previous: stack.top, name: name, value: value ]; stack.top _ temp; RETURN; END; ObtainBinding: PUBLIC PROCEDURE [name: ATOM, stack: ISBinding.StackHandle] RETURNS [TVHandle] = BEGIN FOR temp: ISBinding.Handle _ stack.top, temp.previous UNTIL temp=NIL DO IF temp.name=name THEN RETURN [temp.value]; ENDLOOP; RETURN [NIL]; END; CopyScanStream: PROCEDURE [old: REF ScanStream] RETURNS [new: REF ScanStream] = BEGIN WITH old SELECT FROM s: CharactersScanner => new _ NEW[characters ScanStream _ s^]; s: TokensScanner => new _ NEW[tokens ScanStream _ s^]; ENDCASE => NULL; RETURN; END; CopyOneTV: PROCEDURE [tv: TVHandle] RETURNS [r: TVHandle] = BEGIN WITH tv^ SELECT FROM o: null TVObject => r _ NEW[null TVObject _ o]; o: endOfString TVObject => r _ NEW[endOfString TVObject _ o]; o: endOfStream TVObject => r _ NEW[endOfStream TVObject _ o]; o: endOfScript TVObject => r _ NEW[endOfScript TVObject _ o]; o: integer TVObject => r _ NEW[integer TVObject _ o]; o: atom TVObject => r _ NEW[atom TVObject _ o]; o: string TVObject => r _ NEW[string TVObject _ o]; o: dollar TVObject => r _ NEW[dollar TVObject _ o]; o: characters TVObject => r _ NEW[characters TVObject _ o]; o: plus TVObject => r _ NEW[plus TVObject _ o]; o: minus TVObject => r _ NEW[minus TVObject _ o]; o: times TVObject => r _ NEW[times TVObject _ o]; o: divide TVObject => r _ NEW[divide TVObject _ o]; o: gets TVObject => r _ NEW[gets TVObject _ o]; o: open TVObject => r _ NEW[open TVObject _ o]; o: leftCurly TVObject => r _ NEW[leftCurly TVObject _ o]; o: rightCurly TVObject => r _ NEW[rightCurly TVObject _ o]; o: push TVObject => r _ NEW[push TVObject _ o]; o: pop TVObject => r _ NEW[pop TVObject _ o]; o: node TVObject => r _ NEW[node TVObject _ o]; o: specialChars TVObject => r _ NEW[specialChars TVObject _ o]; o: styleOpen TVObject => r _ NEW[styleOpen TVObject _ o]; o: styleDefinition TVObject => r _ NEW[styleDefinition TVObject _ o]; ENDCASE; RETURN; END; CollectRHS: PROCEDURE [scan: ScanHandle] RETURNS [TVObject] = BEGIN uniaryMinus: BOOLEAN _ FALSE; SELECT scan.stream.token.type FROM gets => AdvanceScan [scan]; ENDCASE => NULL; SELECT scan.stream.token.type FROM plus => AdvanceScan [scan]; -- kill leading uniary plus -- minus => {uniaryMinus _ TRUE; AdvanceScan [scan]}; ENDCASE => NULL; WITH scan.stream.token SELECT FROM t: LeftCurlyTVHandle => BEGIN child: NodeTVHandle; return: NodeTVHandle _ NEW[node TVObject]; AdvanceScan [scan]; child _ CollectNode [scan: scan, bound: TRUE]; DO WITH scan.stream.token SELECT FROM n: NullTVHandle => AdvanceScan[scan]; o: OpenTVHandle => --Remove outer {} and splice innerds into input stream (macro expansion)-- BEGIN AdvanceScan[scan]; --Get rid of open-- scan.stream _ NEW[characters ScanStream _ [ name: NIL, pushed: CopyScanStream[scan.stream], body: characters [cstream: IO.RIS[ISTiogaIntern.PrintNodeContents[NARROW[child.isnode], FALSE]]]]]; AdvanceScan [scan]; -- prime the pump -- EXIT; END; ENDCASE => { return^ _ [body: node[isnode: child.isnode]]; EXIT; }; ENDLOOP; RETURN [return^]; END; t: AtomTVHandle => BEGIN rhsAtom: atom TVObject _ t^; AdvanceScan [scan]; SELECT scan.stream.token.type FROM open => BEGIN b: TVHandle _ ObtainBinding [RemoveDot[rhsAtom.value], scan.bindingStack]; AdvanceScan [scan]; WITH b SELECT FROM n: NodeTVHandle => { --Do "macro expansion" of node-- scan.stream _ NEW[characters ScanStream _ [ name: t.value, pushed: CopyScanStream[scan.stream], body: characters [cstream: IO.RIS[ISTiogaIntern.PrintNodeContents[NARROW[n.isnode]]]]]]; AdvanceScan [scan]; -- prime the pump -- RETURN[CollectRHS[scan]]; }; ENDCASE => RETURN [IF b=NIL THEN rhsAtom ELSE b^]; END; ENDCASE => RETURN [rhsAtom]; END; t: IntegerTVHandle => BEGIN int: integer TVObject _ t^; operator: TVType; IF uniaryMinus THEN int.value _ -int.value; AdvanceScan [scan]; operator _ scan.stream.token.type; SELECT operator FROM times, minus, plus => NULL; ENDCASE => RETURN [int]; AdvanceScan [scan]; BEGIN right: TVObject _ CollectRHS [scan]; WITH right SELECT FROM far: integer TVObject => BEGIN SELECT operator FROM times => int.value _ int.value * far.value; minus => int.value _ int.value - far.value; plus => int.value _ int.value + far.value; ENDCASE => ERROR; RETURN [int]; END; ENDCASE => ERROR ParseFailure [scan, unexpectedDelimiter]; END; END; ENDCASE => {rhs: TVObject _ scan.stream.token^; AdvanceScan [scan]; RETURN [rhs]}; END; RemoveDot: PROC [a: ATOM] RETURNS [ATOM] ~ { RETURN[a]; }; CollectNode: PUBLIC PROCEDURE [ scan: ScanHandle, parent: ISNode.Handle _ NIL, bound: BOOL _ FALSE ] RETURNS [NodeTVHandle] = BEGIN node: NodeTVHandle _ NEW[node TVObject]; primaryImpl: ISNode.Implementation _ NIL; primaryTag: ATOM _ NIL; oldLocalLimit: ISBinding.Anchor; anchor: ISBinding.Anchor; square: ISBinding.Anchor; -- bad usage: no nesting and little syntactic checking of '[]' -- contentBuffer: TVHandle _ NIL; lastBufferedContent: TVHandle _ NIL; BufferOrCall: --LOCAL-- PROCEDURE [con: TVHandle] = BEGIN IF primaryImpl#NIL THEN BEGIN WITH con SELECT FROM cc: NodeTVHandle => BEGIN ie: ISToken.InterscriptContext _ NEW[ISToken.InterscriptContextObject _ [ body: embedded[content: cc] ] ]; [] _ primaryImpl.internalize [ NARROW[node.isnode], ie ]; END; cc: StyleOpenTVHandle => BEGIN ie: ISToken.InterscriptContext _ NEW[ ISToken.InterscriptContextObject _ [ body: styleOpen[identifier: cc] ] ]; [] _ primaryImpl.internalize [ NARROW[node.isnode], ie ]; END; cc: StyleDefinitionTVHandle => BEGIN ie: ISToken.InterscriptContext _ NEW[ ISToken.InterscriptContextObject _ [ body: styleDefinition[definition: cc] ] ]; [] _ primaryImpl.internalize [ NARROW[node.isnode], ie ]; END; ENDCASE => BEGIN ic: ISToken.InterscriptContext _ NEW[ ISToken.InterscriptContextObject _ [ body: content[content: con] ] ]; [] _ primaryImpl.internalize [ NARROW[node.isnode], ic ]; END; END ELSE BEGIN copy: TVHandle _ CopyOneTV[con]; IF lastBufferedContent#NIL THEN {lastBufferedContent.next _ copy; lastBufferedContent _ copy} ELSE contentBuffer _ lastBufferedContent _ copy; END; END; node^ _ [body: node[]]; node.isnode _ ISNode.Create [--scan.allocateWith--]; anchor _ AnchorBindings [scan.bindingStack]; oldLocalLimit _ ISTiogaIntern.localBindingLimit; ISTiogaIntern.localBindingLimit _ anchor; --hack hack-- DO WITH scan.stream.token SELECT FROM t: NullTVHandle => AdvanceScan [scan]; -- lets us not AdvanceScan .. see at rightCurly -- t: EOScTVHandle => SIGNAL ParseFailure [scan,hitEndOfScript]; t: IntegerTVHandle => BEGIN tvo: TVHandle _ NEW[TVObject _ CollectRHS [scan]]; -- to pick up integer expressions as content -- BufferOrCall [tvo]; END; t: MinusTVHandle => BEGIN tvo: TVHandle _ NEW[TVObject _ CollectRHS [scan]]; -- to pick up integer expressions as content -- BufferOrCall [tvo]; END; t: PlusTVHandle => BEGIN tvo: TVHandle _ NEW[TVObject _ CollectRHS [scan]]; -- to pick up integer expressions as content -- BufferOrCall [tvo]; END; t: AtomTVHandle => BEGIN theAtomicTV: TVObject _ scan.stream.token^; theAtom: ATOM _ t.value; AdvanceScan [scan]; WITH scan.stream.token SELECT FROM x: GetsTVHandle => BEGIN rhs: TVHandle _ NEW[TVObject _ CollectRHS [scan]]; AugmentBindings [RemoveDot[theAtom], CopyOneTV[rhs], scan.bindingStack]; END; x: OpenTVHandle => BEGIN original: ATOM; tvo: TVHandle _ NEW[TVObject _ theAtomicTV]; -- may be altered below -- WITH tvo SELECT FROM t0: AtomTVHandle => original _ t0.value; ENDCASE; DO -- handling multiple opens ala Atom^^ -- WITH tvo SELECT FROM -- will surely be atom the first time -- t2: AtomTVHandle => WITH scan.stream.token SELECT FROM t3: OpenTVHandle => BEGIN b: TVHandle _ ObtainBinding [RemoveDot[t2.value], scan.bindingStack]; AdvanceScan [scan]; -- past the open -- IF b#NIL THEN tvo _ b ELSE GOTO EndOfOpenings; END; -- and loop to handle atom bound to atom bound to ... -- ENDCASE => GOTO EndOfOpenings; ENDCASE => GOTO EndOfOpenings; REPEAT EndOfOpenings => NULL; ENDLOOP; WITH tvo SELECT FROM tt: NodeTVHandle => --Splice external node rep into input stream-- BEGIN scan.stream _ NEW[characters ScanStream _ [ name: theAtom, pushed: CopyScanStream[scan.stream], body: characters [cstream: IO.RIS[ISTiogaIntern.PrintNodeContents[NARROW[tt.isnode]]]]]]; AdvanceScan [scan]; -- prime the pump -- END; tt: StringTVHandle => BEGIN scan.stream _ NEW[tokens ScanStream _ [ name: theAtom, pushed: CopyScanStream[scan.stream], body: tokens [tokenList: tt.list] ]]; BEGIN -- warn node impl about the styleOpen -- zz: TVHandle _ NEW[styleOpen TVObject _ [body: styleOpen[name: original]]]; BufferOrCall [zz]; END; AdvanceScan [scan]; -- prime the pump -- END; tt: AtomTVHandle => BufferOrCall [tvo]; -- opens finally got just another atom -- ENDCASE => ERROR; END; -- of open -- ENDCASE => -- just the atom was there -- {a: AtomTVHandle _ NEW[atom TVObject _ [body: atom[value: theAtom]]]; BufferOrCall [a]}; END; -- of atom -- t: CharactersTVHandle => BEGIN BufferOrCall [scan.stream.token]; AdvanceScan [scan]; END; t: StringTVHandle => {BufferOrCall [scan.stream.token]; AdvanceScan [scan]}; t: DollarTVHandle => BEGIN IF primaryImpl=NIL THEN BEGIN -- test this tag for being the primary impl -- im: ISNode.Implementation _ ISNode.GetImplementation [t.value, scan.family]; IF im#NIL AND im.implementationClass=primary THEN BEGIN -- have the primary impl -- ii: ISToken.InterscriptContext _ NEW[ ISToken.InterscriptContextObject _ [ body: initial [parent] ] ]; primaryImpl _ im; primaryTag _ t.value; NARROW[node.isnode, ISNode.Handle].tag _ primaryTag; NARROW[node.isnode, ISNode.Handle].printProc _ primaryImpl.printTioga; primaryImpl.internalize [ NARROW[node.isnode], ii ]; WHILE contentBuffer#NIL DO temp: TVHandle; WITH contentBuffer SELECT FROM cb: NodeTVHandle => BEGIN ie: ISToken.InterscriptContext _ NEW[ ISToken.InterscriptContextObject _ [ body: embedded[content: cb] ] ]; [] _ primaryImpl.internalize [ NARROW[node.isnode], ie ]; END; cb: StyleOpenTVHandle => BEGIN ie: ISToken.InterscriptContext _ NEW[ ISToken.InterscriptContextObject _ [ body: styleOpen[identifier: cb] ] ]; [] _ primaryImpl.internalize [ NARROW[NARROW[node.isnode]], ie ]; END; ENDCASE => BEGIN ic: ISToken.InterscriptContext _ NEW[ ISToken.InterscriptContextObject _ [ body: content[content: contentBuffer] ] ]; [] _ primaryImpl.internalize [ NARROW[NARROW[node.isnode]], ic ]; END; temp _ contentBuffer; contentBuffer _ contentBuffer.next; ENDLOOP; END; END; ISNode.SetTag [NARROW[node.isnode], t.value]; AdvanceScan [scan]; END; t: PushTVHandle => {square _ AnchorBindings[scan.bindingStack]; AdvanceScan [scan]}; t: PopTVHandle => {PruneBindings[scan.bindingStack, square]; AdvanceScan [scan]}; t: LeftCurlyTVHandle => BEGIN child: NodeTVHandle; AdvanceScan [scan]; child _ CollectNode [scan, NARROW[node.isnode]]; DO WITH scan.stream.token SELECT FROM n: NullTVHandle => AdvanceScan[scan]; o: OpenTVHandle => --Remove outer {} and splice innerds into input stream (macro expansion)-- BEGIN AdvanceScan[scan]; --Get rid of open-- scan.stream _ NEW[characters ScanStream _ [ name: NIL, pushed: CopyScanStream[scan.stream], body: characters [cstream: IO.RIS[ISTiogaIntern.PrintNodeContents[NARROW[child.isnode], FALSE]]]]]; AdvanceScan [scan]; -- prime the pump -- EXIT; END; ENDCASE => { BufferOrCall [child]; EXIT; }; ENDLOOP; END; t: RightCurlyTVHandle => BEGIN IF primaryImpl=NIL OR primaryImpl.internalize=NIL THEN BEGIN -- was no dollar that was a primary impl -- ii: ISToken.InterscriptContext _ NEW[InterscriptContextObject _ [body: initial [parent] ] ]; primaryImpl _ ISNode.GetImplementation [( primaryTag_NIL), scan.family]; IF primaryImpl=NIL OR primaryImpl.internalize=NIL THEN ERROR; --<>-- NARROW[node.isnode, ISNode.Handle].printProc _ primaryImpl.printTioga; primaryImpl.internalize [NARROW[node.isnode], ii]; WHILE contentBuffer#NIL DO temp: TVHandle; WITH contentBuffer SELECT FROM cb: NodeTVHandle => BEGIN ie: ISToken.InterscriptContext _ NEW[ ISToken.InterscriptContextObject _ [ body: embedded[content: cb] ] ]; [] _ primaryImpl.internalize [ NARROW[node.isnode], ie ]; END; cb: StyleOpenTVHandle => BEGIN ie: ISToken.InterscriptContext _ NEW[ ISToken.InterscriptContextObject _ [ body: styleOpen[identifier: cb] ] ]; [] _ primaryImpl.internalize [ NARROW[node.isnode], ie ]; END; ENDCASE => BEGIN ic: ISToken.InterscriptContext _ NEW[ ISToken.InterscriptContextObject _ [ body: content[content: contentBuffer] ] ]; [] _ primaryImpl.internalize [ NARROW[node.isnode], ic ]; END; temp _ contentBuffer; contentBuffer _ contentBuffer.next; ENDLOOP; END; IF contentBuffer#NIL THEN ERROR; --<>-- FOR c: ISNode.TagHandle _ NARROW[node.isnode, ISNode.Handle].tagThread, c.next UNTIL c=NIL DO ib: ISToken.InterscriptContext _ NEW[ ISToken.InterscriptContextObject _ [ body: bindings[scan.bindingStack] ] ]; dimpl: ISNode.Implementation _ ISNode.GetImplementation [c.tag, scan.family]; NARROW[node.isnode, ISNode.Handle].tag _ c.tag; IF dimpl#NIL AND dimpl.internalize#NIL THEN dimpl.internalize [ NARROW[node.isnode], ib ]; ENDLOOP; BEGIN ie: ISToken.InterscriptContext _ NEW[ ISToken.InterscriptContextObject _ [ body: end[] ] ]; [] _ primaryImpl.internalize [ NARROW[node.isnode], ie ]; END; PruneBindings [scan.bindingStack, anchor]; ISTiogaIntern.localBindingLimit _ oldLocalLimit; scan.stream.token _ NEW[null TVObject _ [body: null[]]]; -- not AdvanceScan [scan]: might be last node -- RETURN [node]; END; ENDCASE => ERROR ParseFailure [scan, outOfPlaceConstruct]; ENDLOOP; END; SHORTINTEGER: PROC [p: LONG INTEGER] RETURNS [INTEGER] ~ INLINE { IF p < FIRST[INTEGER] OR p > LAST[INTEGER] THEN ERROR; RETURN[INTEGER[p]]; }; ObtainBindingIntegerOrZero: PUBLIC PROCEDURE [ name: ATOM, stack: ISBinding.StackHandle] RETURNS [INTEGER] = BEGIN tv: TVHandle _ ObtainBinding [name, stack]; IF tv=NIL THEN RETURN [0]; WITH tv SELECT FROM tt: IntegerTVHandle => RETURN [SHORTINTEGER [tt.value]]; ENDCASE => RETURN [0]; END; END. ςISScanImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. edit by Ayers 17-Jun-85 14:14:31 Rick Beach, August 1, 1985 2:13:30 pm PDT MKaplan, September 13, 1985 3:14:03 pm PDT allocateWith: ISNode.Handle, The publication encoding is ISO-646, which is eight bit characters. -- Although we extend this to allow for sixteen bit characters, via 377B -- shifts, within "<>" strings, the regular scanner does not have to deal with -- this, since the bytes inside the "<>" are gobbled up by special routines. -- Get: PROCEDURE [s: CharactersScanner] RETURNS [e: Basics.Byte] = INLINE {e _ Peek[s]; s.nextCharacter _ notACharacter}; GetGoodPeek: PROCEDURE [s: CharactersScanner] RETURNS [e: Basics.Byte] = INLINE {e _ s.nextCharacter; s.nextCharacter _ notACharacter}; UseUpPeek: PROCEDURE [s: CharactersScanner] = INLINE {s.nextCharacter _ notACharacter}; Peek: PROCEDURE [s: CharactersScanner] RETURNS [e: Basics.Byte] = INLINE BEGIN IF s.nextCharacter#notACharacter THEN RETURN [s.nextCharacter]; e _ s.nextCharacter _ GetByteAtOffset[s]; BumpStreamOffset[s]; RETURN; END; BumpStreamOffset: PROCEDURE [s: CharactersScanner] = INLINE BEGIN s.byteInBuffer _ s.byteInBuffer + 1; END; GetByteAtOffset: PROCEDURE [s: CharactersScanner] RETURNS [Basics.Byte] = INLINE BEGIN IF s.byteInBuffer>=ISScan.bufferBytes THEN BEGIN IF (s.runningAddress _ s.runningAddress + ISScan.bufferBytes/2) >= s.lastAddressPlusOne THEN SIGNAL ParseFailure [NIL, hitEndOfScript]; s.buffer _ s.runningAddress^; s.byteInBuffer _ 0; END; RETURN [s.buffer[s.byteInBuffer] ]; END; If the token in the stream that was just popped is not 'null' or eos then we assert that it has not been processed and return it. t: characters TVObject _ [ body: characters [ value: [ offset: cs.byteInBuffer, limit: cs.byteInBuffer, bytes: LOOPHOLE[cs.runningAddress], context: XString.vanillaContext ] ] -- font supplied later -- ]; <>-- always get here .. no RETURNs above -- DestroyEnvironment: PUBLIC PROCEDURE [at: REF ISBinding.EnvironmentHandle] = BEGIN at.stack.zone.FREE[at]; garbage collect the other stuff when clinet destroys bindings -- END; in case caller didn't This can be uncommented if you want to look at properties with the EditTool (warning: a couple of other places have to be changed... look for Rope.Concat's or Cat's having "." as an argument). n: Rope.ROPE = Atom.GetPName[a]; FOR k: INT IN [0..Rope.Length[n]-1] DO IF Rope.Fetch[n, k]='. THEN RETURN[Atom.MakeAtom[Rope.Concat[Rope.Substr[n, 0, k], Rope.Substr[n, k+1]]]]; ENDLOOP; ^^ knowing that the only difference between ISNode.Create[x] and -- ISNode.Create[y] is the atom stored into the type field -- scan advanced by CollectRHS: AdvanceScan [scan]; scan advanced by CollectRHS: AdvanceScan [scan]; scan advanced by CollectRHS: AdvanceScan [scan]; Look to see if the lhs is non-qualified (no '.'). If so, assume that this is a style definition and pass it to the node-impl. BEGIN dotTest: Rope.ROPE _ Atom.GetPName[theAtom]; FOR k: INT IN [0..Rope.Length[dotTest]-1] DO IF Rope.Fetch[dotTest, k]='. THEN EXIT REPEAT FINISHED => GOTO Dotless; ENDLOOP; EXITS Dotless => BEGIN sd: TVHandle _ NEW[styleDefinition TVObject _ [body: styleDefinition [ name: theAtom, value: CopyOneTV[rhs]]]]; BufferOrCall [sd]; END; END; fall through having done opens until 'tvo' not an atom or no more opens -- ^^ not NARROW[node.isnode] _ ISNode.Create [aa]; -- we know that the only difference between ISNode.Create[x] and -- ISNode.Create[y] is the atom stored into the type field -- feed to node-impl the content we had to remember while -- we didn't know what the impl was -- ISMessage.PutF["CollectNode: %g\n", IO.atom[t.value]]; --<>-- Κν˜codešœ™Kšœ Οmœ1™™@Kšœžœžœžœ™G—K™K™Kšžœ™—Kšžœ™#Kšžœ™——˜Kš ‘ œžœžœžœ žœ˜9K˜š‘ œž œ žœžœžœžœžœžœž˜dK˜Kšœžœžœ˜'Kšœžœ žœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜ K˜šžœžœžœ žœ˜0Kšœ žœ˜#Kšœžœ ˜Kšžœ˜—Kšžœ žœ žœ"˜=Kš žœžœžœ žœžœ˜:Kšžœ˜ šžœ˜K˜——š‘ œžœž˜5šžœŸ˜!šžœ žœž˜K˜BKšœJ˜JKšžœžœŸ˜0—šž˜Kšœ#˜#šžœžœ˜-š žœžœžœžœŸ˜5Kšœžœ˜&K˜Kšœ™Kšœ˜Kš žœžœžœ žœžœ˜CKšž˜——Kšžœžœ˜ Kšžœ˜—Kšžœ˜—Kšžœ˜K˜—š‘œž œžœž˜Ušžœžœžœžœ˜8Kšžœ8˜<—KšœŸ&˜@Kšžœ˜šžœ˜K˜——š‘œž œžœž˜\Kšœžœ˜ Kšœ žœžœ˜Kšœžœžœ˜K˜šžœŸ#˜&šœžœ˜Kšžœžœ˜(—šžœ ž˜šžœž˜Kš œžœžœžœžœ˜FKšžœžœŸ ˜šžœžœ˜(Kšœžœ˜8Kš œ žœžœžœžœ˜?Kšžœ˜ Kšžœ˜——K˜š ‘ œžœž œ žœžœ˜LKšœ žœ˜Kšžœ˜—K˜š‘œžœž œ˜?Kšžœžœ ˜/—K˜š‘œžœž œ˜Bšžœ!žœ˜.Kšœ"žœ˜CK˜K˜Kšžœ˜ Kšžœ˜K˜——š‘œžœž œ.ž˜SK˜!Kšœ+Ÿ˜@Kšžœ˜K˜—š ‘œžœž œžœ!ž˜PK˜5Kšœžœ˜KšœžœŸ˜.Kšžœ˜ Kšžœ˜—K˜š ‘œžœž œžœ ž™RKšœžœ™Kšœ@™@Kšžœ™K™—š‘ œžœž œ=ž˜aKšœŸ%˜6Kšžœ˜šžœ˜K˜——š ‘œžœž œ žœ3ž˜fKšœžœ˜/Kšœ:˜:Kšœ˜Kšžœ˜šžœ˜K˜——š ‘ œžœž œžœ žœž˜fšžœ3žœžœž˜GKšžœžœžœ˜+Kšžœ˜—Kšžœžœ˜ Kšžœ˜—˜š ‘œž œžœ žœžœž˜Ušžœžœž˜Kšœžœ˜>Kšœžœ˜6Kšžœžœ˜—Kšž˜Kšžœ˜K˜—Kš‘ œž œžœž˜Ašžœžœž˜Kšœžœ˜/Kšœžœ˜>Kšœžœ˜>Kšœžœ˜=Kšœžœ˜5Kšœžœ˜/Kšœžœ˜3Kšœžœ˜3Kšœžœ˜;Kšœžœ˜/Kšœžœ˜1Kšœžœ˜1Kšœžœ˜3Kšœžœ˜/Kšœžœ˜/Kšœžœ˜9Kšœžœ˜;Kšœžœ˜/Kšœžœ˜-Kšœžœ˜/Kšœ žœ˜?Kšœžœ˜9Kšœ#žœ˜E—Kšžœ˜Kšžœ˜Kšžœ˜—K˜š‘ œž œžœž˜CKšœ žœžœ˜!K˜šžœžœ˜#Kšœ˜Kšžœžœ˜Kšœ™—šžœžœ˜#KšœŸœ˜