<> <> <> <> <> <> DIRECTORY Alloc, Code, CodeDefs, ComData, FOpCodes, IntCodeDefs, Log, P5, P5S, P5U, PrincOps, SourceMap, SymbolOps, Symbols, Tree, TreeOps; Statement: PROGRAM IMPORTS MPtr: ComData, CPtr: Code, CodeDefs, Log, P5U, P5, P5S, SymbolOps, TreeOps EXPORTS CodeDefs, P5 = BEGIN OPEN FOpCodes, IntCodeDefs, CodeDefs; <> SEIndex: TYPE = Symbols.SEIndex; ISEIndex: TYPE = Symbols.ISEIndex; ISENull: ISEIndex = Symbols.ISENull; CSEIndex: TYPE = Symbols.CSEIndex; CSENull: CSEIndex = Symbols.CSENull; RecordSEIndex: TYPE = Symbols.RecordSEIndex; RecordSENull: RecordSEIndex = Symbols.RecordSENull; BTIndex: TYPE = Symbols.BTIndex; BTNull: BTIndex = Symbols.BTNull; BitAddress: TYPE = Symbols.BitAddress; BitCount: TYPE = Symbols.BitCount; tb: Tree.Base; -- tree base (local copy) seb: Symbols.Base; -- semantic entry base (local copy) ctxb: Symbols.Base; -- context entry base (local copy) bb: Symbols.Base; -- body base (local copy) cb: CodeDefs.Base; -- code base (local copy) StatementNotify: PUBLIC Alloc.Notifier = BEGIN -- called by allocator whenever table area is repacked seb _ base[Symbols.seType]; ctxb _ base[Symbols.ctxType]; bb _ base[Symbols.bodyType]; tb _ base[Tree.treeType]; cb _ base[codeType]; END; catchEndLabel: Label _ NIL; recentStmt: PUBLIC Tree.Link; -- for debugging DeclList: PUBLIC PROC [cl: CodeList, t: Tree.Link] = { -- maybe some statements, too OneDecl: Tree.Scan = { IF t = Tree.Null THEN RETURN; SELECT TreeOps.OpName[t] FROM decl => DeclItem[cl, TreeOps.GetNode[t]]; typedecl => NULL; ENDCASE => P5U.MoreCode[cl, StatementTree[t]]}; TreeOps.ScanList[t, OneDecl]}; StatementList: PUBLIC PROC [cl: CodeList, t: Tree.Link] = { OneStmt: Tree.Scan = {P5U.MoreCode[cl, StatementTree[t]]}; TreeOps.ScanList[t, OneStmt]}; StatementTree: PUBLIC PROC [t: Tree.Link] RETURNS [l: Node] = BEGIN -- generates code for Mesa statements node: Tree.Index; saveIndex: SourceMap.Loc = MPtr.textIndex; recentStmt _ t; IF t = Tree.Null THEN RETURN [NIL]; BEGIN ENABLE BEGIN CPtr.CodeNotImplemented => IF ~MPtr.switches['d] THEN GO TO unimplementedConstruct; END; WITH t SELECT FROM subtree => BEGIN fIndex: SourceMap.Loc _ CPtr.inlineFileLoc; node _ index; IF fIndex = SourceMap.nullLoc THEN fIndex _ tb[node].info; IF fIndex # SourceMap.nullLoc THEN SELECT tb[node].name FROM list, block, null => NULL; -- info is not a valid file index ENDCASE => {CPtr.fileLoc _ MPtr.textIndex _ fIndex; <> }; SELECT tb[node].name FROM list => l _ Compound[t]; block => l _ Block[node]; start => l _ P5S.Start[node]; restart => l _ P5S.Restart[node]; stop => l _ P5S.Stop[node]; < l _ DumpState[node];>> < GO TO unimplementedConstruct; -- added in Trinity>> < l _ LoadState[node];>> < l _ LoadStateFree[node];>> call, portcall => l _ P5S.Call[node]; signal, error => l _ P5S.SigErr[node]; < l _ SysCallStmt[node];>> syserror => l _ P5.SysError[]; label => l _ P5S.LabelStmt[node]; assign => l _ P5S.Assign[node]; extract => l _ P5S.Extract[node]; if => l _ IfStmt[node]; case => l_ P5.CaseStmtExp[node, FALSE]; bind => l _ P5.BindStmtExp[node, FALSE]; do => l _ DoStmt[node]; exit => l _ P5S.Exit[]; loop => l _ P5S.Loop[]; retry => l _ P5S.Retry[]; continue => l _ P5S.Continue[]; goto => l _ P5S.GoTo[node]; catchmark => l _ P5S.CatchMark[node]; return => l _ P5S.Return[node]; resume => l _ P5S.Resume[node]; reject => l _ Reject[]; result => l _ P5S.Result[node]; open => l _ Open[node]; enable => l _ Enable[node]; checked => l _ StatementTree[tb[node].son[1]]; procinit => l _ P5S.ProcInit[node]; wait => l _ P5S.Wait[node]; notify => l _ Notify[node]; broadcast => l _ Broadcast[node]; join => l _ P5S.Join[node]; unlock => l _ P5S.Unlock[node]; lock => l _ P5S.Lock[node]; subst => l _ P5S.Subst[node]; free => l _ P5S.Free[node]; xerror => l _ P5S.RetWithError[node]; null => NULL; ENDCASE => GO TO unimplementedConstruct; END; ENDCASE; EXITS unimplementedConstruct => Log.Error[unimplemented]; END; MPtr.textIndex _ saveIndex; RETURN END; DeclItem: PROC [cl: CodeList, node: Tree.Index] = { initVal: Node _ IF tb[node].son[3] = Tree.Null THEN NIL ELSE P5.Exp[tb[node].son[3]]; first: BOOL _ TRUE; OneId: Tree.Scan = { sei: ISEIndex _ TreeOps.GetSe[t]; IF NOT seb[sei].constant THEN { var: Var _ P5.VarForSei[sei]; P5U.Declare[cl: cl, var: var, init: initVal]; IF first THEN { first _ FALSE; IF initVal # NIL AND initVal.kind # const THEN initVal _ var}; }; }; TreeOps.ScanList[tb[node].son[1], OneId]; }; <> <> <> <> <> <<>> <<>> Open: PROC [node: Tree.Index] RETURNS [Node] = BEGIN <> <> <> <> <> <<>> RETURN[StatementTree[tb[node].son[2]]]; <> END; <> <> <> <> <<>> <> <> <> <> <> <<>> <> <> <> <> <> <<>> <> <> <> <> <> < >> <> <> <> <> <> < Log.Error[stateVector];>> <> Compound: PROC [t: Tree.Link] RETURNS [Node] = BEGIN cl: CodeList _ P5U.NewCodeList[]; StatementList[cl, t]; RETURN[P5U.MakeBlock[cl]]; END; Block: PROC [node: Tree.Index] RETURNS [Node] = BEGIN cl: CodeList _ P5U.NewCodeList[]; bti: BTIndex = tb[node].info; EnterBlock[cl, bti]; DeclList[cl, tb[node].son[1]]; StatementList[cl, tb[node].son[2]]; RETURN[P5U.MakeBlock[cl]]; <> END; IfStmt: PROC [node: Tree.Index] RETURNS [l: Node] = BEGIN -- generates code for an IF statement test: Node = P5.Exp[tb[node].son[1]]; s1: Node = StatementTree[tb[node].son[2]]; s2: Node = StatementTree[tb[node].son[3]]; else: CaseList = P5U.MakeCaseList[NIL, s2]; then: CaseList = P5U.MakeCaseList[P5U.MakeNodeList[test], s1, else]; l _ z.NEW[cond NodeRep _ [details: cond[then]]]; END; DoStmt: PROC [rootNode: Tree.Index] RETURNS [l: Node] = BEGIN -- generates code for all the loop statments stepLoop, tempIndex, tempEnd, upLoop, forSeqLoop, bigForSeq: BOOL _ FALSE; signed: BOOL _ FALSE; <> sSon, eSon: Tree.Link; node, subNode: Tree.Index; bti: BTIndex _ BTNull; intType: Tree.NodeName; deltaOp: Node; indexVar: Var; endVal: Node; topLabel: Label = P5U.AllocLabel[]; startLabel: Label = P5U.AllocLabel[]; finLabel: Label = P5U.AllocLabel[]; endLabel, loopLabel: Label; labelMark: LabelInfoIndex = P5.GetLabelMark[]; cl: CodeList _ P5U.NewCodeList[]; cvBound: Node; ati: ArithTypeIndex; UpdateCV: PROC = BEGIN delta: Node _ P5U.ApplyOp[oper: deltaOp, args: P5U.MakeNodeList2[indexVar, CPtr.nC1], bits: WordSize]; IF cvBound # NIL THEN delta _ P5U.BoundsCheck[delta, cvBound]; P5U.DoAssign[cl, indexVar, delta]; END; <> [exit: endLabel, loop: loopLabel] _ P5.MakeExitLabel[]; TreeOps.ScanList[tb[rootNode].son[5], P5.LabelCreate]; <> IF tb[rootNode].son[1] = Tree.Null THEN P5U.InsertLabel[cl, topLabel] ELSE BEGIN node _ TreeOps.GetNode[tb[rootNode].son[1]]; bti _ tb[node].info; IF bti # BTNull THEN EnterBlock[cl, bti]; SELECT tb[node].name FROM forseq => BEGIN t1: Tree.Link = tb[node].son[1]; e2: Node = P5.Exp[tb[node].son[2]]; indexVar _ P5.VarForSei[TreeOps.GetSe[t1]]; IF bti # BTNull THEN -- or some better test of locally declared cv P5U.Declare[cl, indexVar, e2] ELSE P5U.DoAssign[cl, indexVar, e2]; P5U.InsertLabel[cl, topLabel]; END; upthru, downthru => BEGIN knownNonEmpty: BOOL = tb[node].attr1; cvBound _ P5.Exp[tb[node].son[3]]; stepLoop _ TRUE; upLoop _ tb[node].name = upthru; subNode _ TreeOps.GetNode[tb[node].son[2]]; intType _ tb[subNode].name; IF tb[subNode].attr1 THEN SIGNAL CPtr.CodeNotImplemented; -- REAL ati _ P5U.ArithTypeForTree[subNode]; WITH tb[node].son[1] SELECT FROM subtree => -- son1 is empty {indexVar _ P5U.CreateTemp[WordSize].var; tempIndex _ TRUE}; symbol => indexVar _ P5.VarForSei[index]; ENDCASE; IF upLoop THEN { deltaOp _ P5U.ArithOp[add, ati]; sSon _ tb[subNode].son[1]; eSon _ tb[subNode].son[2]} ELSE BEGIN deltaOp _ P5U.ArithOp[sub, ati]; SELECT intType FROM intCO => intType _ intOC; intOC => intType _ intCO; ENDCASE; sSon _ tb[subNode].son[2]; eSon _ tb[subNode].son[1]; END; WITH e: eSon SELECT FROM literal => endVal _ P5.Exp[eSon]; symbol => IF seb[e.index].immutable THEN endVal _ P5.Exp[eSon] ELSE BEGIN tv: Var _ P5U.CreateTemp[WordSize].var; P5U.Declare[cl, tv, P5.Exp[eSon]]; endVal _ tv; tempEnd _ TRUE; END; ENDCASE => BEGIN endVal _ P5U.MakeTemp[cl: cl, bits: WordSize, init: P5.Exp[eSon]].var; tempEnd _ TRUE; END; IF tempIndex OR bti # BTNull THEN -- or some better test of locally declared cv P5U.Declare[cl, indexVar, P5.Exp[sSon]] ELSE P5U.DoAssign[cl, indexVar, P5.Exp[sSon]]; IF (intType = intCC OR intType = intOO) AND ~knownNonEmpty THEN BEGIN -- earlier passes check for empty intervals topTest: ARRAY BOOL OF ARRAY BOOL OF Comparator = [ [lt,le], -- down, closed/open [gt,ge]]; -- up, closed/open P5U.CJump[ cl: cl, test: topTest[upLoop][intType = intOO], ati: ati, op1: indexVar, op2: endVal, target: finLabel]; END; P5U.Jump[cl, startLabel]; P5U.InsertLabel[cl, topLabel]; SELECT intType FROM intCC => {UpdateCV[]; P5U.InsertLabel[cl, startLabel]}; intOC => UpdateCV[]; intCO, intOO => NULL; ENDCASE; END; ENDCASE; END; <> IF tb[rootNode].son[2] # Tree.Null THEN { goto: Node = z.NEW[goto NodeRep _ [details: goto[finLabel]]]; case: CaseList _ P5U.MakeCaseList[P5U.MakeNodeList[P5.Exp[tb[rootNode].son[2]]], NIL, P5U.MakeCaseList[NIL, goto]]; cond: Node _ z.NEW[NodeRep.cond _ [details: cond[case]]]; P5U.MoreCode[cl, cond]}; <> <> P5U.MoreCode[cl, StatementTree[tb[rootNode].son[4]]]; <> P5U.InsertLabel[cl, loopLabel]; IF stepLoop THEN BEGIN SELECT intType FROM intCC => NULL; intCO => {UpdateCV[]; P5U.InsertLabel[cl, startLabel]}; intOC => P5U.InsertLabel[cl, startLabel]; intOO => {P5U.InsertLabel[cl, startLabel]; UpdateCV[]}; ENDCASE; P5U.CJump[cl: cl, test: IF upLoop THEN lt ELSE gt, op1: indexVar, op2: endVal, ati: ati, target: topLabel]; P5U.Jump[cl, finLabel]; END ELSE BEGIN IF forSeqLoop THEN P5U.DoAssign[cl, indexVar, P5.Exp[tb[node].son[3]]]; P5U.Jump[cl, topLabel]; END; <> P5.LabelList[cl, tb[rootNode].son[5], endLabel, labelMark]; <> P5U.InsertLabel[cl, finLabel]; P5U.MoreCode[cl, StatementTree[tb[rootNode].son[6]]]; <> P5U.InsertLabel[cl, endLabel]; RETURN[P5U.MakeBlock[cl]]; END; Enable: PROC [node: Tree.Index] RETURNS [l: Node] = BEGIN -- generate code for an ENABLE handler: Node _ SCatchPhrase[tb[node].son[1]]; cl: CodeList _ P5U.NewCodeList[]; range: NodeList; StatementList[cl, tb[node].son[2]]; range _ P5U.ExtractList[cl]; l _ z.NEW[enable NodeRep _ [details: enable[handle: handler, scope: range]]]; END; SCatchPhrase: PUBLIC PROC [t: Tree.Link] RETURNS [l: Node] = BEGIN -- main subr for catchphrases and ENABLEs node: Tree.Index = TreeOps.GetNode[t]; saveCaseCV: Node = CPtr.caseCV; <> regsPtr, except, rtnPtr, argPtr: Var; -- formal parameters cl: CodeList _ P5U.NewCodeList[]; catchLabel: Label _ P5U.AllocLabel[]; -- use [bti] when catch phrases have them armHead, armTail: CaseList _ NIL; enclosingContext: Label _ P5.visibleContext[CPtr.curctxlvl]; lambda: LambdaNode; CatchArm: PROC [t: Tree.Link] = BEGIN node: Tree.Index _ TreeOps.GetNode[t]; -- t is an item tests: NodeList _ P5.ExpList[tb[node].son[1]].head; body: Node _ CatchItem[node: node, argPtr: argPtr]; arm: CaseList _ z.NEW[CaseListRep _ [tests: tests, body: body, rest: NIL]]; IF armTail = NIL THEN armHead _ arm ELSE armTail.rest _ arm; armTail _ arm END; regsPtr _ P5U.FormalVar[PtrSize]; except _ P5U.FormalVar[SignalSize]; rtnPtr _ P5U.FormalVar[PtrSize]; argPtr _ P5U.FormalVar[PtrSize]; lambda _ z.NEW[lambda NodeRep _ [details: lambda[parent: enclosingContext, formalArgs: P5U.MakeVarList[regsPtr, P5U.MakeVarList[except, P5U.MakeVarList2[rtnPtr, argPtr]]], body: NIL]]]; -- will fill in body field soon catchEndLabel _ P5U.AllocLabel[]; CPtr.curctxlvl _ CPtr.curctxlvl + 1; P5.visibleContext[CPtr.curctxlvl] _ catchLabel; CPtr.caseCV _ except; TreeOps.ScanList[tb[node].son[1], CatchArm]; IF tb[node].son[2] # Tree.Null THEN { ec: Node _ CatchItem[node:TreeOps.GetNode[tb[node].son[2]], argPtr: argPtr]; other: CaseList _ z.NEW[CaseListRep _ [tests: NIL, body: ec, rest: NIL]]; IF armHead = NIL THEN armHead _ other ELSE armTail.rest _ other}; P5U.InsertLabel[cl, catchEndLabel]; lambda.body _ P5U.MakeNodeList[z.NEW[NodeRep.cond _ [details: cond[armHead]]]]; catchLabel.node _ lambda; l _ z.NEW[NodeRep.label _ [details: label[catchLabel]]]; CPtr.curctxlvl _ CPtr.curctxlvl-1; CPtr.caseCV _ saveCaseCV; <> END; CatchItem: PROC [node: Tree.Index, argPtr: Node] RETURNS [Node] = BEGIN -- generate code for a CATCH item saveCatchOutRecord: RecordSEIndex = CPtr.catchoutrecord; inRecord: RecordSEIndex; body: Node; bodyStmts: NodeList; cl: CodeList _ P5U.NewCodeList[]; tSei: CSEIndex = SymbolOps.UnderType[tb[node].info]; IF tSei = Symbols.CSENull THEN inRecord _ CPtr.catchoutrecord _ RecordSENull ELSE BEGIN [inRecord, CPtr.catchoutrecord] _ SymbolOps.TransferTypes[tSei]; END; GetSignalParams[cl, argPtr, inRecord]; body _ StatementTree[tb[node].son[2]]; WITH b: body SELECT FROM block => bodyStmts _ b.nodes; ENDCASE => bodyStmts _ P5U.MakeNodeList[body]; IF cl.tail = NIL THEN cl.head _ bodyStmts ELSE cl.tail.rest _ bodyStmts; CPtr.catchoutrecord _ saveCatchOutRecord; RETURN[P5U.MakeBlock[cl]]; END; Bits: PROC [ba: BitAddress] RETURNS [INT] = {RETURN[LONG[LOOPHOLE[ba, CARDINAL]]]}; GetSignalParams: PROC [cl: CodeList, argPtr: Node, irecord: RecordSEIndex] = BEGIN totalBits: BitCount _ P5U.BitsForType[irecord]; sei: ISEIndex; np: CARDINAL _ 0; offset: BitAddress; size: BitCount; nParms: CARDINAL; args: Node; IF irecord = CSENull THEN RETURN; nParms _ P5U.WordsForSei[irecord]; IF nParms = 0 THEN RETURN; args _ P5U.Deref[n: argPtr, bits: totalBits]; sei _ P5U.NextVar[ctxb[seb[irecord].fieldCtx].seList]; UNTIL sei = ISENull DO [offset, size] _ SymbolOps.FnField[sei]; P5U.Declare[cl: cl, var: P5.VarForSei[sei], init: P5U.TakeField[n: args, vl: [disp: Bits[offset], size: size]]]; sei _ P5U.NextVar[SymbolOps.NextSe[sei]]; ENDLOOP; END; EnterBlock: PUBLIC PROC [cl: CodeList, bti: BTIndex] = { <> <> <> <> <> <> <> <> <> }; Reject: PROC RETURNS [l: Node] = BEGIN l _ z.NEW[goto NodeRep _ [details: goto[catchEndLabel]]]; END; Notify: PROC [node: Tree.Index] RETURNS [l: Node] = BEGIN cv: Node _ P5.Exp[tb[node].son[1]]; l _ P5U.ApplyOp[oper: P5U.MesaOpNode[notify], args: P5U.MakeNodeList[cv], bits: 0]; END; Broadcast: PROC [node: Tree.Index] RETURNS [l: Node] = BEGIN cv: Node _ P5.Exp[tb[node].son[1]]; l _ P5U.ApplyOp[oper: P5U.MesaOpNode[broadcast], args: P5U.MakeNodeList[cv], bits: 0]; END; END.