DIRECTORY
CCTypes USING[CCError, CCErrorCase, CreateIndirectNode, GetAnyTargetType, GetBitSize, GetIndirectCreateNode, GetIndirectType, GetRTargetType, GetTypeClass, Operator],
CedarCode USING[CreateCedarNode, GetDataFromNode, GetNodeRepresentation, OperationsBody],
CedarOtherPureTypes USING[CreateIndirectToAnUnknownType, CreateUnknownType, CreateUnknownTypeNode],
CirioMemory,
CirioNubAccess USING[Handle, RemoteAddress, RemoteAddrFault],
CirioTypes,
CPointerTypes USING [CreatePointerType, PointerNodeInfo, PointerNodeInfoBody, CreatePointerNode],
CNumericTypes USING [CreateNumericNode, CreateNumericType, GetDescriptorFromCNumericType, NumericDescriptor, NumericDescriptorBody, PrimaryTag],
Convert USING [Error, IntFromRope, RopeFromChar],
DeferringTypes,
IO,
LoadStateAccess USING [BasicPCInfo, GetBasicPCInfo, LoadStateHandle],
ObjectFiles,
ObjectFilesPrivate,
PBasics USING [BITOR, BITSHIFT, LongNumber, Word],
PBasics16 USING [BITXOR],
Procedures,
RCTW,
RefTab USING [Create, Key, Ref, Store],
RealFns USING [Power],
Records USING[CreateIndirectRecordNode, CreateRecordType, FieldCase, IndirectRecordNodeProcs, RecordTypeProcs],
RMTWPrivate,
Rope USING[Cat, Concat, Equal, FromChar, ROPE],
SGI,
SymTab,
SystemInterface;

RCTWOrdinaries: CEDAR PROGRAM
IMPORTS CCTypes, CedarCode, CedarOtherPureTypes, CirioMemory, CirioNubAccess, CirioTypes, CNumericTypes, Convert, CPointerTypes, DeferringTypes, IO, LoadStateAccess, ObjectFiles, PBasics, PBasics16, Procedures, RCTW, RealFns, Records, RefTab, RMTWPrivate, Rope, SGI, SymTab, SystemInterface
EXPORTS RCTW
= BEGIN OPEN LSA:LoadStateAccess, ObjF:ObjectFiles, RCTW;

CC: TYPE = CirioTypes.CompilerContext;
CCE: ERROR[case: CCTypes.CCErrorCase, msg: Rope.ROPE _ NIL] _ CCTypes.CCError;
SIRep: TYPE ~ INT;
LIRep: TYPE ~ INT;
SCRep: TYPE ~ CARD;
LCRep: TYPE ~ CARD;

AnalyzeType: PUBLIC PROC[sourceStream: IO.STREAM, bracketEntry: BracketEntry, rctw: RCTWData] RETURNS[ati: RCTW.AnalyzedTypeInfo] ~ {
temp: CHAR _ IO.PeekChar[sourceStream];
ati _ NIL;
SELECT TRUE FROM 
IsDigit[temp] OR temp = '( OR temp = '-  => -- This might be a definition
 RETURN[AnalyzeTypeDef[sourceStream, bracketEntry, rctw]];
temp = '* => --This is a pointer type
ati _ AnalyzePointerTypeStab[sourceStream, bracketEntry, rctw];
temp = 'a => --This is an array type - create a pointer
ati _ AnalyzePointerTypeStab[sourceStream, bracketEntry, rctw];
temp = 'b => --This is a bitwise type (SunOS 5.0)
ati _ AnalyzeBitwiseTypeStab[sourceStream, bracketEntry, rctw];
temp = 'R => --This is a floating point type (SunOS 5.0)
ati _ AnalyzeRealTypeStab[sourceStream, bracketEntry, rctw];
temp = 'r => --This is a subrange or a floating point type
ati _ AnalyzeNumericTypeStab[sourceStream, bracketEntry, rctw];
temp = 's OR temp = 'u => --This is a bit field, record or union type.
ati _ AnalyzeRecordTypeStab[sourceStream, bracketEntry, rctw];
temp = 'e => --This is an enumerated type
ati _ AnalyzeEnumeratedTypeStab[sourceStream, bracketEntry, rctw];
temp = 'f OR temp = 'F => --This is a procedure type
ati _ AnalyzeProcedureTypeStab[sourceStream, bracketEntry, rctw];
temp = 'x => --This is a structure (or union?) reference
ati _ AnalyzeReferenceTypeStab[sourceStream, bracketEntry, rctw];
ENDCASE =>
RETURN[AnalyzedUnknownType[Rope.FromChar[temp].Concat[" and then some"], rctw]];  -- for typeClass SELECT

IF ati = NIL THEN CCE[cirioError, IO.PutFR1["ati is NIL in RCTWOrdinaries.AnalyzeType for type beginning with: %g", [character[temp]]]];

RETURN;
};

AnalyzeTypeFromFile: PUBLIC PROC[auxIndex: INT32, wireTables: SGI.WireTables, bracketEntry: BracketEntry, rctw: RCTWData, stab: ObjF.Stab, symTabIndex: CARD] RETURNS[ati: RCTW.AnalyzedTypeInfo _ NIL] ~ TRUSTED {
i,structIndex,auxCount,basicType, numQualifiers: CARD _ 0;
typeInfo: SGI.WireTypeInfoBody;
auxSyms: SGI.AuxSymTable _ wireTables.auxSyms;
type: Type _ NIL;
IndexNil: CARD = 0FFFFFH;	-- max valid index for aux entries
fdIndex: INT32;
thisSym: SGI.WireSTEntry;

IF stab.extRef THEN
{
thisSym _ LOOPHOLE[@wireTables.extSyms[symTabIndex].sym];
fdIndex _ wireTables.extSyms[symTabIndex].fileDescrIndex;
}
ELSE
{
thisSym _ LOOPHOLE[@wireTables.localSyms[symTabIndex]];
fdIndex _ stab.fdIndex;
};

IF auxIndex = IndexNil THEN
{
type _ AnalyzeNumericFileStab[[primary: signed, secondary: integer], 32, rctw].directType;
RETURN[NEW[AnalyzedTypeInfoBody_[atiValid: TRUE, atiIsProc: FALSE, directType: type, rctw: rctw]]];
};

typeInfo _ auxSyms[auxIndex].typeInfo;

basicType _ typeInfo.basicType;

SELECT basicType FROM
SGI.BTChar =>	-- character 
{	
type _ AnalyzeNumericFileStab[[primary: signed, secondary: character], 8, rctw].directType;
};
SGI.BTUchar =>	-- unsigned character
{	
type _ AnalyzeNumericFileStab[[primary: unsigned, secondary: character], 8, rctw].directType;
};
SGI.BTShort =>	-- short 
{	
type _ AnalyzeNumericFileStab[[primary: signed, secondary: shortInteger], 16, rctw].directType;
};
SGI.BTUshort =>	-- unsigned short 
{	
type _ AnalyzeNumericFileStab[[primary: unsigned, secondary: shortInteger], 16, rctw].directType;
};
SGI.BTRange,	-- subrange of int
SGI.BTInt,		-- integer 	
SGI.BTLong =>	-- long
{	
type _ AnalyzeNumericFileStab[[primary: signed, secondary: integer], 32, rctw].directType;
};
SGI.BTAdr,		-- address
SGI.BTUint,		-- unsigned int
SGI.BTUlong =>	-- unsigned long
{	
type _ AnalyzeNumericFileStab[[primary: unsigned, secondary: integer], 32, rctw].directType;
};
SGI.BTFloat,			-- float (real)
SGI.BTDouble =>	-- Double (real 
{	
type _ AnalyzeNumericFileStab[[primary: float], 32, rctw].directType;
};
SGI.BTVoid =>	-- void
{	-- void
type _ AnalyzeNumericFileStab[[primary: signed, secondary: integer], 0, rctw].directType;
};


SGI.BTStruct,	-- Structure (Record)
SGI.BTUnion =>	-- Union (variant)
{
type _ AnalyzeStructTypeFileStab[auxIndex, fdIndex, wireTables, bracketEntry, rctw, stab, symTabIndex].directType;
};
SGI.BTEnum =>	-- Enumerated
{	
type _ AnalyzeEnumeratedTypeFileStab[auxIndex, fdIndex, wireTables, bracketEntry, rctw, stab, symTabIndex].directType;
};
SGI.BTTypedef =>	-- defined via a typedef, isymRef points
{	
type _ AnalyzeTypeDefFileStab[auxIndex, fdIndex, wireTables, bracketEntry, rctw, stab, symTabIndex].directType;
};
SGI.BTString => NULL;	-- Varying Length Character String
SGI.BTBit => NULL;	-- Aligned Bit String

SGI.BTSet => { 	-- pascal sets
type _ CedarOtherPureTypes.CreateUnknownType[rctw.cc, IO.PutFR["<unimplemented .o type pascal sets from %g>", [rope[ObjF.DescribeModule[rctw.module]]] ]]};
SGI.BTComplex => { 	-- fortran complex
type _ CedarOtherPureTypes.CreateUnknownType[rctw.cc, IO.PutFR["<unimplemented .o type fortran complex from %g>", [rope[ObjF.DescribeModule[rctw.module]]] ]]};
SGI.BTDcomplex => {	-- fortran double complex
type _ CedarOtherPureTypes.CreateUnknownType[rctw.cc, IO.PutFR["<unimplemented .o type fortran double complex from %g>", [rope[ObjF.DescribeModule[rctw.module]]] ]]};
SGI.BTIndirect => NULL;	-- forward or unnamed typedef
SGI.BTFixeddec => {	-- Fixed Decimal
type _ CedarOtherPureTypes.CreateUnknownType[rctw.cc, IO.PutFR["<unimplemented .o type Fixed Decimal from %g>", [rope[ObjF.DescribeModule[rctw.module]]] ]]};
SGI.BTFloatdec => {	-- Float Decimal
type _ CedarOtherPureTypes.CreateUnknownType[rctw.cc, IO.PutFR["<unimplemented .o type Float Decimal from %g>", [rope[ObjF.DescribeModule[rctw.module]]] ]]};
SGI.BTPicture => {	-- Picture
type _ CedarOtherPureTypes.CreateUnknownType[rctw.cc, IO.PutFR["<unimplemented .o type Picture from %g>", [rope[ObjF.DescribeModule[rctw.module]]] ]]};

ENDCASE => ERROR;

RETURN[NEW[AnalyzedTypeInfoBody_[atiValid: TRUE, atiIsProc: FALSE, directType: type, rctw: rctw]]];
};


IsDigit: PROC [c: CHAR] RETURNS [BOOL]
= INLINE { RETURN [c IN ['0 .. '9]] };

IsHexDigit: PROC [c: CHAR] RETURNS [BOOL]
= INLINE { RETURN [c IN ['0 .. '9] OR c IN ['a .. 'f] OR c IN ['A .. 'F]] };

RopeFromStream: PROC [sourceStream: IO.STREAM, start: INT] RETURNS [Rope.ROPE] ~ {
current: INT _ sourceStream.GetIndex;
copyStream: IO.STREAM ~ IO.ROS[];
sourceStream.SetIndex[start];
FOR index: INT IN [start..current) DO
copyStream.PutChar[sourceStream.GetChar];
ENDLOOP;
sourceStream.SetIndex[current];
RETURN[copyStream.RopeFromROS[]];
};

GetDecimal: PROC [stream: IO.STREAM] RETURNS [INT] ~ {
token: Rope.ROPE _ "";
{ENABLE Convert.Error => GOTO doesntConvert;
{ ENABLE IO.EndOfStream => GOTO finishUp;

token: Rope.ROPE _ "";
char: CHAR _ IO.PeekChar[stream];

IF char = '- OR char = '+ THEN
BEGIN
token _ Rope.FromChar[IO.GetChar[stream]];
char _ IO.PeekChar[stream]
END;
IF char = '0 THEN
BEGIN
[] _ IO.GetChar[stream];
token _ Rope.Concat[token, "0"];
char _ IO.PeekChar[stream];
IF char = 'x THEN BEGIN
[] _ IO.GetChar[stream];
WHILE IsHexDigit[IO.PeekChar[stream]] DO
token _ Rope.Concat[token, Rope.FromChar[IO.GetChar[stream]]];
ENDLOOP;
RETURN[Convert.IntFromRope[token, 16]]
END
END;
WHILE IsDigit[IO.PeekChar[stream]] DO
token _ Rope.Concat[token, Rope.FromChar[IO.GetChar[stream]]];
ENDLOOP;
RETURN[Convert.IntFromRope[token]];
EXITS
finishUp => RETURN[Convert.IntFromRope[token]];
};
EXITS
doesntConvert => RETURN[-1];
};
};


DebugStabParsing: BOOLEAN _ FALSE;
AnalyzeTypeDef: PROC[sourceStream:IO.STREAM, bracketEntry: RCTW.BracketEntry, rctw: RCTW.RCTWData] RETURNS [RCTW.AnalyzedTypeInfo] ~ { 
typeRef: ROPE _ ObjF.GetTypeRef[rctw.module, sourceStream];
ati: RCTW.AnalyzedTypeInfo _ NIL;
dti: RCTW.AnalyzedTypeInfo;
IF NOT IO.EndOf[sourceStream] AND IO.PeekChar[sourceStream] = '= THEN {--This is a typedef
analyzedTypeInfo: RCTW.AnalyzedTypeInfo;
IF IO.GetChar[sourceStream]#'= THEN ERROR;  -- remove the '= from the stream

dti _ DeferringType[rctw];

IF DebugStabParsing THEN
SystemInterface.ShowReport[Rope.Cat["Creating DeferringType for ", typeRef, " in ", ObjectFiles.DescribeModule[rctw.module]], $urgent];

IF NOT SymTab.Insert
[rctw.typeRefHashTable, typeRef, dti] THEN
CCE[cirioError, Rope.Concat["redefinition of typeRef ", typeRef]];

analyzedTypeInfo _ RCTW.AnalyzeType[sourceStream, bracketEntry, rctw];

IF DebugStabParsing THEN
SystemInterface.ShowReport[Rope.Cat["Defining ", typeRef, " in ", ObjectFiles.DescribeModule[rctw.module]], $urgent];

IF NOT SymTab.Insert[rctw.typeRefHashTable, typeRef, analyzedTypeInfo] THEN {
old: RCTW.AnalyzedTypeInfo ~ NARROW[rctw.typeRefHashTable.Fetch[typeRef].val];
IF old=analyzedTypeInfo THEN ati _ old
ELSE
IF DeferringTypes.IsDeferring[old.directType] THEN {
DeferringTypes.SetUndertype[old.directType, analyzedTypeInfo.directType];

IF DebugStabParsing THEN
SystemInterface.ShowReport[Rope.Cat["Setting UnderType for ", typeRef, " in ", ObjectFiles.DescribeModule[rctw.module]], $urgent];

[] _ SymTab.Replace[rctw.typeRefHashTable, typeRef, analyzedTypeInfo];
ati _ old}
ELSE
IF
DeferringTypes.IsDeferring[analyzedTypeInfo.directType]
THEN {
DeferringTypes.SetUndertype[ analyzedTypeInfo.directType, old.directType];
ati _ analyzedTypeInfo}
ELSE {
SystemInterface.ShowReport[Rope.Cat["redefinition of typeRef ", typeRef, " in ", ObjectFiles.DescribeModule[rctw.module]], $urgent];
[] _ SymTab.Replace[rctw.typeRefHashTable, typeRef, analyzedTypeInfo];
<<CCError[cirioError, Rope.Concat["redefinition of typeRef ", typeRef]];>>};
};
}
ELSE { -- # '= --
found: BOOLEAN;
refany: REF ANY;
[found, refany] _ rctw.typeRefHashTable.Fetch[typeRef];
ati _ NARROW[refany];

IF NOT found THEN ati _ AnalyzedUnknownType[typeRef, rctw];

IF DebugStabParsing THEN
IF found THEN {
SystemInterface.ShowReport[Rope.Cat[typeRef, " FOUND in ", ObjectFiles.DescribeModule[rctw.module]], $urgent];
}
ELSE {
SystemInterface.ShowReport[Rope.Cat[typeRef, " NOT FOUND in ", ObjectFiles.DescribeModule[rctw.module]], $urgent];
};
};
IF ati = NIL THEN CCE[cirioError, IO.PutFR1["ati is NIL in RCTWOrdinaries.AnalyzeTypeDef for typeRef %g", [rope[typeRef]]]];
RETURN[ati];
};
AnalyzeTypeDefFileStab: PROC[auxIndex: INT32, fdIndex: INT32, wireTables: SGI.WireTables, bracketEntry: RCTW.BracketEntry, rctw: RCTW.RCTWData, stab: ObjF.Stab, symTabIndex: CARD] RETURNS [RCTW.AnalyzedTypeInfo] ~ TRUSTED { 

ati: RCTW.AnalyzedTypeInfo _ NIL;
dti: RCTW.AnalyzedTypeInfo;
typeRef: ROPE;
auxSyms: SGI.AuxSymTable _ wireTables.auxSyms;
symBaseIndex, symIndex, stringOffset: CARD;
stringBaseIndex: CARD;
analyzedTypeInfo: RCTW.AnalyzedTypeInfo;
stringTable: SGI.StringTable _ wireTables.localStrings;
currentIndex: CARD;
relIndex: SGI.WireRelIndexBody;
relFileIndex: INT32;
relFileOffset: INT32;

relIndex _ auxSyms[auxIndex+1].relIndex;
IF relIndex.relFileDescrIndex = 0FFFH THEN
{
relFileIndex _ auxSyms[auxIndex+2].relFileIndex;
}
ELSE
{
relFileIndex _ relIndex.relFileDescrIndex;
};
relFileOffset _ wireTables.fileDescr[fdIndex].rfdBase +  relFileIndex;
IF relFileOffset # 0 THEN
fdIndex _ wireTables.relFiles[relFileOffset];

symIndex _ relIndex.index;
symBaseIndex _ wireTables.fileDescr[fdIndex].isymBase;
stringBaseIndex _ wireTables.fileDescr[fdIndex].issBase;
currentIndex _ symIndex + symBaseIndex;

stringOffset _ wireTables.localSyms[currentIndex].symStringIndex;

typeRef _  RopeFromStringTable[stringTable, stringBaseIndex+stringOffset];

dti _ DeferringType[rctw];

IF DebugStabParsing THEN
SystemInterface.ShowReport[Rope.Cat["Creating DeferringType for ", typeRef, " in ", ObjectFiles.DescribeModule[rctw.module]], $urgent];

[] _ SymTab.Insert[rctw.typeRefHashTable, typeRef, dti];

auxIndex _ wireTables.fileDescr[fdIndex].iauxBase + wireTables.localSyms[currentIndex].index;

analyzedTypeInfo _ AnalyzeTypeFromFile[auxIndex, wireTables, bracketEntry, rctw, stab, currentIndex];

IF DebugStabParsing THEN
SystemInterface.ShowReport[Rope.Cat["Defining ", typeRef, " in ", ObjectFiles.DescribeModule[rctw.module]], $urgent];

IF NOT SymTab.Insert[rctw.typeRefHashTable, typeRef, analyzedTypeInfo] THEN {
old: RCTW.AnalyzedTypeInfo ~ NARROW[rctw.typeRefHashTable.Fetch[typeRef].val];
IF old=analyzedTypeInfo THEN ati _ old
ELSE
IF DeferringTypes.IsDeferring[old.directType] THEN {
DeferringTypes.SetUndertype[old.directType, analyzedTypeInfo.directType];

IF DebugStabParsing THEN
SystemInterface.ShowReport[Rope.Cat["Setting UnderType for ", typeRef, " in ", ObjectFiles.DescribeModule[rctw.module]], $urgent];

[] _ SymTab.Replace[rctw.typeRefHashTable, typeRef, analyzedTypeInfo];
ati _ old}
ELSE
IF
DeferringTypes.IsDeferring[analyzedTypeInfo.directType]
THEN {
DeferringTypes.SetUndertype[ analyzedTypeInfo.directType, old.directType];
ati _ analyzedTypeInfo}
ELSE {
ati _ analyzedTypeInfo;

<<[] _ SymTab.Replace[rctw.typeRefHashTable, typeRef, analyzedTypeInfo];
CCError[cirioError, Rope.Concat["redefinition of typeRef ", typeRef]];>>};
};

IF ati = NIL THEN CCE[cirioError, IO.PutFR1["ati is NIL in RCTWOrdinaries.AnalyzeTypeDef for typeRef %g", [rope[typeRef]]]];
RETURN[ati];
};

