-- file [Indigo]<Cedar>BCD>TypeStringsImpl.mesa -- Edited by Satterthwaite, May 21, 1982 1:29 pm -- Edited by Maxwell, 19-Feb-82 11:33:15 (NOTE: we need better error reporting) -- Last Modified On 16-Apr-82 9:43:31 By Paul Rovner DIRECTORY Inline: TYPE USING [HighByte, HighHalf, LowByte, LowHalf], Strings: TYPE USING [SubStringDescriptor, AppendChar], Symbols: TYPE USING [codeANY, codeCHAR, codeINT, CSEIndex, CTXIndex, ISEIndex, HTIndex, HTNull, MDIndex, MDNull, OwnMdi, SEIndex, SENull, StandardContext, typeTYPE], SymbolTable: TYPE USING [Base], TypeStrings: TYPE USING [Code, TypeString]; TypeStringsImpl: PROGRAM IMPORTS Inline, Strings EXPORTS TypeStrings = BEGIN OPEN Symbols, TypeStrings; --******************************************************************* --basic algorithm --******************************************************************* stb: SymbolTable.Base ← NIL; zone: UNCOUNTED ZONE ← NIL; ts: TypeString; Create: PUBLIC PROC [base:SymbolTable.Base, sei:SEIndex, z:UNCOUNTED ZONE] RETURNS[TypeString] = {--n:Entry; --IF base#stb THEN FlushCache[]; IF base=NIL THEN RETURN[NIL]; stb ← base; zone ← z; stackIndex ← defsIndex ← 0; --IF (n←cache[sei]).type=sei THEN RETURN[n.string]; ts ← zone.NEW[StringBody[50]]; stack ← zone.NEW[StackVector]; defs ← zone.NEW[DefsVector]; lastName ← 000C; stateLength ← 0; AppendTypeString[sei]; --n.type ← sei; --n.recursive ← InsertDefinitions[]; IF InsertDefinitions[] THEN Canonicalize[sei]; --n.string ← ts; zone.FREE[@defs]; zone.FREE[@stack]; IF ts.length # ts.maxlength THEN ts ← Adjust[ts,ts.length]; RETURN[ts]}; Adjust: PROC [s:TypeString, n:CARDINAL] RETURNS [new: TypeString] = {new ← zone.NEW[StringBody[n]]; FOR i:CARDINAL IN [0..MIN[n, s.length]) DO Strings.AppendChar[new,s[i]] ENDLOOP; zone.FREE[@s]; RETURN[new]}; Append: PROC [c: CHAR] = {WHILE ts.length >= ts.maxlength DO ts ← Adjust[ts,ts.length+20] ENDLOOP; Strings.AppendChar[ts, c]}; AppendCode: PROC [code: Code] = LOOPHOLE[Append]; AppendCardinal: PROC [c: CARDINAL] = INLINE {Append[LOOPHOLE[Inline.HighByte[c]]]; Append[LOOPHOLE[Inline.LowByte[c]]]}; AppendLongCardinal: PROC [lc: LONG CARDINAL] = {AppendCardinal[Inline.HighHalf[lc]]; AppendCardinal[Inline.LowHalf[lc]]}; AppendString: PROC [s:TypeString] = INLINE {FOR i:CARDINAL IN [0..s.length) DO Append[s[i]] ENDLOOP}; Paint:TYPE = MACHINE DEPENDENT RECORD [ version (0): ARRAY [0..3) OF CARDINAL, index (3): CARDINAL]; GetPaint: PROC [type: SEIndex] RETURNS [paint: Paint] = {SELECT stb.TypeForm[type] FROM enumerated, definition, record, union => {ctx: CTXIndex ← TypeContext[type]; mdi: MDIndex; WITH c: stb.ctxb[ctx] SELECT FROM simple => mdi ← OwnMdi; included => {mdi ← c.module; ctx ← c.map}; ENDCASE => ERROR; paint.index ← LOOPHOLE[ctx]; IF ctx IN StandardContext THEN paint.version ← ALL[0] ELSE paint.version ← LOOPHOLE[stb.mdb[mdi].stamp]}; opaque => paint ← [LOOPHOLE[stb.mdb[OwnMdi].stamp], LOOPHOLE[type]]; ENDCASE => ERROR; }; AppendPaint: PROC [paint:Paint] = { AppendCardinal[paint.version[0]]; AppendCardinal[paint.version[1]]; AppendCardinal[paint.version[2]]; AppendCardinal[paint.index]}; AppendName: PROC [hti: HTIndex] = { length, offset:CARDINAL; IF hti = HTNull THEN {length ← offset ← 0} ELSE length ← stb.ht[hti].ssIndex - (offset ← stb.ht[hti-1].ssIndex); IF length>200B THEN ERROR; -- avoid code for leftParen and rightParen Append[0c + length]; FOR i:CARDINAL IN [offset..offset+length) DO Append[stb.ssb[i]] ENDLOOP; }; AppendField: PROC [iSei: ISEIndex] = INLINE { AppendName[stb.HashForSe[iSei]]; AppendTypeString[stb.seb[iSei].idType]}; AppendTypeString: PROC [type: SEIndex] = BEGIN class:Code; e:StackElement; --strip off definitions type ← UnderStar[type]; --substitute concrete type for opaque type IF stb.TypeForm[type]=opaque THEN type ← OpaqueValue[LOOPHOLE[type,CSEIndex],stb]; --replace type with its set representative FOR i:CARDINAL IN [0..stateLength) DO IF state[i].type = type THEN {type ← state[i].current; EXIT}; ENDLOOP; --check to see if type is recursive IF (e ← Find[type]) # NIL THEN {IF e.name=000C THEN e.name←NewName[]; AppendCode[name]; Append[e.name]; RETURN}; -- general cases Push[type]; SELECT (class ← TypeClass[type]) FROM definition => ERROR; enumerated => {SELECT LOOPHOLE[TypeContext[type],CARDINAL] FROM 4 => AppendCode[boolean]; ENDCASE => {AppendCode[paint]; AppendPaint[GetPaint[type]]}; }; record => {SELECT LOOPHOLE[TypeContext[type],CARDINAL] FROM 6 => AppendCode[text]; 8 => AppendCode[stringBody]; --10 => AppendCode[condition]; --12 => AppendCode[lock]; ENDCASE => {AppendCode[paint]; AppendPaint[GetPaint[type]]}; }; structure => {ctx: CTXIndex = TypeContext[type]; WITH c: stb.ctxb[ctx] SELECT FROM included => IF ~c.complete THEN ERROR; ENDCASE; AppendCode[leftParen]; FOR iSei: ISEIndex ← stb.FirstCtxSe[ctx], stb.NextSe[iSei] WHILE iSei#SENull DO AppendField[iSei] ENDLOOP; AppendCode[rightParen]}; union => {AppendCode[union]; AppendPaint[GetPaint[type]]}; array => {IF Packed[type] THEN AppendCode[packed]; AppendCode[array]; AppendTypeString[Domain[type]]; AppendTypeString[Range[type]]}; sequence => {IF Packed[type] THEN AppendCode[packed]; AppendCode[sequence]; AppendField[Tag[type]]; AppendTypeString[Range[type]]}; subrange => -- 10 bytes {AppendCode[subrange]; AppendTypeString[Ground[type]]; AppendLongCardinal[First[type]]; AppendLongCardinal[Last[type]]}; opaque => {csei:CSEIndex = LOOPHOLE[type]; WITH t: stb.seb[csei] SELECT FROM opaque => IF stb.seb[t.id].idCtx IN StandardContext THEN AppendCode[atomRec] ELSE {AppendCode[opaque]; AppendPaint[GetPaint[type]]}; ENDCASE => ERROR}; countedZone, uncountedZone => {IF Mds[type] THEN AppendCode[mds]; AppendCode[class]}; list => -- list = REF RECORD[cdr] {IF Ordered[type] THEN AppendCode[ordered]; IF ReadOnly[type] THEN AppendCode[readOnly]; AppendCode[list]; AppendTypeString[Cdr[type]]}; relativeRef => {AppendCode[relativeRef]; AppendTypeString[Base[type]]; AppendTypeString[Range[type]]}; ref => {IF ReadOnly[type] THEN AppendCode[readOnly]; IF TypeClass[Range[type]] = any THEN AppendCode[refAny] ELSE {AppendCode[ref]; AppendTypeString[Range[type]]}}; var => {IF ReadOnly[type] THEN AppendCode[readOnly]; AppendCode[var]; AppendTypeString[Range[type]]}; pointer, longPointer => {IF Ordered[type] THEN AppendCode[ordered]; IF ReadOnly[type] THEN AppendCode[readOnly]; AppendCode[class]; AppendTypeString[Range[type]]}; descriptor, longDescriptor => {IF ReadOnly[type] THEN AppendCode[readOnly]; AppendCode[class]; AppendTypeString[Range[type]]}; procedure, safeProc => {AppendCode[class]; AppendTypeString[Domain[type]]; AppendTypeString[Range[type]]}; port, program, signal, error => {IF Safe[type] THEN AppendCode[safe]; AppendCode[class]; AppendTypeString[Domain[type]]; AppendTypeString[Range[type]]}; process => {IF Safe[type] THEN AppendCode[safe]; AppendCode[process]; AppendTypeString[Range[type]]}; nil => {AppendCode[leftParen]; AppendCode[rightParen]}; cardinal, integer, character, longInteger, longCardinal, real, type, any, unspecified => {AppendCode[class]}; globalFrame, localFrame => ERROR; ENDCASE => ERROR; Pop[]; END; OpaqueValue: PROC [type:CSEIndex, base:SymbolTable.Base] RETURNS[val:SEIndex] = { OPEN b1:stb; val ← type; WITH t1: b1.seb[type] SELECT FROM opaque => { mdi1:MDIndex = WITH c1: b1.ctxb[b1.seb[t1.id].idCtx] SELECT FROM included => c1.module, imported => b1.ctxb[c1.includeLink].module, ENDCASE => OwnMdi; mdi2: MDIndex = base.FindMdi[b1.mdb[mdi1].stamp]; IF mdi2 # MDNull AND base.mdb[mdi2].exported THEN { ss: Strings.SubStringDescriptor; sei2: ISEIndex; b1.SubStringForHash[@ss,b1.seb[t1.id].hash]; sei2 ← base.SearchContext[base.FindString[@ss], base.mainCtx]; IF sei2#SENull AND base.seb[sei2].idType=typeTYPE AND base.seb[sei2].public THEN val ← base.UnderType[sei2]}}; ENDCASE}; lastName: CHAR; NewName: PROC RETURNS[CHAR] = {RETURN[lastName ← lastName+1]}; --******************************************************************* --canonicalization --******************************************************************* Canonicalize: PROC [type:SEIndex] = { -- build an equivalence table for the type stateLength ← 0; state ← zone.NEW[StateTable]; AddState[type]; -- gets them all recursively -- minimize the table UNTIL ~Split[] DO NULL ENDLOOP; -- generate a new string ts.length ← 0; AppendTypeString[type]; -- will make use of the equivalences [] ← InsertDefinitions[]; zone.FREE[@state]}; Split: PROC RETURNS [split: BOOL←FALSE]= { -- iterate over all k-equivalent classes, -- splitting them into k+1-equivalent classes FOR i:CARDINAL IN [0..stateLength) DO -- check to see if we have done this class already found: BOOL ← FALSE; FOR j:CARDINAL IN [0..i) DO IF state[i].current=state[j].current THEN found ← TRUE; ENDLOOP; IF found THEN LOOP; -- if not, process the class list ← zone.NEW[ListVector]; list[0] ← state[i].type; listLength ← 1; state[i].next ← state[i].type; FOR j:CARDINAL IN (i..stateLength) DO IF state[j].current#state[i].current THEN LOOP; -- not in the class found ← FALSE; FOR k:CARDINAL IN [0..listLength) DO IF kEQ[state[j].type,list[k]] THEN {state[j].next ← list[k]; found ← TRUE; EXIT}; ENDLOOP; IF found THEN LOOP; -- a new class is born state[j].next ← state[j].type; IF listLength >= maxStateLength THEN ERROR; list[listLength]←state[j].type; listLength ← listLength + 1; split ← TRUE; ENDLOOP; zone.FREE[@list]; ENDLOOP; FOR i:CARDINAL IN [0..stateLength) DO state[i].current ← state[i].next; ENDLOOP; }; AddState: PROC [type:SEIndex] = { class:Code; -- strip off unnecessary definitions type ← UnderStar[type]; --ground:SEIndex ← type; --WHILE TypeClass[ground]=definition DO -- type ← ground; -- ground ← stb.UnderType[type]; -- ENDLOOP; --type ← ground; FOR i:CARDINAL IN [0..stateLength) DO IF state[i].type = type THEN RETURN; ENDLOOP; IF stateLength >= maxStateLength THEN ERROR; state[stateLength] ← [type,SENull,SENull]; stateLength ← stateLength + 1; class ← TypeClass[type]; SELECT class FROM definition => ERROR; record, enumerated => NULL; structure => {FOR iSei:ISEIndex ← stb.FirstCtxSe[TypeContext[type]], stb.NextSe[iSei] WHILE iSei#SENull DO AddState[stb.seb[iSei].idType]; ENDLOOP; }; union => NULL; array => {AddState[Domain[type]]; AddState[Range[type]]}; sequence => {AddState[stb.seb[Tag[type]].idType]; AddState[Range[type]]}; subrange => AddState[Ground[type]]; opaque => NULL; countedZone, uncountedZone => NULL; list => AddState[Cdr[type]]; relativeRef => {AddState[Base[type]]; AddState[Range[type]]}; ref => AddState[Range[type]]; var => AddState[Range[type]]; pointer, longPointer, descriptor, longDescriptor => AddState[Range[type]]; procedure, safeProc, port, program, signal, error => {AddState[Domain[type]]; AddState[Range[type]]}; process => AddState[Range[type]]; nil => NULL; globalFrame, localFrame => ERROR; cardinal, integer, character, longInteger, longCardinal, real, type, any, unspecified => NULL; ENDCASE => ERROR; }; kEQ: PROC [t1,t2:SEIndex] RETURNS[BOOL] = { class1:Code = TypeClass[t1]; class2:Code = TypeClass[t2]; IF class1#class2 THEN RETURN[FALSE]; SELECT class1 FROM definition => ERROR; record, enumerated, union => RETURN[t1=t2]; structure => {iSei1:ISEIndex ← stb.FirstCtxSe[TypeContext[t1]]; iSei2:ISEIndex ← stb.FirstCtxSe[TypeContext[t2]]; DO IF iSei1=SENull OR iSei2=SENull THEN RETURN[iSei1=iSei2]; IF stb.HashForSe[iSei1] # stb.HashForSe[iSei2] THEN RETURN[FALSE]; IF Current[stb.seb[iSei1].idType]#Current[stb.seb[iSei2].idType] THEN RETURN[FALSE]; iSei1 ← stb.NextSe[iSei1]; iSei2 ← stb.NextSe[iSei2]; ENDLOOP; }; array => {RETURN[Current[Domain[t1]]=Current[Domain[t2]] AND Current[Range[t1]]=Current[Range[t2]]]}; sequence => {iSei1: ISEIndex = Tag[t1]; iSei2: ISEIndex = Tag[t2]; RETURN[stb.HashForSe[iSei1] = stb.HashForSe[iSei2] AND Current[stb.seb[iSei1].idType]=Current[stb.seb[iSei2].idType] AND Current[Range[t1]]=Current[Range[t2]]]}; subrange => RETURN[Current[Ground[t1]]=Current[Ground[t2]]]; opaque => RETURN[t1=t2]; countedZone, uncountedZone => RETURN[t1=t2]; list => RETURN[Current[Cdr[t1]]=Current[Cdr[t2]]]; relativeRef => {RETURN[Current[Base[t1]]=Current[Base[t2]] AND Current[Range[t1]]=Current[Range[t2]]]}; ref => RETURN[Current[Range[t1]]=Current[Range[t2]]]; var => RETURN[Current[Range[t1]]=Current[Range[t2]]]; pointer, longPointer, descriptor, longDescriptor => RETURN[Current[Range[t1]]=Current[Range[t2]]]; procedure, safeProc, port, program, signal, error => { RETURN[Current[Domain[t1]]=Current[Domain[t2]] AND Current[Range[t1]]=Current[Range[t2]]]}; process => RETURN[Current[Range[t1]]=Current[Range[t2]]]; type => RETURN[t1=t2]; --***PDR-- nil => RETURN[t1=t2]; any => RETURN[t1=t2]; --***PDR-- unspecified => RETURN[t1=t2]; globalFrame, localFrame => ERROR; cardinal, integer, character, longInteger, longCardinal, real, type, any, unspecified => RETURN[t1=t2]; ENDCASE => ERROR; }; Current: PROC [type:SEIndex] RETURNS[SEIndex] = { type ← UnderStar[type]; FOR i:CARDINAL IN [0..stateLength) DO IF state[i].type=type THEN RETURN[state[i].current]; ENDLOOP; ERROR}; StateTable: TYPE = ARRAY [0..maxStateLength) OF RECORD [type,current,next: SEIndex]; state: LONG POINTER TO StateTable ← NIL; stateLength: CARDINAL; maxStateLength:CARDINAL = 100; ListVector: TYPE = ARRAY [0..maxStateLength) OF SEIndex; list: LONG POINTER TO ListVector ← NIL; listLength: CARDINAL; --******************************************************************* --stack management --******************************************************************* StackElementRecord:TYPE = RECORD[name:CHAR,type:SEIndex,index:CARDINAL]; StackElement:TYPE = LONG POINTER TO StackElementRecord; StackVector: TYPE = ARRAY [0..stackLength) OF StackElementRecord; stack: LONG POINTER TO StackVector ← NIL; stackLength: CARDINAL = 100; stackIndex: CARDINAL ← 0; DefsVector: TYPE = ARRAY [0..defsLength) OF StackElementRecord; defs: LONG POINTER TO DefsVector ← NIL; defsLength: CARDINAL = 30; defsIndex: CARDINAL ← 0; Push: PROC [type:SEIndex] = { IF stackIndex=stackLength THEN ERROR; stack[stackIndex] ← [000C,type,ts.length]; stackIndex ← stackIndex + 1}; Pop: PROC = { IF stackIndex=0 THEN ERROR; stackIndex ← stackIndex - 1; IF stack[stackIndex].name=000C THEN RETURN; IF defsIndex=defsLength THEN ERROR; defs[defsIndex] ← stack[stackIndex]; defsIndex ← defsIndex+1}; Find: PROC [type:SEIndex] RETURNS[StackElement←NIL] = { FOR i:CARDINAL IN [0..stackIndex) DO IF stack[i].type=type THEN RETURN[@stack[i]]; ENDLOOP}; InsertDefinitions: PROC RETURNS [recursive:BOOL ← FALSE] = { WHILE TRUE DO index, j: CARDINAL ← 0; found: BOOL ← FALSE; FOR i:CARDINAL IN [0..defsIndex) DO IF defs[i].name=000C THEN LOOP; IF defs[i].index<index THEN LOOP; index ← defs[i].index; j ← i; found ← recursive ← TRUE; ENDLOOP; IF ~found THEN EXIT; IF ts.length+2 > ts.maxlength THEN ts ← Adjust[ts,ts.length+4]; ts.length ← ts.length + 2; FOR i:CARDINAL DECREASING IN [index+2..ts.length) DO ts[i] ← ts[i-2] ENDLOOP; LOOPHOLE[ts[index],Code] ← definition; ts[index+1] ← defs[j].name; defs[j].name ← 000C; ENDLOOP; lastName ← 000C; defsIndex ← 0}; --******************************************************************* --hash table management --******************************************************************* --Entry:TYPE = LONG POINTER TO EntryRec; --EntryRec:TYPE = RECORD [type:SEIndex, -- recursive:BOOL, -- string:TypeString]; --nullEntry:EntryRec = [SENull, FALSE, NIL]; --array: ARRAY [0..arrayLength) OF EntryRec; --arrayLength:CARDINAL = 47; --FlushCache: PROC = {array ← ALL[nullEntry]}; --cache: PROC [sei:SEIndex] RETURNS[Entry] ={ -- p:CARDINAL ← LOOPHOLE[sei,CARDINAL] MOD arrayLength; -- FOR i:CARDINAL IN [p..arrayLength) DO -- IF array[i].type=SENull THEN RETURN[@array[i]]; -- IF array[i].type=sei THEN RETURN[@array[i]]; -- ENDLOOP; -- FOR i:CARDINAL IN [0..p) DO -- IF array[i].type=SENull THEN RETURN[@array[i]]; -- IF array[i].type=sei THEN RETURN[@array[i]]; -- ENDLOOP; -- ERROR}; ++ too many types!!! --******************************************************************* --procedures that work with the symbol table --******************************************************************* TypeContext: PROC [type: SEIndex] RETURNS [CTXIndex] = { csei: CSEIndex = stb.UnderType[type]; RETURN [WITH t: stb.seb[csei] SELECT FROM enumerated => t.valueCtx, record => t.fieldCtx, definition => t.defCtx, union => t.caseCtx, ENDCASE => ERROR]}; Cdr: PROC [type: SEIndex] RETURNS [SEIndex] = { ctx:CTXIndex = TypeContext[Range[type]]; iSei:ISEIndex ← stb.FirstCtxSe[ctx]; WITH c:stb.ctxb[ctx] SELECT FROM included => IF ~c.complete THEN ERROR; ENDCASE; RETURN [stb.seb[iSei].idType]}; Base: PROC [type: SEIndex] RETURNS [SEIndex] = { csei: CSEIndex = stb.UnderType[type]; RETURN [WITH t: stb.seb[csei] SELECT FROM relative => t.baseType, ENDCASE => ERROR]}; Range: PROC [type: SEIndex] RETURNS [SEIndex] = { csei: CSEIndex = stb.UnderType[type]; RETURN [WITH t: stb.seb[csei] SELECT FROM array => t.componentType, sequence => t.componentType, transfer => t.typeOut, ref => t.refType, relative => t.offsetType, arraydesc => t.describedType, long => Range[t.rangeType], ENDCASE => ERROR]}; Domain: PROC [type: SEIndex] RETURNS [SEIndex] = { csei: CSEIndex = stb.UnderType[type]; RETURN [WITH t: stb.seb[csei] SELECT FROM array => t.indexType, sequence => stb.seb[t.tagSei].idType, union => stb.seb[t.tagSei].idType, transfer => t.typeIn, ENDCASE => ERROR]}; Tag: PROC [type: SEIndex] RETURNS [ISEIndex] = { csei: CSEIndex = stb.UnderType[type]; RETURN [WITH t: stb.seb[csei] SELECT FROM sequence => t.tagSei, union => t.tagSei, ENDCASE => ERROR]}; First: PROC [type: SEIndex] RETURNS [LONG CARDINAL] = { csei: CSEIndex = stb.UnderType[type]; RETURN [SELECT TypeClass[csei] FROM enumerated => 0, subrange => WITH t: stb.seb[csei] SELECT FROM subrange => LONG[t.origin], ENDCASE => ERROR, cardinal => FIRST[CARDINAL], integer => LONG[LOOPHOLE[FIRST[INTEGER], CARDINAL]], character => LONG[LOOPHOLE[FIRST[CHAR], CARDINAL]], longInteger => LOOPHOLE[FIRST[LONG INTEGER]], longCardinal => FIRST[LONG CARDINAL], ENDCASE => ERROR] }; Last: PROC [type: SEIndex] RETURNS [LONG CARDINAL] = { csei: CSEIndex = stb.UnderType[type]; RETURN [SELECT TypeClass[csei] FROM enumerated => WITH t: stb.seb[csei] SELECT FROM enumerated => LOOPHOLE[LONG[t.nValues - 1]], ENDCASE => ERROR, subrange => WITH t: stb.seb[csei] SELECT FROM subrange => LOOPHOLE[LONG[t.origin + t.range]], ENDCASE => ERROR, cardinal => LAST[CARDINAL], integer => LONG[LOOPHOLE[LAST[INTEGER], CARDINAL]], character => LONG[LOOPHOLE[LAST[CHAR], CARDINAL]], longInteger => LOOPHOLE[LAST[LONG INTEGER]], longCardinal => LAST[LONG CARDINAL], ENDCASE => ERROR] }; Safe: PROC [type: SEIndex] RETURNS [BOOL] = { csei: CSEIndex = stb.UnderType[type]; RETURN [WITH t: stb.seb[csei] SELECT FROM transfer => t.safe, ENDCASE => ERROR] }; ReadOnly: PROC [type: SEIndex] RETURNS [BOOL] = { csei: CSEIndex = stb.UnderType[type]; RETURN [WITH t: stb.seb[csei] SELECT FROM long => ReadOnly[t.rangeType], ref => t.readOnly, arraydesc => t.readOnly, ENDCASE => ERROR] }; Ordered: PROC [type: SEIndex] RETURNS [BOOL] = { csei: CSEIndex = stb.UnderType[type]; RETURN [WITH t: stb.seb[csei] SELECT FROM long => Ordered[t.rangeType], ref => t.ordered, ENDCASE => ERROR] }; Packed: PROC [type: SEIndex] RETURNS [BOOL] = { csei: CSEIndex = stb.UnderType[type]; RETURN [WITH t: stb.seb[csei] SELECT FROM array => t.packed, sequence => t.packed, ENDCASE => ERROR] }; Mds: PROC [type: SEIndex] RETURNS[BOOL] = { csei: CSEIndex = stb.UnderType[type]; RETURN [WITH t: stb.seb[csei] SELECT FROM zone => t.mds, ENDCASE => ERROR] }; Ground: PROC [type: SEIndex] RETURNS [SEIndex] = { RETURN [WITH se: stb.seb[type] SELECT FROM id => se.idInfo, -- a definition cons => WITH cse: se SELECT FROM subrange => cse.rangeType, ENDCASE => ERROR, -- NOTE relativeRef not yet ENDCASE => ERROR]}; UnderStar: PROC [type: SEIndex] RETURNS [SEIndex] = { WHILE TypeClass[type]=definition DO type ← stb.UnderType[type]; ENDLOOP; RETURN[type]}; TypeClass: PROC [sei: SEIndex] RETURNS[ans: Code] = BEGIN csei:CSEIndex; --IF type = fhType THEN RETURN[localFrame]; --IF type = nullType THEN RETURN[nil]; --IF type = gfhType THEN RETURN[globalFrame]; --IF type = unspecType THEN RETURN[unspecified]; IF sei=SENull THEN RETURN[nil]; IF stb.seb[sei].seTag = id THEN RETURN[definition]; csei ← stb.UnderType[sei]; ans ← (WITH ser: stb.seb[csei] SELECT FROM basic => SelectBasicClass[ser.code], record => (IF ser.painted THEN record ELSE structure), definition => record, real => real, union => union, array => array, opaque => opaque, sequence => sequence, ref => (IF ser.counted THEN ERROR ELSE pointer), arraydesc => descriptor, long => (WITH rse: stb.seb[stb.UnderType[ser.rangeType]] SELECT FROM ref => (SELECT TRUE FROM rse.var => var, rse.counted => IF rse.list THEN list ELSE ref, ENDCASE => longPointer), basic => (IF rse.code = codeINT THEN longInteger ELSE ERROR), arraydesc => longDescriptor, ENDCASE => IF IsCardinal[ser.rangeType] THEN longCardinal ELSE ERROR), relative => relativeRef, enumerated => enumerated, subrange => IF IsCardinal[csei] THEN cardinal ELSE subrange, transfer => (SELECT ser.mode FROM proc => IF ser.safe THEN safeProc ELSE procedure, port => port, signal => signal, error => error, process => process, program => program, ENDCASE => ERROR), zone => (IF ser.counted THEN countedZone ELSE uncountedZone), mode => type, any => any, ENDCASE => ERROR); END; SelectBasicClass: PROC [code: [0..16)] RETURNS[Code] = INLINE { RETURN [SELECT code FROM codeINT => integer, codeANY => unspecified, codeCHAR => character, ENDCASE => ERROR]}; IsCardinal: PROC [type: SEIndex] RETURNS [BOOL] = { csei: CSEIndex = stb.UnderType[type]; RETURN [WITH t: stb.seb[csei] SELECT FROM subrange => (WITH tt: stb.seb[stb.UnderType[t.rangeType]] SELECT FROM basic => (tt.code = codeINT AND t.origin = 0 AND t.range = LAST[CARDINAL]), ENDCASE => FALSE), ENDCASE => FALSE]}; --******************************************************************* --substitution --******************************************************************* Substitute: PUBLIC PROC [concrete,opaque,type:TypeString,z:UNCOUNTED ZONE] = { maxDef:CHAR ← MaxDefinition[concrete]; IF type.length<opaque.length THEN RETURN; IF HasCode[concrete,opaque] THEN ERROR; -- potentially recursive IF maxDef#000C THEN ERROR; -- potentially recursive zone ← z; FOR i:CARDINAL DECREASING IN [0..type.length-opaque.length] DO IF ~Match[opaque,type,i] THEN LOOP; IF maxDef#000C THEN Rename[concrete,MaxDefinition[type]]; --delete opaque type.length ← type.length - opaque.length; FOR j:CARDINAL IN [i..type.length) DO type[j] ← type[j+opaque.length]; ENDLOOP; --insert concrete IF type.length+concrete.length > type.maxlength THEN type ← Adjust[type,type.length+concrete.length]; type.length ← type.length + concrete.length; FOR j:CARDINAL DECREASING IN [i+concrete.length..type.length) DO type[j] ← type[j-concrete.length]; ENDLOOP; FOR j:CARDINAL IN [0..concrete.length) DO type[i+j] ← concrete[j]; ENDLOOP; ENDLOOP; IF maxDef#000C THEN ReorderDefinitions[type,MaxDefinition[type]]; }; Match: PROC [s1,s2:TypeString,index:CARDINAL] RETURNS[BOOL] = INLINE { FOR i:CARDINAL IN [0..s1.length) DO IF s1[i]#s2[i+index] THEN RETURN[FALSE]; ENDLOOP; RETURN[TRUE]}; ReorderDefinitions: PROC [s:TypeString,last:CHAR] = { a:ARRAY CHAR [001C..020C] OF RECORD[i:CARDINAL,n:CHAR]; skip:CARDINAL ← 0; min,max:CARDINAL ← 0; IF last>020C THEN ERROR; a ← ALL[[0,000C]]; -- build the array of name => index associations FOR i:CARDINAL IN [0..s.length) DO IF skip>0 THEN {skip←skip-1; LOOP}; IF LOOPHOLE[s[i],Code]=opaque THEN skip ← 8; -- skip paint IF LOOPHOLE[s[i],Code]=paint THEN skip ← 8; IF LOOPHOLE[s[i],Code]#name THEN LOOP; IF a[s[i+1]].i=0 THEN a[s[i+1]].i ← i; ENDLOOP; -- sort names by their position in the string FOR i:CHAR IN [001C..last] DO max ← min; min ← s.length; FOR j:CHAR IN [001C..last] DO IF a[j].i >= min THEN LOOP; IF a[j].i <= max THEN LOOP; min ← a[j].i; a[j].n ← i; ENDLOOP; ENDLOOP; -- replace definitions and names with their new names; FOR i:CARDINAL IN [0..s.length) DO IF skip>0 THEN {skip←skip-1; LOOP}; IF LOOPHOLE[s[i],Code]=opaque THEN skip ← 8; -- skip paint IF LOOPHOLE[s[i],Code]=paint THEN skip ← 8; IF ~(LOOPHOLE[s[i],Code] IN [definition..name]) THEN LOOP; s[i+1] ← a[s[i+1]].n; ENDLOOP; }; MaxDefinition: PROC [s:TypeString] RETURNS[max:CHAR] = { skip:CARDINAL←0; max ← 000C; FOR i:CARDINAL IN [0..s.length) DO IF skip>0 THEN {skip←skip-1; LOOP}; IF LOOPHOLE[s[i],Code]=opaque THEN skip ← 8; -- skip paint IF LOOPHOLE[s[i],Code]=paint THEN skip ← 8; IF LOOPHOLE[s[i],Code]#definition THEN LOOP; max ← MAX[max,s[i+1]]; ENDLOOP; }; Rename: PROC [s:TypeString,offset:CHAR] = { skip:CARDINAL←0; FOR i:CARDINAL IN [0..s.length) DO IF skip>0 THEN {skip←skip-1; LOOP}; IF LOOPHOLE[s[i],Code]=opaque THEN skip ← 8; -- skip paint IF LOOPHOLE[s[i],Code]=paint THEN skip ← 8; IF ~(LOOPHOLE[s[i],Code] IN [definition..name]) THEN LOOP; s[i+1] ← s[i+1]+LOOPHOLE[offset]; ENDLOOP; }; HasCode: PROC [s:TypeString,code:Code] RETURNS[BOOL]= { skip:CARDINAL←0; FOR i:CARDINAL IN [0..s.length) DO IF skip>0 THEN {skip←skip-1; LOOP}; IF LOOPHOLE[s[i],Code]=opaque THEN skip ← 8; -- skip paint IF LOOPHOLE[s[i],Code]=paint THEN skip ← 8; IF LOOPHOLE[s[i],Code]=code THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]}; END..