<> <> <> <> <> DIRECTORY Convert USING [ CardFromRope, IntFromRope ], FS USING [ StreamOpen ], IO USING [ card, int, rope, BreakProc, CharClass, Close, GetTokenRope, PutF, PutFR, STREAM ], PriorityQueue USING [ Create, SortPred ], Rope USING [ ROPE, Cat, Concat, Equal, IsEmpty, Length, Substr ], RopeList USING [ Cons, Map ], SiroccoBaseDef USING [ MkCType, SendError ], SiroccoCGDef USING [ Generic, ItemKind, ValueKind ], SymTab USING [ Copy, Create, EachPairAction, Fetch, GetSize, Insert, Key, Pairs, Ref ], SiroccoPrivate USING [ AbstractValue, AbstractValueObject, AquireState, CComponent, CComponentBody, CONTEXT, ContextRep, CType, CTypeBody, Handle, InterfaceItem, ITEM, NodeRep, PQItem, RIB, SCOPE, ScopeRep, TABLES, TablesBody, TypeGraph, TypeGraphNode ]; SiroccoBase1Impl: CEDAR PROGRAM IMPORTS Convert, FS, IO, PriorityQueue, Rope, RopeList, SymTab, SiroccoBaseDef, SiroccoPrivate EXPORTS SiroccoBaseDef, SiroccoPrivate ~ { OPEN SiroccoBaseDef, SiroccoCGDef, SiroccoPrivate; ROPE: TYPE ~ Rope.ROPE; PQFirst: PUBLIC PriorityQueue.SortPred ~ { one: REF PQItem ~ NARROW[x]; two: REF PQItem ~ NARROW[y]; RETURN[( one.position < two.position )]; }; <> UpdateItem: PUBLIC PROC [ left: TypeGraph, name: ROPE, node: TypeGraphNode, value: AbstractValue ] RETURNS [ new: TypeGraph ] ~ { item: ITEM ~ ItemFromContext[left.context, name]; itemtype: REF NodeRep ~ NARROW[item.type]; itemvalue: REF AbstractValueObject ~ NARROW[item.value]; SELECT TRUE FROM item.type = NIL => { ERROR }; item.value = NIL => { ERROR }; itemtype.specifics # NIL => { ERROR }; itemvalue.specifics # NIL => { ERROR }; ENDCASE => { NULL }; itemtype.specifics _ node; itemvalue.specifics _ value; new _ left; }; <> CreateContext: PUBLIC PROC [rib: RIB, scope: SCOPE, name: ROPE, pgm: CARD, version: CARD] RETURNS [context: CONTEXT] ~ { scope.id _ name; scope.pgm _ pgm; scope.version _ version; context _ NEW [ContextRep _ [ rib: rib, scope: scope ]]; }; ItemFromContext: PUBLIC PROC [context: CONTEXT, name: ROPE] RETURNS [item: ITEM] ~ { item _ ItemFromScope[context.scope, name]; }; <> EmptyScope: PUBLIC PROC [] RETURNS [new: SCOPE] ~ { id: ROPE ~ ""; pgm: CARD ~ 0; version: CARD ~ 0; items: SymTab.Ref ~ SymTab.Create[]; tables: TABLES ~ NIL; new _ NEW [ScopeRep _ [ id: id, pgm: pgm, version: version, items: items, tables: tables ]]; }; ItemConcat: PUBLIC PROC [old: SCOPE, item: ITEM] RETURNS [new: SCOPE] ~ { IF ( NOT SymTab.Insert[old.items, item.name, item] ) THEN ERROR; new _ old; }; ItemFromScope: PUBLIC PROC [scope: SCOPE, name: ROPE] RETURNS [item: ITEM] ~ { WITH SymTab.Fetch[scope.items, name].val SELECT FROM i: ITEM => item _ i; ENDCASE => ERROR; }; <> EmptyRIB: PUBLIC PROC [] RETURNS [new: RIB] ~ { new _ SymTab.Create[]; }; ScopeConcat: PUBLIC PROC [old: RIB, scope: SCOPE] RETURNS [new: RIB] ~ { IF ( NOT SymTab.Insert[old, scope.id, scope] ) THEN ERROR; new _ old; }; ScopeFromRIB: PUBLIC PROC [rib: RIB, name: ROPE] RETURNS [scope: SCOPE] ~ { scope _ NIL; }; <> ImportItem: PUBLIC PROC [t: TABLES, interface, item: SymTab.Key] RETURNS [entry: InterfaceItem] ~ { entry _ ItemFromInterface[InterfaceFromName[t, interface], item]; }; TypeNameForItem: PUBLIC PROC [entry: InterfaceItem] RETURNS [type: ROPE] ~ { type _ entry.type; }; ConstantForItem: PUBLIC PROC [entry: InterfaceItem] RETURNS [constant: ROPE] ~ { constant _ entry.constant; }; ValueFromName: PUBLIC PROC [constant: ROPE] RETURNS [value: CARD] ~ { value _ Convert.CardFromRope[constant]; }; <<"Fetch" procedures>> FetchFromTypeTable: PUBLIC PROC [t1: TABLES, key: ROPE] RETURNS [value: CType] ~ { value _ CTypeFromName[t1, key]; -- just change the name in the ThreeC4 code! }; CTypeFromName: PROC [tables: TABLES, type: ROPE] RETURNS [ctype: CType] ~ { WITH SymTab.Fetch[tables.typeTable, type].val SELECT FROM ct: CType => ctype _ ct; ENDCASE => ERROR; }; ItemFromInterface: PROC [x: SymTab.Ref, name: SymTab.Key] RETURNS [item: InterfaceItem] ~ { WITH SymTab.Fetch[x, name].val SELECT FROM entry: REF InterfaceItem => item _ entry^; ENDCASE => [] _ SendError["Undeclared Remote Identifier"]; }; InterfaceFromName: PROC [t: TABLES, name: SymTab.Key] RETURNS [s: SymTab.Ref] ~ { WITH SymTab.Fetch[t.globalTable, name].val SELECT FROM symtab: SymTab.Ref => s _ symtab; ENDCASE => ERROR; }; <<"Check" procedures>> Array: PUBLIC PROC [constantType: ROPE, tables: TABLES] RETURNS [yes: BOOLEAN] ~ { ctype: CType ~ CTypeFromName[tables, constantType]; yes _ ( ctype.class = array ); }; CheckCanonicalType: PUBLIC PROC [r1, r2: ROPE] RETURNS [same: BOOLEAN] ~ { IF ( NOT (same _ Rope.Equal[r1, r2]) ) THEN [] _ SendError[Rope.Cat["Type Mismatch Expected ", r2, " found ", r1]]; }; CheckResultsForSourceAndSink: PUBLIC PROC [results: CComponent] RETURNS [ok: BOOLEAN] ~ { ok _ TRUE; FOR tail: CComponent _ results, tail.sibling WHILE ( tail # NIL ) DO IF ( ( Rope.Equal[tail.type, "SOURCE"] ) OR ( Rope.Equal[tail.type, "SINK"] ) ) THEN { [] _ SendError["Result Has Source or Sink"]; ok _ FALSE; EXIT; }; ENDLOOP; }; <> ClassToRope: PROC [class: Generic] RETURNS [rope: ROPE] ~ { SELECT class FROM array => rope _ "ARRAY"; bool => rope _ "BOOLEAN"; card16 => rope _ "CARDINAL"; card32 => rope _ "LONGCARDINAL"; choice => rope _ "CHOICE"; enum => rope _ "ENUMERATION"; error => rope _ "ERROR"; int16 => rope _ "INTEGER"; int32 => rope _ "LONGINTEGER"; proc => rope _ "PROCEDURE"; record => rope _ "RECORD"; seq => rope _ "SEQUENCE"; sink => rope _ "SINK"; source => rope _ "SOURCE"; string => rope _ "STRING"; unspec => rope _ "UNSPECIFIED"; ENDCASE => ERROR; }; RopeToClass: PROC [rope: ROPE] RETURNS [class: Generic] ~ { SELECT TRUE FROM Rope.Equal[rope, "ARRAY"] => class _ array; Rope.Equal[rope, "BOOLEAN"] => class _ bool; Rope.Equal[rope, "CARDINAL"] => class _ card16; Rope.Equal[rope, "CHOICE"] => class _ choice; Rope.Equal[rope, "ENUMERATION"] => class _ enum; Rope.Equal[rope, "ERROR"] => class _ error; Rope.Equal[rope, "INTEGER"] => class _ int16; Rope.Equal[rope, "LONGCARDINAL"] => class _ card32; Rope.Equal[rope, "LONGINTEGER"] => class _ int32; Rope.Equal[rope, "PROCEDURE"] => class _ proc; Rope.Equal[rope, "RECORD"]=> class _ record; Rope.Equal[rope, "SEQUENCE"] => class _ seq; Rope.Equal[rope, "SINK"] => class _ sink; Rope.Equal[rope, "SOURCE"] => class _ source; Rope.Equal[rope, "STRING"] => class _ string; Rope.Equal[rope, "UNSPECIFIED"] => class _ unspec; ENDCASE => ERROR; }; MkPrimitiveCType: PUBLIC PROC [g: Generic] RETURNS [ctype: CType, name: ROPE] ~ { name _ ClassToRope[g]; ctype _ NEW[CTypeBody _ [bound: 0, children: NIL, class: g]]; }; CompareTypes: PUBLIC PROC [first: CType, second: CType, tables: TABLES] RETURNS [INT _ 1] ~ { Mismatch: PROC ~ { [] _ SendError["Type Mismatch"]; }; CompareCComponents: PROC [first: CComponent, second: CComponent] ~ { SELECT TRUE FROM ( ( first = NIL ) AND ( second = NIL ) ) => RETURN; ( first = NIL ) => Mismatch[]; ( second = NIL ) => Mismatch[]; ( NOT Rope.Equal[first.name, second.name] ) => Mismatch[]; ( first.val # second.val ) => Mismatch[]; ( NOT Rope.Equal[first.type, second.type] ) => { one: CType ~ CTypeFromName[tables, first.type]; two: CType ~ CTypeFromName[tables, second.type]; [] _ CompareTypes[one, two, tables]; }; ENDCASE => NULL; CompareCComponents[first.sibling, second.sibling]; }; <> SELECT first.class FROM enum, record, choice => { NULL }; -- Comparison of names already done bool, card16, card32, int16, int32, string, unspec => { IF ( first.class # second.class ) THEN Mismatch[]; }; array, seq => { IF ( first.class = second.class ) AND ( first.bound = second.bound ) THEN { CompareCComponents[first.children, second.children]; IF ( GetLengthOfCComponentList[first.children, first.bound] # 0 ) THEN ERROR; } }; proc, error => { IF ( second.class # card16 ) THEN { IF ( first.class # second.class ) OR ( first.bound # second.bound ) THEN Mismatch[] ELSE CompareCComponents[first.children, second.children]; }; }; ENDCASE => { Mismatch[] }; }; TypeOfSequence: PUBLIC PROC [sequenceName: ROPE, tables: TABLES] RETURNS [typeOf: ROPE] ~ { ctype: CType ~ CTypeFromName[tables, sequenceName]; typeOf _ ctype.children.type; }; GetTypeOfComponent: PUBLIC PROC [id: ROPE, name: ROPE, tables: TABLES] RETURNS [typeOf: ROPE] ~ { ctype: CType ~ CTypeFromName[tables, name]; FOR tail: CComponent _ ctype.children, tail.sibling WHILE ( tail # NIL ) DO IF ( Rope.Equal[tail.name, id] ) THEN { typeOf _ tail.type; RETURN }; ENDLOOP; ERROR; }; GetCType: PUBLIC PROC [id: ROPE, list: CComponent, tables: TABLES] RETURNS [type: CType, name: ROPE] ~ { FOR tail: CComponent _ list, tail.sibling WHILE ( tail # NIL ) DO IF ( Rope.Equal[id, tail.name] ) THEN { RETURN[CTypeFromName[tables, tail.name], tail.type]; } ENDLOOP; [] _ SendError["Type Mismatch"]; }; GetTypeOfElement: PUBLIC PROC [name: ROPE, tables: TABLES] RETURNS [typeOf: ROPE] ~ { ctype: CType ~ CTypeFromName[tables, name]; list: CComponent ~ ctype.children; IF ( list = NIL ) THEN ERROR; typeOf _ list.type; }; GetLengthOfCComponentList: PUBLIC PROC [list: CComponent, initial: INT] RETURNS [final: INT] ~ { FOR tail: CComponent _ list, tail.sibling WHILE ( tail # NIL ) DO initial _ initial.PRED; ENDLOOP; final _ (0 - initial); IF ( final >= 0 ) THEN { final _ (0 - initial); RETURN; } ELSE [] _ SendError["Type Mismatch"]; -- Incorrect Length }; SeeIfArrOrSeq: PUBLIC PROC [first: CType, size: CARD, tables: TABLES] RETURNS [type: CType, name: ROPE] ~ { SELECT TRUE FROM ( first.class = array ) => { IF ( first.bound # size ) THEN [] _ SendError["Wrong number of elements in array constant"]; }; ( first.class = seq ) => { IF ( size > first.bound ) THEN [] _ SendError["Too many elements in sequence constant"]; }; ENDCASE => [] _ SendError["Type Mismatch"]; type _ CTypeFromName[tables, first.children.type]; name _ first.children.type; }; <> Merge: PROC [t1, t2: SymTab.Ref] RETURNS [new: SymTab.Ref] ~ { EachPair: SymTab.EachPairAction ~ { IF ( NOT SymTab.Insert[new, key, val] ) THEN ERROR; }; big, small: SymTab.Ref; IF ( SymTab.GetSize[t1] > SymTab.GetSize[t2] ) THEN { big _ t1; small _ t2 } ELSE { big _ t2; small _ t1 }; new _ SymTab.Copy[big]; IF ( SymTab.Pairs[small, EachPair] ) THEN ERROR; }; DiskToTable: PUBLIC PROC [id: ROPE, pgm, version: CARD] RETURNS [scope: SCOPE] ~ { ProgramFile: PROC RETURNS [name: ROPE] ~ { name _ IO.PutFR["%gP%gV%g", IO.rope[id], IO.card[pgm], IO.card[version] ]; }; info: REF InterfaceItem; keyRope: ROPE; sibling: CComponent; fname: ROPE ~ Rope.Concat[ProgramFile[], ".Tables"]; sourceStream: IO.STREAM _ FS.StreamOpen[fname]; successful: BOOLEAN; table: SymTab.Ref _ SymTab.Create[]; token: ROPE; type: CType; NextToken: PROC RETURNS [text: ROPE] ~ { charsSkipped: INT; [text, charsSkipped] _ IO.GetTokenRope[sourceStream, Control]; }; Control: IO.BreakProc ~ { SELECT char FROM '\r, '| => RETURN[sepr]; ENDCASE => RETURN[other]; }; Normalize: PROC [arg: ROPE] RETURNS [res: ROPE] ~ { length: INT ~ Rope.Length[arg]; res _ IF (length > 1) THEN Rope.Substr[arg, 0, length.PRED] ELSE ""; }; TokenToInt: PROC [arg: ROPE] RETURNS [res: INT] ~ { length: INT ~ Rope.Length[arg]; res _ IF (length > 1) THEN Convert.IntFromRope[Rope.Substr[arg, 0, length.PRED]] ELSE 0; }; scope _ NEW [ScopeRep _ [id, pgm, version, NIL, CreateTables[]]]; [] _ SymTab.Insert[scope.tables.directory, id, ProgramFile[]]; token _ NextToken[]; -- Skip Heading keyRope _ token _ NextToken[]; -- Get First Key WHILE ( NOT Rope.Equal[keyRope, "TypeTables"] ) DO -- While Local Table is not exhausted info _ NEW[InterfaceItem]; info.type _ token _ NextToken[]; info.constant _ Normalize[token _ NextToken[]]; token _ NextToken[]; -- Throw away Function Header token _ NextToken[]; WHILE ( NOT Rope.Equal[token, "~~~~~"] ) DO info.functions _ RopeList.Cons[info.functions, token]; token _ NextToken[]; ENDLOOP; info.value _ NIL; successful _ SymTab.Insert[table, keyRope, info]; keyRope _ token _ NextToken[]; ENDLOOP; [] _ SymTab.Insert[scope.tables.globalTable, id, table]; -- Local Tables over token _ NextToken[]; -- Skip Type Heading keyRope _ token _ NextToken[]; -- Get First Type Name WHILE ( NOT Rope.Equal[keyRope, "."] ) DO -- Process Type Table type _ NEW[CTypeBody]; -- Allocate CType type.class _ RopeToClass[token _ NextToken[]]; -- Get Class type.bound _ Convert.CardFromRope[token _ NextToken[]]; -- Get bound token _ NextToken[]; IF ( NOT Rope.Equal[token, "TYPE"] ) THEN { -- Are there any children sibling _ NEW[CComponentBody]; type.children _ sibling --First Child }; WHILE ( NOT Rope.Equal[token, "TYPE"] ) DO sibling.name _ Normalize[token]; sibling.val _ TokenToInt[token _ NextToken[]]; sibling.type _ Normalize[token _ NextToken[]]; token _ NextToken[]; IF ( NOT Rope.Equal[token, "TYPE"] ) THEN { sibling.sibling _ NEW[CComponentBody]; --Rest Of the Children sibling _ sibling.sibling; } ENDLOOP; [] _ SymTab.Insert[scope.tables.typeTable, keyRope, type]; -- Enter Type keyRope _ token _ NextToken[]; -- Get Next Type Name ENDLOOP; token _ NextToken[]; --Skip Header keyRope _ token _ NextToken[]; WHILE ( NOT Rope.Equal[keyRope, "."] ) DO token _ NextToken[]; [] _ SymTab.Insert[scope.tables.functionTable, keyRope, token]; keyRope _ token _ NextToken[]; ENDLOOP; }; TableMerge: PUBLIC PROC [t1, t2: TABLES] RETURNS [new: TABLES] ~ { new _ t1; new.unresolvedConstantTable _ Merge[t1.unresolvedConstantTable, t2.unresolvedConstantTable]; new.unresolvedTypeTable _ Merge[t1.unresolvedTypeTable, t2.unresolvedTypeTable]; }; <> Collapse: PUBLIC PROC ~ { failure: BOOLEAN; outStream: IO.STREAM; tables: TABLES; h: SiroccoPrivate.Handle; AddUsedTypes: SymTab.EachPairAction ~ { usedTable: SymTab.Ref ~ tables.condensedTypeTable; TraverseCtype: PUBLIC PROC [type: CType] ~ { FOR list: CComponent _ type.children, list.sibling WHILE (list # NIL) DO IF ( NOT Rope.IsEmpty[list.type] ) THEN { ctype: CType ~ CTypeFromName[tables, list.type]; IF ( SymTab.Insert[usedTable, list.type, ctype] ) THEN TraverseCtype[ctype]; }; ENDLOOP; }; entry: REF InterfaceItem ~ NARROW[val]; ctype: CType ~ CTypeFromName[tables, entry.type]; IF ( NOT SymTab.Insert[usedTable, entry.type, ctype] ) THEN RETURN[FALSE]; TraverseCtype[ctype]; }; WriteOutLocalTableEntry: SymTab.EachPairAction ~ { keyRope: ROPE _ NARROW[key]; entry: REF InterfaceItem _ NARROW[val]; FuctionsToDisk: PROC[name: ROPE] ~ { IO.PutF[outStream, "%g|", IO.rope[name] ]; }; IO.PutF[outStream, "|%g|%g|%g |\nFunctions|", IO.rope[keyRope], IO.rope[entry.type], IO.rope[entry.constant] ]; RopeList.Map[entry.functions, FuctionsToDisk]; IO.PutF[outStream, "~~~~~\n"] }; WriteOutTypeTableEntry: SymTab.EachPairAction ~ { type: CType _ NARROW[val]; keyRope: ROPE _ NARROW[key]; list: CComponent _ type.children; IO.PutF[outStream, "TYPE|%g|%g|%g|\n", IO.rope[keyRope], IO.rope[ClassToRope[type.class]], IO.card[type.bound] ]; WHILE ( list # NIL ) DO IO.PutF[outStream, "%g |%g |%g |\n", IO.rope[list.name], IO.int[list.val], IO.rope[list.type] ]; list _ list.sibling; ENDLOOP; }; WriteOutFunctionTableEntry: SymTab.EachPairAction ~ { IO.PutF[outStream, "%g|%g\n", IO.rope[NARROW[key]], IO.rope[NARROW[val]] ] }; h _ SIGNAL SiroccoPrivate.AquireState; tables _ h.allTheTables; failure _ SymTab.Pairs[tables.localTable, AddUsedTypes]; outStream _ FS.StreamOpen[Rope.Concat[h.programKey,"Tables"], $create]; IO.PutF[outStream, "LocalTables\n"]; failure _ SymTab.Pairs[tables.localTable, WriteOutLocalTableEntry]; IO.PutF[outStream, "\nTypeTables\n"]; failure _ SymTab.Pairs[tables.condensedTypeTable, WriteOutTypeTableEntry]; IO.PutF[outStream, "\nTYPE|.\n"]; IO.PutF[outStream, "\nFunctions\n"]; failure _ SymTab.Pairs[tables.functionTable, WriteOutFunctionTableEntry]; IO.PutF[outStream, "\n.\n"]; IO.Close[outStream]; }; CreateTables: PUBLIC PROC RETURNS [t: TABLES] ~ { h: SiroccoPrivate.Handle ~ SIGNAL SiroccoPrivate.AquireState; InsertValue: PROC [key: ROPE, type: Generic] RETURNS [ok: BOOLEAN] ~ { ok _ SymTab.Insert[h.allTheTables.typeTable, key, MkCType[type, 0, NIL]] }; h.allTheTables _ NEW [TablesBody]; <> h.allTheTables.condensedTypeTable _ SymTab.Create[]; h.allTheTables.directory _ SymTab.Create[]; h.allTheTables.errors _ SymTab.Create[]; h.allTheTables.functionTable _ SymTab.Create[]; h.allTheTables.globalTable _ SymTab.Create[]; h.allTheTables.index _ PriorityQueue.Create[PQFirst]; -- just plain vanilla, please! h.allTheTables.localTable _ SymTab.Create[]; h.allTheTables.procedures _ SymTab.Create[]; h.allTheTables.typeTable _ SymTab.Create[]; h.allTheTables.unresolvedConstantTable _ SymTab.Create[]; h.allTheTables.unresolvedTypeTable _ SymTab.Create[]; h.allTheTables.workTable _ SymTab.Create[]; <> <> <> <> <> <> <> <> <> <> <<>> RETURN[h.allTheTables]; }; }.