DeferringType: PROC [rctw: RCTWData] RETURNS [RCTW.AnalyzedTypeInfo] ~ {
deferringType: Type _ DeferringTypes.CreateDeferringType[rctw.cc];
analyzedTypeInfo: AnalyzedTypeInfo _ NEW[AnalyzedTypeInfoBody _ [atiValid: TRUE, atiIsProc: FALSE, directType: deferringType, rctw: rctw]];
RETURN[analyzedTypeInfo]
};



AnalyzeReferenceTypeStab: PROC [sourceStream: IO.STREAM, bracketEntry: BracketEntry, rctw: RCTWData] RETURNS[ati: AnalyzedTypeInfo] ~ {
x: CHAR ~ sourceStream.GetChar[];
kind: CHAR ~ sourceStream.GetChar[];
peek, colon: CHAR;
ref, dot: ROPE;
IF x#'x THEN ERROR;
IF kind#'s AND kind#'u THEN CCE [syntax, Rope.Concat["x", Rope.FromChar[kind]]];
peek _ sourceStream.PeekChar[];
IF RefTok[peek] # other THEN CCE [syntax, Rope.Cat["x", Rope.FromChar[kind], Rope.FromChar[peek]]];
ref _ IO.GetTokenRope[sourceStream, RefTok].token;
colon _ sourceStream.GetChar[];
dot _ Rope.Cat["x", Rope.FromChar[kind], ref, Rope.FromChar[colon]];
IF colon#': THEN CCE [syntax, dot];
RETURN AnalyzedUnknownType[dot, rctw]};
RefTok: PROC [char: CHAR] RETURNS [IO.CharClass]
~ {RETURN [SELECT char FROM ': => break, ENDCASE => other]};

AnalyzedUnknownType: PUBLIC PROC [typeRef: Rope.ROPE, rctw: RCTWData] RETURNS [AnalyzedTypeInfo] ~ {
analyzedTypeInfo: AnalyzedTypeInfo _ NEW[AnalyzedTypeInfoBody _ [
atiValid: TRUE, atiIsProc: FALSE,
directType: CedarOtherPureTypes.CreateUnknownType[rctw.cc, IO.PutFR["<unimplemented .o type %g from %g>", [rope[typeRef]], [rope[ObjF.DescribeModule[rctw.module]]] ]],
rctw: rctw]];
RETURN[analyzedTypeInfo]
};

UnimplementedTypeNode: PROC[indirectType: Type, rctw: RCTWData, explanation: Rope.ROPE, indirect: BOOL] RETURNS[Node] = {
targetType: Type ~ CedarOtherPureTypes.CreateUnknownType[rctw.cc, explanation];
IF indirect THEN RETURN[CedarOtherPureTypes.CreateIndirectToAnUnknownType[targetType, explanation, rctw.cc]];
RETURN[CedarOtherPureTypes.CreateUnknownTypeNode[targetType, explanation, rctw.cc]]};

AnalyzedPointerTypeStab: TYPE = REF AnalyzedPointerTypeStabBody;
AnalyzedPointerTypeStabBody: TYPE = RECORD[
rctw: RCTWData,
directType: Type,
size: CARD,
directTargetType: Type
];

AnalyzePointerTypeStab: PROC[sourceStream: IO.STREAM, bracketEntry:  BracketEntry, rctw: RCTWData] RETURNS[AnalyzedTypeInfo] ~ {
array: BOOL ~ SELECT sourceStream.GetChar[] FROM '* => FALSE, 'a => TRUE, ENDCASE => ERROR CCE[cirioError, "can't happen: AnalyzePointerTypeStab called with stream at non-* non-a char"];
indexATI: AnalyzedTypeInfo ~ IF array THEN AnalyzeType[sourceStream, bracketEntry, rctw] ELSE NIL;
sep: Rope.ROPE ~ IF array
THEN SELECT sourceStream.GetChar[] FROM
'; => ";",
ENDCASE => ERROR CCE[cirioError, "found array type constructor (in DBX stab) without semicolon between index and element types"]
ELSE NIL;
targetATI: AnalyzedTypeInfo ~ AnalyzeType[sourceStream, bracketEntry, rctw];
IF array THEN RETURN AnalyzedUnknownType["Arrays aren't implemented yet.", rctw]; --arrays are NOT just pointers - rather than duplicate the code in RMTWCompounds, wait 'till we can call it
{private: AnalyzedPointerTypeStab ~ NEW[AnalyzedPointerTypeStabBody_[
rctw: rctw,
size: 32,
directTargetType: targetATI.directType]];
bti: BasicTypeInfo ~ NEW [BasicTypeInfoPrivate _ [CreatePointerIndirect, GetPointerBitSize, private]];
private.directType _ CPointerTypes.CreatePointerType[private.directTargetType, rctw.cc, bti];
RETURN[NEW[AnalyzedTypeInfoBody_[atiValid: TRUE, atiIsProc: FALSE, directType: private.directType, rctw: rctw]]]}};

AnalyzePointerTypeFileStab: PUBLIC PROC[auxIndex: INT32, wireTables: SGI.WireTables, bracketEntry:  BracketEntry, rctw: RCTWData, stab: ObjF.Stab, symTabIndex: CARD] RETURNS[AnalyzedTypeInfo] ~ {
targetType: Type ~ AnalyzeTypeFromFile[auxIndex, wireTables, bracketEntry, rctw, stab, symTabIndex].directType;
{private: AnalyzedPointerTypeStab ~ NEW[AnalyzedPointerTypeStabBody_[
rctw: rctw,
size: 32,
directTargetType: targetType]];
bti: BasicTypeInfo ~ NEW [BasicTypeInfoPrivate _ [CreatePointerIndirect, GetPointerBitSize, private]];
private.directType _ CPointerTypes.CreatePointerType[private.directTargetType, rctw.cc, bti];
RETURN[NEW[AnalyzedTypeInfoBody_[atiValid: TRUE, atiIsProc: FALSE, directType: private.directType, rctw: rctw]]]}};


GetPointerBitSize: PROC[bti: BasicTypeInfo, cc: CC, indirectType, targetType: Type] RETURNS[CARD] ~ {
private: AnalyzedPointerTypeStab _ NARROW[bti.btiData];
RETURN[private.size]};

CreatePointerIndirect: PROC [bti: BasicTypeInfo, cc: CC, indirectType, targetType: Type, mem: Mem] RETURNS [Node] ~ {
private: AnalyzedPointerTypeStab _ NARROW[bti.btiData];
nodeData: REF PointerNodeData _ NEW[PointerNodeData _ [private, mem]];
RETURN[CedarCode.CreateCedarNode[PointerOps, indirectType, nodeData]]};

PointerNodeData: TYPE = RECORD[
private: AnalyzedPointerTypeStab,
mem: Mem];

PointerOps: REF CedarCode.OperationsBody _ NEW[CedarCode.OperationsBody_[
store: PointerStore,
load: PointerLoad]];

PointerDirect: TYPE ~ REF PointerDirectPrivate;
PointerDirectPrivate: TYPE ~ RECORD [
addr: CARD,
eltSize: INT,
pnd: REF PointerNodeData,
targetMem: Mem];

PointerStore: PROC[valType: Type, valNode: Node, indirectType: Type, indirectNode: Node, cc: CC] = {
nodeData: REF PointerNodeData ~ NARROW[CedarCode.GetDataFromNode[indirectNode]];
rctw: RCTWData ~ nodeData.private.rctw;
mem: Mem ~ nodeData.mem;
pointerSize: CARD ~ nodeData.private.size;
valInfo: REF ANY ~ CedarCode.GetDataFromNode[valNode];
WITH valInfo SELECT FROM
valPni: CPointerTypes.PointerNodeInfo => {
valPD: PointerDirect ~ NARROW[valPni.data];
mem.MemWrite[valPD.addr, 32, zeroBA]};
ENDCASE => CCE[operation, "Can't store a non-C pointer into a C pointer"];
RETURN};

cNIL: CARD _ 0;

PointerLoad: PROC[indirectType: Type, indirectNode: Node, cc: CC] RETURNS[Node] = {
nodeData: REF PointerNodeData _ NARROW[CedarCode.GetDataFromNode[indirectNode]];
rctw: RCTWData _ nodeData.private.rctw;
mem: Mem _ nodeData.mem;
pointerSize: CARD _ nodeData.private.size;
{ENABLE {
CirioNubAccess.RemoteAddrFault => GOTO unknownAddress;
CCE => GOTO unknownAddress};
fieldSizeBa: BitAddr _ mem.MemGetSize[];
fieldSize: CARD _ fieldSizeBa.BaToBits[];
addrBits: CARD _ mem.MemRead[bitsPerPtr, zeroBA];
<<IF (addr.byteAddress = cNIL AND addr.bitOffset = 0) OR addr.nil OR NOT addr.valid THEN RETURN[CPointerTypes.CreateNilPointerNode[cc]];>>
{directTargetType: Type ~ nodeData.private.directTargetType;
indirectTargetType: Type ~ CCTypes.GetIndirectType[directTargetType];
referentSize: CARD _ 0;
referentSizeBa: BitAddr _ unspecdBA;
targetMem: Mem;
info: CPointerTypes.PointerNodeInfo;
{ --MJS, January 10, 1992: Made the targetMem use the referentSize, so that NumericLoad will have a meaningful fieldSize
ENABLE CCE => CONTINUE;
referentSize _ CCTypes.GetBitSize[indirectTargetType, cc];
referentSizeBa _ CirioMemory.BitsToBa[referentSize]};
targetMem _ CirioMemory.CreateSimpleMem[[rctw.nub, LOOPHOLE[addrBits], 0, addrBits=0 OR addrBits=CARD.LAST, TRUE], referentSizeBa];
info _ NEW[CPointerTypes.PointerNodeInfoBody _ [
clientTargetType: directTargetType,
indirectToClientTarget: CCTypes.CreateIndirectNode[indirectTargetType, targetMem, cc],
add: PointerAdd,
subtract: PointerSubtract,
compare: PointerCompare,
data: NEW [PointerDirectPrivate _ [addrBits, referentSize, nodeData, targetMem]] ]];
RETURN[CPointerTypes.CreatePointerNode[nodeData.private.directType, info, cc]];
};
EXITS
unknownAddress => RETURN[UnimplementedTypeNode[indirectType, rctw, "pointer at (not to) bad address", FALSE]];
}};

PointerAdd: PROC [node: Node, offsetNode: Node, info: CPointerTypes.PointerNodeInfo, cc: CC] RETURNS [Node]
~ {RETURN OffsetPointer[node, offsetNode, +1, info, cc]};

PointerSubtract: PROC [leftNode: Node, rightNode: Node, cc: CC] RETURNS [Node] ~ {
WITH CedarCode.GetDataFromNode[leftNode] SELECT FROM
pni: CPointerTypes.PointerNodeInfo => RETURN OffsetPointer[leftNode, rightNode, -1, pni, cc];
ENDCASE => CCE[cirioError, "C PointerSubtract called with left node not a C pointer"]};

OffsetPointer: PROC [node: Node, offsetNode: Node, sgn: [-1..+1], pni: CPointerTypes.PointerNodeInfo, cc: CC] RETURNS [Node] ~ {
pd: PointerDirect ~ NARROW[pni.data];
pnd: REF PointerNodeData ~ pd.pnd;
rctw: RCTWData ~ pnd.private.rctw;
bitOffset: INT ~ sgn*pd.eltSize*(WITH CedarCode.GetDataFromNode[offsetNode] SELECT FROM
ri: REF INT => ri^,
rc: REF CARD => LOOPHOLE[rc^, INT],
rc: REF CHAR => rc^.ORD,
ENDCASE => CCE[operation, "can't add something besides an integer to a pointer"]);
byteOffset: INT ~ bitOffset/8;
IF pd.eltSize=0 THEN CCE[operation, "can't shift that pointer"];
IF bitOffset # byteOffset*8 THEN CCE[operation, "pointer addition must yield a byte-aligned offset"];
{
newAddr: INT ~ LOOPHOLE[pd.addr, INT] + byteOffset;
shiftedMem: Mem ~ pd.targetMem.MemShift[CirioTypes.BitsToBa[bitOffset]];
referentIndirect: Node ~ CCTypes.GetIndirectCreateNode[pnd.private.directTargetType, shiftedMem, cc];
newPni: CPointerTypes.PointerNodeInfo ~ NEW[CPointerTypes.PointerNodeInfoBody _ [
clientTargetType: pni.clientTargetType,
indirectToClientTarget: referentIndirect,
add: PointerAdd,
subtract: PointerSubtract,
compare: PointerCompare,
data: NEW [PointerDirectPrivate _ [LOOPHOLE[newAddr], pd.eltSize, pnd, pd.targetMem]]
]];
RETURN[CPointerTypes.CreatePointerNode[pnd.private.directType, newPni, cc]]}};

PointerCompare: PROC [leftNode: Node, rightNode: Node, op: CCTypes.Operator, cc: CC] RETURNS [Node] ~ {
leftPni: CPointerTypes.PointerNodeInfo ~ WITH CedarCode.GetDataFromNode[leftNode] SELECT FROM
pni: CPointerTypes.PointerNodeInfo => pni,
ENDCASE => CCE[cirioError, "C pointer compare called with non-pointer left arg"];
leftPd: PointerDirect ~ NARROW[leftPni.data];
rightPni: CPointerTypes.PointerNodeInfo ~ WITH CedarCode.GetDataFromNode[rightNode] SELECT FROM
pni: CPointerTypes.PointerNodeInfo => pni,
ENDCASE => CCE[cirioError, "C pointer compare called with non-pointer right arg"];
rightPd: PointerDirect ~ NARROW[rightPni.data];
ans: BOOL ~ SELECT op FROM
$eq => leftPd.addr = rightPd.addr,
$ne => leftPd.addr # rightPd.addr,
$le => leftPd.addr <= rightPd.addr,
$lt => leftPd.addr < rightPd.addr,
$ge => leftPd.addr >= rightPd.addr,
$gt => leftPd.addr > rightPd.addr,
ENDCASE => CCE[cirioError, IO.PutFR1["unexpected comparison op (%g) between C pointers", [atom[op]] ]];
ansType: Type ~ CNumericTypes.CreateNumericType[NEW[CNumericTypes.NumericDescriptorBody _ [signed, integer]], cc, NIL];
RETURN CNumericTypes.CreateNumericNode[ansType, NEW [INT _ IF ans THEN 1 ELSE 0]]};


RemoteAddressNormalize: PROC [address: CirioNubAccess.RemoteAddress] RETURNS [CirioNubAccess.RemoteAddress] ~ {
newAddress: CirioNubAccess.RemoteAddress _ IF address.nil THEN
[h: address.h, byteAddress: 0 , bitOffset: 0, nil: address.nil, valid: address.valid]
ELSE
[h: address.h, byteAddress: address.byteAddress + address.bitOffset / 8, bitOffset: address.bitOffset MOD 8, nil: address.nil, valid: address.valid];
RETURN[newAddress]
};

RemoteAddressByteDifference: PROC [left: CirioNubAccess.RemoteAddress, right: CirioNubAccess.RemoteAddress, bitSize: CARD] RETURNS [diff: CARD, negative: BOOL] ~ {
newLeft: CirioNubAccess.RemoteAddress;
newRight: CirioNubAccess.RemoteAddress;
IF NOT(left.valid AND right.valid) THEN
CCE[cirioError];
newLeft _ RemoteAddressNormalize[left];
newRight _ RemoteAddressNormalize[right];
IF newLeft.bitOffset # 0 OR newRight.bitOffset # 0 THEN
CCE[cirioError];
RETURN[ABS[(newLeft.byteAddress - newRight.byteAddress) / bitSize], newLeft.byteAddress < newRight.byteAddress];
};

IntFromBool: PROC [b: BOOL] RETURNS [INT] ~ {
IF b THEN
RETURN[1]
ELSE
RETURN[0]
};

RemoteAddressCompare: PROC [left: CirioNubAccess.RemoteAddress, right: CirioNubAccess.RemoteAddress, op: CCTypes.Operator] RETURNS [INT] ~ {
difference: CARD;
negative: BOOLEAN;
[difference, negative] _ RemoteAddressByteDifference[left, right, 1];
RETURN[
SELECT op FROM
$le => IntFromBool[negative OR difference = 0],
$lt => IntFromBool[negative],
$eq => IntFromBool[difference = 0],
$ne => IntFromBool[difference # 0],
$gt => IntFromBool[difference # 0 AND ~negative],
$ge => IntFromBool[~negative],
ENDCASE => CCE[cirioError]];
};


AnalyzeEnumeratedTypeStab: PROC [sourceStream: IO.STREAM, bracketEntry:  BracketEntry, rctw: RCTWData] RETURNS [AnalyzedTypeInfo] ~ {
desc: CNumericTypes.NumericDescriptor;
type: Type;
private: AnalyzedNumericTypeStabPrivate;
constantsHashTable: RefTab.Ref _ RefTab.Create[17, RefIntEqual, RefIntHash];
listed: LIST OF DotOListings _ NIL;
bti: BasicTypeInfo;
char: CHAR _ IO.GetChar[sourceStream];
WHILE NOT IO.EndOf[sourceStream] AND IO.PeekChar[sourceStream] # '; DO 
value: INT;
symbol: Rope.ROPE _ GetTokenRope[sourceStream];
ls: DotOListings _ NARROW[bracketEntry.symbolHashTable.Fetch[symbol].val];
IF IO.GetChar[sourceStream] # ':
THEN CCE[cirioError, "missing colon in enumerated type construction"];
value _ GetDecimal[sourceStream];
IF ls#NIL THEN CCE[cirioError, IO.PutFR["enumerator (%g=%g) clashes with some existing symbol in the same scope", [rope[symbol]], [integer[value]] ]];
listed _ CONS[NEW[DotOGlorp[enumerator] _ [NIL, enumerator[symbol, value, NIL]]], listed];
IF NOT bracketEntry.symbolHashTable.Insert[symbol, listed.first] THEN ERROR;
[] _ RefTab.Store[constantsHashTable, NEW[INT _ value], symbol];
IF IO.PeekChar[sourceStream] = ', THEN char _ IO.GetChar[sourceStream];
ENDLOOP;
desc _ NEW[CNumericTypes.NumericDescriptorBody _ [primary: signed, secondary: enumeration, enumerationConstants: constantsHashTable]];
private _ NEW[AnalyzedNumericTypeStabPrivateBody_[rctw: rctw, desc: desc, bitSize: 32]];
bti _ NEW [BasicTypeInfoPrivate _ [CreateNumericIndirect, GetNumericBitSize, private]];
type _ CNumericTypes.CreateNumericType[desc, rctw.cc, bti];
FOR listed _ listed, listed.rest WHILE listed#NIL DO
WITH listed.first SELECT FROM
x: DotOEnumr => x.type _ type;
ENDCASE => ERROR;
ENDLOOP;
RETURN[NEW[AnalyzedTypeInfoBody _ [
atiValid: TRUE, atiIsProc: FALSE,
directType: type,
rctw: rctw]]]
};

AnalyzeEnumeratedTypeFileStab: PROC [auxIndex: INT32, fdIndex: INT32, wireTables: SGI.WireTables, bracketEntry:  BracketEntry, rctw: RCTWData, stab: ObjF.Stab, symTabIndex: CARD] RETURNS [AnalyzedTypeInfo] ~ TRUSTED {
desc: CNumericTypes.NumericDescriptor;
type: Type;
private: AnalyzedNumericTypeStabPrivate;
constantsHashTable: RefTab.Ref _ RefTab.Create[17, RefIntEqual, RefIntHash];
listed: LIST OF DotOListings _ NIL;
bti: BasicTypeInfo;
symBaseIndex, symIndex, currentIndex: CARD;
auxSyms: SGI.AuxSymTable _ wireTables.auxSyms;
endIndex: CARD;
stringOffset, stringBaseIndex: CARD;
stringTable: SGI.StringTable _ wireTables.localStrings;
relIndex: SGI.WireRelIndexBody;
relFileIndex: INT32;
relFileOffset: INT32;
relIndex _ auxSyms[auxIndex+1].relIndex;
IF relIndex.relFileDescrIndex = 0FFFH THEN
{
relFileIndex _ auxSyms[auxIndex+2].relFileIndex;
}
ELSE
{
relFileIndex _ relIndex.relFileDescrIndex;
};
relFileOffset _ wireTables.fileDescr[fdIndex].rfdBase +  relFileIndex;
IF relFileOffset # 0 THEN
fdIndex _ wireTables.relFiles[relFileOffset];

symIndex _ relIndex.index;
symBaseIndex _ wireTables.fileDescr[fdIndex].isymBase;
stringBaseIndex _ wireTables.fileDescr[fdIndex].issBase;

currentIndex _ symIndex + symBaseIndex;
endIndex _ wireTables.localSyms[currentIndex].index - 1;

currentIndex _ currentIndex + 1;

WHILE currentIndex < endIndex DO 
value: INT;
symbol: Rope.ROPE;
ls: DotOListings;

stringOffset _ wireTables.localSyms[currentIndex].symStringIndex;
value _ wireTables.localSyms[currentIndex].value;

symbol _ RopeFromStringTable[stringTable, stringBaseIndex+stringOffset];

ls _ NARROW[bracketEntry.symbolHashTable.Fetch[symbol].val];

IF ls#NIL THEN CCE[cirioError, IO.PutFR["enumerator (%g=%g) clashes with some existing symbol in the same scope", [rope[symbol]], [integer[value]] ]];
listed _ CONS[NEW[DotOGlorp[enumerator] _ [NIL, enumerator[symbol, value, NIL]]], listed];
IF NOT bracketEntry.symbolHashTable.Insert[symbol, listed.first] THEN ERROR;
[] _ RefTab.Store[constantsHashTable, NEW[INT _ value], symbol];

currentIndex _ currentIndex +1;
ENDLOOP;
desc _ NEW[CNumericTypes.NumericDescriptorBody _ [primary: signed, secondary: enumeration, enumerationConstants: constantsHashTable]];
private _ NEW[AnalyzedNumericTypeStabPrivateBody_[rctw: rctw, desc: desc, bitSize: 32]];
bti _ NEW [BasicTypeInfoPrivate _ [CreateNumericIndirect, GetNumericBitSize, private]];
type _ CNumericTypes.CreateNumericType[desc, rctw.cc, bti];
FOR listed _ listed, listed.rest WHILE listed#NIL DO
WITH listed.first SELECT FROM
x: DotOEnumr => x.type _ type;
ENDCASE => ERROR;
ENDLOOP;
RETURN[NEW[AnalyzedTypeInfoBody _ [
atiValid: TRUE, atiIsProc: FALSE,
directType: type,
rctw: rctw]]]
};


RefIntEqual: PROC [key1, key2: RefTab.Key] RETURNS [BOOL] ~ {
RETURN [NARROW[key1, REF INT]^ = NARROW[key2, REF INT]^]
};

RefIntHash: PROC [key: RefTab.Key] RETURNS [CARDINAL] ~ {
lc: PBasics.LongNumber ~ [int[NARROW[key, REF INT]^]];
RETURN [PBasics16.BITXOR[lc.lo, lc.hi]]};


AnalyzedProcedure: TYPE ~ REF AnalyzedProcedurePrivate;
AnalyzedProcedurePrivate: TYPE ~ RECORD [
rctw: RCTWData,
resultATI: AnalyzedTypeInfo
];

AnalyzeProcedureTypeStab: PROC[sourceStream: IO.STREAM, bracketEntry:  BracketEntry, rctw: RCTWData] RETURNS[AnalyzedTypeInfo] = {
f: CHAR ~ sourceStream.GetChar[];
IF f#'f AND f#'F THEN CCE[cirioError, "AnalyzeProcedureTypeStab[not f]"];
{protoResult: AnalyzedTypeInfo ~ AnalyzeType[sourceStream, bracketEntry, rctw];
ap: AnalyzedProcedure ~ NEW[AnalyzedProcedurePrivate _ [rctw, protoResult]];
bti: BasicTypeInfo ~ NEW [BasicTypeInfoPrivate _ [CreateProcIndirect, BitSizeIs32, ap]];
procType: Type ~ Procedures.CreateProcedureType[CCTypes.GetAnyTargetType[rctw.cc], protoResult.directType, rctw.cc, bti];
RETURN[NEW[AnalyzedTypeInfoBody _ [
atiValid: TRUE, atiIsProc: TRUE,
directType: procType,
rctw: rctw]]]}};

AnalyzeProcedureTypeFileStab: PUBLIC PROC [auxIndex: INT32, wireTables: SGI.WireTables, bracketEntry:  BracketEntry, rctw: RCTWData, stab: ObjF.Stab, symTabIndex: CARD] RETURNS[AnalyzedTypeInfo] = {


{protoResult: AnalyzedTypeInfo ~ AnalyzeTypeFromFile[auxIndex, wireTables, bracketEntry, rctw, stab, symTabIndex];
ap: AnalyzedProcedure ~ NEW[AnalyzedProcedurePrivate _ [rctw, protoResult]];
bti: BasicTypeInfo ~ NEW [BasicTypeInfoPrivate _ [CreateProcIndirect, BitSizeIs32, ap]];
procType: Type ~ Procedures.CreateProcedureType[CCTypes.GetAnyTargetType[rctw.cc], protoResult.directType, rctw.cc, bti];
RETURN[NEW[AnalyzedTypeInfoBody _ [
atiValid: TRUE, atiIsProc: TRUE,
directType: procType,
rctw: rctw]]]}};

BitSizeIs32: PROC [bti: BasicTypeInfo, cc: CC, indirectType, targetType: Type] RETURNS [CARD]
~ {RETURN[32]};

ProcIndirectData: TYPE ~ REF ProcIndirectDataPrivate;
ProcIndirectDataPrivate: TYPE ~ RECORD [ap: AnalyzedProcedure, directType: Type, mem: Mem];

CreateProcIndirect: PROC[bti: BasicTypeInfo, cc: CC, indirectType, targetType: Type, mem: Mem] RETURNS[Node] ~ {
ap: AnalyzedProcedure ~ NARROW[bti.btiData];
pid: ProcIndirectData ~ NEW[ProcIndirectDataPrivate _ [ap, targetType, mem]];
RETURN CedarCode.CreateCedarNode[ProcIndirectOps, indirectType, pid]};

ProcIndirectOps: REF CedarCode.OperationsBody _ NEW[CedarCode.OperationsBody_[
store: ProcStore,
load: ProcLoad]];

ProcDirectData: TYPE ~ REF ProcDirectDataPrivate;
ProcDirectDataPrivate: TYPE ~ RECORD [
lsh: LSA.LoadStateHandle,
pc: CARD,
desc: Rope.ROPE _ NIL];

ProcStore: PROC[valType: Type, valNode: Node, indirectType: Type, indirectNode: Node, cc: CC] ~ {
CCE[operation, "Can't store into a C procedure location"]};

ProcLoad: PROC[indirectType: Type, indirectNode: Node, cc: CC] RETURNS[Node] ~ {
pid: ProcIndirectData ~ NARROW[CedarCode.GetDataFromNode[indirectNode]];
rctw: RCTWData ~ pid.ap.rctw;
directType: Type ~ pid.directType;
pdd: ProcDirectData ~ NEW[ProcDirectDataPrivate _ [rctw.lsh, 0]];
pni: Procedures.ProcedureNodeInfo ~ NEW [Procedures.ProcedureNodeInfoBody _ [
call: CallProc, show: DescribeProc, data: pdd]];
codeStart: BitAddr ~ pid.mem.MemGetStart[];
pdd.pc _ codeStart.BaToPtr[];
RETURN Procedures.CreateProcedureNode[directType, pni]};

CallProc: PROC[args: Node, cc: CC, data: REF ANY] RETURNS[Node]
~ {CCE[unimplemented, "C procedure call not implemented"]};

DescribeProc: PROC[to: IO.STREAM, data: REF ANY, depth, width: INT] ~ {
pdd: ProcDirectData ~ NARROW[data];
IF pdd.desc=NIL THEN {
lsh: LSA.LoadStateHandle ~ pdd.lsh;
bpi: REF LSA.BasicPCInfo ~ LSA.GetBasicPCInfo[lsh, pdd.pc];
IF bpi=NIL THEN pdd.desc _ IO.PutFR["pc=0x%x (not known to dynamic loader)", [cardinal[pdd.pc]] ]
ELSE {
entryPC: CARD ~ bpi.lsi[text].base + bpi.moduleRelativeBaseAddr + bpi.procedureModuleRelativeBaseAddr;
IF entryPC=pdd.pc
THEN pdd.desc _ bpi.procedureName
ELSE pdd.desc _ IO.PutFR["%g+0x%x", [rope[bpi.procedureName]], [cardinal[pdd.pc-entryPC]] ];
};
};
to.PutRope[pdd.desc]};

AnalyzedNumericTypeStabPrivate: TYPE = REF AnalyzedNumericTypeStabPrivateBody;
AnalyzedNumericTypeStabPrivateBody: TYPE = RECORD[
rctw: RCTWData,
desc: CNumericTypes.NumericDescriptor,
bitSize: CARD];
Analyze: PROC[body: CNumericTypes.NumericDescriptorBody, length: CARD, rctw: RCTWData] RETURNS[AnalyzedTypeInfo] =
BEGIN
desc: CNumericTypes.NumericDescriptor ~ NEW [CNumericTypes.NumericDescriptorBody _ body];
private: AnalyzedNumericTypeStabPrivate ~ NEW[AnalyzedNumericTypeStabPrivateBody _ [rctw: rctw, desc: desc, bitSize: length]];
bti: BasicTypeInfo ~ NEW [BasicTypeInfoPrivate _ [CreateNumericIndirect, GetNumericBitSize, private]];
type: Type ~ CNumericTypes.CreateNumericType[desc, rctw.cc, bti];
RETURN[NEW[AnalyzedTypeInfoBody _ [
atiValid: TRUE, atiIsProc: FALSE,
directType: type,
rctw: rctw]]];
END;

AnalyzeBitwiseTypeStab: PROC[sourceStream: IO.STREAM, bracketEntry:  BracketEntry, rctw: RCTWData] RETURNS[AnalyzedTypeInfo] =
BEGIN
initialIndex: INT _ sourceStream.GetIndex;
byteSizeVal: INT;
minVal: INT;
maxVal: INT;
primaryTag: CNumericTypes.PrimaryTag;
char: CHAR _ IO.GetChar[sourceStream];
char _ IO.GetChar[sourceStream];
SELECT char FROM
's => primaryTag _ signed;
'u => primaryTag _ unsigned;
ENDCASE => CCE[cirioError, "missing 's or 'u in num type const"];
IF IO.PeekChar[sourceStream] = 'c THEN [] _ IO.GetChar[sourceStream];
byteSizeVal _ GetDecimal[sourceStream];
IF IO.GetChar[sourceStream] # '; THEN CCE[cirioError, "missing ; in num type const"];
minVal _ GetDecimal[sourceStream];
IF IO.GetChar[sourceStream] # '; THEN CCE[cirioError, "missing ; in num type const"];
maxVal _ GetDecimal[sourceStream];
SELECT TRUE FROM
byteSizeVal = BYTES[INT32] AND minVal = 0 AND maxVal = BITS[INT32] => 
RETURN Analyze[[primary: primaryTag, secondary: integer], 32, rctw];
byteSizeVal = BYTES[BYTE] AND minVal = 0 AND maxVal = BITS[BYTE] => 
RETURN Analyze[[primary: primaryTag, secondary: character], 8, rctw];
byteSizeVal = BYTES[INT16] AND minVal = 0 AND maxVal = BITS[INT16] => 
RETURN Analyze[[primary: primaryTag, secondary: shortInteger], 16, rctw];
byteSizeVal = BYTES[INT64] AND minVal = 0 AND maxVal = BITS[INT64] => 
RETURN Analyze[[primary: primaryTag, secondary: longInteger], 64, rctw];
ENDCASE =>
RETURN[AnalyzedUnknownType[RopeFromStream[sourceStream, initialIndex], rctw]];
END;

AnalyzeRealTypeStab: PROC[sourceStream: IO.STREAM, bracketEntry:  BracketEntry, rctw: RCTWData] RETURNS[AnalyzedTypeInfo] =
BEGIN
initialIndex: INT _ sourceStream.GetIndex;
tagVal: INT;
byteSizeVal: INT;
char: CHAR _ IO.GetChar[sourceStream];
tagVal _ GetDecimal[sourceStream];
IF IO.GetChar[sourceStream] # '; THEN CCE[cirioError, "missing ; in num type const"];
byteSizeVal _ GetDecimal[sourceStream];
SELECT byteSizeVal FROM
4 => --This is a single precision floating point
RETURN[Analyze[[primary: float], 32, rctw]];
8 => --This is a double precision floating point
RETURN[Analyze[[primary: double], 64, rctw]];
16 => --This is a double precision floating point
RETURN[Analyze[[primary: longDouble], 128, rctw]];
ENDCASE =>
RETURN[AnalyzedUnknownType[RopeFromStream[sourceStream, initialIndex], rctw]];
END;

AnalyzeNumericFileStab: PUBLIC PROC[body: CNumericTypes.NumericDescriptorBody, length: CARD, rctw: RCTWData] RETURNS[RCTW.AnalyzedTypeInfo] =
BEGIN
desc: CNumericTypes.NumericDescriptor ~ NEW [CNumericTypes.NumericDescriptorBody _ body];
private: AnalyzedNumericTypeStabPrivate ~ NEW[AnalyzedNumericTypeStabPrivateBody _ [rctw: rctw, desc: desc, bitSize: length]];
bti: BasicTypeInfo ~ NEW [BasicTypeInfoPrivate _ [CreateNumericIndirect, GetNumericBitSize, private]];
type: Type ~ CNumericTypes.CreateNumericType[desc, rctw.cc, bti];
RETURN[NEW[AnalyzedTypeInfoBody _ [
atiValid: TRUE, atiIsProc: FALSE,
directType: type,
rctw: rctw]]];
END;

AnalyzeNumericTypeStab: PROC[sourceStream: IO.STREAM, bracketEntry:  BracketEntry, rctw: RCTWData] RETURNS[AnalyzedTypeInfo] =
BEGIN
initialIndex: INT _ sourceStream.GetIndex;
minVal: INT;
maxVal: INT;
ati: RCTW.AnalyzedTypeInfo;
char: CHAR _ IO.GetChar[sourceStream];
ati _ AnalyzeTypeDef[sourceStream, bracketEntry, rctw];
IF IO.GetChar[sourceStream] # '; THEN CCE[cirioError, "missing ; in num type const"];
minVal _ GetDecimal[sourceStream];
IF IO.GetChar[sourceStream] # '; THEN CCE[cirioError, "missing ; in num type const"];
maxVal _ GetDecimal[sourceStream];
IF maxVal = 0 THEN
BEGIN
SELECT minVal FROM
4 => --This is a single precision floating point
RETURN[Analyze[[primary: float], 32, rctw]];
8 => --This is a double precision floating point
RETURN[Analyze[[primary: double], 64, rctw]];
ENDCASE =>
RETURN[AnalyzedUnknownType[RopeFromStream[sourceStream, initialIndex], rctw]];
END
ELSE
BEGIN
SELECT TRUE FROM
minVal = INT32.FIRST AND maxVal = INT32.LAST => 
RETURN Analyze[[primary: signed, secondary: integer], 32, rctw];
minVal = 0 AND maxVal = 127  => 
RETURN Analyze[[primary: signed, secondary: character], 8, rctw];
minVal = 0 AND maxVal = 255  => 
RETURN Analyze[[primary: unsigned, secondary: character], 8, rctw];
minVal = FIRST[INT16] AND maxVal = LAST[INT16]  => 
RETURN Analyze[[primary: signed, secondary: shortInteger], 16, rctw];
minVal = 0 AND maxVal = LAST[CARD16]  => 
RETURN Analyze[[primary: unsigned, secondary: shortInteger], 16, rctw];
minVal = 0 AND LOOPHOLE[maxVal, CARD] = LAST[CARD] => 
RETURN Analyze[[primary: unsigned, secondary: integer], 32, rctw];
ENDCASE =>
RETURN[AnalyzedUnknownType[RopeFromStream[sourceStream, initialIndex], rctw]];
END
END;
GetNumericBitSize: PROC[bti: BasicTypeInfo, cc: CC, indirectType, targetType: Type] RETURNS[CARD] = {
private: AnalyzedNumericTypeStabPrivate _ NARROW[bti.btiData];
RETURN[private.bitSize]};
CreateNumericIndirect: PROC[bti: BasicTypeInfo, cc: CC, indirectType, targetType: Type, mem: Mem] RETURNS[Node] = {
private: AnalyzedNumericTypeStabPrivate _ NARROW[bti.btiData];
nodeData: REF NumericNodeData _ NEW[NumericNodeData _ [private.rctw, private.desc, targetType, mem]];
RETURN[CedarCode.CreateCedarNode[NumericOps, indirectType, nodeData]]};

NumericNodeData: TYPE = RECORD[
rctw: RCTWData,
desc: CNumericTypes.NumericDescriptor,
targetType: Type,
mem: Mem];

NumericOps: REF CedarCode.OperationsBody _ NEW[CedarCode.OperationsBody_[
store: NumericStore,
load: NumericLoad]];

NumericStore: PROC[valType: Type, valNode: Node, indirectType: Type, indirectNode: Node, cc: CC] = {
nodeData: REF NumericNodeData ~ NARROW[CedarCode.GetDataFromNode[indirectNode]];
mem: Mem ~ nodeData.mem;
type: Type ~ CCTypes.GetRTargetType[indirectType, cc];
descriptor: CNumericTypes.NumericDescriptor ~ CNumericTypes.GetDescriptorFromCNumericType[type, cc];
valRep: REF ANY ~ CedarCode.GetNodeRepresentation[valNode, cc];
Bitch: PROC ~ {CCE[operation, "storing non-C numbers into C numeric locations"]};
fieldSize: BitAddr ~ mem.MemGetSize[];
SELECT fieldSize.BaToBits[] FROM
0 => CCE[operation, "storing into 0-bit numeric location"];
8 => WITH valRep SELECT FROM
x: REF CHAR => mem.MemWrite[x^.ORD, 8, zeroBA];
ENDCASE => Bitch[];
16 => SELECT descriptor.primary FROM
signed => WITH valRep SELECT FROM
x: REF INTEGER => mem.MemWrite[offset:zeroBA, bitSize:16, bits: IF x^>=0 THEN CARD[x^] ELSE CARD[INT[x^]+65536]];
ENDCASE => Bitch[];
unsigned => WITH valRep SELECT FROM
x: REF CARDINAL => mem.MemWrite[offset:zeroBA, bitSize:16, bits:x^];
ENDCASE => Bitch[];
ENDCASE => CCE[cirioError, "unexpected 16-bit descriptor"];
32 => SELECT descriptor.primary FROM
signed =>WITH valRep SELECT FROM
x: REF INT => mem.MemWrite[offset:zeroBA, bitSize:32, bits:LOOPHOLE[x^]];
ENDCASE => Bitch[];
unsigned => WITH valRep SELECT FROM
x: REF CARD => mem.MemWrite[offset:zeroBA, bitSize:32, bits:x^];
ENDCASE => Bitch[];
float => WITH valRep SELECT FROM
x: REF REAL => mem.MemWrite[offset:zeroBA, bitSize:32, bits:LOOPHOLE[x^]];
ENDCASE => Bitch[];
ENDCASE => CCE[cirioError, "unexpected 32-bit descriptor"];
64 => CCE[unimplemented, "double store"];
ENDCASE => CCE[cirioError, "strange numeric width"]};

NumericLoad: PROC[indirectType: Type, indirectNode: Node, cc: CC] RETURNS[Node] ~ {
nodeData: REF NumericNodeData ~ NARROW[CedarCode.GetDataFromNode[indirectNode]];
mem: Mem ~ nodeData.mem;
type: Type ~ CCTypes.GetRTargetType[indirectType, cc];
descriptor: CNumericTypes.NumericDescriptor ~ CNumericTypes.GetDescriptorFromCNumericType[type, cc];
{ENABLE CirioNubAccess.RemoteAddrFault => GOTO unknownAddress;
fieldSize: BitAddr ~ mem.MemGetSize[];
SELECT fieldSize.BaToBits[] FROM
0 => RETURN[LoadFromUnknownIndirect[indirectType, indirectNode, cc]];
8 => {
bits: CARD _ mem.MemRead[offset: zeroBA, bitSize: 8];
char: CHAR _ VAL[BYTE[bits]];
RETURN CNumericTypes.CreateNumericNode[type, NEW[CHAR _ char]]};
16 => SELECT descriptor.primary FROM
signed => {
bits: CARD _ mem.MemRead[offset: zeroBA, bitSize: 16];
word: INTEGER _ IF bits <= LAST[INT16] THEN bits ELSE INT[bits] - INT[LAST[CARD16]].SUCC;
RETURN CNumericTypes.CreateNumericNode[type, NEW[SIRep _ word]]};
unsigned => {
bits: CARD _ mem.MemRead[offset: zeroBA, bitSize: 16];
RETURN CNumericTypes.CreateNumericNode[type, NEW[SCRep _ bits]]};
ENDCASE => CCE[cirioError, "NumericLoad: unrecognized 16-bit primary"];
32 => {
typeClass: CirioTypes.TypeClass _ CCTypes.GetTypeClass[type];
SELECT typeClass FROM
$numeric => {
SELECT descriptor.primary FROM
signed => {
bits: CARD _ mem.MemRead[offset: zeroBA, bitSize: 32];
word: INT _ LOOPHOLE[bits];
RETURN CNumericTypes.CreateNumericNode[type, NEW[LIRep _ word]]};
unsigned => {
word: CARD _ mem.MemRead[offset: zeroBA, bitSize: 32];
RETURN CNumericTypes.CreateNumericNode[type, NEW[LCRep _ word]]};
float => {
bits: CARD _ mem.MemRead[offset: zeroBA, bitSize: 32];
word: REAL _ LOOPHOLE[bits];
RETURN CNumericTypes.CreateNumericNode[type, NEW[REAL _ word]]};
ENDCASE => CCE[cirioError, "NumericLoad: unrecognized 32-bit primary"];
};
ENDCASE => CCE[cirioError, "NumericLoad: unrecognized 32-bit type class"];
};
64 => RETURN[NumericLoad64BitsIndirect[indirectType, indirectNode, cc]];
ENDCASE => RETURN[NumericLoadBitFieldIndirect[indirectType, indirectNode, cc]];
EXITS unknownAddress => RETURN[LoadFromUnknownIndirect[indirectType, indirectNode, cc]]}};

NumericLoad64BitsIndirect: PROC[indirectType: Type, indirectNode: Node, cc: CC] RETURNS[Node] = {
oneWord: BitAddr ~ CirioTypes.BitsToBa[32];
nodeData: REF NumericNodeData _ NARROW[CedarCode.GetDataFromNode[indirectNode]];
mem: Mem _ nodeData.mem;
type: Type _ CCTypes.GetRTargetType[indirectType, cc];
word1: PBasics.Word _ LOOPHOLE[mem.MemRead[offset: zeroBA, bitSize: 32], PBasics.Word];
word2: PBasics.Word _ LOOPHOLE[mem.MemRead[offset: oneWord, bitSize: 32], PBasics.Word];
sign: INT _ LOOPHOLE[PBasics.BITSHIFT[word1, -31], CARD] * -2 + 1;
exponent: INT _ LOOPHOLE[PBasics.BITSHIFT[word1, -20], CARD];
mantissa: REAL _ LOOPHOLE[PBasics.BITSHIFT[PBasics.BITOR[PBasics.BITSHIFT[word1, 12], PBasics.BITSHIFT[word2, -20]], -1], CARD] * RealFns.Power[2, -32] *2 + 1;
word:REAL _ sign * RealFns.Power[2, exponent - 1023] * mantissa;

wordNode: Node _ CNumericTypes.CreateNumericNode[type, NEW[REAL _ word]];
RETURN[wordNode]};

NumericLoadBitFieldIndirect: PROC[indirectType: Type, indirectNode: Node, cc: CC] RETURNS[Node] = {
nodeData: REF NumericNodeData _ NARROW[CedarCode.GetDataFromNode[indirectNode]];
mem: Mem _ nodeData.mem;
type: Type _ CCTypes.GetRTargetType[indirectType, cc];
typeClass: CirioTypes.TypeClass _ CCTypes.GetTypeClass[type];
SELECT typeClass FROM
$numeric =>
BEGIN
descriptor: CNumericTypes.NumericDescriptor _ CNumericTypes.GetDescriptorFromCNumericType[type, cc];
SELECT descriptor.primary FROM
signed =>
BEGIN
SELECT descriptor.secondary FROM
integer => 
BEGIN
bits: CARD _ mem.MemRead[offset: zeroBA, bitSize: 32];
word: INT _ LOOPHOLE[bits];
wordNode: Node _ CNumericTypes.CreateNumericNode[type, NEW[LIRep _ word]];
RETURN[wordNode];
END;
ENDCASE => CCE[cirioError];  -- descriptor.secondary
END;
ENDCASE => CCE[cirioError];  -- descriptor.primary
END;
ENDCASE => CCE[cirioError];  -- typeClass
};

LoadFromUnknownIndirect: PROC[indirectType: Type, indirectNode: Node, cc: CC] RETURNS[Node] =
BEGIN
wordType: Type _ CedarOtherPureTypes.CreateUnknownType[cc, "Unimplemented type"];
wordNode: Node _  CedarOtherPureTypes.CreateIndirectToAnUnknownType[wordType, "Unimplemented type", cc];
RETURN[wordNode];
END;





AnalyzeRecordTypeStab: PROC[sourceStream: IO.STREAM, bracketEntry: BracketEntry, rctw: RCTWData] RETURNS[AnalyzedTypeInfo] = {
analyzedCTX: AnalyzedCTX;
RETURN[AnalyzeCTX[sourceStream, bracketEntry, rctw]];
};

AnalyzeCTX: PROC[sourceStream: IO.STREAM, bracketEntry: BracketEntry, rctw: RCTWData] RETURNS[AnalyzedTypeInfo] = {
fieldCount: INT _ 0;
fieldNameList: LIST OF Rope.ROPE _ NIL;
atiList: LIST OF AnalyzedTypeInfo _ NIL;
bitOffsetList: LIST OF INT _ NIL;
bitSizeList: LIST OF INT _ NIL;
byteSize: INT;
lastBitOffset: INT _ -1;  -- Assume there are no negative offsets
lastBitSize: INT;
totalBitSize: CARD;
result: AnalyzedCTX;
resultATI: AnalyzedTypeInfo;

char: CHAR _ IO.GetChar[sourceStream];
byteSize _ GetDecimal[sourceStream];
WHILE NOT IO.EndOf[sourceStream] DO
bitSize: INT;
bitOffset: INT;
ati: AnalyzedTypeInfo;
fieldName: Rope.ROPE;
IF IO.PeekChar[sourceStream] = '; THEN  EXIT;
fieldName _ GetTokenRope[sourceStream];
IF IO.GetChar[sourceStream] # ': THEN CCE[cirioError];
ati _ AnalyzeType[sourceStream, bracketEntry, rctw];
IF IO.GetChar[sourceStream] # ', THEN CCE[cirioError];
bitOffset _ GetDecimal[sourceStream];
IF IO.GetChar[sourceStream] # ', THEN CCE[cirioError];
bitSize _ GetDecimal[sourceStream];
IF IO.GetChar[sourceStream] # '; THEN CCE[cirioError];
fieldNameList _ CONS[fieldName, fieldNameList];
atiList _ CONS[ati, atiList];
bitOffsetList _ CONS[bitOffset, bitOffsetList];
bitSizeList _ CONS[bitSize, bitSizeList];
IF bitOffset > lastBitOffset THEN {
lastBitOffset _ bitOffset;
lastBitSize _ bitSize;
};
fieldCount _ fieldCount +1
ENDLOOP;

totalBitSize _ lastBitOffset + lastBitSize;

result _ NEW[AnalyzedCTXBody[fieldCount]];
result.blockRecord _ FALSE;
result.rctw _ rctw;
result.bitSize _ CirioTypes.BitsToBa[totalBitSize];
FOR i:INT DECREASING IN [0..fieldCount) DO
result[i] _ [
name: fieldNameList.first,
fiValid: TRUE,
fiIsProc: atiList.first.atiIsProc,
fieldDirectType: atiList.first.directType,
fieldCase: nodeTimeReadWrite,
fieldLoc: NEW[BitStretch _ [CirioTypes.BitsToBa[bitOffsetList.first], CirioTypes.BitsToBa[bitSizeList.first] ]]
];
fieldNameList _ fieldNameList.rest;
atiList _ atiList.rest;
bitOffsetList _ bitOffsetList.rest;
bitSizeList _ bitSizeList.rest;
ENDLOOP;
result.recordType _ Records.CreateRecordType[CTXRecordTypeProcs, rctw.cc, result];
resultATI _ NEW[AnalyzedTypeInfoBody _ [atiValid: TRUE, atiIsProc: FALSE, directType: result.recordType, rctw: rctw]];
RETURN[resultATI]};

RopeFromStringTable: PROC [table: SGI.StringTable, offset: CARD]
RETURNS [name: Rope.ROPE _ NIL] =
TRUSTED
{
c: CHAR;

DO
c _ LOOPHOLE[table[offset]];
IF (c = VAL[0]) THEN
EXIT;
name _ name.Concat[Convert.RopeFromChar[from: c, quote: FALSE]];
offset _ offset + 1;
ENDLOOP;

RETURN
};

AnalyzeStructTypeFileStab: PROC[auxIndex: INT32, fdIndex: INT32, wireTables: SGI.WireTables, bracketEntry: BracketEntry, rctw: RCTWData, stab: ObjF.Stab, symTabIndex: CARD] RETURNS[AnalyzedTypeInfo] = TRUSTED {
fieldCount: INT _ 0;
fieldNameList: LIST OF Rope.ROPE _ NIL;
atiList: LIST OF AnalyzedTypeInfo _ NIL;
bitOffsetList: LIST OF INT _ NIL;
bitSizeList: LIST OF INT _ NIL;
lastBitOffset: INT _ -1;  -- Assume there are no negative offsets
lastBitSize: INT;
totalBitSize: CARD;
result: AnalyzedCTX;
resultATI: AnalyzedTypeInfo;
auxSyms: SGI.AuxSymTable _ wireTables.auxSyms;
symBaseIndex, symIndex, currentIndex, memberIndex: CARD;
stringBaseIndex: CARD;
endStruct: CARD;
stringOffset: CARD;
bitSize: INT32;
bitOffset: INT32 _ 0;
stringTable: SGI.StringTable _ wireTables.localStrings;
relIndex: SGI.WireRelIndexBody;
relFileIndex: INT32;
relFileOffset: INT32;


IF auxSyms[auxIndex+1].symIndex = -1 THEN 
{
resultATI _ NEW[AnalyzedTypeInfoBody _ [atiValid: TRUE, atiIsProc: FALSE, directType: AnalyzeNumericFileStab[[primary: signed, secondary: integer], 0, rctw].directType, rctw: rctw]];
RETURN[resultATI]
};

relIndex _ auxSyms[auxIndex+1].relIndex;
IF relIndex.relFileDescrIndex = 0FFFH THEN
{
relFileIndex _ auxSyms[auxIndex+2].relFileIndex;
}
ELSE
{
relFileIndex _ relIndex.relFileDescrIndex;
};
relFileOffset _ wireTables.fileDescr[fdIndex].rfdBase +  relFileIndex;
IF relFileOffset # 0 THEN
fdIndex _ wireTables.relFiles[relFileOffset];

symIndex _ relIndex.index;
symBaseIndex _ wireTables.fileDescr[fdIndex].isymBase;
stringBaseIndex _ wireTables.fileDescr[fdIndex].issBase;
currentIndex _ symIndex + symBaseIndex;
endStruct _ wireTables.localSyms[currentIndex].index + symBaseIndex - 1;


memberIndex _ currentIndex + 1;

WHILE memberIndex < endStruct DO
ati: AnalyzedTypeInfo;
fieldName: Rope.ROPE;

stringOffset _ wireTables.localSyms[memberIndex].symStringIndex;
fieldName _ RopeFromStringTable[stringTable, stringBaseIndex+stringOffset];
auxIndex _ wireTables.fileDescr[fdIndex].iauxBase + wireTables.localSyms[memberIndex].index;
ati _ AnalyzeTypeFromFile[auxIndex, wireTables, bracketEntry, rctw, stab, memberIndex];
bitSize _ SGI.CalcSymbolSize[memberIndex, fdIndex, wireTables, FALSE];
bitOffset _ wireTables.localSyms[memberIndex].value;

fieldNameList _ CONS[fieldName, fieldNameList];
atiList _ CONS[ati, atiList];
bitOffsetList _ CONS[bitOffset, bitOffsetList];
bitSizeList _ CONS[bitSize, bitSizeList];
IF bitOffset > lastBitOffset THEN {
lastBitOffset _ bitOffset;
lastBitSize _ bitSize;
};
fieldCount _ fieldCount +1;
memberIndex _ memberIndex +1
ENDLOOP;

totalBitSize _ lastBitOffset + lastBitSize;

result _ NEW[AnalyzedCTXBody[fieldCount]];
result.blockRecord _ FALSE;
result.rctw _ rctw;
result.bitSize _ CirioTypes.BitsToBa[totalBitSize];
FOR i:INT DECREASING IN [0..fieldCount) DO
result[i] _ [
name: fieldNameList.first,
fiValid: TRUE,
fiIsProc: atiList.first.atiIsProc,
fieldDirectType: atiList.first.directType,
fieldCase: nodeTimeReadWrite,
fieldLoc: NEW[BitStretch _ [CirioTypes.BitsToBa[bitOffsetList.first], CirioTypes.BitsToBa[bitSizeList.first] ]]
];
fieldNameList _ fieldNameList.rest;
atiList _ atiList.rest;
bitOffsetList _ bitOffsetList.rest;
bitSizeList _ bitSizeList.rest;
ENDLOOP;
result.recordType _ Records.CreateRecordType[CTXRecordTypeProcs, rctw.cc, result];
resultATI _ NEW[AnalyzedTypeInfoBody _ [atiValid: TRUE, atiIsProc: FALSE, directType: result.recordType, rctw: rctw]];
RETURN[resultATI]};


CTXRecordTypeProcs: PUBLIC REF Records.RecordTypeProcs _ NEW[Records.RecordTypeProcs_[
createIndirectNode: CTXRecordsCreateIndirectNode,
getBitSize: CTXRecordsGetBitSize,
getPaint: CTXRecordsGetPaint,
comparePaint: CTXRecordsComparePaint,
nFields: CTXRecordsNFields,
fieldIndexToName: CTXRecordsFieldIndexToName,
nameToFieldIndex: CTXRecordsNameToFieldIndex,
fieldIndexToType: CTXRecordsFieldIndexToType,
fieldIndexToFieldCase: CTXRecordsFieldIndexToFieldCase,
fieldIndexToCompileTimeConstantValue: CTXRecordsFieldIndexToTypeTimeConstant]];

CTXRecordsGetPaint: PROC[data: REF ANY] RETURNS[REF ANY] = {
ac: AnalyzedCTX _ NARROW[data];
RETURN[ac]};

CTXRecordsComparePaint: PROC[data: REF ANY, otherPaint: REF ANY] RETURNS[BOOLEAN] =
BEGIN
ac: AnalyzedCTX _ NARROW[data];
IF otherPaint = NIL THEN CCE[cirioError]; -- we shouldn't be called in this situation
WITH otherPaint SELECT FROM
other: AnalyzedCTX => RETURN[ac = other];
ENDCASE => RETURN[FALSE];
END;

CTXRecordsNFields: PROC[data: REF ANY] RETURNS[INT] =
BEGIN
ac: AnalyzedCTX _ NARROW[data];
RETURN[ac.nFields];
END;

CTXRecordsFieldIndexToName: PROC[index: INT, data: REF ANY] RETURNS[Rope.ROPE] =
BEGIN
ac: AnalyzedCTX _ NARROW[data];
RETURN[ac.fields[index].name];
END;

CTXRecordsNameToFieldIndex: PROC[name: Rope.ROPE, data: REF ANY] RETURNS[INT] =
BEGIN
ac: AnalyzedCTX _ NARROW[data];
FOR I: INT IN [0..ac.nFields) DO
IF Rope.Equal[name, ac.fields[I].name] THEN RETURN[I];
ENDLOOP;
RETURN[-1];
END;

CTXRecordsFieldIndexToType: PROC[index: INT, cc: CC, data: REF ANY] RETURNS [Type] ~ {
ac: AnalyzedCTX ~ NARROW[data];
IF NOT ac.fields[index].fiValid THEN {
directType: Type ~ IF ac.blockRecord
THEN NARROW[ac.fields[index].idStab, DotOListing].directType
ELSE ac.fields[index].directType;
ac.fields[index].fieldDirectType _ directType;
ac.fields[index].fieldCase _ IF ac.blockRecord AND ac.fields[index].fiIsProc THEN nodeTimeConstant ELSE nodeTimeReadWrite;
ac.fields[index].fiValid _ TRUE;
IF ac.blockRecord THEN ac.fields[index].fieldLoc _ VarLocFromDotOListings[ac.fields[index].idStab, ac.rctw];
};
RETURN [ac.fields[index].fieldDirectType]};

CTXRecordsFieldIndexToFieldCase: PROC[index: INT, cc: CC, data: REF ANY] RETURNS[Records.FieldCase] ~ {
ac: AnalyzedCTX ~ NARROW[data];
[] _ CTXRecordsFieldIndexToType[index, cc, data]; --ensure ac.fields[index].fiValid
RETURN [ac.fields[index].fieldCase]};
CTXRecordsFieldIndexToTypeTimeConstant: PROC[index: INT, cc: CC, data: REF ANY] RETURNS[Node] ~ {
ac: AnalyzedCTX ~ NARROW[data];
IF NOT ac.blockRecord THEN CCE[cirioError, "asking for type-time constant from a non-block C record"];
WITH ac[index].idStab SELECT FROM
x: DotOEnumr => RETURN CNumericTypes.CreateNumericNode[x.type, NEW[LIRep _ x.value]];
x: DotOListing => CCE[cirioError, IO.PutFR1["asking for field %g as type-time constant", [integer[index]] ]];
ENDCASE => ERROR;
};

CTXRecordsGetBitSize: PROC[indirectType: Type, cc: CC, data: REF ANY] RETURNS[CARD] = {
ac: AnalyzedCTX ~ NARROW[data];
RETURN [ac.bitSize.BaToBits[]]};

CTXRecordsCreateIndirectNode: PROC [cc: CC, data: REF ANY, indirectType, targetType: Type, mem: CirioTypes.Mem] RETURNS [Node] ~ {
ac: AnalyzedCTX ~ NARROW[data];
nodeData: REF RecordNodeData ~ NEW [RecordNodeData _ [ac, targetType, mem]];
RETURN[Records.CreateIndirectRecordNode[targetType, RecordProcs, nodeData, ac.rctw.cc]]};

RecordNodeData: TYPE = RECORD[
private: AnalyzedCTX,
targetType: Type,
mem: Mem];

RecordProcs: REF Records.IndirectRecordNodeProcs _ NEW[Records.IndirectRecordNodeProcs_[
selectField: RecordSelectField,
fieldIndexToNodeTimeConstantValue: RecordIndexToNTConstant]];

RecordSelectField: PROC[index: INT, indirectFieldType: Type, data: REF ANY, cc: CC] RETURNS[Node] = {
nodeData: REF RecordNodeData ~ NARROW[data];
ac: AnalyzedCTX ~ nodeData.private;
rctw: RCTWData ~ ac.rctw;
fieldType: Type;
subMem: Mem;
IF ac.blockRecord THEN {
varLoc: VarLoc _ NARROW[ac.fields[index].fieldLoc];
IF NOT ac.fields[index].fiValid THEN CCE[cirioError, "select block record field with NOT fiValid"];
subMem _ RMTWPrivate.SelectVarLoc[rctw.nub, nodeData.mem, varLoc];
RETURN CCTypes.CreateIndirectNode[indirectFieldType, subMem, cc]}
ELSE {
fieldLoc: REF BitStretch _ NARROW[ac.fields[index].fieldLoc];
IF NOT ac.fields[index].fiValid THEN CCE[cirioError, "trying to select an unanalyzed field"];
IF fieldLoc = NIL THEN RETURN UnimplementedTypeNode[indirectFieldType, rctw, IO.PutFR1["ordinary record field (index %g) with unknown location", [integer[index]]], TRUE];
subMem _ nodeData.mem.MemSubfield[fieldLoc^];
RETURN CCTypes.CreateIndirectNode[indirectFieldType, subMem, cc]}};

RecordIndexToNTConstant: PROC[index: INT, fieldType: Type, data: REF ANY, cc: CC] RETURNS[Node] ~ {
nodeData: REF RecordNodeData ~ NARROW[data];
ac: AnalyzedCTX ~ nodeData.private;
rctw: RCTWData ~ ac.rctw;
fieldLoc: REF ANY ~ ac.fields[index].fieldLoc;
IF NOT ac.fields[index].fiValid THEN CCE[cirioError, "trying to construct the node-time constant value for an unanalyzed field"];
IF ac.fields[index].fieldCase#nodeTimeConstant THEN CCE[cirioError, ac.fields[index].name.Concat[" is not a node-time constant"]];
WITH fieldLoc SELECT FROM
vl: VarLoc => {
codeMem: Mem ~ RMTWPrivate.SelectVarLoc[rctw.nub, nodeData.mem, vl];
pcBa: BitAddr ~ codeMem.MemGetStart[];
pc: CARD ~ pcBa.BaToPtr[];
pdd: ProcDirectData ~ NEW[ProcDirectDataPrivate _ [rctw.lsh, pc]];
pni: Procedures.ProcedureNodeInfo ~ NEW [Procedures.ProcedureNodeInfoBody _ [
call: CallProc, show: DescribeProc, data: pdd]];
RETURN Procedures.CreateProcedureNode[fieldType, pni]};
ENDCASE => CCE[cirioError, "RecordIndexToNTConstant[fieldLoc not a Varloc"]};

END..


���
RCTWOrdinaries.mesa
Copyright Ó 1989, 1990, 1991, 1992 by Xerox Corporation.  All rights reserved.
Hopcroft, August 18, 1989 6:25:15 pm PDT
Last changed by Theimer on October 9, 1989 2:06:28 pm PDT
Sturgis, January 2, 1990 12:21:25 pm PST
Last tweaked by Mike Spreitzer on April 10, 1992 6:19 pm PDT
Philip James, February 24, 1992 10:22 am PST
Laurie Horton, June 24, 1992 6:47 pm PDT
Chauser, June 1, 1992 1:10 pm PDT
Katsuyuki Komatsu December 17, 1992 5:59 pm PST
Jas, January 5, 1993 12:04 pm PST

If this is a definition, then check if already defined.
If so, then ERROR.
Otherwise,
Create a DeferringType that is undefined.
Do the analysis (recursively).
Set the DeferringType to the result of the analysis.
Return the DeferringType.

If a typeref but not a definition, then check if defined.
If not, create an UnknownType.
Return the UnknownType.
Otherwise,
Return the Type.

If not a typeref, then
Do the analysis (recursively).
Return the Type.

access the current symbol entry and the file descriptor index
Record Types
Unknown Types
GetDecimal: PROC [stream: IO.STREAM] RETURNS [INT] ~ {
token: Rope.ROPE _ "";
value: INT _ -1;
base: CARD _ 10;
parsed: BOOL _ FALSE;
char: CHAR _ IO.PeekChar[stream];
IF char = '- OR char = '+ THEN {
token _ Rope.FromChar[IO.GetChar[stream]];
char _ IO.PeekChar[stream];
};
IF char = '0 THEN {
[] _ IO.GetChar[stream];
token _ Rope.Concat[token, "0"];
base _ 10;
parsed _ FALSE;
IF NOT IO.EndOf[stream] THEN {
parsed _ TRUE;
char _ IO.PeekChar[stream];
IF char = 'x THEN {
[] _ IO.GetChar[stream];
WHILE NOT IO.EndOf[stream] AND IsHexDigit[IO.PeekChar[stream]] DO
token _ Rope.Concat[token, Rope.FromChar[IO.GetChar[stream]]];
ENDLOOP;
base _ 16;
parsed _ TRUE;
};
};
};
IF NOT parsed THEN {
WHILE NOT IO.EndOf[stream] AND IsDigit[IO.PeekChar[stream]] DO
token _ Rope.Concat[token, Rope.FromChar[IO.GetChar[stream]]];
ENDLOOP;
base _ 10;
parsed _ TRUE;
};

IF parsed THEN {
value _ Convert.IntFromRope[token, base ! 
Convert.Error => {
value _ LOOPHOLE[(Convert.CardFromRope[token, base]), INT];
CONTINUE;
};
];
};
RETURN[value];
};
Create a DeferringType as a place holder and put it in the hash table


Create a DeferringType as a place holder and put it in the hash table
the new auxIndex is the stTypedef symbols` auxIndex


Deferring Types
Unknown Types
PointerTypes

we nest a block to handle unknown address, allowing nodeData to be visible
PointerAdd: PROC [node: Node, offsetNode: Node, info: CPointerTypes.PointerNodeInfo, cc: CC] RETURNS [Node] ~ {
nodeData: REF PointerNodeData _ NARROW[CedarCode.GetDataFromNode[node]];
bfs: BitFieldSchema _ nodeData.nsData.bfs;
mem: Mem _ nodeData.mem;
addr: CirioNubAccess.RemoteAddress _ bfs.procs.followPointer[bfs, nodeData.mem];
offset: INT _ NARROW[CedarCode.GetDataFromNode[offsetNode], REF INT]^;
bitSize: CARD _ nodeData.nsData.private.analyzedTargetTypeStab.bitSize[ nodeData.nsData.private.analyzedTargetTypeStab, cc];
normalizedAddr: CirioNubAccess.RemoteAddress _ RemoteAddressNormalize[addr];
newAddr: CirioNubAccess.RemoteAddress _  [nub: normalizedAddr.nub, byteAddress: normalizedAddr.byteAddress + (offset * bitSize) / 8,  bitOffset: normalizedAddr.bitOffset + (offset * bitSize) MOD 8, nil: FALSE, valid: normalizedAddr.valid];
newMem: Mem _ CreateRawMem[newAddr];
newNodeData: REF PointerNodeData _ NEW[PointerNodeData _ [nsData: nodeData.nsData, mem: newMem]];
RETURN[CPointerTypes.CreatePointerNode[nodeData.nsData.private.type, info, cc]];
};
PointerSubtract: PROC [leftNode: Node, rightNode: Node, cc: CC] RETURNS [Node] ~ {
leftNodeData: REF PointerNodeData _ NARROW[CedarCode.GetDataFromNode[leftNode]];
leftrctw: RCTWData _ leftNodeData.nsData.private.rctw;
leftBfs: BitFieldSchema _ leftNodeData.nsData.bfs;
leftMem: Mem _ leftNodeData.mem;
leftAddr: CirioNubAccess.RemoteAddress _ leftBfs.procs.followPointer[leftBfs, leftMem];
bitSize: CARD _ leftNodeData.nsData.private.analyzedTargetTypeStab.bitSize[ leftNodeData.nsData.private.analyzedTargetTypeStab, leftrctw];
rightNodeData: REF PointerNodeData _ NARROW[CedarCode.GetDataFromNode[rightNode]];
rightBfs: BitFieldSchema _ rightNodeData.nsData.bfs;
rightMem: Mem _ rightNodeData.mem;
rightAddr: CirioNubAccess.RemoteAddress _ rightBfs.procs.followPointer[rightBfs, rightMem];
difference: INT _  RemoteAddressByteDifference[leftAddr, rightAddr, bitSize];
newType: Type _ CNumericTypes.CreateNumericType[NEW[CNumericTypes.NumericDescriptorBody _ [primary: signed, secondary: integer]], cc];
RETURN[CNumericTypes.CreateNumericNode[newType, NEW[INT _ difference]]];
};

PointerCompare: PROC [leftNode: Node, rightNode: Node, op: CCTypes.Operator, cc: CC] RETURNS [Node] ~ {
leftNodeData: REF PointerNodeData _ NARROW[CedarCode.GetDataFromNode[leftNode]];
leftrctw: RCTWData _ leftNodeData.nsData.private.rctw;
leftBfs: BitFieldSchema _ leftNodeData.nsData.bfs;
leftMem: Mem _ leftNodeData.mem;
leftAddr: CirioNubAccess.RemoteAddress _ leftBfs.procs.followPointer[leftBfs, leftMem];
bitSize: CARD _ leftNodeData.nsData.private.analyzedTargetTypeStab.bitSize[ leftNodeData.nsData.private.analyzedTargetTypeStab, leftrctw];
rightNodeData: REF PointerNodeData _ NARROW[CedarCode.GetDataFromNode[rightNode]];
rightBfs: BitFieldSchema _ rightNodeData.nsData.bfs;
rightMem: Mem _ rightNodeData.mem;
rightAddr: CirioNubAccess.RemoteAddress _ rightBfs.procs.followPointer[rightBfs, rightMem];
returnValue: INT _ RemoteAddressCompare[leftAddr, rightAddr, op];
newType: Type _ CNumericTypes.CreateNumericType[NEW[CNumericTypes.NumericDescriptorBody _ [primary: signed, secondary: integer]], cc];
RETURN[CNumericTypes.CreateNumericNode[newType, NEW[INT _ returnValue]]];
};


Should be inline eventually
$le => IntFromBool[difference <= 0],
$lt => IntFromBool[difference < 0],
$eq => IntFromBool[difference = 0],
$ne => IntFromBool[difference # 0],
$gt => IntFromBool[difference > 0],
$ge => IntFromBool[difference >= 0],
Enumerated Types
This is an enumerated type
This is an enumerated type


set the current index to the first stMember
C Procedures

C Numeric Types


This is a bitwise type (SunOS 5.0)
This is a floating point type (SunOS 5.0)
This is a subrange or a floating point type
This is a floating point type
This is a subrange type


Note: subrange types need to be fixed to correctly compute the actual bit size of the representation.  Currently they use a value in the descriptor that describes the supertype.
Theimer: Need to eventually change the 32 to a more general constant defn.
Record Types
As a special dispensation, in order to handle empty argument/result records, this procedure will accept ctxh=NIL to produce an effectively empty record.
Note: Assuming that no C records have variants.
now we can build the result

Note: Assuming that no C records have variants.
there was a pointer to an undefined structure that never got dereferenced.
 just return a void

the index field is the reference to one symbol past the stEnd symbol for the structure
set the current index to the first stMember

the new auxIndex is the stMember symbols` auxIndex
now we can build the result

we shall use the address of the record data as the paint.  Note that we are trusting the assorted hash table mechanisms to prevent the construction of more than one RecordData for a given record type.
We could speed this up by using atoms
here is where we finally compute the field type, after we haved exited from the local type construction routine for the record as a whole.

should never happen, this field should have been filled in when someone inspected the type of the field.
should never happen, this field should have been filled in when someone inspected the type of the field.

Ê?��•NewlineDelimiter
–
"cedar" style™�code™K™NK™(K™9K™(K™<K™,K™(K™!K™/K™!—K˜�šÏk	˜	Kšœœ™˜¦Kšœ
œJ˜YKšœœJ˜cKšœ˜Kšœœ)˜=Kšœ˜KšœœN˜aKšœœ}˜Kšœœ$˜1Kšœ˜Kšœ˜Kšœœ0˜EK˜K˜Kšœœœœ˜2Kšœ
œœ˜K˜Kšœ˜Kšœœ˜'Kšœœ	˜Kšœœb˜oK˜Kšœœœ˜/K˜Kšœ˜Kšœ˜—K˜�KšÐlnœœ˜KšœŠœ@œK˜¢Kšœ˜KšœœœœÏnœœ˜9K˜�Kšœœ˜&Kšœœ&œœ˜NKšœœœ˜Kšœœœ˜Kšœœœ˜Kšœœœ˜K˜�šŸœœœœœ.œœ˜…™�™7K™šœ
™
Kšœ)™)K™K™4™K™�———™9™K™—™
K™—K™�—™K™K™—K™�Kšœœœ˜'šœœ˜
šœœœ˜šœœœÏc˜IKšœœ3˜:—šœ
 ˜%Kšœ?˜?—šœ
 *˜7Kšœ?˜?—šœ
 $˜1Kšœ?˜?—šœ
 +˜8Kšœ<˜<—šœ
 -˜:Kšœ?˜?—šœ
œ ,˜FKšœ>˜>—šœ
 ˜)KšœB˜B—šœ
