-- file Pass3Xc.mesa -- last modified by Satterthwaite, February 24, 1983 3:30 pm DIRECTORY A3: TYPE USING [ CanonicalType, LongPath, OperandLhs, OperandType, OrderedType, TargetType, TypeForTree], Alloc: TYPE USING [Notifier], ComData: TYPE USING [idCARDINAL, idCHAR, typeINTEGER, typeStringBody], Copier: TYPE USING [SEToken, nullSEToken, CtxFirst, CtxNext, CtxValue], Log: TYPE USING [Error, ErrorN, ErrorNode, ErrorTree], P3: TYPE USING [ Attr, fullAttr, NPUse, MergeNP, phraseNP, And, Exp, ForceType, Interval, MakeLongType, MakeRefType, RAttr, Rhs, RPop, RPush, RType, SequenceField, TypeExp, VoidExp], P3S: TYPE USING [safety], Symbols: TYPE USING [ Base, SERecord, Type, ISEIndex, CSEIndex, CTXIndex, nullType, ISENull, typeANY, seType], SymbolOps: TYPE USING [ MakeNonCtxSe, NormalType, RCType, ReferentType, TypeForm, UnderType], Tree: TYPE USING [Base, Index, Link, Null, treeType], TreeOps: TYPE USING [ FreeNode, GetNode, IdentityMap, ListLength, NthSon, OpName, PopTree, PushSe, PushTree, PushNode, SetAttr, SetInfo, UpdateList]; Pass3Xc: PROGRAM IMPORTS A3, Copier, Log, P3, P3S, SymbolOps, TreeOps, dataPtr: ComData EXPORTS P3 = { OPEN SymbolOps, Symbols, TreeOps, A3, P3; tb: Tree.Base; -- tree base address (local copy) seb: Symbols.Base; -- se table base address (local copy) ExpCNotify: PUBLIC Alloc.Notifier = { -- called by allocator whenever table area is repacked seb ← base[seType]; tb ← base[Tree.treeType]}; -- ranges Range: PUBLIC PROC [t: Tree.Link, type: CSEIndex] RETURNS [val: Tree.Link] = { subType: Type; SELECT OpName[t] FROM subrangeTC => { val ← RewriteSubrange[GetNode[t]]; Interval[val, IF type # typeANY THEN type ELSE dataPtr.typeINTEGER, FALSE]}; IN [intOO .. intCC] => { val ← t; Interval[val, IF type # typeANY THEN type ELSE dataPtr.typeINTEGER, FALSE]}; ENDCASE => IF TypeForm[type] # long THEN { val ← TypeExp[t]; RPush[TargetType[UnderType[TypeForTree[val]]], fullAttr]; phraseNP ← none} ELSE { val ← MakeEndPoints[t]; Interval[val, type, FALSE]}; subType ← RType[]; IF ~OrderedType[subType] AND subType # typeANY THEN Log.Error[nonOrderedType]; RETURN}; RewriteSubrange: PROC [node: Tree.Index] RETURNS [Tree.Link] = { subNode: Tree.Index = GetNode[tb[node].son[2]]; PushTree[tb[subNode].son[1]]; PushTree[IdentityMap[tb[node].son[1]]]; PushNode[apply, -2]; tb[subNode].son[1] ← PopTree[]; PushTree[tb[subNode].son[2]]; PushTree[tb[node].son[1]]; PushNode[apply, -2]; tb[subNode].son[2] ← PopTree[]; tb[node].son[1] ← tb[node].son[2] ← Tree.Null; FreeNode[node]; RETURN [[subtree[subNode]]]}; MakeEndPoints: PROC [t: Tree.Link] RETURNS [Tree.Link] = { PushTree[t]; PushNode[first, 1]; PushTree[IdentityMap[t]]; PushNode[last, 1]; PushNode[intCC, 2]; RETURN [PopTree[]]}; -- operations on enumerated types SEToken: TYPE = Copier.SEToken; Span: PUBLIC PROC [type: CSEIndex] RETURNS [first, last: SEToken] = { subType: CSEIndex = TargetType[type]; vCtx: CTXIndex = WITH seb[subType] SELECT FROM enumerated => valueCtx, ENDCASE => ERROR; WITH t: seb[type] SELECT FROM enumerated => {first ← CtxFirst[vCtx]; last ← CtxLast[vCtx]}; subrange => { IF t.mark4 THEN { first ← Copier.CtxValue[vCtx, t.origin]; last ← Copier.CtxValue[vCtx, t.origin + t.range]} ELSE { node: Tree.Index = LOOPHOLE[t.range]; subNode: Tree.Index = GetNode[tb[node].son[2]]; first ← EnumeratedValue[tb[subNode].son[1], vCtx]; last ← EnumeratedValue[tb[subNode].son[2], vCtx]; SELECT tb[subNode].name FROM intOO, intOC => first ← CtxSucc[vCtx, first]; ENDCASE; SELECT tb[subNode].name FROM intOO, intCO => last ← CtxPred[vCtx, last]; ENDCASE}}; ENDCASE => first ← last ← Copier.nullSEToken; RETURN}; EnumeratedValue: PROC [t: Tree.Link, vCtx: CTXIndex] RETURNS [SEToken] = { WITH t SELECT FROM symbol => { sei: ISEIndex = index; RETURN [SELECT TRUE FROM ~seb[sei].constant => Copier.nullSEToken, (seb[sei].idCtx = vCtx) OR seb[sei].mark4 => Copier.CtxValue[vCtx, seb[sei].idValue], ENDCASE => EnumeratedValue[InitTree[sei], vCtx]]}; subtree => { node: Tree.Index = index; RETURN [SELECT tb[node].name FROM first => Span[UnderType[TypeForTree[tb[node].son[1]]]].first, last => Span[UnderType[TypeForTree[tb[node].son[1]]]].last, pred => CtxPred[vCtx, EnumeratedValue[tb[node].son[1], vCtx]], succ => CtxSucc[vCtx, EnumeratedValue[tb[node].son[1], vCtx]], ENDCASE => Copier.nullSEToken]}; ENDCASE => RETURN [Copier.nullSEToken]}; CtxFirst: PROC [ctx: CTXIndex] RETURNS [SEToken] = Copier.CtxFirst; CtxLast: PROC [ctx: CTXIndex] RETURNS [last: SEToken] = { last ← Copier.nullSEToken; FOR t: SEToken ← Copier.CtxFirst[ctx], Copier.CtxNext[ctx, t] UNTIL t = Copier.nullSEToken DO last ← t ENDLOOP; RETURN}; CtxSucc: PROC [ctx: CTXIndex, t: SEToken] RETURNS [SEToken] = Copier.CtxNext; CtxPred: PROC [ctx: CTXIndex, t: SEToken] RETURNS [pred: SEToken] = { next: SEToken; pred ← Copier.nullSEToken; IF t # Copier.nullSEToken THEN { next ← Copier.CtxFirst[ctx]; UNTIL next = t OR next = Copier.nullSEToken DO pred ← next; next ← Copier.CtxNext[ctx, next] ENDLOOP}; RETURN}; InitTree: PROC [sei: ISEIndex] RETURNS [Tree.Link] = INLINE { RETURN [tb[LOOPHOLE[seb[sei].idValue, Tree.Index]].son[3]]}; -- operations on addresses AddrOp: PUBLIC PROC [node: Tree.Index, target: CSEIndex] = { SELECT tb[node].name FROM addr => Addr[node, target]; base => Base[node, target]; length => Length[node]; arraydesc => Desc[node, target]; ENDCASE => ERROR}; Addr: PROC [node: Tree.Index, target: CSEIndex] = { OPEN tb[node]; type: CSEIndex; attr: Attr; subType: CSEIndex = NormalType[target]; var: BOOL = WITH t: seb[subType] SELECT FROM ref => t.var, ENDCASE => FALSE; counted: BOOL ← FALSE; IF P3S.safety = checked AND ~var THEN Log.ErrorNode[unsafeOperation, node]; son[1] ← Exp[son[1], typeANY]; FOR t: Tree.Link ← son[1], NthSon[t, 1] DO SELECT OpName[t] FROM uparrow => { subType: CSEIndex = NormalType[OperandType[NthSon[t, 1]]]; WITH p: seb[subType] SELECT FROM ref => IF p.counted THEN counted ← TRUE; ENDCASE; EXIT}; cast, openx => NULL; ENDCASE => EXIT; ENDLOOP; SELECT OperandLhs[son[1]] FROM counted => IF var THEN { son[1] ← SafenRef[son[1]]; IF RCType[RType[]] # none THEN Log.ErrorTree[unimplemented, son[1]]}; none => Log.ErrorTree[nonAddressable, son[1]]; ENDCASE; type ← MakeRefType[ cType:RType[], hint:subType, counted:counted AND ~var, var:var]; IF var THEN {Log.ErrorNode[unimplemented, node]; attr2 ← FALSE} ELSE IF (attr2 ← LongPath[son[1]]) THEN type ← MakeLongType[type, target]; attr ← RAttr[]; RPop[]; RPush[type, attr]}; SafenRef: PROC [t: Tree.Link] RETURNS [v: Tree.Link] = { WITH t SELECT FROM subtree => { node: Tree.Index = index; SELECT tb[node].name FROM dot, uparrow, dindex, reloc => { PushTree[tb[node].son[1]]; PushNode[safen, 1]; SetInfo[OperandType[tb[node].son[1]]]; tb[node].son[1] ← PopTree[]; v ← t}; dollar, index, seqindex, loophole, cast, openx, pad, chop => { tb[node].son[1] ← SafenRef[tb[node].son[1]]; v ← t}; cdot => { tb[node].son[2] ← SafenRef[tb[node].son[2]]; v ← t}; apply, safen => v ← t; ENDCASE => ERROR}; ENDCASE => v ← t; RETURN}; StripRelative: PROC [rType: CSEIndex] RETURNS [type: CSEIndex, bType: Type] = { WITH seb[rType] SELECT FROM relative => {type ← UnderType[offsetType]; bType ← baseType}; ENDCASE => {type ← rType; bType ← nullType}; RETURN}; MakeRelativeType: PROC [type: CSEIndex, bType: Type, hint: CSEIndex] RETURNS [CSEIndex] = { rType, tType: CSEIndex; WITH seb[hint] SELECT FROM relative => IF offsetType = type AND UnderType[baseType] = UnderType[bType] THEN RETURN [hint]; ENDCASE; tType ← IF TypeForm[bType] = long OR TypeForm[type] = long THEN MakeLongType[NormalType[type], type] ELSE type; rType ← MakeNonCtxSe[SERecord.cons.relative.SIZE]; seb[rType].typeInfo ← relative[ baseType: bType, offsetType: type, resultType: tType]; seb[rType].mark3 ← seb[rType].mark4 ← TRUE; RETURN [rType]}; Base: PROC [node: Tree.Index, target: CSEIndex] = { OPEN tb[node]; type, aType, nType, subTarget: CSEIndex; bType: Type; attr: Attr; long: BOOL; IF P3S.safety = checked THEN Log.ErrorNode[unsafeOperation, node]; IF ListLength[son[1]] = 1 THEN { son[1] ← Exp[son[1], typeANY]; [aType, bType] ← StripRelative[CanonicalType[RType[]]]; attr ← RAttr[]; RPop[]; nType ← NormalType[aType]; [subTarget, ] ← StripRelative[target]; WITH seb[nType] SELECT FROM array => { name ← addr; IF OperandLhs[son[1]] = none THEN Log.ErrorTree[nonAddressable, son[1]]; long ← LongPath[son[1]]}; arraydesc => {long ← seb[aType].typeTag = long; nType ← UnderType[describedType]}; ENDCASE => IF nType # typeANY THEN Log.ErrorTree[typeClash, son[1]]} ELSE { Log.ErrorN[listLong, ListLength[son[1]]-1]; son[1] ← UpdateList[son[1], VoidExp]; long ← FALSE}; type ← MakeRefType[nType, NormalType[subTarget]]; IF (attr2 ← long) THEN type ← MakeLongType[type, subTarget]; IF bType # nullType THEN type ← MakeRelativeType[type, bType, target]; attr.const ← FALSE; RPush[type, attr]; RETURN}; Length: PROC [node: Tree.Index] = { OPEN tb[node]; type, subType: CSEIndex; attr: Attr; IF ListLength[son[1]] = 1 THEN { son[1] ← Exp[son[1], typeANY]; type ← UnderType[RType[]]; attr ← RAttr[]; RPop[]; subType ← IF seb[type].mark3 THEN NormalType[StripRelative[CanonicalType[type]].type] ELSE typeANY; WITH seb[subType] SELECT FROM array => { IF subType # type THEN son[1] ← ForceType[son[1], subType]; attr.const ← TRUE}; arraydesc => attr.const ← FALSE; ENDCASE => { attr.const ← TRUE; IF type # typeANY THEN Log.ErrorTree[typeClash, son[1]]}} ELSE { attr.const ← TRUE; Log.ErrorN[listLong, ListLength[son[1]]-1]; son[1] ← UpdateList[son[1], VoidExp]}; RPush[dataPtr.typeINTEGER, attr]; RETURN}; Desc: PROC [node: Tree.Index, target: CSEIndex] = { OPEN tb[node]; type, subType: CSEIndex; attr: Attr; saveNP: NPUse; aType, bType: Type ← nullType; cType, iType: Type; fixed: {none, range, both} ← none; packed: BOOL ← FALSE; long: BOOL; subTarget: CSEIndex = StripRelative[target].type; nTarget: CSEIndex = NormalType[subTarget]; IF P3S.safety = checked THEN Log.ErrorNode[unsafeOperation, node]; SELECT ListLength[son[1]] FROM 1 => { rType: Type; nType: CSEIndex; nDerefs: CARDINAL ← 0; son[1] ← Exp[son[1], typeANY]; IF OperandLhs[son[1]] = none THEN Log.ErrorTree[nonAddressable, son[1]]; long ← LongPath[son[1]]; subType ← CanonicalType[RType[]]; attr ← RAttr[]; IF subType # RType[] THEN son[1] ← ForceType[son[1], subType]; RPop[]; nType ← NormalType[subType]; WHILE seb[nType].typeTag = ref AND (nDerefs ← nDerefs+1) < 64 DO long ← seb[subType].typeTag = long; subType ← CanonicalType[ReferentType[nType]]; PushTree[son[1]]; PushNode[uparrow, 1]; SetInfo[subType]; SetAttr[2, long]; SetAttr[3, FALSE]; son[1] ← PopTree[]; nType ← NormalType[subType]; ENDLOOP; PushTree[son[1]]; IF seb[subType].typeTag = record THEN { sei: ISEIndex = SequenceField[LOOPHOLE[subType]]; SELECT TRUE FROM (sei # ISENull) => { subType ← UnderType[seb[sei].idType]; WITH s: seb[subType] SELECT FROM sequence => { PushSe[sei]; PushNode[dollar, 2]; SetInfo[subType]; SetAttr[2, long]}; ENDCASE => ERROR}; (subType = dataPtr.typeStringBody) => NULL; -- fake sequence ENDCASE => {Log.ErrorTree[typeClash, son[1]]; subType ← typeANY}}; WITH t: seb[subType] SELECT FROM array => {rType ← aType ← OperandType[son[1]]; fixed ← both}; sequence => { rType ← cType ← t.componentType; packed ← t.packed; iType ← seb[t.tagSei].idType; fixed ← both; IF ~t.controlled THEN Log.ErrorTree[typeClash, son[1]]}; record => { -- StringBody rType ← cType ← dataPtr.idCHAR; packed ← TRUE; iType ← dataPtr.idCARDINAL; fixed ← both}; ENDCASE => { rType ← cType ← typeANY; IF subType # typeANY THEN Log.ErrorTree[typeClash, son[1]]}; subType ← MakeRefType[rType, typeANY]; IF long THEN subType ← MakeLongType[subType, typeANY]; PushNode[addr, 1]; SetInfo[subType]; SetAttr[2, long]; son[1] ← PopTree[]}; 3 => { subNode: Tree.Index = GetNode[son[1]]; tb[subNode].son[1] ← Exp[tb[subNode].son[1], typeANY]; [subType,bType] ← StripRelative[CanonicalType[RType[]]]; attr ← RAttr[]; RPop[]; saveNP ← phraseNP; SELECT seb[NormalType[subType]].typeTag FROM basic, ref => NULL; ENDCASE => Log.ErrorTree[typeClash, tb[subNode].son[1]]; long ← seb[subType].typeTag = long; tb[subNode].son[2] ← Rhs[tb[subNode].son[2], dataPtr.typeINTEGER]; attr ← And[RAttr[], attr]; RPop[]; phraseNP ← MergeNP[saveNP][phraseNP]; IF tb[subNode].son[3] # Tree.Null THEN { tb[subNode].son[3] ← TypeExp[tb[subNode].son[3]]; cType ← TypeForTree[tb[subNode].son[3]]; fixed ← range}}; ENDCASE; IF aType = nullType THEN { WITH seb[nTarget] SELECT FROM arraydesc => { subType ← UnderType[describedType]; WITH t: seb[subType] SELECT FROM array => IF fixed = none OR (fixed = range AND UnderType[t.componentType] = UnderType[cType]) THEN { aType ← describedType; GO TO old}; ENDCASE}; ENDCASE; GO TO new; EXITS old => NULL; new => { aType ← MakeNonCtxSe[SERecord.cons.array.SIZE]; seb[aType] ← [mark3: TRUE, mark4: TRUE, body: cons[array[ packed: packed, indexType: IF fixed < both THEN dataPtr.idCARDINAL ELSE iType, componentType: IF fixed > none THEN cType ELSE typeANY]]]}}; -- make type description BEGIN WITH t: seb[nTarget] SELECT FROM arraydesc => IF UnderType[t.describedType] = UnderType[aType] THEN GO TO old; ENDCASE => IF fixed = none AND target = typeANY THEN Log.ErrorNode[noTarget, node]; GO TO new; EXITS old => type ← nTarget; new => { type ← MakeNonCtxSe[SERecord.cons.arraydesc.SIZE]; seb[type].typeInfo ← arraydesc[ readOnly:FALSE, var: FALSE, describedType:aType]; seb[type].mark3 ← seb[type].mark4 ← TRUE}; END; IF (attr2 ← long) THEN type ← MakeLongType[type, subTarget]; IF bType # nullType THEN type ← MakeRelativeType[type, bType, target]; attr.const ← FALSE; RPush[type, attr]; RETURN}; }.