PWPLABasicsImpl:
CEDAR
PROGRAM
IMPORTS Atom, BoolOps, CDDirectory, CDExpr, CDIO, FS, IO, PW, Rope
EXPORTS PWPLABasics
SHARES CDDirectory = BEGIN
OPEN PWPLABasics;
Error: PUBLIC ERROR[ec: ErrorCode, msg: ROPE] ~ CODE;
-- Looks for name1, name2, then name3; if absent, return NIL and screams if required
GetTile:
PROC[from:
CD.Design, name1, name2, name3:
ROPE ←
NIL, required:
BOOL]
RETURNS [obj:
CD.Object] =
BEGIN
obj ←
SELECT
TRUE
FROM
IsPresent[from, name1] => PW.Get[from, name1],
IsPresent[from, name2] => PW.Get[from, name2],
IsPresent[from, name3] => PW.Get[from, name3],
ENDCASE => NIL;
IF obj =
NIL
AND required
THEN
BEGIN
PW.WriteF["PWPLA could not find tile '%g'", IO.rope[name1]];
IF name2 # NIL THEN PW.WriteF[" nor '%g'", IO.rope[name2]];
IF name3 # NIL THEN PW.WriteF[" nor '%g'", IO.rope[name3]];
PW.WriteF[".\n'"];
ERROR Error[MissingTile, NIL];
END;
END;
IsPresent:
PROC [whereTilesAre:
CD.Design, name:
ROPE]
RETURNS [
BOOL] =
{RETURN[CDDirectory.Fetch[whereTilesAre, name].found]};
-- Check if all names are non-NIL
AllPresent:
PUBLIC
PROC [list:
LIST
OF
CD.Object]
RETURNS [b:
BOOL ←
TRUE] =
{WHILE list#NIL DO b ← b AND list.first#NIL; list ← list.rest; ENDLOOP};
RequiredTile:
PUBLIC
PROC [from:
CD.Design, name1, name2, name3:
ROPE ←
NIL]
RETURNS [
CD.Object] =
{RETURN[GetTile[from, name1, name2, name3, TRUE]]};
OptionalTile:
PUBLIC
PROC [from:
CD.Design, name1, name2, name3:
ROPE ←
NIL]
RETURNS [
CD.Object] =
{RETURN[GetTile[from, name1, name2, name3, FALSE]]};
ListRefAnyToListRope:
PUBLIC
PROC [list:
LIST
OF
REF]
RETURNS [
LIST
OF
ROPE] =
BEGIN
RETURN[IF list=NIL THEN NIL ELSE CONS[NARROW[list.first], ListRefAnyToListRope[list.rest]]];
END;
ListRefAnyToListOfListRope:
PUBLIC
PROC [list:
LIST
OF
REF]
RETURNS [llr:
LIST
OF
LIST
OF
ROPE] =
BEGIN
IF list=NIL THEN RETURN[NIL];
llr ←
CONS[
ListRefAnyToListRope[NARROW[list.first, LIST OF REF]],
ListRefAnyToListOfListRope[list.rest]];
END;
Length:
PUBLIC
PROC [list:
LIST
OF
ROPE]
RETURNS [length:
INT ← 0] =
BEGIN
WHILE list # NIL DO length ← length+1; list ← list.rest; ENDLOOP;
END;
EnsureSize:
PUBLIC
PROC [list:
LIST
OF
ROPE, quantity:
INT] =
{IF Length[list] # quantity THEN ERROR};
-- Read equations one at a time, converting to sum-of-products as we go
GetEQN:
PUBLIC
PROC[par: SymTab.Ref, inNames, outNames:
LIST
OF
ROPE]
RETURNS[BoolOps.TruthTable] =
BEGIN
tt: BoolOps.TruthTable;
inAtoms, reverseAtoms: LIST OF ATOM ← NIL;
eqnTrees, reversedEqnTrees: LIST OF BoolOps.Tree ← NIL;
message: ROPE;
allErrorMessages: ROPE ← NIL;
IF inNames =
NIL
OR outNames =
NIL
THEN
ERROR Error[ParameterErrors, "Both 'Inputs' and 'Outputs' must be specified."];
-- read equations one at a time, converting to sum-of-products as we go
FOR outs:
LIST
OF
ROPE ← outNames, outs.rest
WHILE outs #
NIL
DO
eqn: ROPE ← NIL;
t: BoolOps.Tree ← NIL;
eqn ← CDExpr.FetchRope[par, outs.first].val;
IF eqn =
NIL
THEN {
allErrorMessages ← Rope.Cat[allErrorMessages, "Equation for output '", outs.first, "' is missing.\n"];
};
FOR i:
INT
DECREASING
IN [0 .. Rope.Length[eqn])
DO
-- remove trailing semicolon
ch: CHAR ← Rope.Fetch[eqn, i];
IF ch # '
AND ch # '\t
AND ch # '\n
THEN {
IF ch = '; AND i > 0 THEN eqn ← Rope.Substr[eqn, 0, i];
EXIT;
};
ENDLOOP;
message ← NIL;
t ← BoolOps.RopeToTree[eqn ! BoolOps.Error => {message ← msg; CONTINUE}];
IF message #
NIL
THEN
allErrorMessages ← Rope.Cat[allErrorMessages, "Could not translate equation for output '", outs.first, Rope.Cat["', error was: ", message, "\n"]]
ELSE {
message ← NIL;
t ← BoolOps.TreeToSOP[t ! BoolOps.Error => {message ← msg; CONTINUE}];
IF message #
NIL
THEN
allErrorMessages ← Rope.Cat[allErrorMessages, "Could not translate output '", outs.first, Rope.Cat["' to sum-of-products form, error was: ", message, "\n"]]
ELSE {
reversedEqnTrees ← CONS[t, reversedEqnTrees];
};
};
ENDLOOP;
IF ~Rope.Equal[allErrorMessages, NIL] THEN ERROR Error[ParameterErrors, allErrorMessages];
-- reverse our list of equations since it is backwards
FOR trees:
LIST
OF BoolOps.Tree ← reversedEqnTrees, trees.rest
WHILE trees #
NIL
DO
eqnTrees ← CONS[trees.first, eqnTrees];
ENDLOOP;
-- create a list of atoms from the input names
FOR ins:
LIST
OF
ROPE ← inNames, ins.rest
WHILE ins #
NIL
DO
reverseAtoms ← CONS[Atom.MakeAtom[ins.first], reverseAtoms];
ENDLOOP;
FOR ins:
LIST
OF
ATOM ← reverseAtoms, ins.rest
WHILE ins #
NIL
DO
inAtoms ← CONS[ins.first, inAtoms];
ENDLOOP;
-- make a truth table
message ← NIL;
tt ← BoolOps.SOPToTT[inAtoms, eqnTrees ! BoolOps.Error => {message ← msg; CONTINUE}];
IF message #
NIL
THEN
ERROR Error[ParameterErrors, Rope.Cat["Could not translate equations to truth table form, error was: ", message, "\n"]];
RETURN[tt];
END;
FetchTT:
PUBLIC
PROC [par: SymTab.Ref]
RETURNS [truthTable: BoolOps.TruthTable] =
BEGIN
-- get the truth table from a file
GetTTFile:
PROC[ttFile:
ROPE]
RETURNS[tt: BoolOps.TruthTable] =
BEGIN
ttStream: IO.STREAM;
explanation: ROPE;
IF ttFile = NIL THEN RETURN[NIL];
ttStream ← FS.StreamOpen[fileName: ttFile, wDir: CDIO.GetWorkingDirectory[] ! FS.Error => IF error.group = user THEN {ttStream ← NIL; CONTINUE}];
IF ttStream =
NIL
THEN
ERROR Error[ParameterErrors, Rope.Cat["Could not open truth table file '", ttFile, "'.\n"]];
tt ← BoolOps.StreamToTT[ttStream ! BoolOps.Error => {explanation ← msg; CONTINUE}];
IF explanation #
NIL
THEN
ERROR Error[ParameterErrors, Rope.Cat["Error in reading truth table: ", explanation, "\n"]];
END;
-- read the truth table directly from parameters file
GetTT:
PROC[par: SymTab.Ref]
RETURNS[BoolOps.TruthTable] =
BEGIN
ref: REF ANY;
ref ← CDExpr.FetchRef[par, "TruthTable"].val;
IF ref = NIL THEN RETURN[NIL];
IF ~ISTYPE[ref, BoolOps.TruthTable] THEN ERROR Error[ParameterErrors, Rope.Cat["TruthTable option is not of type BoolOps.TruthTable!"]];
RETURN[NARROW[ref]];
END;
-- get a truth table
SELECT
TRUE
FROM
CDExpr.FetchRope[par, "TruthTableFile"].found =>
truthTable ← GetTTFile[CDExpr.FetchRope[par, "TruthTableFile"].val]; -- Read TruthTable from a file
CDExpr.FetchRef[par, "TruthTable"].found =>
truthTable ← GetTT[par]; -- Read TruthTable directly
ENDCASE =>
-- should be GetEQN[inputNames, outputNames]
truthTable ← NIL;
END;
DumpTruthTable:
PUBLIC
PROC [tt: BoolOps.TruthTable, ttFile:
ROPE] =
BEGIN
-- dump truth table to file
ttStream: IO.STREAM;
message: ROPE ← NIL;
ttStream ← FS.StreamOpen[fileName: ttFile, wDir: CDIO.GetWorkingDirectory[], accessOptions: $create ! FS.Error => IF error.group = user THEN {ttStream ← NIL; CONTINUE}];
IF ttStream = NIL THEN ERROR Error[NoDump, Rope.Cat["Could not create truth table dump file '", ttFile, "'.\n"]];
BoolOps.TTToStream[tt, ttStream ! BoolOps.Error => {message ← msg; CONTINUE}];
IF message # NIL THEN ERROR Error[NoDump, Rope.Cat["Could not dump truth table to file '", ttFile, "', error was: ", message, "\n"]];
END;
END.