-- file MDRulesImpl.mesa rewritten by PGS, 31-Jan-83 11:08 -- last edit by Schmidt, January 6, 1983 2:00 pm -- last edit by Satterthwaite, January 31, 1983 11:08 am -- Pilot 6.0/ Mesa 7.0 -- ParseTable becomes ModelParseTable -- Note this module can be called recusively by nested instances -- of parsers DIRECTORY CWF: TYPE USING [WF0, WF1], Dir: TYPE USING [FileInfo], FileStream: TYPE USING [SetIndex], LongString: TYPE USING [AppendChar, EquivalentString], MDModel: TYPE USING [ AddToEndOfList, APPLSymbol, CheckNotNil, CkType, FreeStringsOf, GetFileInfo, GetSrcCreate, HasAStringName, LETSymbol, LISTSymbol, LocForSp, LOCSymbol, MergeIntoList, MODELSymbol, NarrowToAPPL, NarrowToLOC, NarrowToSTRING, NarrowToTYPE, NewSymAPPL, NewSymLET, NewSymLOC, NewSymMODEL, NewSymOPEN, NewSymPROC, NewSymSTRING, NewSymTYPE, OPENSymbol, PROCSymbol, PushInputStream, STRINGSymbol, Sym, Symbol, SymbolSeq, TYPESymbol, ZeroOut], ModelParseTable: TYPE USING [ProdDataRef, tokenID, TSymbol], MoveFiles: TYPE USING [BringOverRemoteFile], P1: FROM "ModelParseDefs" USING [ ActionStack, InvokeParser, LinkStack, Value, ValueStack], Stream: TYPE USING [Handle], String: TYPE USING [AppendChar, AppendString], Subr: TYPE USING [ CopyString, debugflg, EndsIn, FileError, FreeString, GetLine, LongZone, NewStream, Prefix, Read, strcpy, SubStrCopy, TTYProcs], TypeScript: TYPE USING[TS]; MDRulesImpl: PROGRAM IMPORTS CWF, FileStream, LongString, MDModel, MoveFiles, P1, String, Subr EXPORTS P1, MDModel = { -- MDS usage!!! parseRoot: MDModel.LISTSymbol ← NIL; symbolseq: MDModel.SymbolSeq; contseq: ContSeq; -- these four variables are saved and restored by recursive calls to the parser v: P1.ValueStack; l: P1.LinkStack; q: P1.ActionStack; proddata: ModelParseTable.ProdDataRef; -- makethismodel: BOOL; officialwindow: Subr.TTYProcs ← NIL; officialTypeScript: TypeScript.TS ← NIL; -- endof MDS usage!!! MAXCONT: NAT = 500; ContSeq: TYPE = LONG POINTER TO ContSeqRecord; ContSeqRecord: TYPE = RECORD[ size: CARDINAL ← 0, body: SEQUENCE maxsize: CARDINAL OF ContRecord ]; ContRecord: TYPE = RECORD[ ptr: MDModel.Symbol ← NIL, isopen: BOOL ← FALSE, block: BOOL ← FALSE ]; -- ptr is either a list of terms or a single element within this scope -- an entry that is "block" stops the context scan -- the entry is not included in the smaller scope -- this is called ONCE from MDParseImpl ParseInit: PUBLIC PROC[ ss: MDModel.SymbolSeq, make: BOOL, typeScript: TypeScript.TS, ttywindow: Subr.TTYProcs] = { longzone: UNCOUNTED ZONE = Subr.LongZone[]; symbolseq ← ss; contseq ← longzone.NEW[ContSeqRecord[MAXCONT]]; symbolseq.controlv ← MDModel.NewSymTYPE[symbolseq]; symbolseq.controlv.defn ← TRUE; symbolseq.controlv.typesym ← Subr.CopyString["CONTROL"L]; symbolseq.controlv.typeName ← Subr.CopyString["CONTROL"L]; makethismodel ← make; officialwindow ← ttywindow; officialTypeScript ← typeScript}; AssignDescriptors: PUBLIC PROC [ qd: P1.ActionStack, vd: P1.ValueStack, ld: P1.LinkStack, pp: ModelParseTable.ProdDataRef] = { q ← qd; v ← LOOPHOLE[vd]; l ← ld; proddata ← pp}; -- the interpretation rules LinkToSource: PROC [index: CARDINAL] = {}; -- links: BOOL; codelinks: BOOL = TRUE; framelinks: BOOL = FALSE; -- this is called by the parser ProcessQueue: PUBLIC PROC [qI, top: CARDINAL] = BEGIN -- save: CARDINAL; vTop: P1.Value; FOR i: CARDINAL IN [0 .. qI) DO top ← top-q[i].tag.pLength+1; vTop ← v[top]; SELECT proddata[q[i].transition].rule FROM 0 => -- -- TABLE: ModelParseData -- TYPE: ModelParseTable -- EXPORTS: SELF -- GOAL: goal -- TERMINALS: -- id str , : -- ; ] -- [ . ( ) * -- = ~ ! filename -- number -- LET OPEN FRAMEPTRTYPE -- TYPE STRING -- PLUS THEN PROC RETURNS -- -- ALIASES: -- id tokenID -- str tokenSTR -- number tokenNUM -- filename tokenFILENAME -- . initialSymbol -- PRODUCTIONS: -- goal ::= . source NULL; 1 => -- source ::= first exp { parseRoot ← MakeProperList[v[top+1].r]; IF Subr.debugflg THEN CWF.WF0["source reduction\n"L]; -- pop off the last ] Pop[]; -- IF contseq.size = 1 THEN { -- pop off CONTROL context -- Pop[]; -- }; }; 2 => -- first ::= { -- This context is the first one available to the model Push[val~NIL, isopen~FALSE, isqualified~FALSE]; }; 3 => -- exp ::= explist part -- exp ::= expseq part -- explist ::= explist part , -- expseq ::= expseq part ; { old: MDModel.Symbol = vTop.r; c: CARDINAL; IF v[top+1].r ~= NIL THEN -- not syntax error vTop ← [ref[MDModel.MergeIntoList[vTop.r, v[top+1].r, symbolseq, normal]]]; -- skip any OPEN's that may have been added -- during the insertion of this scope IF contseq.size = 0 THEN ERROR; c ← contseq.size-1; WHILE c > 0 AND contseq[c].isopen DO c ← c - 1; ENDLOOP; IF old ~= NIL AND contseq[c].ptr = old THEN { contseq[c].ptr ← vTop.r; contseq[c].ptr.qualified ← old.qualified; }; -- CWF.WF1["list is:\n%z\n"L, vTop.r]; }; 4 => -- exp ::= part -- explist ::= part , -- expseq ::= part ; { c: CARDINAL; -- this is the first element in a scope IF contseq.size = 0 THEN ERROR; c ← contseq.size-1; WHILE c > 0 AND contseq[c].isopen DO c ← c - 1; ENDLOOP; IF contseq[c].ptr = NIL THEN contseq[c].ptr ← vTop.r; }; 5 => -- part ::= id : call { sym: MDModel.Symbol = v[top+2].r; str: LONG STRING ← vTop.r; sp: MDModel.Symbol = HandleContAPPL[str, contseq, symbolseq, TRUE]; MDModel.CheckNotNil[sp]; -- IF sp.defn THEN CWF.WF1["sym %s already defn\n"L, -- MDModel.Sym[sp]]; MergeTypes[sto~sp,sfrom~sym]; sp.defn ← TRUE; vTop ← [ref[sp]]; Subr.FreeString[str]; -- CWF.WF1["part is:\n%z\n"L, sp]; }; 6 => -- part ::= : call { sp: MDModel.Symbol; str: LONG STRING; stemp: STRING ← [40]; sym: MDModel.Symbol = v[top+1].r; sploc: MDModel.LOCSymbol ← MDModel.LocForSp[sym]; IF sploc = NIL THEN { CWF.WF0["Error - no principal part specified.\n"L]; RETURN; }; MDModel.CkType[sploc, $typeLOC]; IF sploc.prinpart = 0 THEN str ← sploc.tail ELSE { i: CARDINAL ← sploc.prinpart; WHILE i < sploc.sext.length AND sploc.sext[i] ~= '! DO String.AppendChar[stemp, sploc.sext[i]]; i ← i + 1; ENDLOOP; str ← stemp; }; sp ← HandleContAPPL[str, contseq, symbolseq, TRUE]; MDModel.CheckNotNil[sp]; -- IF sp.defn THEN CWF.WF1["sym %s already defn\n"L, -- MDModel.Sym[sp]]; MergeTypes[sto~sp,sfrom~sym]; sp.defn ← TRUE; vTop ← [ref[sp]]; -- now we fix the IdImpl problem: -- what is its type? WITH sp SELECT FROM spt: MDModel.APPLSymbol => { stemp: STRING ← [100]; Subr.strcpy[stemp, spt.applsym]; stemp.length ← stemp.length - 4; spt.appltype ← HandleContTYPE[stemp, contseq, symbolseq, FALSE]; } ENDCASE => MDModel.CkType[sp, $typeTYPE]; -- note this doesn't work for -- :@idImpl[]; }; 7 => -- part ::= call NULL; 8 => -- part ::= * : id { -- short for "idImpl: id" sptype, spappl: MDModel.Symbol; str: STRING ← [30]; Subr.strcpy[str, v[top+2].r]; Subr.FreeString[v[top+2].r]; sptype ← HandleContTYPE[str, contseq,symbolseq, FALSE]; String.AppendString[str, "Impl"L]; spappl ← HandleContAPPL[str, contseq,symbolseq, TRUE]; -- IF spappl.defn THEN -- CWF.WF1["sym %s already defn\n"L,MDModel.Sym[spappl]]; MergeTypes[sto~spappl, sfrom~sptype]; spappl.defn ← TRUE; vTop ← [ref[spappl]]; }; 9 => -- part ::= id : * { -- short for "id: TYPE, idImpl: id" sp, sptype: MDModel.Symbol; sym: MDModel.LISTSymbol; str: STRING ← [30]; Subr.strcpy[str, vTop.r]; Subr.FreeString[vTop.r]; sptype ← HandleContTYPE[str, contseq, symbolseq, TRUE]; String.AppendString[str, "Impl"L]; sp ← HandleContAPPL[str, contseq, symbolseq, TRUE]; WITH sp SELECT FROM spappl: MDModel.APPLSymbol => spappl.appltype ← sptype; ENDCASE => CWF.WF1["Error -- %s should be an interface record.\n"L, str]; sym ← MDModel.AddToEndOfList[NIL, sptype, normal, symbolseq]; sym ← MDModel.AddToEndOfList[sym, sp, normal, symbolseq]; vTop ← [ref[sym]]; }; 10 => -- part ::= id * { -- short for "id, idImpl" sid1, sid2: MDModel.Symbol; sym: MDModel.LISTSymbol; str: STRING ← [30]; Subr.strcpy[str, vTop.r]; Subr.FreeString[vTop.r]; [sid1] ← LookupInContext[str, contseq]; String.AppendString[str, "Impl"L]; [sid2] ← LookupInContext[str, contseq]; sym ← MDModel.AddToEndOfList[NIL, sid1, normal, symbolseq]; sym ← MDModel.AddToEndOfList[sym, sid2, normal, symbolseq]; vTop ← [ref[sym]]; }; 11 => -- part ::= LET group { splet: MDModel.LETSymbol = MDModel.NewSymLET[symbolseq]; splet.letgrp ← MakeProperList[v[top+1].r]; vTop ← [ref[splet]]; -- this makes the variables defined in group accessible -- to stmts below Push[val~splet.letgrp, isopen~TRUE, isqualified~FALSE]; -- OPENS the Let group -- now set LET parent FOR splist: MDModel.LISTSymbol ← splet.letgrp, splist.rest WHILE splist ~= NIL DO FillInLetParent[splist.first, splet]; ENDLOOP; }; 12 => -- part ::= LET group bindop call { splet: MDModel.LETSymbol = MDModel.NewSymLET[symbolseq]; splet.letgrp ← MakeProperList[v[top+1].r]; splet.letval ← v[top+3].r; vTop ← [ref[splet]]; -- this makes the variables defined in group accessible -- to stmts below Push[val~splet.letgrp, isopen~TRUE, isqualified~FALSE]; -- OPENS the Let group -- now set LET parent FOR splist: MDModel.LISTSymbol ← splet.letgrp, splist.rest WHILE splist ~= NIL DO FillInLetParent[splist.first, splet]; ENDLOOP; }; 13 => -- part ::= OPEN call { sp: MDModel.OPENSymbol = MDModel.NewSymOPEN[symbolseq]; sp.open ← v[top+1].r; vTop ← [ref[sp]]; -- if call is a filename the just process include file IF sp.open ~= NIL AND sp.open.stype = $typeLOC THEN { sploc: MDModel.LOCSymbol = MDModel.NarrowToLOC[sp.open]; IF sploc.nestedmodel ~= NIL THEN Push[val~sploc.nestedmodel.model, isopen~TRUE, isqualified~FALSE]; } ELSE IF sp.open ~= NIL THEN { -- this is the qualified case, an OPEN of a variable Push[val~MDModel.NarrowToAPPL[sp.open].appltype, isopen~TRUE, isqualified~TRUE]; }; }; 14 => -- call ::= primary NULL; 15 => -- call ::= primary group { sp: MDModel.Symbol = vTop.r; splist: MDModel.Symbol = v[top+1].r; IF sp = NIL THEN RETURN; -- syntax error WITH sp SELECT FROM spt: MDModel.LOCSymbol => { spl: MDModel.LISTSymbol ← (spt.parmlist ← MakeProperList[splist]); -- this makes any variables mentioned in "group" -- that are not yet defined accessible -- to scopes below this, so they may be defined there: Push[val~spl, isopen~TRUE, isqualified~FALSE]; -- why doesn't this work? -- WHILE spl ~= NIL DO -- IF ~spl.first.defn THEN -- Push[val~spl.first, isopen~TRUE, isqualified~FALSE]; -- spl ← spl.rest; -- ENDLOOP; }; spt: MDModel.PROCSymbol => spt.procval ← MakeProperList[splist]; ENDCASE => NULL; }; 16 => -- call ::= primary bindop call { sp: MDModel.Symbol = vTop.r; spval: MDModel.Symbol = v[top+2].r; IF sp = NIL THEN RETURN; -- syntax error IF sp.stype = $typeTYPE AND MDModel.NarrowToTYPE[sp].typesym = NIL THEN { -- is being declared? MDModel.NarrowToTYPE[sp].typeval ← spval; vTop ← [ref[sp]]; } ELSE { spa: MDModel.APPLSymbol = MDModel.NewSymAPPL[symbolseq]; spa.appltype ← vTop.r; spa.applval ← spval; vTop ← [ref[spa]]; }; -- this makes anything defined in the PLUS or THEN list -- available. This might happen if the variables are used -- before they are defined. WITH spval SELECT FROM splist: MDModel.LISTSymbol => Push[val~splist, isopen~TRUE, isqualified~FALSE]; ENDCASE => NULL; }; 17 => -- call ::= primary PLUS call { vTop ← [ref[MDModel.MergeIntoList[vTop.r, v[top+2].r, symbolseq, plus]]]; }; 18 => -- call ::= primary THEN call { vTop ← [ref[MDModel.MergeIntoList[vTop.r, v[top+2].r, symbolseq, then]]]; }; 19 => -- primary ::= subprimary NULL; 20 => -- subprimary ::= str { str: LONG STRING ← vTop.r; sp: MDModel.STRINGSymbol = MDModel.NewSymSTRING[symbolseq]; IF str ~= NIL THEN { sp.strval ← Subr.CopyString[str]; Subr.FreeString[str]; }; vTop ← [ref[sp]]; }; 21 => -- subprimary ::= id { str: LONG STRING ← vTop.r; IF str ~= NIL THEN { sp: MDModel.Symbol = HandleContTYPE[str, contseq, symbolseq, FALSE]; -- could be part of a LET -- IF ~sp.defn THEN -- CWF.WF1["Symbol %s not defn\n"L,MDModel.Sym[sp]]; vTop ← [ref[sp]]; Subr.FreeString[str]; }; }; 22 => -- primary ::= unitid NULL; 23 => -- subprimary ::= ( call ) vTop ← v[top+1]; 24 => -- primary ::= group NULL; 25 => -- subprimary ::= TYPE { sp: MDModel.TYPESymbol = MDModel.NewSymTYPE[symbolseq]; vTop ← [ref[sp]]; }; 26 => -- subprimary ::= FRAMEPTRTYPE { sp: MDModel.TYPESymbol = MDModel.NewSymTYPE[symbolseq]; sp.frameptr ← TRUE; vTop ← [ref[sp]]; }; 27 => -- subprimary ::= TYPE id { -- although id is of type id, we never look it up, just use it as a string str: LONG STRING ← v[top+1].r; sp: MDModel.TYPESymbol = MDModel.NewSymTYPE[symbolseq]; sp.typeName ← Subr.CopyString[str]; vTop ← [ref[sp]]; Subr.FreeString[str]; }; 28 => -- subprimary ::= FRAMEPTRTYPE id { -- although id is of type id, we never look it up, just use it as a string str: LONG STRING ← v[top+1].r; sp: MDModel.TYPESymbol = MDModel.NewSymTYPE[symbolseq]; sp.typeName ← Subr.CopyString[str]; sp.frameptr ← TRUE; vTop ← [ref[sp]]; Subr.FreeString[str]; }; 29 => -- subprimary ::= STRING { sp: MDModel.STRINGSymbol = MDModel.NewSymSTRING[symbolseq]; vTop ← [ref[sp]]; }; 30 => -- primary ::= PROC group { sp: MDModel.PROCSymbol = MDModel.NewSymPROC[symbolseq]; sp.procparm ← MakeProperList[v[top+1].r]; Push[val~sp.procparm, isopen~TRUE, isqualified~FALSE]; -- OPENS the procedure parameters vTop ← [ref[sp]]; }; 31 => -- primary ::= PROC group RETURNS group { sp: MDModel.PROCSymbol = MDModel.NewSymPROC[symbolseq]; sp.procparm ← MakeProperList[v[top+1].r]; sp.procret ← MakeProperList[v[top+3].r]; Push[val~sp.procparm, isopen~TRUE, isqualified~FALSE]; -- OPENS the procedure parameters Push[val~sp.procret, isopen~TRUE, isqualified~FALSE]; -- OPENS the procedure results vTop ← [ref[sp]]; }; 32 => -- subprimary ::= subprimary . id { sp: MDModel.Symbol = FindElementOf[vTop.r, v[top+2].r]; Subr.FreeString[v[top+2].r]; IF sp ~= NIL THEN sp.qualified ← TRUE; vTop ← [ref[sp]]; }; 33 => -- group ::= lb rb vTop ← [ref[(NIL).LONG]]; 34 => -- group ::= lb exp rb vTop ← v[top+1]; 35 => -- lb ::= [ Push[val~NIL, isopen~FALSE, isqualified~FALSE]; 36 => -- rb ::= ] Pop[]; 37 => -- bindop ::= = = -- bindop ::= ~ NULL; 38 => -- unitid ::= filename { sp: MDModel.LOCSymbol; IF vTop.r = NIL THEN GOTO out; -- syntax error sp ← ProcessFilename[vTop.r]; Subr.FreeString[vTop.r]; vTop ← [ref[sp]]; IF sp = NIL THEN GOTO out; IF LongString.EquivalentString[sp.sext, "model"L] THEN [sp.nestedmodel] ← ParseLoc[sp, officialTypeScript, officialwindow]; EXITS out => NULL; }; 39 => -- unitid ::= filename ! number { sp: MDModel.LOCSymbol; IF vTop.r = NIL THEN GOTO out; -- syntax error sp ← ProcessFilename[vTop.r]; Subr.FreeString[vTop.r]; vTop ← [ref[sp]]; IF sp = NIL THEN GOTO out; sp.createtime ← v[top+2].s; IF LongString.EquivalentString[sp.sext, "model"L] THEN [sp.nestedmodel] ← ParseLoc[sp, officialTypeScript, officialwindow]; EXITS out => NULL; }; ENDCASE => ERROR; v[top] ← vTop; ENDLOOP; END; MakeProperList: PROC[oldlist: MDModel.Symbol] RETURNS[MDModel.LISTSymbol] = { RETURN [WITH oldlist SELECT FROM splist: MDModel.LISTSymbol => splist, ENDCASE => IF oldlist = NIL THEN MDModel.LISTSymbol.NIL ELSE MDModel.AddToEndOfList[NIL, oldlist, $normal, symbolseq]]}; FillInLetParent: PROC[spelem1: MDModel.Symbol, splet: MDModel.LETSymbol] = { WITH spelem1 SELECT FROM spelem: MDModel.TYPESymbol => { IF spelem.typeval ~= NIL THEN CWF.WF1["Warning: %s is defined in a TYPE and a LET stmt.\n"L, spelem.typesym]; IF spelem.letparent ~= NIL THEN CWF.WF1["Warning: %s is defined in two LET stmts.\n"L, spelem.typesym]; spelem.letparent ← splet}; spelem: MDModel.APPLSymbol => { IF spelem.applval ~= NIL THEN CWF.WF1["Warning: %s is defined in an APPL and a LET stmt.\n"L, spelem.applsym]; IF spelem.letparent ~= NIL THEN CWF.WF1["Warning: %s is defined in two LET stmts.\n"L, spelem.applsym]; spelem.letparent ← splet}; ENDCASE => NULL}; -- only retrieves models -- returns NIL if the loc is not a model -- need to save a few descriptors ParseLoc: PUBLIC PROC[ sploc: MDModel.LOCSymbol, typeScript: TypeScript.TS, ttywindow: Subr.TTYProcs] RETURNS[symmodel: MDModel.MODELSymbol, nerrors: CARDINAL ← 0] = { savev: P1.ValueStack; savel: P1.LinkStack; saveq: P1.ActionStack; saveproddata: ModelParseTable.ProdDataRef; parsed: BOOL; sh: Stream.Handle; savecontinx: CARDINAL; fi: Dir.FileInfo; IF ~LongString.EquivalentString[sploc.sext, "model"L] THEN RETURN[NIL]; symmodel ← NIL; -- this procedure is only executed for MODEL files MoveFiles.BringOverRemoteFile[sploc, makethismodel, typeScript, ttywindow]; fi ← MDModel.GetFileInfo[sploc]; IF ~fi.srcPresent THEN RETURN; -- lookup to see if we already analyzed it FOR i:CARDINAL IN [0 .. symbolseq.modelSeq.size) DO symmodel ← symbolseq.modelSeq[i]; IF symmodel.modelcreate = MDModel.GetSrcCreate[fi] THEN RETURN[symmodel, 0]; ENDLOOP; sh ← Subr.NewStream[fi.srcFileName, Subr.Read ! Subr.FileError => GOTO err]; IF sploc.host = NIL THEN { -- peek in first line of model line: STRING ← [400]; newloc: MDModel.LOCSymbol; [] ← Subr.GetLine[sh, line]; IF Subr.Prefix[line, "--["L] THEN { line[1] ← '@; -- keeps ProcessFilename happy Subr.SubStrCopy[line, line, 1]; newloc ← ProcessFilename[line]; sploc.host ← newloc.host; sploc.path ← newloc.path; newloc.host ← NIL; newloc.path ← NIL; }; FileStream.SetIndex[sh, 0]}; MDModel.PushInputStream[sh]; savev ← v; savel ← l; saveq ← q; saveproddata ← proddata; CWF.WF1["Nested Parse of %s.\n"L, fi.srcFileName]; savecontinx ← IF contseq.size = 0 THEN 0 ELSE contseq.size - 1; IF savecontinx > 0 THEN contseq[savecontinx].block ← TRUE; Push[val~symbolseq.controlv, isopen~FALSE, isqualified~FALSE]; -- push on control context [complete~parsed, nErrors~nerrors] ← P1.InvokeParser[]; CWF.WF1["End of nested Parse, %u errors.\n"L, @nerrors]; Pop[]; -- pop off control contseq[savecontinx].block ← FALSE; v ← savev; l ← savel; q ← saveq; proddata ← saveproddata; symmodel ← MDModel.NewSymMODEL[symbolseq]; symmodel.modelfilename ← Subr.CopyString[fi.srcFileName]; symmodel.modelcap ← fi.srcCap; symmodel.modelcreate ← MDModel.GetSrcCreate[fi]; symmodel.model ← parseRoot; -- add to model list IF symbolseq.modelSeq.size >= symbolseq.modelSeq.maxsize THEN CWF.WF0["Error - too many models.\n"L] ELSE { symbolseq.modelSeq[symbolseq.modelSeq.size] ← symmodel; symbolseq.modelSeq.size ← symbolseq.modelSeq.size + 1}; EXITS err => NULL; }; ProcessFilename: PUBLIC PROC[fn: LONG STRING] RETURNS[sploc: MDModel.LOCSymbol] = { host: STRING ← [40]; -- Ivy directory: STRING ← [60]; -- Schmidt>Pilot body: STRING ← [50]; -- Junk ext: STRING ← [50]; -- Mesa prinpart: CARDINAL ← 0; t: STRING ← [100]; sep: STRING ← [20]; savefn: STRING ← [100]; GetNext: PROC[pat: LONG STRING] = { i: CARDINAL ← 0; pat.length ← 0; IF fn[i] = '[ OR fn[i] = '] OR fn[i] = '< OR fn[i] = '> OR fn[i] = '* OR fn[i] = '↑ OR fn[i] = '@ OR fn[i] = '. THEN { LongString.AppendChar[pat, fn[0]]; Subr.SubStrCopy[fn, fn, 1]; RETURN}; WHILE i < fn.length DO IF fn[i] = '[ OR fn[i] = '] OR fn[i] = '< OR fn[i] = '> OR fn[i] = '* OR fn[i] = '↑ OR fn[i] = '@ OR fn[i] = '. THEN EXIT; LongString.AppendChar[pat, fn[i]]; i ← i + 1; ENDLOOP; Subr.SubStrCopy[fn, fn, i]}; sploc ← NIL; IF fn = NIL THEN ERROR; Subr.strcpy[savefn, fn]; IF fn[0] ~= '@ THEN ERROR; GetNext[t]; -- skip @ GetNext[t]; IF t[0] = '[ THEN { GetNext[t]; Quote[t]; Subr.strcpy[host, t]; GetNext[t]; IF t[0] ~= '] THEN { CWF.WF1["Error - missing ']' in '%s'.\n"L, savefn]; RETURN}; GetNext[t]}; IF t[0] = '< THEN { GetNext[t]; GetNext[sep]; WHILE sep.length # 0 AND sep[0] = '> DO Quote[t]; String.AppendString[directory, t]; GetNext[t]; GetNext[sep]; IF sep.length # 0 AND sep[0] = '> THEN String.AppendChar[directory, '>]; ENDLOOP}; -- now is just a name.ext.ext -- get name Quote[t]; Subr.strcpy[body, t]; IF fn.length > 0 OR sep.length > 0 THEN { IF sep.length = 0 THEN GetNext[sep]; IF sep[0] ~= '. THEN { CWF.WF1["Error - missing '.' in '%s'.\n"L, savefn]; RETURN}; DO GetNext[t]; IF t[0] = '* THEN { prinpart ← ext.length; GetNext[t]}; Quote[t]; IF ext.length > 0 THEN String.AppendChar[ext, '.]; String.AppendString[ext, t]; GetNext[sep]; IF sep.length = 0 THEN EXIT; IF sep[0] ~= '. THEN { CWF.WF1["Error - missing '.' in '%s'.\n"L, savefn]; RETURN}; ENDLOOP}; sploc ← MDModel.NewSymLOC[symbolseq]; sploc.host ← IF host.length = 0 THEN NIL ELSE Subr.CopyString[host]; sploc.path ← IF directory.length = 0 THEN NIL ELSE Subr.CopyString[directory]; sploc.tail ← Subr.CopyString[body]; sploc.sext ← Subr.CopyString[IF ext.length = 0 THEN "Mesa" ELSE ext]; sploc.prinpart ← prinpart; -- CWF.WF4["Debug: [%s]<%s>%s.%s\n"L, sploc.host, sploc.path, sploc.tail, sploc.sext]--}; Quote: PROC[s: STRING] = { sp: MDModel.Symbol; IF s[s.length - 1] ~= '↑ THEN RETURN; s.length ← s.length - 1; [sp] ← LookupInContext[s, contseq]; IF sp = LONG[NIL] OR sp.stype ~= $typeSTRING THEN CWF.WF0["error"L]; Subr.strcpy[s,MDModel.NarrowToSTRING[sp].strval]}; -- if the file is not on local disk, we must retrieve it, -- then we stack the stream handle TokenValue: PUBLIC PROC [s: ModelParseTable.TSymbol] RETURNS [P1.Value] = { RETURN [SELECT s FROM ModelParseTable.tokenID => LOOPHOLE[LONG[0]], ENDCASE => LOOPHOLE[LONG[0]]]}; FindElementOf: PROC[sym: MDModel.Symbol, element: LONG STRING] RETURNS[node: MDModel.Symbol] = { node ← NIL; WITH sym SELECT FROM record: MDModel.APPLSymbol => { WITH record.appltype SELECT FROM spstart: MDModel.LISTSymbol => { WHILE spstart ~= NIL DO stry: MDModel.Symbol; MDModel.CkType[spstart, $typeLIST]; stry ← spstart.first; IF stry.stype IN MDModel.HasAStringName AND MDModel.Sym[stry] ~= NIL AND LongString.EquivalentString[MDModel.Sym[stry], element] THEN RETURN[stry]; spstart ← spstart.rest; ENDLOOP}; ENDCASE => { CWF.WF1["Error - %s is not a record\n"L, MDModel.Sym[sym]]; RETURN}; }; ENDCASE => { CWF.WF1["Error - %s has wrong type-- should be record.\n"L, MDModel.Sym[sym]]; RETURN}}; MergeTypes: PROC[sto: MDModel.Symbol, sfrom: MDModel.Symbol] = { s: LONG STRING; IF sto.stype IN MDModel.HasAStringName THEN s ← MDModel.Sym[sto]; -- this is for the case idImpl: id, where sfrom is id and -- idImpl should have type id IF (sfrom.stype = $typeTYPE AND MDModel.NarrowToTYPE[sfrom].typesym ~= NIL) OR sfrom.stype = $typeLIST THEN { sto↑ ← [vpart~typeAPPL[ appltype~sfrom, applval~NIL, applsym~s, configname~NIL, letparent~NIL, interfaceseq~NIL]]; RETURN}; -- this is for the :@file default IF sfrom.stype = $typeLOC THEN { -- distinguish two cases: :@id[] and :@idImpl -- the :@id[] returns a TYPE -- the :@idImpl returns a typeAPPL IF Subr.EndsIn[s, "impl"L] THEN sto↑ ← [vpart~typeAPPL[ applsym~s, appltype~NIL, applval~sfrom, configname~NIL, letparent~NIL, interfaceseq~NIL]] ELSE sto↑ ← [vpart~typeTYPE[ typeval~sfrom, typesym~s, typeName~Subr.CopyString[s], frameptr~FALSE, letparent~NIL, uniqueno~0]]; RETURN}; sto↑ ← sfrom↑; IF sto.stype IN MDModel.HasAStringName THEN WITH sto SELECT FROM sto1: MDModel.TYPESymbol => { sto1.typesym ← s; sto1.typeName ← Subr.CopyString[IF sto1.typeName = NIL THEN s ELSE sto1.typeName]}; sto1: MDModel.PROCSymbol => sto1.procsym ← s; sto1: MDModel.STRINGSymbol => sto1.strsym ← s; sto1: MDModel.APPLSymbol => sto1.applsym ← s; ENDCASE => ERROR; -- bad select MergeTypes MDModel.FreeStringsOf[sfrom]; MDModel.ZeroOut[sfrom]}; Push: PROC[val: MDModel.Symbol, isopen, isqualified: BOOL] = { newcont: ContRecord = [val, isopen, FALSE]; IF val ~= NIL THEN { WITH val SELECT FROM splist: MDModel.LISTSymbol => { -- if a list, then set the qualified bit to isqualified for each elem WHILE splist ~= NIL DO splist.first.qualified ← isqualified; splist ← splist.rest; ENDLOOP}; ENDCASE; val.qualified ← isqualified}; IF contseq.size >= contseq.maxsize THEN CWF.WF0["Too many pushes.\n"L] ELSE { contseq[contseq.size] ← newcont; contseq.size ← contseq.size + 1}}; Pop: PROC = { newcont: ContRecord = []; WHILE contseq.size > 0 AND contseq[contseq.size-1].isopen DO contseq.size ← contseq.size - 1; ENDLOOP; IF contseq.size = 0 THEN CWF.WF0["Too many pops\n"L] ELSE { contseq.size ← contseq.size - 1; contseq[contseq.size] ← newcont}}; LookupInContext: PROC[sym: LONG STRING, contseq: ContSeq] RETURNS[sp: MDModel.Symbol, isnewscope: BOOL] = { spsym: LONG STRING; isnewscope ← TRUE; FOR i: CARDINAL DECREASING IN [0 .. contseq.size) DO { IF contseq[i].block THEN EXIT; sp ← contseq[i].ptr; IF sp = NIL THEN GOTO loop; WITH sp SELECT FROM splist: MDModel.LISTSymbol => { -- sp is a list WHILE splist ~= NIL DO spa: MDModel.Symbol = splist.first; IF spa.stype IN MDModel.HasAStringName AND (spsym ← MDModel.Sym[spa]) ~= NIL AND spsym.length = sym.length AND LongString.EquivalentString[sym, spsym] THEN RETURN[spa, isnewscope]; splist ← splist.rest; ENDLOOP}; ENDCASE => { IF sp.stype NOT IN MDModel.HasAStringName THEN GOTO loop; spsym ← MDModel.Sym[sp]; IF spsym ~= NIL AND spsym.length = sym.length AND LongString.EquivalentString[sym, spsym] THEN RETURN[sp, isnewscope]}; GOTO loop; EXITS loop => IF ~contseq[i].isopen THEN isnewscope ← FALSE; }; ENDLOOP; RETURN[NIL, TRUE]}; -- if the sym is already defined, assume it is a new definition -- if definitional then this is a context where something can be defined HandleContTYPE: PROC[sym: LONG STRING, contseq: ContSeq, symbolseq: MDModel.SymbolSeq, definitional: BOOL] RETURNS[sp: MDModel.Symbol] = { news: BOOL; [sp, news] ← LookupInContext[sym, contseq]; IF sp = NIL OR (sp.defn AND definitional) THEN { IF ~news THEN CWF.WF1["Error -%s is multiply defined.\n"L, sym]; sp ← IdInsertTYPE[sym, symbolseq]}}; -- if the sym is already defined, assume it is a new definition HandleContAPPL: PROC[sym: LONG STRING, contseq: ContSeq, symbolseq: MDModel.SymbolSeq, definitional: BOOL] RETURNS[sp: MDModel.Symbol] = { news: BOOL; [sp, news] ← LookupInContext[sym, contseq]; IF sp = NIL OR (sp.defn AND definitional) THEN { IF ~news THEN CWF.WF1["Error -%s is multiply defined.\n"L, sym]; sp ← IdInsertAPPL[sym, symbolseq]}}; IdInsertTYPE: PROC[s: LONG STRING, symbolseq: MDModel.SymbolSeq] RETURNS[sto: MDModel.TYPESymbol] = { sto ← MDModel.NewSymTYPE[symbolseq]; sto.typesym ← Subr.CopyString[s]; sto.typeName ← Subr.CopyString[s]}; -- questionable IdInsertAPPL: PROC[s: LONG STRING, symbolseq: MDModel.SymbolSeq] RETURNS[sto: MDModel.APPLSymbol] = { sto ← MDModel.NewSymAPPL[symbolseq]; sto.applsym ← Subr.CopyString[s]}; }. UNUSED PRODUCTIONS -- callexplist ::= callexplist ; call => exp NULL; -- callexplist ::= call => exp NULL; -- call ::= SELECT call FROM [ callexplist ] NULL; -- also, we need to get rid of the $ stuff from the source reduction