DIRECTORY
Alloc: TYPE USING [Notifier],
Basics: TYPE USING [bitsPerChar, BITOR, BITSHIFT],
Code: TYPE USING [CodeNotImplemented, curctxlvl],
CodeDefs:
TYPE
USING [
Base, BoVarIndex, BYTE, codeType, ConsDestination, LabelCCIndex, Lexeme,
MaxParmsInStack, NullLex, StackLocRec, StoreOptions, TempStateRecord,
VarComponent, VarIndex, VarNull, wordlength],
ComData: TYPE USING [tC0],
Counting: TYPE USING [Allocate, FillCounted, LoadSystemZone, VarVarAssignCounted],
FOpCodes:
TYPE
USING [
qADD, qAF, qBLT, qBLTL, qBLZL, qDSUB, qDUP, qGA, qIOR, qLA,
qLCO, qLI, qLP, qMUL, qREC, qREC2, qSHIFT, qSUB, qWS,
qWSCDL, qWSCIDL, qWSD, qWSDL, qWSF, qWSL, qWSLF],
LiteralOps: TYPE USING [MasterString, StringIndex],
Literals: TYPE USING [Base, MSTIndex, stType],
P5:
TYPE
USING [
ConstructOnStack, Exp, GenTempLex, MoveToCodeWord, MultiZero, P5Error,
PushRhs, PopTempState, PushTempState, SAssign, StoreMod, SysCall,
WriteCodeWord, ZoneOp],
P5L:
TYPE
USING [
AdjustComponent, ComponentForLex, ComponentForSE, CopyToTemp,
CopyVarItem, EasilyLoadable, FieldOfComponent, GenAdd, GenVarItem,
LoadAddress, LoadComponent, LoadVar, MakeBo, ModComponent,
OVarItem, ReleaseVarItem,ReusableCopies, TOSAddrLex, TOSLex,
VarForLex, VarVarAssign, Words],
P5U:
TYPE
USING [
ComputeFrameSize, InsertLabel, LabelAlloc, MakeTreeLiteral, NextVar, NilTree,
OperandType, Out0, Out1, Out2, OutJump, PushLitVal, RecordConstant,
TreeLiteral, TreeLiteralValue, TypeForTree, WordAligned, WordsForOperand],
PrincOps: TYPE USING [AVHeapSize, FieldDescriptor, LocalOverhead, sStringInit],
Stack:
TYPE
USING [
Also, ComponentForBackup, Decr, Dump, Forget, Incr, Loc, Mark, Pop,
TempStore, Top],
Symbols:
TYPE
USING [
Base, ArraySEIndex, BitAddress, BitCount, ContextLevel, CSEIndex, CTXIndex,
ISEIndex, ISENull,
lG, lZ, RecordSEIndex, RefClass, SEIndex, seType, typeANY],
SymbolOps:
TYPE
USING [
BitsPerElement, Cardinality, FirstCtxSe, FnField, NextSe, RCType, RecField,
RecordRoot, ReferentType, UnderType, VariantField, WordsForType],
Tree: TYPE USING [Base, Index, Link, Map, NodeName, Null, Scan, treeType],
TreeOps:
TYPE
USING [
FreeNode, FreeTree, GetNode, GetSe, ListLength, MakeList, NthSon, OpName,
PushTree, ReverseUpdateList, ScanList, UpdateList];
MainConstruct:
PROC [
maint: Tree.Link,
rSei: CSEIndex,
fa: PROC [ISEIndex] RETURNS [BitAddress, CARDINAL],
atO: OffsetRef,
fieldSei: ISEIndex ← ISENull] =
BEGIN -- workhorse subroutine for construction in memory
tOffset: VarComponent.frame = atO^;
totalBits: CARDINAL = tOffset.wSize*wordlength + tOffset.bSize;
rcSei: RecordSEIndex;
AssignField:
PROC [root: Tree.Link] =
BEGIN
offset: VarComponent.frame;
rep: BitAddress;
res: CARDINAL;
fieldType: CSEIndex = UnderType[seb[fieldSei].idType];
IF root # Tree.Null
THEN
BEGIN
[rep, res] ← fa[fieldSei];
offset ← tOffset;
P5L.FieldOfComponent[var: @offset, wd: rep.wd, bd: rep.bd,
wSize: res/wordlength, bSize: res MOD wordlength];
IF fa # FnField
AND totalBits <= wordlength
THEN
P5L.AdjustComponent[
var: @offset, rSei: rcSei, fSei: fieldSei, tBits: totalBits];
DO
-- until we get to something interesting
SELECT TreeOps.OpName[root]
FROM
pad =>
BEGIN
root ← TreeOps.NthSon[root, 1];
offset.wSize ← P5U.WordsForOperand[root]; offset.bSize ← 0;
END;
cast => root ← TreeOps.NthSon[root, 1];
ENDCASE => EXIT;
ENDLOOP;
SELECT TreeOps.OpName[root]
FROM
construct =>
MainConstruct[TreeOps.NthSon[root, 2], P5U.OperandType[root], RecField, @offset];
union => UnionConstruct[TreeOps.GetNode[root], rcSei, atO];
rowcons => Row[TreeOps.GetNode[root], @offset];
all => [] ← AllConstruct[TreeOps.GetNode[root], @offset];
mwconst => ConstantFill[fieldType, @offset, root];
ENDCASE => {ConstructCountDown[]; ConsAssign[fieldType, @offset, root]};
END; -- IF root # Tree.Null
fieldSei ← P5U.NextVar[NextSe[fieldSei]];
END; -- of AssignField
IF fieldSei = ISENull
THEN
WITH seb[rSei]
SELECT
FROM
record =>
BEGIN
rcSei ← RecordRoot[LOOPHOLE[rSei]];
fieldSei ← P5U.NextVar[FirstCtxSe[seb[rcSei].fieldCtx]];
END;
ENDCASE => P5.P5Error[589]
ELSE rcSei ← LOOPHOLE[rSei];
TreeOps.ScanList[maint, AssignField];
END; -- of MainConstruct
Row:
PROC [node: Tree.Index, atO: OffsetRef] =
BEGIN -- handles ARRAY construction
aSei: ArraySEIndex = LOOPHOLE[UnderType[tb[node].info]];
IF seb[aSei].typeTag # array THEN P5.P5Error[580];
IF tb[node].attr1
THEN
BEGIN -- row of string literals
c: CARDINAL = P5.MoveToCodeWord[];
n: CARDINAL ← 0;
localText, globalText: BOOL ← FALSE;
TextItem:
PROC [t: Tree.Link] =
BEGIN
msti: Literals.MSTIndex = LiteralOps.MasterString[
LiteralOps.StringIndex[NARROW[t, Tree.Link.literal].index]];
IF stb[msti].local THEN localText ← TRUE ELSE globalText ← TRUE;
P5.WriteCodeWord[stb[msti].info];
n ← n+1;
END;
IF cd.pLoaded THEN {SavePointer[]; PopPointer[]};
TreeOps.ScanList[tb[node].son[2], TextItem];
ConstructCountDown[];
Stack.Dump[]; Stack.Mark[];
P5U.Out1[FOpCodes.qLCO, c]; P5U.PushLitVal[n];
P5U.RecordConstant[c, n];
IF localText
AND globalText
OR cd.remaining # 0
AND ~cd.inFrame
THEN
SIGNAL CPtr.CodeNotImplemented;
P5U.Out1[IF localText THEN FOpCodes.qLA ELSE FOpCodes.qGA, 0];
LoadPointerCopy[atO, 0];
IF cd.pLength # 1
THEN
-- does a long pointer to array of short strings
SIGNAL CPtr.CodeNotImplemented; -- make any sense?
P5.SysCall[PrincOps.sStringInit];
END
ELSE
BEGIN -- not all string literals
offset: VarComponent.frame ← atO^;
eWSize: CARDINAL;
eBSize: [0..wordlength);
cSei: CSEIndex = UnderType[seb[aSei].componentType];
AssignElement:
PROC [t: Tree.Link] =
BEGIN
DO
-- until we get to something interesting
SELECT TreeOps.OpName[t]
FROM
pad =>
BEGIN
t ← TreeOps.NthSon[t, 1];
offset.wSize ← P5U.WordsForOperand[t]; offset.bSize ← 0;
END;
cast => t ← TreeOps.NthSon[t, 1];
ENDCASE => EXIT;
ENDLOOP;
SELECT TreeOps.OpName[t]
FROM
rowcons => Row[TreeOps.GetNode[t], @offset];
construct =>
MainConstruct[TreeOps.NthSon[t, 2], P5U.OperandType[t], RecField, @offset];
all =>
-- convert this later
[] ← AllConstruct[TreeOps.GetNode[t], @offset];
mwconst => ConstantFill[cSei, @offset, t];
ENDCASE =>
IF t # Tree.Null THEN {ConstructCountDown[]; ConsAssign[cSei, @offset, t]};
P5L.ModComponent[var: @offset, wd: eWSize, bd: offset.bSize];
offset.wSize ← eWSize; offset.bSize ← eBSize;
END; -- of AssignElement
totalBits: BitCount = atO.wSize.LONG*wordlength + atO.bSize;
grain: BitCount = BitsPerElement[seb[aSei].componentType, seb[aSei].packed];
packed: BOOL;
fillBits: CARDINAL;
IF grain >= wordlength
THEN
BEGIN
packed ← FALSE; fillBits ← 0;
eBSize ← 0; eWSize ← WordsForType[seb[aSei].componentType];
END
ELSE
BEGIN
packed ← TRUE;
fillBits ← totalBits - Cardinality[UnderType[seb[aSei].indexType]]*grain;
IF fillBits # 0
AND totalBits > wordlength
THEN
cd.remaining ← cd.remaining+1;
eWSize ← 0; eBSize ← grain;
END;
IF fillBits # 0
AND totalBits <= wordlength
THEN
BEGIN
bs: CARDINAL = eBSize + fillBits;
offset.wSize ← bs / wordlength;
offset.bSize ← bs MOD wordlength;
fillBits ← 0;
END
ELSE {offset.wSize ← eWSize; offset.bSize ← eBSize};
TreeOps.ScanList[tb[node].son[2], AssignElement];
IF fillBits # 0
THEN
BEGIN
offset.wSize ← 0; offset.bSize ← fillBits;
ConstructCountDown[]; ConsAssign[typeANY, @offset, MPtr.tC0];
END;
END;
END;
UnionConstruct:
PROC [node: Tree.Index, rootSei: RecordSEIndex, atO: OffsetRef] =
BEGIN -- construct a union part, atO^ is offset of beginning of record
tOffset: VarComponent.frame = atO^;
offset: VarComponent.frame ← atO^;
fieldSei: ISEIndex;
vCtx: Symbols.CTXIndex;
uSei: CSEIndex = UnderType[tb[node].info];
rcSei: RecordSEIndex;
tSei: ISEIndex;
tagged: BOOL;
tagValue: CARDINAL;
tBits: CARDINAL = tOffset.wSize*wordlength + tOffset.bSize;
WITH u: seb[uSei]
SELECT
FROM
union =>
BEGIN
tagged ← u.controlled;
IF tagged
THEN
BEGIN
tagAddr: BitAddress = seb[u.tagSei].idValue;
tagSize: [0..wordlength] = seb[u.tagSei].idInfo;
P5L.FieldOfComponent[
var: @offset, wd: tagAddr.wd, bd: tagAddr.bd,
wSize: tagSize/wordlength, bSize: tagSize MOD wordlength];
IF tBits <= wordlength
THEN
P5L.AdjustComponent[var: @offset, rSei: rootSei, fSei: u.tagSei, tBits: tBits];
END;
END;
ENDCASE => ERROR;
tSei ← TreeOps.GetSe[tb[node].son[1]];
tagValue ← seb[tSei].idValue;
rcSei ← LOOPHOLE[UnderType[tSei], RecordSEIndex];
vCtx ← seb[rcSei].fieldCtx;
fieldSei ← P5U.NextVar[FirstCtxSe[vCtx]];
IF tagged
THEN
BEGIN
IF fieldSei # ISENull
AND seb[fieldSei].idCtx # vCtx
THEN
BEGIN -- a dummy fill field
fillSize: [0..wordlength) = seb[fieldSei].idInfo;
b: CARDINAL = offset.bSize + fillSize;
tagValue ← Basics.BITSHIFT[tagValue, fillSize];
offset.bSize ← b MOD wordlength; offset.wSize ← b/wordlength;
fieldSei ← P5U.NextVar[NextSe[fieldSei]];
END;
ConstructCountDown[];
ConsAssign[typeANY, @offset, P5U.MakeTreeLiteral[tagValue]];
END
ELSE
IF fieldSei # ISENull
AND seb[fieldSei].idCtx # vCtx
THEN
BEGIN -- no tag, but a fill field anyway
fillSize: [0..wordlength) = seb[fieldSei].idInfo;
fillAddr: BitAddress = seb[fieldSei].idValue; -- can't be full word
P5L.FieldOfComponent[
var: @offset, wd: fillAddr.wd, bd: fillAddr.bd, bSize: fillSize];
IF tBits <= wordlength
THEN
P5L.AdjustComponent[var: @offset, rSei: rootSei, fSei: fieldSei, tBits: tBits];
ConsAssign[typeANY, @offset, MPtr.tC0];
fieldSei ← P5U.NextVar[NextSe[fieldSei]];
END;
IF fieldSei # ISENull
THEN
MainConstruct[tb[node].son[2], rootSei, RecField, atO, fieldSei];
END;
ListCons:
PUBLIC
PROC[node: Tree.Index]
RETURNS[Lexeme] = {
pSei: CSEIndex = UnderType[tb[node].info];
rSei: CSEIndex = UnderType[ReferentType[pSei]];
long: BOOL = tb[node].attr2;
counted: BOOL = tb[node].attr3;
pLength: CARDINAL = WordsForType[pSei];
zoneTree: Tree.Link;
zoneVar: Lexeme.se;
nwords: CARDINAL = WordsForType[rSei];
k: CARDINAL ← TreeOps.ListLength[tb[node].son[2]];
destVar: Lexeme.se ← P5.GenTempLex[pLength];
restVar: Lexeme.se ← (IF k > 1 THEN P5.GenTempLex[pLength] ELSE NullLex);
rest: Tree.Link ← P5U.NilTree[pSei];
PushSize: PROC = {P5U.PushLitVal[nwords]};
ConsItem: Tree.Map = {
r: VarIndex;
saveCd: ConsDestination = cd;
saveTempList: TempStateRecord = P5.PushTempState[];
list: Tree.Link;
listNode: Tree.Index;
offset: VarComponent.frame;
cd ← [options: [init: TRUE, counted: counted], ignoreSafen: FALSE]; -- + many defaults
TreeOps.PushTree[t]; TreeOps.PushTree[rest];
list ← TreeOps.UpdateList[TreeOps.MakeList[2], CountDups];
listNode ← NARROW[list, Tree.Link.subtree].index;
IF counted
THEN
Counting.Allocate[zone: zoneTree, type: rSei, catch: Tree.Null, pushSize: NIL]
ELSE {
P5.ZoneOp[zone: zoneTree, index: 0, pushArg: PushSize, catch: Tree.Null, long: long];
Stack.Incr[pLength]};
P5.SAssign[destVar.lexsei];
offset ← [wSize: nwords, space: frame[wd: 0]];
r ← P5L.GenVarItem[bo];
cb[r] ← [body: bo[base: P5L.ComponentForLex[destVar], offset: offset]];
[] ← SetConsDest[r, FALSE];
MainConstruct[list, rSei, RecField, @offset];
IF (k ← k-1) # 0
THEN {
sTemp: Lexeme.se = destVar;
rest ← [symbol[destVar.lexsei]];
destVar ← restVar; restVar ← sTemp};
v ← tb[listNode].son[1];
tb[listNode].son[1] ← Tree.Null; [] ← TreeOps.FreeTree[list];
cd ← saveCd; P5.PopTempState[saveTempList]};
Stack.Dump[];
IF tb[node].son[1] = Tree.Null
THEN {
zoneVar ← P5.GenTempLex[pLength];
Counting.LoadSystemZone[]; P5.SAssign[zoneVar.lexsei];
zoneTree ← [symbol[zoneVar.lexsei]]}
ELSE zoneTree ← tb[node].son[1];
tb[node].son[2] ← TreeOps.ReverseUpdateList[tb[node].son[2], ConsItem];
RETURN [destVar]};
RowCons:
PUBLIC
PROC [t: Tree.Link, node: Tree.Index, options: StoreOptions]
RETURNS [Lexeme] =
BEGIN -- array (expression) construction
r, rr: VarIndex;
aSei: ArraySEIndex = LOOPHOLE[UnderType[tb[node].info]];
aWords: CARDINAL = WordsForType[aSei];
saveCd: ConsDestination = cd;
offset: VarComponent.frame;
cd ← [options: options, ignoreSafen: t = Tree.Null OR t.tag = symbol]; -- + many defaults
IF tb[node].attr1 THEN cd.remaining ← 1
ELSE tb[node].son[2] ← TreeOps.UpdateList[tb[node].son[2], CountDups];
r ← P5L.VarForLex[
IF t = Tree.Null
THEN P5.GenTempLex[aWords]
ELSE P5.Exp[t]];
rr ← SetConsDest[r, options.expr];
offset ← [wSize: cd.wSize, bSize: cd.bSize, space: frame[]];
Row[node, @offset];
IF cd.remaining # 0 THEN SIGNAL ConstructionError;
cd ← saveCd;
RETURN [[bdo[rr]]]
END;