-- file SMTreeBuildImpl.mesa rewritten by PGS, 11-Aug-83 14:19 -- last modified by Satterthwaite, August 11, 1983 2:18 pm -- last edit by Schmidt, June 11, 1982 3:12 pm -- pgs [defs: SMParseTable, bcd: SMParseData, grammar: SML] ← SMTreeBuildImpl.mesa; -- output: new version of SMTreeBuildImpl.mesa, tables in SMParseData.bcd -- interface on SMParseTable.mesa -- log on PGS.Log, grammar on SML.grammar, -- errors on SMParseData.errlog DIRECTORY Atom: TYPE USING [MakeAtom], SMP1: TYPE --P1-- USING [ActionStack, LinkStack, Value, ValueStack], SMParseTable: TYPE ParseTable USING [ProdDataRef], Rope: TYPE USING [Fetch, Flatten, FromChar, Length, ROPE, Substr, Text], SMTree: TYPE Tree USING [AttrId, Link, Name, NodeName, null], SMTreeOps: TYPE --TreeOps-- USING [ TM, NSons, PopTree, PushTree, PushName, PushNode, PushText, SetAttr, SetInfo, UpdateSons], SMCommentTable: TYPE USING [Index], SMOps: TYPE USING [MS]; -- this program is monitored by the ML in SMReaderImpl SMTreeBuildImpl: CEDAR PROGRAM IMPORTS Atom, Rope, SMTreeOps EXPORTS SMP1 ~ { -- parse tree building OPEN P1~~SMP1, Tree~~SMTree, TreeOps~~SMTreeOps, SMParseTable, SMCommentTable; Op: TYPE ~ Tree.NodeName; -- local data base (supplied by parser) cm: SMOps.MS; tm: TreeOps.TM; v: P1.ValueStack; l: P1.LinkStack; q: P1.ActionStack; prodData: ProdDataRef; -- initialization/termination AssignDescriptors: PUBLIC PROC[ qd: P1.ActionStack, vd: P1.ValueStack, ld: P1.LinkStack, pp: ProdDataRef, model: SMOps.MS] ~ { q ← qd; v ← vd; l ← ld; prodData ← pp; cm ← model; tm ← cm.tm}; -- stack manipulation -- note that r and s may be overlaid in some parameterizations PushHashV: PROC[k: NAT] ~ { tm.PushName[NARROW[v[k].t]]; tm.PushNode[$locator,1]; LinkToSource[k]}; PushStringLitV: PROC[k: NAT] ~ { tm.PushText[NARROW[v[k].t]]; tm.PushNode[$locator,1]; LinkToSource[k]}; -- the interpretation rules LinkToSource: PROC[index: CARDINAL] ~ {tm.SetInfo[l[index]]}; -- propagated attributes ProcessQueue: PUBLIC PROC[qI, top: CARDINAL] ~ { FOR i: CARDINAL IN [0..qI) DO GetRule: PROC[n: CARDINAL] RETURNS [CARDINAL] ~ TRUSTED INLINE { RETURN [prodData[n].rule]}; top ← top-q[i].tag.pLength+1; SELECT GetRule[q[i].transition] FROM -- basic tree building 0 => -- TABLE: SMParseData TYPE: ParseTable EXPORTS: SELF -- GOAL: goal -- TERMINALS: -- name string , : ; -- ] filename -- [ . ~ = > -- + - * / \ ↑ -- ( ) -- LAMBDA LET REC IN -- TYPE STRING ENV NIL CONTROL -- THEN CROSS -- endfile -- ALIASES: -- name tokenID -- string tokenSTR -- filename tokenFILENAME -- . initialSymbol -- endfile tokenEOF -- PRODUCTIONS: -- goal ::= . source NULL; 1 => -- source ::= exp endfile NULL; 2 => -- exp ::= LAMBDA term = > exp IN exp { tm.PushNode[$lambda, 3]; LinkToSource[top]; }; 3 => -- exp ::= LAMBDA term IN exp { node: Tree.Link = tm.PopTree; tm.PushTree[Tree.null]; tm.PushTree[node]; tm.PushNode[$lambda, 3]; LinkToSource[top]; }; 4 => -- exp ::= LET term IN exp { tm.PushNode[$let, 2]; LinkToSource[top]; }; 5 => -- exp ::= term - > exp { tm.PushNode[$arrow, 2]; LinkToSource[top]; }; 6 => -- exp ::= term NULL; 7 => -- term ::= term + factor { tm.PushNode[$union, 2]; LinkToSource[top]; }; 8 => -- term ::= term THEN factor { tm.PushNode[$then, 2]; LinkToSource[top]; }; 9 => -- term ::= term - factor { tm.PushNode[$exclusion, 2]; LinkToSource[top]; }; 10 => -- term ::= term ↑ factor { tm.PushNode[$restriction, 2]; LinkToSource[top]; }; 11 => -- term ::= term \ factor { tm.PushNode[$splitUpper, 2]; LinkToSource[top]; }; 12 => -- term ::= term / factor { tm.PushNode[$splitLower, 2]; LinkToSource[top]; }; 13 => -- term ::= factor NULL; 14 => -- factor ::= appl CROSS factor { tm.PushNode[$cross, 2]; LinkToSource[top]; }; 15 => -- factor ::= appl CROSS CROSS factor { tm.PushNode[$cross2, 2]; LinkToSource[top]; }; 16 => -- factor ::= appl NULL; 17 => -- appl ::= appl bracket { tm.PushNode[$apply, 2]; LinkToSource[top]; }; 18 => -- appl ::= appl * bracket { tm.PushNode[$applyDefault, 2]; LinkToSource[top]; }; 19 => -- appl ::= primary NULL; 20 => -- primary ::= name PushHashV[top]; 21 => -- primary ::= string PushStringLitV[top]; 22 => -- primary ::= TYPE { tm.PushTree[Tree.null]; tm.PushNode[$type, 1]; LinkToSource[top]; }; 23 => -- primary ::= TYPE name { PushHashV[top+1]; tm.PushNode[$type, 1]; }; 24 => -- primary ::= STRING tm.PushNode[$typeSTRING, 0]; 25 => -- term ::= CONTROL tm.PushNode[$control, 0]; 26 => -- primary ::= ENV { tm.PushNode[$env, 0]; LinkToSource[top]; }; 27 => -- primary ::= NIL { tm.PushNode[$nil, 0]; LinkToSource[top]; }; 28 => -- primary ::= filename ProcessFileName[NARROW[v[top].t]]; 29 => -- primary ::= bracket NULL; 30 => -- primary ::= primary . name { PushHashV[top+2]; tm.PushNode[$subscript, 2]; LinkToSource[top]; }; 31 => -- bracket ::= group NULL; 32 => -- bracket ::= [ decl ] { tm.PushNode[$decl, v[top+1].n]; tm.SetAttr[1, TRUE]; LinkToSource[top]; }; 33 => -- bracket ::= [ binding ] { tm.PushNode[$bind, v[top+1].n]; LinkToSource[top]; }; 34 => -- bracket ::= REC [ binding ] { tm.PushNode[$bindRec, v[top+2].n]; LinkToSource[top]; }; 35 => -- bracket ::= ( exp ) NULL; 36 => -- group ::= [ expList ] tm.PushNode[$group, v[top+1].n]; 37 => -- group ::= [ ] tm.PushNode[$group, 0]; 38 => -- expList ::= exp -- expListC ::= exp , -- expListS ::= exp ; v[top].n ← 1; 39 => -- expList ::= expListC exp -- expList ::= expListS exp -- expListC ::= expListC exp , -- expListS ::= expListS exp ; v[top].n ← v[top].n + 1; 40 => -- decl ::= declElem -- declC ::= declElem , -- declS ::= declElem ; v[top].n ← 1; 41 => -- decl ::= declC declElem -- decl ::= declS declElem -- declC ::= declC declElem , -- declS ::= declS declElem ; v[top].n ← v[top].n + 1; 42 => -- declElem ::= name : exp { PushHashV[top]; tm.PushNode[$declElem, -2]; }; 43 => -- binding ::= bindElem -- bindingC ::= bindElem , -- bindingS ::= bindElem ; v[top].n ← 1; 44 => -- binding ::= bindingC bindElem -- binding ::= bindingS bindElem -- bindingC ::= bindingC bindElem , -- bindingS ::= bindingS bindElem ; v[top].n ← v[top].n + 1; 45 => -- bindElem ::= [ decl ] ~ exp { exp: Tree.Link = tm.PopTree; tm.PushNode[$decl, v[top+1].n]; tm.SetAttr[1, FALSE]; LinkToSource[top]; tm.PushTree[exp]; tm.PushNode[$bindElem, 2]; }; 46 => -- bindElem ::= declElem ~ exp { exp: Tree.Link = tm.PopTree; tm.PushNode[$decl, 1]; tm.SetAttr[1, FALSE]; tm.PushTree[exp]; tm.PushNode[$bindElem, 2]; }; 47 => -- bindElem ::= name ~ exp { exp: Tree.Link = tm.PopTree; v[top].t ← PushImplicitDecl[tm, v[top].t]; tm.PushNode[$decl, 1]; tm.SetAttr[1, FALSE]; tm.PushTree[exp]; tm.PushNode[$bindElem, 2]; }; 48 => -- bindElem ::= group ~ exp { exp: Tree.Link = tm.PopTree; group: Tree.Link = tm.PopTree; tm.UpdateSons[group, PushImplicitDecl]; tm.PushNode[$decl, TreeOps.NSons[group]]; tm.SetAttr[1, FALSE]; tm.PushTree[exp]; tm.PushNode[$bindElem, 2]; }; -- error or unimplemented ENDCASE => ERROR; ENDLOOP}; PushImplicitDecl: PROC[tm: TreeOps.TM, t: Tree.Link] RETURNS[Tree.Link] ~ { tm.PushTree[t]; tm.PushTree[Tree.null]; tm.PushNode[$declElem, 2]; RETURN[Tree.null]}; MakeName: PROC[r: Rope.ROPE] RETURNS[Tree.Name] ~ { RETURN[Atom.MakeAtom[r]]}; ProcessFileName: PROC[name: Rope.Text] ~ { t, sep: Rope.Text ← NIL; index: CARDINAL ← 0; n: CARDINAL; max: INT ~ name.Length[]; GetNext: PROC RETURNS[pat: Rope.Text] ~ { ch: CHAR; start: INT; IF index >= max THEN RETURN[NIL]; ch ← name.Fetch[index]; SELECT ch FROM '[, '], '<, '>, '↑, '@, '., '! => { pat ← Rope.FromChar[ch]; index ← index + 1; RETURN}; ENDCASE; pat ← NIL; start ← index; WHILE index < max DO ch ← name.Fetch[index]; SELECT ch FROM '[, '], '<, '>, '*, '↑, '@, '., '! => EXIT; ENDCASE; index ← index + 1; ENDLOOP; IF index > start THEN pat ← Rope.Flatten[name, start, index-start]}; CheckNext: PROC[ch: CHAR] RETURNS[BOOL] ~ { t: Rope.Text ~ GetNext[]; RETURN[t.Fetch[0] = ch]}; PushPart: PROC[part: Rope.Text] ~ { IF (part.Fetch[part.Length[]-1] = '↑) THEN { tm.PushName[MakeName[part.Substr[0, part.Length[]-1]]]; tm.PushNode[$unQuote, 1]} ELSE tm.PushText[part]}; IF ~CheckNext['@] THEN ERROR; t ← GetNext[]; IF t.Fetch[0] = '[ THEN { t ← GetNext[]; PushPart[t]; IF ~CheckNext[']] THEN { -- ["Error - missing ']' in '%s'.\n"L, savefn]; ERROR}; t ← GetNext[]} ELSE tm.PushTree[Tree.null]; IF t.Fetch[0] = '< THEN { t ← GetNext[]; sep ← GetNext[]; n ← 0; WHILE sep.Length[] > 0 AND sep.Fetch[0] = '> DO PushPart[t]; n ← n + 1; t ← GetNext[]; sep ← GetNext[]; ENDLOOP; tm.PushNode[$uiList, n]} ELSE tm.PushTree[Tree.null]; -- now is just a name.ext.ext -- get name n ← 1; PushPart[t]; IF index < name.Length[] OR sep.Length[] > 0 THEN { IF sep.Length = 0 THEN sep ← GetNext[]; IF sep.Fetch[0] ~= '. THEN { -- CWF.WF1["Error - missing '.' in '%s'.\n"L, savefn]; ERROR}; DO PushPart[GetNext[]]; n ← n + 1; sep ← GetNext[]; IF sep = NIL OR sep.Length = 0 THEN EXIT; IF sep.Fetch[0] = '! THEN EXIT; IF sep.Fetch[0] ~= '. THEN { -- CWF.WF1["Error - missing '.' in '%s'.\n"L, savefn]; ERROR}; ENDLOOP}; tm.PushNode[$uiList, n]; IF sep ~= NIL AND sep.Fetch[0] = '! THEN { hex, highest: BOOL ← FALSE; t ← GetNext[]; FOR n: INT IN [0 .. t.Length[]) DO ch: CHAR ~ t.Fetch[n]; SELECT t.Fetch[n] FROM IN ['0 .. '9] => NULL; IN ['a .. 'f], IN ['A..'F] => hex ← TRUE; 'h, 'H => highest ← TRUE; ENDCASE => { -- CWF.WF1["Error - invalid version id: %s\n"L, t]; ERROR} ENDLOOP; IF (hex AND t.Length # 12) OR (highest AND t.Length # 1) THEN { -- CWF.WF1["Error - invalid version id: %s\n"L, t]; ERROR}; tm.PushText[t]} ELSE tm.PushTree[Tree.null]; -- host directory namelist number tm.PushNode[$unitId, 4]}; }. xx => -- declElem ::= group : exp tm.PushNode[$declElem, 2];