œ ˜4KšœA˜A—šœ
 +˜8KšœA˜A—šœ˜
KšœL ˜i————˜�š
œœœœ
œd˜ˆK˜�—Kšœ˜—Kšœ˜K˜�—šŸœœœœhœœœœœ˜ÓKšœ1œ˜:Jšœ˜Jšœ.˜.Jšœ
œ˜Jšœ
œ "˜<Jšœ	œ˜J˜J˜�J™=šœ
˜J˜Jšœ
œ'˜9Jšœ9˜9J˜—š˜J˜Jšœ
œ%˜7Jšœ˜J˜—J˜�šœ˜J˜JšœZ˜ZJšœœ!œ
œ"˜cJ˜J˜�—J˜&J˜�J˜J˜�šœ˜šœ 
˜J˜Jšœ[˜[Jšœ˜—šœ ˜$Jšœ˜Jšœ]˜]Jšœ˜—šœ 	˜Jšœ˜Jšœ_˜_Jšœ˜—šœ ˜"Jšœ˜Jšœa˜aJšœ˜—Jšœ
 ˜Jšœ ˜šœ ˜Jšœ˜JšœZ˜ZJšœ˜—Jšœ 
˜Jšœ
 ˜šœ ˜Jšœ˜Jšœ\˜\Jšœ˜—Jšœ ˜šœ ˜ Jšœ˜JšœE˜EJšœ˜—šœ ˜Jšœ ˜	JšœY˜YJšœ˜J˜�—J˜�J™Jšœ ˜#šœ ˜!Jšœ˜Jšœr˜rJ˜—šœ
 ˜Jšœ˜Jšœv˜vJ˜—šœ )˜9Jšœ˜Jšœo˜oJ˜—Jšœœ "˜8Jšœ
