-- file Pass4D.mesa -- last modified by Satterthwaite, September 10, 1982 12:09 pm DIRECTORY Alloc: TYPE USING [Notifier], ComData: TYPE USING [definitionsOnly, mainCtx, textIndex, typeCARDINAL], PrincOps: TYPE USING [GFTIndex, globalbase, localbase], Log: TYPE USING [Error, ErrorSei, ErrorTree, Warning], P4: TYPE USING [ Repr, none, signed, unsigned, both, other, Mark, OwnGfi, currentLevel, AdjustBias, BitsForType, CheckFields, ConstantInterval, EmptyInterval, ForceType, Interval, LayoutArgs, LayoutFields, MakeEPLink, NeutralExp, RewriteAssign, Rhs, StructuredLiteral, TreeLiteral, TreeLiteralValue, VPop, VRep], Symbols: TYPE USING [ Base, ExtensionType, SEIndex, ISEIndex, CSEIndex, RecordSEIndex, CTXIndex, CBTIndex, BitAddress, WordLength, SENull, CBTNull, codeANY, codeCHAR, codeINT, lG, lZ, RootBti, typeANY, typeTYPE, seType, ctxType, bodyType], SymbolOps: TYPE USING [ ArgRecord, Cardinality, ConstantId, CtxEntries, EnterExtension, FindExtension, FirstCtxSe, LinkMode, NextSe, NormalType, RCType, SearchContext, TypeLink, UnderType, WordsForType], Tree: TYPE USING [Base, Index, Link, Map, NodeName, Scan, Null, treeType], TreeOps: TYPE USING [ CopyTree, FreeNode, FreeTree, GetNode, IdentityMap, ListHead, ListLength, NthSon, OpName, PopTree, PushList, PushNode, PushTree, ScanList, SetAttr, SetInfo, UpdateList]; Pass4D: PROGRAM IMPORTS Log, P4, SymbolOps, TreeOps, dataPtr: ComData EXPORTS P4 = { OPEN TreeOps, SymbolOps, Symbols; tb: Tree.Base; -- tree base address (local copy) seb: Symbols.Base; -- se table base address (local copy) ctxb: Symbols.Base; -- context table base address (local copy) bb: Symbols.Base; -- body table base address (local copy) DeclNotify: PUBLIC Alloc.Notifier = { -- called by allocator whenever table area is repacked tb ← base[Tree.treeType]; seb ← base[seType]; ctxb ← base[ctxType]; bb ← base[bodyType]}; VarInit: PUBLIC SIGNAL RETURNS [BOOLEAN] = CODE; OwnGfi: PrincOps.GFTIndex = P4.OwnGfi; ItemId: PROC [t: Tree.Link] RETURNS [ISEIndex] = { RETURN [WITH t SELECT FROM symbol => index, subtree => ItemId[tb[index].son[1]], ENDCASE => ERROR]}; FirstId: PROC [node: Tree.Index] RETURNS [ISEIndex] = { RETURN [ItemId[ListHead[tb[node].son[1]]]]}; DeclItem: PUBLIC PROC [item: Tree.Link] = { node: Tree.Index = GetNode[item]; initFlag, eqFlag: BOOLEAN; ExpInit: PROC = INLINE { OPEN tb[node]; type: CSEIndex = UnderType[TypeForDecl[node]]; son[3] ← P4.Rhs[son[3], type]; IF eqFlag THEN { t: Tree.Link ← son[3]; WHILE OpName[t] = cast DO t ← NthSon[t, 1] ENDLOOP; IF P4.TreeLiteral[t] THEN { DefineSEValue[ids:son[1], value:P4.TreeLiteralValue[t]]; GO TO defined}; IF ConstInit[t] THEN { DefineSEValue[ids:son[1]]; AugmentSEValue[son[1], value, son[3]]; son[3] ← Tree.Null; GO TO defined}; IF seb[type].typeTag = transfer THEN WITH t SELECT FROM symbol => { sei: ISEIndex = index; IF seb[sei].constant THEN { DefineSEValue[ids:son[1], value:seb[sei].idValue, info:seb[sei].idInfo]; IF seb[sei].extended THEN AugmentSEValue[son[1], form, FindExtension[sei].tree, TRUE]; GO TO defined}}; ENDCASE; DefineSEVar[ids:son[1]]; EXITS defined => son[3] ← FreeTree[son[3]]}; SELECT seb[NormalType[type]].typeTag FROM ref, arraydesc, relative => IF ListLength[son[1]] # 1 AND son[3] # Tree.Null AND ~P4.StructuredLiteral[son[3]] THEN Log.Warning[pointerInit]; ENDCASE; P4.VPop[]}; BodyInit: PROC = INLINE { expNode: Tree.Index = GetNode[tb[node].son[3]]; bti: CBTIndex = tb[expNode].info; IF eqFlag THEN { IF tb[expNode].attr3 THEN { -- inline DefineSEValue[ids:tb[node].son[1], info:bti]; AugmentSEValue[tb[node].son[1], form, IF dataPtr.definitionsOnly THEN TrimTree[tb[node].son[3]] ELSE Tree.Null]} ELSE DefineSEValue[ ids: tb[node].son[1], value: P4.MakeEPLink[bb[bti].entryIndex, OwnGfi], info: bti]; tb[node].son[3] ← Tree.Null} ELSE {PushNode[body, 0]; SetInfo[bti]; tb[node].son[3] ← PopTree[]}}; saveIndex: CARDINAL = dataPtr.textIndex; IF tb[node].attr3 = P4.Mark THEN RETURN; -- already processed tb[node].attr3 ← P4.Mark; dataPtr.textIndex ← tb[node].info; initFlag ← (tb[node].son[3] # Tree.Null); IF tb[node].name = typedecl THEN { ENABLE VarInit => {RESUME [FALSE]}; TypeExp[tb[node].son[2]]; CheckDefaults[item]} ELSE { OPEN tb[node]; op: Tree.NodeName = OpName[son[3]]; IF son[2] # Tree.Null THEN TypeExp[son[2], op = body]; IF initFlag THEN { eqFlag ← attr1; SELECT op FROM body, procinit => BodyInit[]; signalinit => IF eqFlag THEN { expNode: Tree.Index = GetNode[son[3]]; DefineSEValue[son[1], P4.MakeEPLink[tb[expNode].info, OwnGfi], RootBti]; son[3] ← FreeTree[son[3]]}; inline => { expNode: Tree.Index = GetNode[son[3]]; tb[expNode].son[1] ← UpdateList[tb[expNode].son[1], InlineOp]; DefineSEValue[ids:son[1]]; AugmentSEValue[son[1], value, son[3]]; son[3] ← Tree.Null}; ENDCASE => ExpInit[]}}; MarkAndCheckSE[tb[node].son[1], initFlag]; dataPtr.textIndex ← saveIndex}; TypeForDecl: PROC [node: Tree.Index] RETURNS [SEIndex] = { RETURN [IF tb[node].son[2] # Tree.Null THEN TypeForTree[tb[node].son[2]] ELSE seb[FirstId[node]].idType]}; ConstInit: PROC [t: Tree.Link] RETURNS [BOOLEAN] = { RETURN [IF OpName[t] # all THEN P4.StructuredLiteral[t] ELSE ConstInit[NthSon[t, 1]]]}; InlineOp: Tree.Map = {RETURN [UpdateList[t, P4.NeutralExp]]}; DefineSEVar: PROC [ids: Tree.Link] = { UpdateSE: Tree.Scan = { sei: ISEIndex = ItemId[t]; seb[sei].constant ← FALSE}; ScanList[ids, UpdateSE]}; DefineSEValue: PROC [ids: Tree.Link, value: UNSPECIFIED←0, info: CBTIndex←CBTNull] = { UpdateSE: Tree.Scan = { sei: ISEIndex = ItemId[t]; seb[sei].constant ← TRUE; seb[sei].idValue ← value; seb[sei].idInfo ← info}; ScanList[ids, UpdateSE]}; AugmentSEValue: PROC [ ids: Tree.Link, type: ExtensionType, extension: Tree.Link, copy: BOOLEAN←FALSE] = { UpdateSE: Tree.Scan = { sei: ISEIndex = ItemId[t]; EnterExtension[sei, type, IF copy THEN IdentityMap[extension] ELSE extension]; copy ← TRUE}; ScanList[ids, UpdateSE]}; MarkAndCheckSE: PROC [ids: Tree.Link, initialized: BOOLEAN] = { UpdateSE: Tree.Scan = { sei: ISEIndex = ItemId[t]; seb[sei].mark4 ← TRUE; IF dataPtr.definitionsOnly THEN CheckDefinition[sei, initialized]; IF seb[sei].idType = typeTYPE AND ctxb[seb[sei].idCtx].level # lZ THEN seb[sei].idValue ← sei - FIRST[ISEIndex]}; ScanList[ids, UpdateSE]}; CheckDefinition: PROC [sei: ISEIndex, initialized: BOOLEAN] = { SELECT seb[sei].idCtx FROM dataPtr.mainCtx => SELECT LinkMode[sei] FROM val => IF ~initialized OR seb[sei].extended THEN RETURN; ref => IF ~initialized THEN RETURN; manifest, type => IF ConstantId[sei] THEN RETURN; ENDCASE; ENDCASE => RETURN; Log.ErrorSei[nonDefinition, sei]}; CheckDefaults: PROC [t: Tree.Link] = { TestDefaults: Tree.Scan = { node: Tree.Index = GetNode[t]; saveIndex: CARDINAL = dataPtr.textIndex; sei: ISEIndex = FirstId[node]; dataPtr.textIndex ← tb[node].info; IF seb[sei].extended THEN { type: CSEIndex = UnderType[IF seb[sei].idType = typeTYPE THEN sei ELSE seb[sei].idType]; nType: CSEIndex = NormalType[type]; TestDefault: Tree.Map = { IF OpName[t] = void THEN v ← t ELSE { v ← P4.AdjustBias[P4.Rhs[t, type], -BiasForType[type]]; IF P4.TreeLiteral[v] AND ( WITH n: seb[nType] SELECT FROM basic => n.code # codeINT OR P4.VRep[] = P4.signed, ENDCASE => TRUE) THEN v ← P4.ForceType[v, type]; P4.VPop[]; IF ~(ConstDefault[v] OR (SIGNAL VarInit[])) THEN Log.ErrorTree[nonConstant, v]}; RETURN}; t: Tree.Link ← FindExtension[sei].tree; v: Tree.Link ← UpdateList[IdentityMap[t], TestDefault]; IF t.tag # symbol AND P4.StructuredLiteral[v] THEN UpdateDefaults[tb[node].son[1], v] ELSE v ← FreeTree[v]}; dataPtr.textIndex ← saveIndex}; IF dataPtr.definitionsOnly THEN ScanList[t, TestDefaults]}; UpdateDefaults: PROC [ids: Tree.Link, v: Tree.Link] = { copy: BOOLEAN ← FALSE; UpdateDefault: Tree.Scan = { sei: ISEIndex = ItemId[t]; old: Tree.Link ← FindExtension[sei].tree; EnterExtension[sei, default, IF copy THEN IdentityMap[v] ELSE v]; copy ← TRUE; [] ← FreeTree[old]}; ScanList[ids, UpdateDefault]}; ConstDefault: PROC [t: Tree.Link] RETURNS [const: BOOLEAN] = { TestItem: Tree.Scan = {IF t # Tree.Null AND ~ConstDefault[t] THEN const ← FALSE}; SELECT OpName[t] FROM construct, rowcons, union => { const ← TRUE; ScanList[NthSon[t, 2], TestItem]}; ENDCASE => const ← ConstInit[t]; RETURN}; TrimTree: Tree.Map = { WITH t SELECT FROM subtree => { node: Tree.Index = index; SELECT tb[node].name FROM body => { OPEN tb[node]; PushTree[TrimTree[son[1]]]; PushTrimDecls[son[2]]; PushTree[TrimTree[son[3]]]; PushTree[TrimTree[son[4]]]; PushNode[body, 4]; SetInfo[info]; SetAttr[1, attr1]; SetAttr[2, attr2]; SetAttr[3, attr3]; v ← PopTree[]}; block => { OPEN tb[node]; PushTrimDecls[son[1]]; PushTree[TrimTree[son[2]]]; PushNode[block, 2]; SetInfo[info]; SetAttr[1, attr1]; SetAttr[2, attr2]; SetAttr[3, attr3]; v ← PopTree[]}; cdot => v ← TrimTree[tb[node].son[2]]; ENDCASE => v ← CopyTree[[@tb, t], TrimTree]}; ENDCASE => v ← t; RETURN}; PushTrimDecls: PROC [t: Tree.Link] = { IF OpName[t] = initlist THEN { node: Tree.Index = GetNode[t]; PushTree[TrimTree[tb[node].son[1]]]; PushTrimDecls[tb[node].son[2]]; PushNode[initlist, 2]; SetInfo[tb[node].info]} ELSE { n: CARDINAL ← 0; PushDecl: Tree.Scan = { node: Tree.Index = GetNode[t]; SELECT tb[node].name FROM typedecl => NULL; decl => IF tb[node].son[3] # Tree.Null THEN { OPEN tb[node]; PushTree[TrimTree[son[1]]]; PushTree[Tree.Null]; PushTree[TrimTree[son[3]]]; PushNode[decl, 3]; SetInfo[info]; SetAttr[1, attr1]; SetAttr[2, attr2]; SetAttr[3, ~P4.Mark]; n ← n+1}; ENDCASE => ERROR}; ScanList[t, PushDecl]; PushList[n]}}; DeclUpdate: PUBLIC PROC [item: Tree.Link] RETURNS [update: Tree.Link] = { node: Tree.Index = GetNode[item]; IF tb[node].name = typedecl OR tb[node].son[3] = Tree.Null THEN update ← Tree.Null ELSE { OPEN tb[node]; type: CSEIndex = UnderType[TypeForDecl[node]]; rewrite: BOOLEAN = SELECT OpName[tb[node].son[3]] FROM body, signalinit => FALSE, ENDCASE => TRUE; n: CARDINAL = ListLength[tb[node].son[1]]; ScanList[tb[node].son[1], PushTree]; PushTree[tb[node].son[3]]; FOR i: CARDINAL IN [1 .. n] DO IF i = n THEN PushNode[assign, 2] ELSE {PushNode[assignx, 2]; SetInfo[type]}; SetInitAttr[type, ConstInit[tb[node].son[3]]]; IF rewrite THEN PushTree[P4.RewriteAssign[GetNode[PopTree[]], type]]; ENDLOOP; SetInfo[info]; update ← PopTree[]; tb[node].son[3] ← Tree.Null}; FreeNode[node]; RETURN}; SetInitAttr: PROC [type: CSEIndex, const: BOOLEAN] = { SetAttr[1, TRUE]; IF P4.currentLevel = lG AND ~const THEN SELECT RCType[type] FROM simple => {SetAttr[2, TRUE]; SetAttr[3, FALSE]}; composite => {SetAttr[2, TRUE]; SetAttr[3, TRUE]}; ENDCASE => SetAttr[2, FALSE] ELSE SetAttr[2, FALSE]}; TypeExp: PUBLIC PROC [typeExp: Tree.Link, body, indirect: BOOLEAN ← FALSE] = { -- body => arg records subsumed by frame WITH typeExp SELECT FROM symbol => IF ~indirect THEN { iSei: ISEIndex = index; IF ~seb[iSei].mark4 THEN DeclItem[[subtree[index: seb[iSei].idValue]]]}; subtree => { node: Tree.Index = index; SELECT tb[node].name FROM discrimTC => TypeExp[tb[node].son[1], FALSE, indirect]; cdot => TypeExp[tb[node].son[2], body, indirect]; implicitTC, linkTC => NULL; frameTC => NULL; ENDCASE => { OPEN tb[node]; sei: CSEIndex = info; IF ~seb[sei].mark4 THEN WITH type: seb[sei] SELECT FROM enumerated => IF type.machineDep THEN [nValues:type.nValues, sparse:type.sparse] ← LayoutEnum[son[1], type.valueCtx]; record => { ENABLE VarInit => {RESUME [FALSE]}; ScanList[son[1], DeclItem]; IF attr1 THEN ScanList[son[1], AssignPositions]; WITH type SELECT FROM notLinked => IF attr1 THEN P4.CheckFields[LOOPHOLE[sei, RecordSEIndex], 0] ELSE P4.LayoutFields[LOOPHOLE[sei, RecordSEIndex], 0]; ENDCASE; ExtractFieldAttributes[LOOPHOLE[sei, RecordSEIndex]]; CheckDefaults[son[1]]}; ref => { IF type.var AND FALSE THEN Log.Error[unimplemented]; TypeExp[son[1], FALSE, TRUE]}; array => { IF son[1] # Tree.Null THEN TypeExp[son[1]]; TypeExp[son[2], FALSE, indirect]}; arraydesc => TypeExp[son[1], FALSE, TRUE]; transfer => { origin, newOrigin: CARDINAL; rSei: RecordSEIndex; origin ← SELECT type.mode FROM program => PrincOps.globalbase, signal, error => PrincOps.localbase+1, proc => PrincOps.localbase, ENDCASE => 0; IF OpName[son[1]] # anyTC THEN { ScanList[son[1], DeclItem]; CheckDefaults[son[1]]}; rSei ← ArgRecord[type.typeIn]; IF rSei # SENull THEN { seb[rSei].hints.comparable ← TRUE; -- for now newOrigin ← P4.LayoutArgs[rSei, origin, body]; seb[rSei].length ← (newOrigin - origin)*WordLength; seb[rSei].mark4 ← TRUE; origin ← newOrigin}; IF OpName[son[2]] # anyTC THEN { ScanList[son[2], DeclItem]; CheckDefaults[son[2]]}; rSei ← ArgRecord[type.typeOut]; IF rSei # SENull THEN { seb[rSei].hints.comparable ← TRUE; -- for now seb[rSei].length ← (P4.LayoutArgs[rSei, origin, body]-origin)*WordLength; seb[rSei].mark4 ← TRUE}}; definition => NULL; union => { DeclItem[son[1]]; IF attr1 AND type.controlled THEN AssignPositions[son[1]]; ProcessVariants[UnderType[seb[type.tagSei].idType], son[2]]}; sequence => { DeclItem[son[1]]; IF attr1 AND type.controlled THEN AssignPositions[son[1]]; TypeExp[son[2], FALSE, indirect]}; relative => {TypeExp[son[1], FALSE, TRUE]; TypeExp[son[2], FALSE, TRUE]}; opaque => IF son[1] # Tree.Null THEN { son[1] ← P4.Rhs[son[1], dataPtr.typeCARDINAL]; P4.VPop[]; IF P4.TreeLiteral[son[1]] THEN type.length ← P4.TreeLiteralValue[son[1]]*WordLength}; zone => NULL; subrange => { subNode: Tree.Index; tSei: CSEIndex = UnderType[type.rangeType]; TypeExp[son[1], FALSE, indirect]; subNode ← GetNode[son[2]]; IF P4.Interval[subNode, 0, P4.both] THEN [type.origin, type.range] ← P4.ConstantInterval[subNode ! P4.EmptyInterval => {type.empty ← TRUE; RESUME}] ELSE type.origin ← type.range ← 0; type.filled ← TRUE; SELECT P4.VRep[] FROM P4.none => Log.ErrorTree[mixedRepresentation, son[2]]; P4.unsigned => IF type.origin < 0 THEN Log.Error[subrangeNesting]; ENDCASE; P4.VPop[]; WITH cover: seb[tSei] SELECT FROM subrange => -- incomplete test IF type.origin < cover.origin OR (~type.empty AND type.range > cover.range) THEN Log.Error[subrangeNesting]; ENDCASE => NULL; son[2] ← FreeTree[son[2]]}; long => TypeExp[son[1], FALSE, indirect]; any => NULL; ENDCASE => ERROR; seb[sei].mark4 ← TRUE}}; ENDCASE => ERROR}; -- machine dependent representations EvalUnsigned: PROC [t: Tree.Link, default: CARDINAL] RETURNS [v: Tree.Link, n: CARDINAL] = { v ← P4.Rhs[t, dataPtr.typeCARDINAL]; P4.VPop[]; n ← IF P4.TreeLiteral[v] THEN P4.TreeLiteralValue[v] ELSE default; RETURN}; LayoutEnum: PROC [t: Tree.Link, ctx: CTXIndex] RETURNS [sparse: BOOLEAN, nValues: CARDINAL] = { sei: ISEIndex; started: BOOLEAN; last: CARDINAL; AssignElement: Tree.Scan = { val: CARDINAL; WITH t SELECT FROM subtree => { node: Tree.Index = index; [tb[node].son[2], val] ← EvalUnsigned[tb[node].son[2], IF started THEN last+1 ELSE 0]}; ENDCASE => val ← IF started THEN last+1 ELSE 0; IF ~started THEN {sparse ← (val#0); started ← TRUE} ELSE { IF val <= last THEN Log.ErrorSei[enumOrder, sei]; IF val # last+1 THEN sparse ← TRUE}; last ← seb[sei].idValue ← val; sei ← NextSe[sei]}; started ← sparse ← FALSE; sei ← FirstCtxSe[ctx]; ScanList[t, AssignElement]; nValues ← IF ~started THEN 0 ELSE last+1; RETURN}; AssignPositions: PROC [item: Tree.Link] = { node: Tree.Index = GetNode[item]; saveIndex: CARDINAL = dataPtr.textIndex; type: SEIndex = TypeForTree[tb[node].son[2]]; nB, nW: CARDINAL; AssignPosition: Tree.Scan = { wd, bL, bR: CARDINAL; dB: CARDINAL = IF nB=0 THEN 0 ELSE nB-1; sei: ISEIndex = ItemId[t]; node: Tree.Index = GetNode[NthSon[t, 2]]; [tb[node].son[1], wd] ← EvalUnsigned[tb[node].son[1], 0]; IF tb[node].son[2] = Tree.Null THEN { bL ← 0; bR ← IF nB = 0 THEN 0 ELSE nW*WordLength - 1} ELSE { subNode: Tree.Index = GetNode[tb[node].son[2]]; [tb[subNode].son[1], bL] ← EvalUnsigned[tb[subNode].son[1], 0]; [tb[subNode].son[2], bR] ← EvalUnsigned[tb[subNode].son[2], dB]}; wd ← wd + bL/WordLength; IF bR >= bL THEN bR ← bR - (bL/WordLength)*WordLength; bL ← bL MOD WordLength; IF (SELECT TRUE FROM (nB = 0) => bR < bL, (nB >= WordLength) => bL # 0 OR bR # bL + dB, ENDCASE => bR > WordLength OR bR < bL + dB) THEN { Log.ErrorSei[fieldPosition, sei]; bR ← bL + dB}; seb[sei].idValue ← BitAddress[wd:wd, bd:bL]; seb[sei].idInfo ← IF nB=0 AND tb[node].son[2] = Tree.Null THEN 0 ELSE bR-bL + 1}; dataPtr.textIndex ← tb[node].info; nB ← P4.BitsForType[type]; nW ← (nB+(WordLength-1))/WordLength; ScanList[tb[node].son[1], AssignPosition]; dataPtr.textIndex ← saveIndex}; ExtractFieldAttributes: PROC [rType: RecordSEIndex] = { -- compatibility version type: CSEIndex; comparable, privateFields: BOOLEAN; comparable ← TRUE; privateFields ← FALSE; FOR sei: ISEIndex ← FirstCtxSe[seb[rType].fieldCtx], NextSe[sei] UNTIL sei = SENull DO IF ~seb[sei].public THEN privateFields ← TRUE; type ← UnderType[seb[sei].idType]; WITH t: seb[type] SELECT FROM record => IF ~t.hints.comparable AND ~ComparableType[type] THEN comparable ← FALSE; array => IF ~ComparableType[type] THEN comparable ← FALSE; union => IF ~t.hints.equalLengths THEN comparable ← FALSE; sequence => comparable ← FALSE; ENDCASE; ENDLOOP; seb[rType].hints.comparable ← comparable; seb[rType].hints.privateFields ← privateFields}; ProcessVariants: PROC [tagType: CSEIndex, list: Tree.Link] = { lb, ub: CARDINAL; MapTag: PROC [vSei: ISEIndex] RETURNS [CARDINAL] = { WITH t: seb[tagType] SELECT FROM enumerated => IF t.machineDep THEN { sei: ISEIndex = SearchContext[seb[vSei].hash, t.valueCtx]; IF sei # SENull THEN RETURN [seb[sei].idValue]}; ENDCASE; RETURN [seb[vSei].idValue]}; CheckTag: Tree.Scan = { sei: ISEIndex = ItemId[t]; tag: CARDINAL = MapTag[sei]; IF tag NOT IN [lb .. ub) THEN Log.ErrorSei[boundsFault, sei]; seb[sei].idValue ← tag - lb}; ProcessVariant: Tree.Scan = { saveIndex: CARDINAL = dataPtr.textIndex; node: Tree.Index = GetNode[t]; dataPtr.textIndex ← tb[node].info; ScanList[tb[node].son[1], CheckTag]; DeclItem[t]; dataPtr.textIndex ← saveIndex}; lb ← BiasForType[tagType]; ub ← lb + Cardinality[tagType]; ScanList[list, ProcessVariant]}; TypeForTree: PUBLIC PROC [t: Tree.Link] RETURNS [SEIndex] = { RETURN [WITH t SELECT FROM symbol => index, subtree => tb[index].info, ENDCASE => typeANY]}; CanonicalType: PUBLIC PROC [type: CSEIndex] RETURNS [CSEIndex] = { RETURN [WITH t: seb[type] SELECT FROM subrange => CanonicalType[UnderType[t.rangeType]], record => IF t.hints.unifield AND CtxEntries[t.fieldCtx] = 1 THEN CanonicalType[UnderType[seb[ctxb[t.fieldCtx].seList].idType]] ELSE type, ENDCASE => type]}; BiasForType: PUBLIC PROC [type: CSEIndex] RETURNS [INTEGER] = { RETURN [IF type = SENull THEN 0 ELSE WITH t: seb[type] SELECT FROM subrange => t.origin, record => IF t.hints.unifield AND CtxEntries[t.fieldCtx] = 1 THEN BiasForType[UnderType[seb[ctxb[t.fieldCtx].seList].idType]] ELSE 0, ENDCASE => 0]}; RepForType: PUBLIC PROC [type: CSEIndex] RETURNS [P4.Repr] = { RETURN [IF type = SENull THEN P4.none ELSE WITH t: seb[type] SELECT FROM basic => SELECT t.code FROM codeANY => P4.both + P4.other, codeINT => P4.signed, codeCHAR => P4.both, ENDCASE => P4.other, enumerated => P4.both, ref => P4.unsigned, record => IF t.hints.unifield AND CtxEntries[t.fieldCtx] = 1 THEN RepForType[UnderType[seb[ctxb[t.fieldCtx].seList].idType]] ELSE P4.other, relative => RepForType[UnderType[t.offsetType]], subrange => IF t.origin >= 0 THEN (IF CARDINAL[t.origin] + t.range > 77777b THEN P4.unsigned ELSE P4.both) ELSE (IF t.range <= 77777b THEN P4.signed ELSE P4.none), long => RepForType[UnderType[t.rangeType]], opaque => IF t.lengthKnown THEN P4.both + P4.other ELSE P4.none, ENDCASE => P4.other]}; SparseRep: PUBLIC PROC [type: CSEIndex] RETURNS [BOOLEAN] = { nType: CSEIndex = NormalType[type]; RETURN [WITH seb[nType] SELECT FROM enumerated => sparse, ENDCASE => FALSE]}; WordsForType: PUBLIC PROC [type: CSEIndex] RETURNS [CARDINAL] = { RETURN [IF ~seb[type].mark4 THEN (P4.BitsForType[type]+(WordLength-1))/WordLength ELSE SymbolOps.WordsForType[type]]}; ComparableType: PUBLIC PROC [type: CSEIndex] RETURNS [BOOLEAN] = { -- compatibility version RETURN [WITH t: seb[type] SELECT FROM record => t.hints.comparable OR t.argument, -- for now array => ~SparseRep[UnderType[t.indexType]] AND ComparableType[UnderType[t.componentType]], opaque => t.lengthKnown, any => FALSE, ENDCASE => TRUE]}; DefaultBasicOps: PUBLIC PROC [type: SEIndex, size: CARDINAL] RETURNS [BOOLEAN] = { uType: CSEIndex = UnderType[type]; next: SEIndex; FOR s: SEIndex ← type, next DO WITH se: seb[s] SELECT FROM id => { sei: ISEIndex = LOOPHOLE[s]; IF seb[sei].extended THEN { IF OpName[FindExtension[sei].tree] # void THEN RETURN [FALSE] ELSE EXIT}; next ← seb[sei].idInfo}; cons => WITH t: se SELECT FROM ref => IF t.counted THEN RETURN [FALSE] ELSE EXIT; array => next ← t.componentType; record => IF t.hints.default THEN RETURN [FALSE] ELSE EXIT; transfer => IF t.mode = port THEN RETURN [FALSE] ELSE EXIT; long => next ← t.rangeType; zone => IF t.counted THEN RETURN [FALSE] ELSE EXIT; ENDCASE => EXIT; ENDCASE; ENDLOOP; RETURN [WordsForType[uType]*WordLength = size AND ComparableType[uType] AND TypeLink[uType] = SENull]}; }.