SiroccoBase1Impl.Mesa
Copyright Ó 1986, 1987 by Xerox Corporation. All rights reserved.
Bhargava, August 9, 1986 2:56:46 pm PDT
Demers, December 29, 1986 9:48:13 pm PST
Bill Jackson (bj) August 25, 1987 6:46:38 pm PDT
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 )];
};
Scopes, Ribs & Contexts
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;
};
Context
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];
};
Scope
EmptyScope: PUBLIC PROC [] RETURNS [new: SCOPE] ~ {
id: ROPE ~ "<program>";
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;
};
Ribs
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;
};
Interface/Item procedures
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;
};
xxxx
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];
};
Check on status of unspecified
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;
};
xxxx
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.STREAMFS.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];
};
Junk
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: ROPENARROW[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: ROPENARROW[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.condensedFunctionTable ← SymTab.Create[]; XXXX
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[];
Put Predefined Values: integer, boolean, etc. into the table
IF ( NOT InsertValue["BOOLEAN", bool] ) THEN ERROR;
IF ( NOT InsertValue["CARDINAL", card16] ) THEN ERROR;
IF ( NOT InsertValue["LONGCARDINAL", card32] ) THEN ERROR;
IF ( NOT InsertValue["INTEGER", int16] ) THEN ERROR;
IF ( NOT InsertValue["LONGINTEGER", int32] ) THEN ERROR;
IF ( NOT InsertValue["STRING", string] ) THEN ERROR;
IF ( NOT InsertValue["SOURCE", source] ) THEN ERROR;
IF ( NOT InsertValue["SINK", sink] ) THEN ERROR;
IF ( NOT InsertValue["UNSPECIFIED", unspec] ) THEN ERROR;
RETURN[h.allTheTables];
};
}.