œ ˜(J˜�J™
šœ ˜Jšœ6œc˜›—šœ ˜&Jšœ6œg˜Ÿ—šœ ˜-Jšœ6œn˜¦—Jšœœ ˜5šœ ˜$Jšœ6œe˜—šœ ˜$Jšœ6œe˜—šœ 
˜Jšœ6œ_˜——J˜�Jšœœ˜J˜�—Jšœœ!œ
œ"˜c—Kšœ˜˜�K˜�—š
Ðbnœœœœœ˜&Kšœœœœ˜&—K˜�š
¡
œœœœœ˜)Kšœœœœœœœœ˜L—K˜�šŸœœœœ	œœœ˜RKšœ	œ˜%Kš	œœœœœ˜!Kšœ˜šœœœ˜%Kšœ)˜)—Kšœ˜Kšœ˜Kšœ˜!K˜K˜�—šŸ
œœ
œœœœ˜6Kšœœ˜šœœœ˜,šœœœœ
˜)K˜�Kšœœ˜Kšœœœ˜!K˜�Kšœœ˜š˜Kšœœ˜*Kšœœ˜Kšœ˜—šœ˜Kš˜Kšœœ˜K˜ Kšœœ˜šœœ˜Kšœœ˜šœœ˜(Kšœ)œ˜>—Kšœ˜Kšœ ˜&Kš˜—Kšœ˜—šœ	œ˜%Kšœ)œ˜>—Kšœ˜Kšœ˜#š˜Kšœœ˜/—K˜—š˜Kšœœ˜—K˜—K˜K˜�—šŸ
œœ
œœœœ™6Kšœœ™Kšœœ™Kšœœ™Kšœœœ™Kšœœœ™!šœœœ™ Kšœœ™*Kšœœ™Kšœ™—šœœ™Kšœœ™K™ K™
Kšœ	œ™šœœœœ™Kšœ	œ™Kšœœ™šœœ™Kšœœ™šœœœœœ™AKšœ)œ™>—Kšœ™K™
Kšœ	œ™Kšœ™—K™—Kšœ™—šœœœ™šœœœœ	œ™>Kšœ)œ™>—Kšœ™K™
Kšœ	œ™K™—K™�šœœ™šœ*™*šœ™Kšœœ&œ™;Kšœ™	Kšœ™—Kšœ™—Kšœ™—Kšœ™K™—K˜�KšŸœœœ˜"š¡œœœœœœœœ˜‡Kšœ	œ.˜;Kšœœœ˜!Kšœœ˜š
œœœœœœ ˜Zšœœ˜(Kš	œœœœ  ˜LK˜�K™EKšœÏbœ˜K˜�šœ˜Kšœ‡˜‡—K˜�šœœ˜šœ&˜*Kšœ?˜BK˜�——Kšœœ/˜FK˜�šœ˜Kšœu˜u—K˜�šœœAœ˜MKšœœœ+˜NKšœœ
˜&š˜Kšœ,œ˜4KšœI˜IK˜�šœ˜Kšœ‚˜‚—K˜�KšœF˜FKšœ
˜
š˜š˜Kšœ7˜7—šœ˜KšœJ˜JKšœ˜—šœ˜Kšœ„˜„KšœF˜FKšœL˜L———K˜—Kšœ˜—šœ 
˜Kšœœ˜Kšœœœ˜Kšœ7˜7Kšœœ	˜K˜�Jšœœœ*˜;J˜�šœ˜šœœ˜Kšœn˜n—K˜šœ˜Kšœr˜r—J˜—Kšœ˜——Kš
œœœœ
œX˜|Kšœ˜Kšœ˜—K™�š¡Ÿœœœœ,œœ)œœœœ˜àK˜�Kšœœœ˜!Kšœœ˜Kšœ	œ˜Jšœ.˜.Jšœ&œ˜+Jšœœ˜Kšœœ˜(Jšœ7˜7Jšœœ˜Jšœ˜Jšœœ˜Jšœœ˜K˜�K™�Jšœ(˜(šœ$˜*J˜Jšœ0˜0J˜—š˜J˜Jšœ*˜*Jšœ˜—JšœF˜Fšœ˜Jšœ-˜-—J˜�Jšœ˜Jšœ6˜6Kšœ8˜8Kšœ'˜'J˜�JšœA˜AJ˜�KšœJ˜JK˜�K™Ešœ¢œ˜K˜�—šœ˜Kšœ‡˜‡K˜�—šœ8˜8K˜�—K™3šœ]˜]J˜�—šœe˜eK˜�—šœ˜Kšœu˜uK˜�—šœœAœ˜MKšœœœ+˜NKšœœ
˜&š˜Kšœ,œ˜4KšœI˜IK˜�šœ˜Kšœ‚˜‚—K˜�KšœF˜FKšœ
˜
š˜š˜Kšœ7˜7—šœ˜KšœJ˜JKšœ˜—šœ˜Kšœ˜K˜�KšœH˜HKšœJ˜J———K˜K˜�—Kš
œœœœ
œX˜|Kšœ˜Kšœ˜—K™�K™�K™˜�š¡
œœœœ˜HKšœB˜BKšœ%œ#œ
œ*˜‹Kšœ˜K˜K˜�——K˜�K™
˜�š
Ÿœœœœ.œ˜‡Kšœœ˜!Kšœœ˜$Kšœ
œ˜Kšœ
œ˜Kšœœœ˜Kšœ	œ	œœ1˜PKšœ˜KšœœœC˜cKšœœ*˜2Kšœ˜KšœD˜DKšœ
œœ˜#Kšœ!˜'š
Ÿœœœœœ˜0Kš	œœœœœ˜<—K˜�—š
Ÿœœœœœ˜dšœ%œ˜AKšœ
œ
œ˜!Kšœ;œj˜§Kšœ
˜
—Kšœ˜K˜—K˜�š
Ÿœœ7œœœ
˜yKšœO˜OKšœ
œœV˜mKšœO˜U——K˜�K™™�Kšœœœ˜@šœœœ˜+Kšœ˜Kšœ˜Kšœœ˜K˜Kšœ˜—K˜�š
Ÿœœœœ/œ˜€Kšœœœœœœœœœ\˜ºKš	œœœ/œœ˜bšœ
œœ˜šœœ˜'K˜
Kšœœœl˜€—Kšœœ˜	—KšœL˜LKšœœœ> k˜½šœ$œ˜EK˜Kšœ	˜	Kšœ)˜)—KšœœN˜fKšœ]˜]Kšœœ!œ
œ2˜s—K˜�šŸœœœœiœœ˜ÃKšœo˜ošœ$œ˜EK˜Kšœ	˜	Kšœ˜—KšœœN˜fKšœ]˜]Kšœœ!œ
œ2˜s—K˜�K˜�š
Ÿœœœ"œœ˜eKšœ#œ˜7Kšœ˜—K˜�šŸœœœ,œ˜uKšœ#œ˜7Kšœ
œœ#˜FKšœA˜G—K˜�šœœœ˜Kšœ!˜!K˜
—K˜�šŸ
œœœ˜IKšœ˜Kšœ˜—K˜�Kšœœœ˜/šœœœ˜%Kšœœ˜Kšœ	œ˜
Kšœœ˜Kšœ˜—K˜�š¡œœKœ˜dKšœ
œœ*˜PKšœ'˜'Kšœ˜Kšœ
œ˜*Kšœ	œœ&˜6šœ	œ˜šœ*˜*Kšœœ˜+Kšœ&˜&—Kšœœ<˜J—Kšœ˜—K˜�Kšœœ˜K˜�š¡œœ-œœ
˜SKšœ
œœ*˜PK˜'Kšœ˜Kšœ
œ˜*KšœJ™Jšœœ˜	Kšœ"œ˜6Kšœœ˜—Kšœ(˜(Kšœœ˜)Kšœ
œ#˜1KšœŠ˜ŠKšœ<˜<KšœE˜EKšœœ˜Kšœ$˜$Kšœ˜Kšœ$˜$šœ v˜xKšœœœ˜Kšœ:˜:Kšœ5˜5—Kšœ3œœ
œœœ˜ƒšœœ&˜0Kšœ#˜#KšœV˜VKšœ˜K˜Kšœ˜KšœœK˜T—KšœI˜OKšœ˜š˜KšœœNœ˜n—šœ˜K˜�——šŸ
œœIœœ˜kKšœœ0˜9—K˜�šŸœœ'œœ˜Ršœ%œ˜4Kšœ&œ1˜]KšœœI˜W——K˜�šŸ
œœWœœ˜€Kšœœ˜%Kšœœ˜"Kšœ"˜"šœœœ'œ˜WKšœœœ˜Kš	œœœœœ˜#Kšœœœœ˜KšœœD˜R—Kšœœ˜Kšœœœ(˜@KšœœœA˜eKšœ˜Kšœ	œœ
œ˜3KšœH˜HKšœe˜ešœ(œ&˜QKšœ'˜'Kšœ)˜)Kšœ˜K˜Kšœ˜Kšœœœ*˜UK˜—KšœH˜N—K˜�šŸœœ=œœ˜gšœ)œ%œ˜]Kšœ*˜*KšœœC˜Q—Kšœœ˜-šœ*œ&œ˜_Kšœ*˜*KšœœD˜R—Kšœœ˜/šœœœ˜K˜"K˜"K˜#K˜"K˜#K˜"Kšœœ
œJ˜g—Kšœ0œ?œ˜wKšœ*œœœœœ˜S—K˜�šŸ
œœMœ™oKšœ
œœ"™HKšœ*™*Kšœ™KšœP™PK™FKšœ|™|KšœL™LKšœï™ïK™$Kšœ
œQ™aKšœP™PK™—K˜�šŸœœ+œ™RKšœœœ&™PKšœ6™6Kšœ2™2Kšœ ™ KšœW™WKšœŠ™ŠKšœœœ'™RKšœ4™4Kšœ"™"Kšœ[™[KšœM™MKšœ†™†KšœH™HK™K™�—šŸœœAœ™gKšœœœ&™PKšœ6™6Kšœ2™2Kšœ ™ KšœW™WKšœŠ™ŠKšœœœ'™RKšœ4™4Kšœ"™"Kšœ[™[KšœA™AKšœ†™†KšœI™IK™K™�K™�—šŸœœ)œ#˜ošœ+œ
˜>KšœU˜U—š˜Kšœfœ,˜•—Kšœ˜K˜K˜�—š¡œœTœœœœ˜£Kšœ&˜&Kšœ'˜'šœœœ˜'Kšœ
˜—Kšœ'˜'Kšœ)˜)šœœ˜7Kšœ
˜—Kšœœf˜pK˜—K˜�Kš
Ÿœœœœœ˜-™šœ˜	Kšœ˜	—š˜Kšœ˜	—K˜—K˜�š¡œœaœœ˜ŒKšœœ˜Kšœ
œ˜KšœE˜Ešœ˜šœ˜Kšœœ˜/Kšœ˜K˜#K˜#Kšœ"œ˜1K˜K™$Kšœ#™#K™#K™#K™#K™$Kšœœ˜——K˜—K˜�—K™˜�š
¡œœœœ/œ˜…K™K˜&K˜Kšœ(˜(K˜LKšœœœœ˜#Kšœ˜Kšœœœ˜&šœœœœœœ˜GKšœœ˜Kšœ
œ˜/Kšœœ1˜Jšœœ˜ Kšœœ>˜F—K˜!Kš
œœœœ
œu˜–Kš	œ	œœœœ
˜ZKšœœ;œœ˜LKšœ&œœ˜@Kšœœœœ˜GKšœ˜—Kšœœ|˜†Kšœ
œK˜XKšœœN˜WK˜;šœœœ˜4šœœ˜Kšœ˜Kšœœ˜—Kšœ˜—šœœ˜#Kšœ
œ
œ˜!Kšœ˜Jšœ
˜
—K˜—K˜�š¡œœœœiœœœ˜ÙK™K˜&K˜Kšœ(˜(K˜LKšœœœœ˜#Kšœ˜Jšœ&œ˜+Jšœ.˜.Jšœ
œ˜Jšœœ˜$Jšœ7˜7Jšœ˜Jšœœ˜Jšœœ˜J™�K™�Jšœ(˜(šœ$˜*J˜Jšœ0˜0J˜—š˜J˜Jšœ*˜*Jšœ˜—JšœF˜Fšœ˜Jšœ-˜-—J˜�Jšœ˜Jšœ6˜6Kšœ8˜8J˜�Kšœ'˜'Jšœ8˜8K˜�K™+Kšœ ˜ J˜�šœœ˜!Kšœœ˜Kšœ
œ˜Kšœ˜K˜�KšœA˜Ašœ1˜1J˜�—KšœH˜HK˜�Kšœœ1˜<K˜�Kš
œœœœ
œu˜–Kš	œ	œœœœ
˜ZKšœœ;œœ˜LKšœ&œœ˜@K˜�Kšœ˜Kšœ˜—Kšœœ|˜†Kšœ
œK˜XKšœœN˜WK˜;šœœœ˜4šœœ˜Kšœ˜Kšœœ˜—Kšœ˜—šœœ˜#Kšœ
œ
œ˜!Kšœ˜Jšœ
˜
—K˜—K˜�K˜�š¡œœœœ˜=Kšœœœœœœœ˜8K˜—K˜�š¡
œœœœ˜9Kšœœœœ˜6Kšœœ˜)—K˜�K˜�—™K™�Kšœœœ˜7šœœœ˜)Kšœ˜Kšœ˜K˜—K˜�š
Ÿœœœœ/œ˜‚Kšœœ˜!Kšœœœœ0˜IKšœO˜OKšœœ1˜LKšœœ@˜XKšœy˜yšœœ˜#Kšœ
œ
œ˜ K˜K˜——K˜�š
Ÿœœœiœœ˜ÆK˜�K˜�Kšœr˜rKšœœ1˜LKšœœ@˜XKšœy˜yšœœ˜#Kšœ
œ
œ˜ K˜K˜——K˜�š
Ÿœœœ"œœ˜]Kšœœ˜—K˜�Kšœœœ˜5Kšœœœ5˜[K˜�šŸœœœ,œ
˜pKšœœ˜,Kšœœ2˜MKšœ@˜F—K˜�šŸœœœ˜NK˜K˜—K˜�Kšœœœ˜1šœœœ˜&Kšœœ˜Kšœœ˜	Kšœœœ˜—K˜�šŸ	œœKœ˜aKšœ8˜;—K˜�šŸœœ-œœ
˜PKšœœ*˜HKšœ˜Kšœ"˜"Kšœœ(˜Ašœ$œ&˜MK˜0—Kšœ+˜+Kšœ˜Kšœ2˜8—K˜�šŸœœœœœœ˜?Kšœœ5˜;—K˜�šŸœœœœœœœ˜GKšœœ˜#šœ
œœ˜Kšœœ˜#Kšœœœœ˜;KšœœœœD˜ašœ˜Kšœ	œY˜fšœ˜Kšœ˜!KšœœJ˜\—K˜—K˜—Kšœ˜—K˜�—™K™�Kšœ œœ$˜Nšœ$œœ˜2Kšœ˜Kšœ&˜&Kšœ	œ˜—K™�šŸœœ4œœ˜rKš˜Kšœ(œ.˜YKšœ*œQ˜~KšœœN˜fK˜Ašœœ˜#Kšœ
œ
œ˜!Kšœ˜Kšœ˜—Kšœ˜K˜�—š
Ÿœœœœ/œ˜~Kš˜Kšœ
 ™"Kšœœ˜*Kšœ
œ˜Kšœœ˜Kšœœ˜Kšœ%˜%Kšœœœ˜&Kšœœ˜ šœ˜Kšœ˜Kšœ˜Kšœœ3˜A—Kšœœœœ˜EKšœ'˜'Kšœœœœ,˜UK˜"Kšœœœœ,˜UK˜"šœœ˜š
œœœœœ
œœ˜FKšœ>˜D—š
œœœœœ
œœ˜DKšœ?˜E—š
œœœœœ
œœ˜FKšœC˜I—š
œœœœœ
œœ˜FKšœB˜H—šœ˜
KšœH˜N——Kšœ˜K˜�—š
Ÿœœœœ/œ˜{Kš˜Kšœ
 ™)Kšœœ˜*Kšœœ˜Kšœ
œ˜Kšœœœ˜&K˜"Kšœœœœ,˜UKšœ'˜'šœ
˜šœ +˜0Kšœ&˜,—šœ +˜0Kšœ'˜-—šœ +˜1Kšœ,˜2—šœ˜
KšœH˜N——Kšœ˜—K˜�šŸœœœ4œœœ˜Kš˜Kšœ(œ.˜YKšœ*œQ˜~KšœœN˜fK˜Ašœœ˜#Kšœ
œ
œ˜!Kšœ˜Kšœ˜—Kšœ˜J˜�—š
Ÿœœœœ/œ˜~Kš˜K™+Kšœœ˜*Kšœœ˜Kšœœ˜Kšœœ˜Kšœœœ˜&Kšœ7˜7Kšœœœœ,˜UK˜"Kšœœœœ,˜UK˜"šœ˜Kš˜K™šœ˜šœ +˜0Kšœ&˜,—šœ +˜0Kšœ'˜-—šœ˜
KšœH˜N——Kš˜—š˜š˜K™šœœ˜šœ	œœœ
œœ˜0Kšœ:˜@—šœœ˜ Kšœ;˜A—šœœ˜ Kšœ=˜C—šœ	œœœ
œœ˜3Kšœ?˜E—šœœ
œœ˜)KšœA˜G—šœœœ	œœœ˜6Kšœ<˜B—šœ˜
KšœH˜N———Kš˜—Kšœ˜—K™�š
Ÿœœœ"œœ˜eKšœ*œ˜>Kšœ˜—K™�šŸœœœ,œ
˜sKšœ*œ˜>Kšœ
œœB˜eKšœA˜G—K˜�šœœœ˜Kšœ˜Kšœ&˜&K˜K˜
—K˜�šŸ
œœœ˜IKšœ˜Kšœ˜—K˜�šŸœœKœ˜dKšœ
œœ*˜PKšœ˜Kšœ6˜6Kšœd˜dKšœœœ0˜?KšŸœœœ?˜QK˜&šœ˜ Kšœœ3˜;šœœœ˜Kšœœœœ
˜/Kšœ˜—šœœ˜$šœ
œœ˜!Kšœœœ2œœœœœœ
˜qKšœ˜—šœœœ˜#Kšœœœ5˜DKšœ˜—Kšœœ-˜;—šœœ˜$šœ	œœ˜ Kšœœœ1œ˜IKšœ˜—šœœœ˜#Kšœœœ5˜@Kšœ˜—šœ	œœ˜ Kšœœœ1œ˜JKšœ˜—Kšœœ-˜;—Kšœœ ˜)Kšœœ'˜5——˜�K™±—šŸœœ-œœ
˜SKšœ
œœ*˜PKšœ˜Kšœ6˜6Kšœd˜dKšœœ#œ˜>K˜&šœ˜ Kšœœ:˜Ešœ˜Kšœœ+˜5Kšœœœœ˜Kšœ'œœ˜@—šœœ˜$šœ˜Kšœœ,˜6Kšœœœ	œœœœœ	œœœœ˜YKšœ'œ˜A—šœ
˜
Kšœœ,˜6Kšœ'œ˜A—Kšœœ9˜G—šœ˜Kšœ=˜=šœ˜˜
šœ˜šœ˜Kšœœ,˜6Kšœœœ˜Kšœ'œ˜A—šœ
˜
Kšœœ,˜6Kšœ'œ˜A—šœ
˜
Kšœœ,˜6Kšœœœ˜Kšœ'œœ˜@—Kšœœ9˜G—Kšœ˜—Kšœœ<˜J—K˜—Kšœœ<˜HKšœœ>˜O—Kšœœ<˜Z—K˜�š¡œœ-œœ
˜aK˜+Kšœ
œœ*˜PKšœ˜Kšœ6˜6Kšœœ9˜WKšœœ:˜XKš	œœœ	œœ˜BKš	œ
œœ	œœ˜=Kšœ
œœ	œ	œ	œœœ!˜ŸKšœœ7˜@K˜�Kšœ7œœ
˜IKšœ˜—K˜�š¡œœ-œœ
˜cKšœ
œœ*˜PKšœ˜Kšœ6˜6Kšœ=˜=šœ˜˜Kš˜Kšœd˜dšœ˜šœ	˜	Kš˜šœ˜ šœ˜Kš˜šœœ,˜6K™J—Kšœœœ˜Kšœ7œ˜JKšœ˜Kšœ˜—Kšœœ ˜4—Kšœ˜—Kšœœ ˜2—Kšœ˜—Kšœœ ˜)—Kšœ˜—K˜�š¡œœ-œœ˜]Kš˜K˜QK˜hKšœ˜Kšœ˜——K˜�K˜�K˜�™K˜�K˜�š
Ÿœœœœ.œ˜~Kšœ˜Kšœ/˜5Kšœ˜—K˜�Kšœmœ(™˜š
Ÿ
œœœœ.œ˜sK™/Kšœœ˜Kš	œœœœœ˜'Kšœ	œœœ˜(Kš	œœœœœ˜!Kš	œ
œœœœ˜Kšœ
œ˜Kšœœ '˜AKšœ
œ˜Kšœœ˜Kšœ˜Kšœ˜K˜�Kšœœœ˜&K˜$šœœœ˜#Kšœ	œ˜
Kšœœ˜Kšœ˜Kšœœ˜Kšœœœœ˜-K˜'Kšœœœœ
˜6Kšœ4˜4Kšœœœœ
˜6K˜%Kšœœœœ
˜6K˜#Kšœœœœ
˜6Kšœœ˜/Kšœ
œ˜Kšœœ˜/Kšœœ˜)šœœ˜#K˜K˜Kšœ˜—K˜Kšœ˜—K˜�K˜+K˜�K™K™�Kšœ	œ˜*Kšœœ˜Kšœ˜Kšœ3˜3š	œœ
œœ˜*šœ
˜
Kšœ˜Kšœ	œ˜Kšœ"˜"Kšœ*˜*Kšœ˜Kšœ
œb˜oKšœ˜—K˜#K˜K˜#K˜Kšœ˜—KšœR˜RKšœœ#œ
œ.˜vKšœ
˜—K˜�šŸœœ"œ˜@Jšœ
œœ˜!—Jš˜˜Jšœœ˜—˜�š˜Jšœœ˜šœœ˜Jšœ˜—Jšœ8œ˜@Jšœ˜Jšœ˜——˜�Jš˜—J˜J˜�šŸœœœœhœœœ˜ÒK™/Kšœœ˜Kš	œœœœœ˜'Kšœ	œœœ˜(Kš	œœœœœ˜!Kš	œ
œœœœ˜Kšœœ '˜AKšœ
œ˜Kšœœ˜Kšœ˜Kšœ˜Jšœ.˜.Jšœ3œ˜8Jšœœ˜Jšœœ˜Jšœœ˜Kšœ	œ˜Kšœœ˜Jšœ7˜7Jšœ˜Kšœœ˜Jšœœ˜J˜�J˜�šœ#œ˜*K˜K™JK™Kšœœ#œ
œn˜¶Kšœ˜Kšœ˜K˜�—Jšœ(˜(šœ$˜*J˜Jšœ0˜0J˜—š˜J˜Jšœ*˜*Jšœ˜—JšœF˜Fšœ˜Jšœ-˜-—J˜�Jšœ˜Jšœ6˜6Kšœ8˜8Kšœ'˜'K™�K™VšœH˜HJ˜�—K˜�K™+Kšœ˜K˜�šœ˜ Kšœ˜Kšœœ˜K˜�Kšœ@˜@KšœK˜KK™�K™2Jšœ\˜\KšœW˜WKšœ?œ˜FKšœ4˜4K˜�Kšœœ˜/Kšœ
œ˜Kšœœ˜/Kšœœ˜)šœœ˜#K˜K˜Kšœ˜—K˜Kšœ˜Kšœ˜—K˜�K˜+K˜�K™K™�Kšœ	œ˜*Kšœœ˜Kšœ˜Kšœ3˜3š	œœ
œœ˜*šœ
˜
Kšœ˜Kšœ	œ˜Kšœ"˜"Kšœ*˜*Kšœ˜Kšœ
œb˜oKšœ˜—K˜#K˜K˜#K˜Kšœ˜—KšœR˜RKšœœ#œ
œ.˜vKšœ
˜—K˜�K˜�šŸœœœœ˜VKšœ1˜1Kšœ!˜!Kšœ˜Kšœ%˜%Kšœ˜Kšœ-˜-Kšœ-˜-Kšœ-˜-Kšœ7˜7KšœO˜O—K˜�K™ÈšŸœœœœœœœ˜<Kšœœ˜Kšœ˜—K˜�šŸœœœœœœœœ˜SKš˜Kšœœ˜Kš	œœœœ +˜Ušœœ˜Kšœœ
˜)Kšœœœ˜—Kšœ˜—K˜�šŸœœœœœœ˜5Kš˜Kšœœ˜Kšœ
˜Kšœ˜—K˜�šŸœœœœœœœ˜PKš˜Kšœœ˜Kšœ˜Kšœ˜—˜�K™%—šŸœœœœœœœ˜OKš˜Kšœœ˜š	œŸœœœ˜ Kšœ%œœ˜6Kšœ˜—Kšœ˜Kšœ˜—K˜�šŸœœœœœœœ˜VKšœœ˜šœœœ˜&K™Ššœœ˜$Kšœœ1˜<Kšœ˜!—Kšœ.˜.Kš	œœœœœ˜zKšœœ˜ KšœœV˜lKšœ˜—Kšœ%˜+—K˜�šŸœœœœœœœ˜gKšœœ˜Kšœ2 !˜SKšœ˜%—K™�šŸ&œœœœœœœ
˜aKšœœ˜KšœœœœH˜fšœœ˜!Kšœœ)œ˜UKšœœ
œI˜mKšœœ˜—K˜—K˜�šŸœœœœœœœ˜WKšœœ˜Jšœ˜ —K˜�šŸœœœœœ7œ˜‚Kšœœ˜Kšœ
œœ*˜LKšœS˜Y—K˜�šœœœ˜Kšœ˜K˜K˜
—K˜�šŸœœ#œ"˜XKšœ˜Kšœ=˜=—K˜�šŸœœœ!œœœœ
˜eKšœ
œœ˜,Kšœ#˜#Kšœ˜Kšœ˜Kšœ˜šœœ˜Kšœœ˜3šœœœœ;˜cKšœh™h—KšœB˜BKšœ;˜A—šœ˜Kšœ
œœ˜=šœœœœ5˜]Kšœh™h—Kšœœœœ0œUœ˜ªK˜-Kšœ=˜C——K˜�šŸœœœœœœœ
˜cKšœ
œœ˜,Kšœ#˜#Kšœ˜Kšœ
œœ˜.KšœœœœY˜Kšœ-œœK˜‚šœ
œ˜˜KšœD˜DKšœ&˜&Kšœœ˜Kšœœ)˜Bšœ$œ&˜MK˜0—Kšœ1˜7—Kšœœ?˜M——K˜�—K™�Kšœ˜J˜�J˜�—�…—����è†��Er