-- File: ScriptParseImpl.mesa - last edit by -- Karlton: 2-Sep-82 14:07:38 DIRECTORY ScriptHash USING [Create, Destroy, Handle, Hash, nullVal, Val], ScriptNode USING [QualifiedID, QualifiedIDSequence, Type], ScriptParse USING [ ErrorCode, InitScan, NextSymbol, ScanHandle, Terminal, TerminalType], ScriptTree USING [AddNode, Create, Destroy, Handle, MoveNode, TreeHandle], Stream USING [Handle]; ScriptParseImpl: PROGRAM IMPORTS ScriptHash, ScriptParse, ScriptTree EXPORTS ScriptParse = { CantReduce: ERROR = CODE; Error: PUBLIC ERROR [ code: ScriptParse.ErrorCode, position: LONG CARDINAL] = CODE; Handle: TYPE = ScriptTree.Handle; lookAhead: CARDINAL = 2; CurNext: TYPE = {current, next}; nullVal: ScriptHash.Val = ScriptHash.nullVal; Frame: TYPE = POINTER TO GlobalData; GlobalData: TYPE = RECORD [ terminals: ARRAY [0..lookAhead) OF ScriptParse.Terminal, current: CARDINAL, scan: ScriptParse.ScanHandle, idSeq: ScriptNode.QualifiedID ← NIL, idCount: CARDINAL ← 0, idTable, univTable: ScriptHash.Handle ← NIL, tree: ScriptTree.TreeHandle, z: UNCOUNTED ZONE]; Internalize: PUBLIC PROCEDURE [stream: Stream.Handle, z: UNCOUNTED ZONE] RETURNS [univ, id: ScriptHash.Handle, tree: ScriptTree.TreeHandle]= { frame: GlobalData ← [ z: z, idTable: ScriptHash.Create[z, 50, 3, 20, FALSE], univTable: ScriptHash.Create[z, 20, 2, 20, TRUE], idSeq: z.NEW[ScriptNode.QualifiedIDSequence[5]], scan: NIL, terminals: , current: 0, tree: ScriptTree.Create[z]]; frame.scan ← ScriptParse.InitScan[ stream, frame.univTable, frame.idTable, frame.z]; FOR i: CARDINAL IN [0..lookAhead) DO frame.terminals[i] ← ScriptParse.NextSymbol[frame.scan] ENDLOOP; -- InitUniversalTable[f]; Unit[@frame ! CantReduce => ERROR Error[parse, frame.terminals[frame.current].pos]; UNWIND => { frame.univTable.Destroy[]; frame.idTable.Destroy[]; ScriptTree.Destroy[frame.tree]; frame.z.FREE[@frame.idSeq]}]; frame.z.FREE[@frame.idSeq]; RETURN[frame.univTable, frame.idTable, frame.tree]}; CheckAndAdvance: PROCEDURE [f: Frame, type: ScriptParse.TerminalType] = { IF Type[f] # type THEN ERROR CantReduce; Advance[f]}; Advance: PROCEDURE [f: Frame] = { f.terminals[f.current] ← ScriptParse.NextSymbol[f.scan]; f.current ← (f.current + 1) MOD lookAhead}; Type: PROCEDURE [f: Frame, which: CurNext ← current] RETURNS [ScriptParse.TerminalType] = { RETURN[SELECT which FROM current => f.terminals[f.current].type, next => f.terminals[1 - f.current].type, ENDCASE => ERROR]}; CopyIdSequence: PROCEDURE [f: Frame, longer: CARDINAL ← 0] RETURNS [qid: ScriptNode.QualifiedID] = { qid ← f.z.NEW[ScriptNode.QualifiedIDSequence[f.idCount + longer]]; FOR i: CARDINAL IN [0..f.idCount) DO qid[i] ← f.idSeq[i] ENDLOOP}; AddIdToSeq: PROC [f: Frame] = { WITH term: f.terminals[f.current] SELECT FROM id => { IF f.idCount = f.idSeq.length THEN { tempSeq: ScriptNode.QualifiedID ← CopyIdSequence[f, 5]; f.z.FREE[@f.idSeq]; f.idSeq ← tempSeq}; f.idSeq[f.idCount] ← term.hash; f.idCount ← f.idCount + 1}; ENDCASE => ERROR CantReduce}; TryName: PROCEDURE [f: Frame] = { IF f.idCount > 0 THEN RETURN; IF Type[f] # id THEN RETURN; AddIdToSeq[f]; WHILE Type[f, next] = dot DO Advance[f]; -- id which is at the front Advance[f]; -- dot in order to get the next id (hopefully) at the front AddIdToSeq[f]; ENDLOOP}; GetList: PROCEDURE [ f:Frame, proc: PROCEDURE [f: Frame, parent, son: Handle] RETURNS [new: Handle], node: Handle] = { last: Handle ← NIL; DO SELECT Type[f] FROM bar, rightParen, rightBrace, rightBracket, quote => EXIT; -- only things that end lists ENDCASE => last ← proc[f, node, last]; ENDLOOP}; -- and here are the productions Unit: PROCEDURE [f: Frame] = { node: Handle; CheckAndAdvance[f, start]; CheckAndAdvance[f, versionId]; node ← ScriptTree.AddNode[f.tree, NIL, NIL]; -- define the root Node[f, node]; CheckAndAdvance[f, stop]}; Node: PROCEDURE [f: Frame, node: Handle] = { node.node ← [node[NIL, NIL]]; CheckAndAdvance[f, leftBrace]; ItemList[f, node]; CheckAndAdvance[f, rightBrace]}; Name: PROCEDURE [f: Frame] = { IF f.idCount = 0 THEN ERROR CantReduce; Advance[f]; f.idCount ← 0}; Id: PROCEDURE [f: Frame] = { IF f.idCount # 1 THEN ERROR CantReduce; Advance[f]; f.idCount ← 0}; ItemList: PROCEDURE [f: Frame, node: Handle] = {GetList[f, Item, node]}; BindingList: PROCEDURE [f: Frame, node: Handle] = {GetList[f, Binding, node]}; Item: PROCEDURE [f: Frame, parent, son: Handle] RETURNS [new: Handle] = { TryName[f]; SELECT Type[f] FROM links => new ← Links[f, parent, son]; universal => { SELECT Type[f, next] FROM dollar => new ← Label[f, parent, son]; colonEqual => new ← GlobalBinding[f, parent, son]; ENDCASE => new ← Content[f, parent, son]}; id => { SELECT Type[f, next] FROM upArrow, colon => new ← Link[f, parent, son]; leftArrow => new ← LocalBinding[f, parent, son]; colonEqual => new ← GlobalBinding[f, parent, son]; ENDCASE => new ← Content[f, parent, son]}; ENDCASE => new ← Content[f, parent, son]}; Content: PROCEDURE [f: Frame, parent, son: Handle] RETURNS [new: Handle] = { TryName[f]; SELECT Type[f] FROM leftBrace => { new ← ScriptTree.AddNode[f.tree, parent, son]; Node[f, new]}; ENDCASE => new ← Term[f, parent, son]}; Term: PROCEDURE [f: Frame, parent, son: Handle] RETURNS [new: Handle] = { new ← Primary[f, parent, son]; SELECT Type[f] FROM plus, minus, times, divide => { left: Handle = new; new ← Op[f, parent, new]; ScriptTree.MoveNode[ tree: f.tree, node: left, newParent: new, newLeftSibling: NIL]; [] ← Term[f, new, left]}; ENDCASE => NULL}; Primary: PROCEDURE [f: Frame, parent, son: Handle] RETURNS [new: Handle] = { TryName[f]; SELECT Type[f] FROM boolean, integer, real, string => new ← Literal[f, parent, son]; universal => IF Type[f, next] = leftBracket THEN new ← Application[f, parent, son] ELSE new ← Literal[f, parent, son]; leftParen => {Advance[f]; new ← SelectionOrVector[f, parent, son]}; id => SELECT Type[f, next] FROM percent => new ← Indirection[f, parent, son]; leftBracket => new ← Application[f, parent, son]; ENDCASE => new ← Invocation[f, parent, son]; ENDCASE => ERROR CantReduce}; Indirection: PROCEDURE [f: Frame, parent, son: Handle] RETURNS [new: Handle] = { new ← ScriptTree.AddNode[f.tree, parent, son]; new.node ← [percent[CopyIdSequence[f]]]; Name[f]; CheckAndAdvance[f, percent]}; Invocation: PROCEDURE [f: Frame, parent, son: Handle] RETURNS [new: Handle] = { new ← ScriptTree.AddNode[f.tree, parent, son]; new.node ← [qualifiedID[ids: CopyIdSequence[f]]]; Name[f]}; SelectionOrVector: PROCEDURE [f: Frame, parent, son: Handle] RETURNS [new: Handle] = { IF Type[f] = question THEN {Advance[f]; new ← Selection[f, parent, son]} ELSE new ← Vector[f, parent, son]}; Vector: PROCEDURE [f: Frame, parent, son: Handle] RETURNS [new: Handle] = { new ← ScriptTree.AddNode[f.tree, parent, son]; new.node ← [vector[]]; ItemList[f, new]}; Selection: PROCEDURE [f: Frame, parent, son: Handle] RETURNS [new: Handle]= { first, second, third: Handle; new ← ScriptTree.AddNode[f.tree, parent, son]; new.node ← [choice[]]; first ← Term[f, new, NIL]; CheckAndAdvance[f, bar]; -- get the first bar second ← ScriptTree.AddNode[f.tree, new, first]; third ← ScriptTree.AddNode[f.tree, new, second]; ItemList[f, second]; CheckAndAdvance[f, bar]; -- get the second bar ItemList[f, third]; CheckAndAdvance[f, rightParen]}; Application: PROCEDURE [f: Frame, parent, son: Handle] RETURNS [new: Handle] = { new ← ScriptTree.AddNode[f.tree, parent, son]; TryName[f]; WITH term: f.terminals[f.current] SELECT FROM universal => { new.node ← [univApplication[term.hash]]; Advance[f]}; id => { new.node ← [application[CopyIdSequence[f]]]; Name[f]}; ENDCASE => ERROR CantReduce; CheckAndAdvance[f, leftBracket]; [] ← ItemList[f, new]; CheckAndAdvance[f, rightBracket]}; Literal: PROCEDURE [f: Frame, parent, son: Handle] RETURNS [new: Handle] = { new ← ScriptTree.AddNode[f.tree, parent, son]; WITH term: f.terminals[f.current] SELECT FROM boolean => {new.node ← [boolean[term.boolean]]; Advance[f]}; integer => {new.node ← [integer[term.integer]]; Advance[f]}; string => {new.node ← [string[term.string]]; Advance[f]}; -- same heap real => {new.node ← [real[term.real]]; Advance[f]}; universal => {new.node ← [atom[term.hash]]; Advance[f]}; ENDCASE => ERROR CantReduce}; Op: PROCEDURE [f: Frame, parent, son: Handle] RETURNS [new: Handle] = { new ← ScriptTree.AddNode[f.tree, parent, son]; SELECT Type[f] FROM plus => {new.node ← [expression[plus]]; Advance[f]}; times => {new.node ← [expression[multiply]]; Advance[f]}; minus => {new.node ← [expression[minus]]; Advance[f]}; divide => {new.node ← [expression[divide]]; Advance[f]}; ENDCASE => ERROR CantReduce}; Binding: PROCEDURE [f: Frame, parent, son: Handle] RETURNS [new: Handle] = { SELECT Type[f, next] FROM leftArrow => new ← LocalBinding[f, parent, son]; colonEqual => new ← GlobalBinding[f, parent, son]; ENDCASE => ERROR CantReduce}; LocalBinding: PROCEDURE [f: Frame, parent, son: Handle] RETURNS [new: Handle] = { idSeq: ScriptNode.QualifiedID; TryName[f]; IF Type[f] # id OR Type[f, next] # leftArrow THEN ERROR CantReduce; new ← ScriptTree.AddNode[f.tree, parent, son]; idSeq ← CopyIdSequence[f]; Name[f]; Advance[f]; -- over leftArrow new.node ← [localBind[lhs: idSeq]]; RHS[f, new]}; GlobalBinding: PROCEDURE [f: Frame, parent, son: Handle] RETURNS [new: Handle] = { TryName[f]; new ← ScriptTree.AddNode[f.tree, parent, son]; IF Type[f, next] # colonEqual THEN ERROR CantReduce; WITH term: f.terminals[f.current] SELECT FROM id => { new.node ← [globalBind[lhs: CopyIdSequence[f], univ: FALSE]]; Name[f]}; universal => { idSeq: ScriptNode.QualifiedID ← f.z.NEW[ScriptNode.QualifiedIDSequence[1]]; idSeq[0] ← term.hash; new.node ← [globalBind[lhs: idSeq, univ: TRUE]]; Advance[f]}; ENDCASE => ERROR CantReduce; Advance[f]; -- over colonEqual RHS[f, new]}; RHS: PROCEDURE [f: Frame, node: Handle] = { SELECT Type[f] FROM plus, minus, times, divide => { new: Handle = Op[f, node, NIL]; [] ← Term[f, new, NIL]}; quote => { new: Handle = ScriptTree.AddNode[f.tree, node, NIL]; Advance[f]; new.node ← [quotedExpression[]]; ItemList[f, new]; CheckAndAdvance[f, quote]}; leftBracket => { new: Handle = ScriptTree.AddNode[f.tree, node, NIL]; left: Handle = ScriptTree.AddNode[f.tree, new, NIL]; right: Handle = ScriptTree.AddNode[f.tree, new, left]; new.node ← [environment[]]; Advance[f]; ItemList[f, left]; CheckAndAdvance[f, bar]; BindingList[f, right]; CheckAndAdvance[f, rightBracket]}; ENDCASE => { [] ← Content[f, node, NIL]}}; Label: PROCEDURE [f: Frame, parent, son: Handle] RETURNS [new: Handle] = { TryName[f]; SELECT Type[f] FROM universal => RETURN[Tag[f, parent, son]]; id => RETURN[Link[f,parent, son]]; ENDCASE => ERROR CantReduce}; Tag: PROCEDURE [f: Frame, parent, son: Handle] RETURNS [new: Handle] = { new ← ScriptTree.AddNode[f.tree, parent, son]; WITH term: f.terminals[f.current] SELECT FROM universal => {new.node ← [dollar[term.hash]]; Advance[f]}; ENDCASE => ERROR CantReduce; CheckAndAdvance[f, dollar]}; Link: PROCEDURE [f: Frame, parent, son: Handle] RETURNS [new: Handle] = { new ← ScriptTree.AddNode[f.tree, parent, son]; WITH term: f.terminals[f.current] SELECT FROM colon => {new.node ← [target[CopyIdSequence[f]]]; Name[f]; Advance[f]}; upArrow => {new.node ← [source[CopyIdSequence[f]]]; Name[f]; Advance[f]}; ENDCASE => ERROR CantReduce}; Links: PROCEDURE [f: Frame, parent, son: Handle] RETURNS [new: Handle] = { Advance[f]; new ← ScriptTree.AddNode[f.tree, parent, son]; TryName[f]; WITH term: f.terminals[f.current] SELECT FROM id => new.node ← [links[term.hash]]; ENDCASE => ERROR CantReduce; Id[f]}; -- main line code }. -- of ScriptParseImpl