FSMTool.mesa;
Originally written in C by Interactive Systems Corp.
Rewritten in Mesa by Jim Gasbarro
Disclaimer: This code is awful. I'm not proud of it, but it works...
Last edited by Gasbarro on August 1, 1985 1:38:51 pm PDT
DIRECTORY
Buttons,
Commander,
Containers,
FS,
IO,
Rope,
Rules,
VFonts,
ViewerClasses,
ViewerIO,
ViewerOps,
ViewerTools;
FSMTool: CEDAR PROGRAM     
IMPORTS Buttons, Commander, Containers, FS, IO, Rope, Rules, VFonts, ViewerIO, ViewerOps, ViewerTools =
BEGIN
entryHeight: CARDINAL = 15; -- how tall to make each line of items
entryVSpace: CARDINAL = 8;  -- vertical leading space between lines
entryHSpace: CARDINAL = 10;  -- horizontal space between items in a line
viewerout,in,out,tempfile,results: IO.STREAM;
MaxPos: INT = 70;
MaxSet: INT = 70;
setcnt,noutputs: INT ← 0;
nspos,fileindex: INT;
vnames: ARRAY [0..MaxPos) OF Rope.ROPE;
sset: ARRAY [0..MaxSet] OF Rope.ROPE;
filename: Rope.ROPE;
MaxFact: INT = 20;
MaxPI: INT = 30;
MaxTerm: INT = 30;
MaxInTerm: INT = 30;
DontCare: INT = 0;
TrueTerm: INT = 1;
FalseTerm: INT = 2;
EndList: INT = -1;
NotCore: INT = -1;
NoMerge: INT = -1;
exp: REF ExpRep ← NEW[ExpRep];
ExpRep: TYPE = ARRAY [0..MaxTerm+MaxInTerm) OF ARRAY [0..MaxFact) OF INT;
ptr: REF PtrRep ← NEW[PtrRep];
PtrRep: TYPE = ARRAY [0..MaxInTerm) OF INT;
prodofsums: REF ProdofsumsRep ← NEW[ProdofsumsRep];
ProdofsumsRep: TYPE = ARRAY [0..MaxTerm) OF ARRAY[0..MaxPI) OF INT;
ninpterms: INT;
Handle: TYPE = REF FSMToolRec;
FSMToolRec: TYPE = RECORD [ -- the data for a particular tool instance
outer: Containers.Container ← NIL, -- handle for the enclosing container
height: CARDINAL ← 0,  -- height measured from the top of the container
fsm: FSMViewer];  -- the FSM viewer's state
MakeFSMTool: Commander.CommandProc = BEGIN
my: Handle ← NEW[FSMToolRec];
my.outer ← Containers.Create[[-- construct the outer container  
name: "FSM Tool",
iconic: TRUE,
column: left,
scrollable: FALSE ]];
MakeFSM[my];
ViewerOps.SetOpenHeight[my.outer, my.height];
ViewerOps.PaintViewer[my.outer, all];
END;
FSMViewer: TYPE = RECORD [
input: ViewerClasses.Viewer ← NIL,
output: IO.STREAM]; 
MakeFSM: PROC [handle: Handle] = BEGIN
promptButton, computeButton: Buttons.Button;
rule: Rules.Rule;
handle.height ← handle.height + entryVSpace;
promptButton ← Buttons.Create[
info: [
name: "Filename:",
wy: handle.height,
wh: entryHeight,
parent: handle.outer,
border: FALSE ],
proc: Prompt,
clientData: handle];
handle.fsm.input ← ViewerTools.MakeNewTextViewer[ [
parent: handle.outer,
wx: promptButton.wx + promptButton.ww + entryHSpace,
wy: handle.height+2,
ww: 40*VFonts.CharWidth['0],
wh: entryHeight,
scrollable: FALSE,
border: FALSE]];
computeButton ← Buttons.Create[
info: [
name: "Compute State Equations",
wx: handle.fsm.input.wx + handle.fsm.input.ww + entryHSpace,
wy: handle.height,
ww:,
wh: entryHeight,
parent: handle.outer,
border: TRUE],
clientData: handle,
proc: ComputeStateEquations];
handle.height ← handle.height + entryHeight + entryVSpace;
rule ← Rules.Create[ [ -- create a bar to separate sections 1 and 2
parent: handle.outer,
wy: handle.height,
ww: handle.outer.cw,
wh: 2]];
Containers.ChildXBound[handle.outer, rule]; -- constrain rule to be width of parent
[ , viewerout] ← ViewerIO.CreateViewerStreams[name:"Fred", viewer:ViewerOps.CreateViewer[flavor: $TypeScript, info:[parent: handle.outer,
wy: handle.height+2,
ww: 100*VFonts.CharWidth['0],
wh: 56 * entryHeight,
scrollable: TRUE,
border: FALSE]]];
handle.height ← handle.height + 10 * entryHeight;
END;
Prompt: Buttons.ButtonProc = BEGIN
force the selection into the user input field
handle: Handle ← NARROW[clientData]; -- get our data
ViewerTools.SetSelection[handle.fsm.input];  -- force the selection
END;
ComputeStateEquations: Buttons.ButtonProc = BEGIN
handle: Handle ← NARROW[clientData];
i,j,nterms,minterms: INT;
k: INT ← 0;
headerFile: IO.STREAM;
filename ← ViewerTools.GetContents[handle.fsm.input];
in ← FS.StreamOpen[Rope.Cat[filename, ".fsm"]];
out ← FS.StreamOpen["eqns.tmp", $create];
nspos ← Parsenames[];
FOR i IN [0..noutputs) DO
setcnt ← 0;
IO.PutF[viewerout,"Processing %g...\n", IO.rope[vnames[i+1]]];
Findterms[Getvarpos[vnames[i+1]],"0"];
tempfile ← FS.StreamOpen["state.tmp", $create];
Termstofile[];
Convert[];
IO.Close[tempfile];
ENDLOOP;
IO.Close[in];
in ← out;
IO.SetIndex[in,0];
fileindex ← IO.GetIndex[in];
IO.PutF[viewerout,"\nMinimizing terms...\n\n"];
results ← FS.StreamOpen[Rope.Cat[filename, ".pal"], $create];
IO.PutF[results, Rope.Cat["\n-- File: ", filename, ".pal\n-- Created by FSMTool %g"], IO.time[]];
headerFile ← FS.StreamOpen[Rope.Cat[filename, ".hdr"]];
WHILE NOT IO.EndOf[headerFile] DO
IO.PutChar[results, IO.GetChar[headerFile]];
ENDLOOP;
IO.Close[headerFile];
IO.PutF[results,"BEGIN\n\n"];
WHILE (nterms ← Getexp[]) # 0 DO
FOR i IN [0..MaxInTerm) DO
ptr[i] ← 0;
ENDLOOP;
FOR i IN [0..MaxTerm) DO
FOR j IN [0..MaxPI) DO
prodofsums[i] [j] ← 0;
ENDLOOP;
ENDLOOP;
ninpterms ← nterms;
FOR i IN [0..nterms) DO
FOR j IN [0..MaxFact) DO
exp[MaxTerm + i] [j] ← exp[i] [j];
ENDLOOP;
ENDLOOP;
minterms ← Minimize[nterms];
IO.PutF[viewerout, "Number of terms required for %g = %g\n", IO.rope[vnames[k←k+1]], IO.int[minterms]];
Report[0,minterms,k];
ENDLOOP;
IO.PutF[results,"\nEND\n"];
IO.PutF[viewerout, "\nResults are in file %g.pal\n\n", IO.rope[filename]];
IO.Close[results];
IO.Close[in];
END;
SkipOver: PROC [stream: IO.STREAM, breakProc: IO.BreakProc] RETURNS [] = {
c: CHAR;
DO
IF IO.EndOf[stream] THEN RETURN;
SELECT breakProc[c ← IO.GetChar[stream]] FROM
break => {IO.Backup[stream, c]; EXIT};
other => {IO.Backup[stream, c]; EXIT};
sepr => NULL
ENDCASE => ERROR;
ENDLOOP;
};
WSButNotCR: IO.BreakProc = TRUSTED {
RETURN[SELECT char FROM
IO.SP, IO.TAB => sepr,
ENDCASE => other];
};
NotWhiteSpace: IO.BreakProc = TRUSTED {
RETURN[SELECT char FROM
IO.SP, IO.TAB, IO.CR => other,
ENDCASE => sepr];
};
NotCR: IO.BreakProc = TRUSTED {
RETURN[SELECT char FROM
IO.CR => other,
ENDCASE => sepr];
};
Parsenames: PROC [] RETURNS [pos: INTEGER ← -1] = {
buf: Rope.ROPE;
--WHILE (Rope.Compare[s1:buf ← IO.GetSequence[stream: in, charProc: IO.LineAtATime], s2:"Transition", case:TRUE] < equal) AND (IO.EndOf[in] = FALSE) DO
--IO.PutF[viewerout, "%g\n", IO.rope[buf]];
--ENDLOOP;
[] ← IO.SkipWhitespace[in];
DO
IF IO.PeekChar[in] = IO.CR THEN {
IF noutputs = 0 THEN {
IO.PutF[viewerout, "Input/Output seperator '|' not found\n"];
ERROR;
};
fileindex ← IO.GetIndex[in];
EXIT;
};
pos ← pos+1;
[buf,] ← IO.GetTokenRope [in];
IF Rope.Equal[buf,"|"] THEN {
pos ← pos-1; 
noutputs ← pos;
}
ELSE {
vnames[pos] ← buf;
IF Duplicate[pos] THEN IO.PutF[viewerout,"%g is multiply defined at [%g]\n", IO.rope[vnames[pos]], IO.int[IO.GetIndex[in]]];
};
SkipOver[in, WSButNotCR];
ENDLOOP;
};
Duplicate: PROC [n: INT] RETURNS [BOOL] = {
i: INT;
FOR i IN [0..n) DO
IF Rope.Equal[vnames[i],vnames[n]] THEN RETURN [TRUE];
ENDLOOP;
RETURN [FALSE];
};
Findterms: PROC [pos: INT, val: Rope.ROPE] = {
i: INT;
buf0,buf1: Rope.ROPE;
IO.SetIndex[in,fileindex];
DO
buf0 ← Readfield[];
IF buf0 = NIL THEN EXIT;  
FOR i IN [1..pos) DO
Skipfield[];
ENDLOOP;
buf1 ← Readfield[];
IF Rope.Equal[buf1, val] THEN Insertset[buf0];
SkipOver[in, NotCR];
ENDLOOP;
};
Readfield: PROC RETURNS [Rope.ROPE] = {
field: Rope.ROPE;
[] ← IO.SkipWhitespace[in];
IF IO.EndOf[in] THEN RETURN[NIL];
[field,] ← IO.GetTokenRope[in];
RETURN[field];
};
Skipfield: PROC = {
[] ← IO.SkipWhitespace[in];
SkipOver[in, NotWhiteSpace];
};
Insertset: PROC [t:Rope.ROPE] = {
IF ~Inset[t] THEN {
sset[setcnt] ← t;
setcnt ← setcnt+1;
};
};
Inset: PROC [t:Rope.ROPE] RETURNS [BOOL] = {
i: INT;
FOR i IN [0..setcnt) DO
IF Rope.Equal[sset[i], t] THEN RETURN[TRUE];
ENDLOOP;
RETURN[FALSE];
};
Getvarpos: PROC [buf:Rope.ROPE] RETURNS [INT] = {
i: INT;
FOR i IN [0..nspos] DO
IF Rope.Equal[buf,vnames[i]] THEN RETURN[i];
ENDLOOP;
IO.PutF[viewerout, "%g not found\n", IO.rope[buf]];
ERROR;
};
Termstofile: PROC [] = {
pos: INT ← -1;
c: CHAR;
buf,line: Rope.ROPE;
IO.SetIndex[in,fileindex];
DO
IF IO.EndOf[in] THEN EXIT;
c ← IO.GetChar[in];
SELECT c FROM
IO.CR => {IF pos >= 0 AND pos < nspos THEN IO.PutF[viewerout, "ERROR: Not enough Boolean entries at [%g]\n", IO.int[IO.GetIndex[in]]];
pos ← -1;
line ← NIL;
};
IO.SP, IO.TAB => NULL;
ENDCASE => {
pos ← pos + 1;
IF pos > nspos THEN IO.PutF[viewerout, "ERROR: Too many Boolean entries at [%g]\n", IO.int[IO.GetIndex[in]]];
IF pos = nspos OR pos = 0 THEN {
IO.Backup[in, c];
buf ← Readfield[];
line ← Rope.Cat[line,buf," "];
IF pos = nspos AND Inset[buf] THEN {
IO.PutF[tempfile,line];
IO.PutF[tempfile, "\n"];
};
} ELSE {
SELECT c FROM
'0 => line ← Rope.Cat[line,"0 "];
'1 => line ← Rope.Cat[line,"1 "];
'x,'X => line ← Rope.Cat[line,"X "];
ENDCASE => IO.PutF[viewerout, "ERROR: Illegal Boolean value at [%g]\n", IO.int[IO.GetIndex[in]]];
IF IO.EndOf[in] THEN EXIT;
c ← IO.PeekChar[in];
IF c#IO.SP AND c#IO.CR AND c#IO.TAB THEN IO.PutF[viewerout, "ERROR: Illegal Boolean value at [%g]\n", IO.int[IO.GetIndex[in]]];
};
};
ENDLOOP;
};
Convert: PROC [] = {
pos: INT ← -1;
c: CHAR;
first: BOOLTRUE;
needcr: BOOLFALSE;
IO.SetIndex[tempfile,0];
DO
IF IO.EndOf[tempfile] THEN EXIT;
c ← IO.GetChar[tempfile];
SELECT c FROM
IO.CR => {
first ← TRUE;
pos ← -1;
};
IO.SP, IO.TAB => NULL;
'0, '1 => {
pos ← pos + 1;
IF ~first THEN IO.PutF[out, " & "] ELSE {
IF needcr THEN IO.PutF[out, " +\n"];
needcr ← FALSE;
first ← FALSE;
};
needcr ← TRUE;
IF c = '0 THEN IO.PutF[out, "N"] ELSE IO.PutF[out, "A"];
IO.PutF[out, "%g", IO.int[pos]];
};
ENDCASE => {
pos ← pos + 1;
SkipOver[tempfile, NotWhiteSpace];
};
ENDLOOP;
IO.PutF[out, ";\n\n"];
};
Getexp: PROC [] RETURNS [INT] = {
i,j: INT;
FOR i IN [0..MaxTerm+MaxInTerm) DO
FOR j IN [0..MaxFact) DO
exp[i] [j] ← 0;
ENDLOOP;
ENDLOOP;
[] ← IO.SkipWhitespace[in];
IF IO.EndOf[in] THEN RETURN[0];
i ← 0;
WHILE Getterm[i] AND (i < (MaxTerm - 1)) DO
i ← i + 1;
ENDLOOP;
RETURN[i+1];
};
Getterm: PROC [i: INT] RETURNS[BOOL] = {
k: INT;
c: CHAR;
WHILE (k ← Getfact[]) # 0 DO
IF (k >= MaxFact) OR (k <= -MaxFact) THEN {
IO.PutF[viewerout, "Factor number too big: %g\n", IO.int[k]];
ERROR;
};
IF k >= 0 THEN exp[i] [k - 1] ← TrueTerm ELSE exp[i] [-(k + 1)] ← FalseTerm;
[] ← IO.SkipWhitespace[in];
c ← Getop[];
SELECT c FROM
'+ => RETURN[TRUE];
'; => RETURN[FALSE];
'& => NULL;
ENDCASE => {
IO.PutF[viewerout, "Invalid operator: %g\n", IO.char[c]];
ERROR;
};
ENDLOOP;
RETURN[FALSE];
};
Getfact: PROC [] RETURNS [INT] = {
c: CHAR;
[] ← IO.SkipWhitespace[in];
IF IO.EndOf[in] THEN RETURN[0];
c ← IO.GetChar[in];
IF c = 'a OR c = 'A THEN RETURN[IO.GetInt[in] + 1];
IF c = 'n OR c = 'N THEN RETURN[-(IO.GetInt[in] + 1)];
IO.PutF[viewerout, "Invalid operand: %g\n", IO.char[c]];
ERROR;
};
Getop: PROC [] RETURNS[CHAR] = {
c: CHAR;
[] ← IO.SkipWhitespace[in];
IF IO.EndOf[in] THEN ERROR;
c ← IO.GetChar[in];
IF c = '+ OR c = '& OR c = '; THEN RETURN[c];
IO.PutF[viewerout, "Invalid Operator: %g\n", IO.char[c]];
ERROR;
};
Minimize: PROC [nterms: INT] RETURNS[INT] = {
nprimes: INT;
nprimes ← Findprimes[nterms];
RETURN[Selectprimes[nprimes]];
};
Findprimes: PROC [nterms: INT] RETURNS[INT] = {
merged,addterm: BOOL;
i,j,nt: INT;
k: INT;
addterm ← TRUE;
WHILE addterm = TRUE DO
merged ← TRUE;
WHILE merged = TRUE DO
merged ← FALSE;
i ← 0;
WHILE i < (nterms-1) DO
j ← i+1;
WHILE j < nterms DO
IF (k ← Combine[i,j]) # NoMerge THEN {
merged ← TRUE;
Remove[j,nterms];
nterms ← nterms - 1;
j ← j - 1;
exp[i] [k] ← DontCare;
};
j ← j+1;
ENDLOOP;
i ← i+1;
ENDLOOP;
ENDLOOP;
nt ← nterms;
FOR i IN [0..(nterms-1)) DO
FOR j IN [i+1..nterms) DO
IF Formcon[i,j,nt] AND Addcon[nt] THEN {
IF nt < MaxTerm - 1 THEN nt ← nt+1 ELSE {
IO.PutF[viewerout, "Table overflow\n"];
ERROR;
};
};
ENDLOOP;
ENDLOOP;
addterm ← (nt # nterms);
nterms ← Compact[nt];
ENDLOOP;
RETURN[nterms];
};
Formcon: PROC [i,j: INT, k: INT] RETURNS [BOOL] = {
ncomps: INT ← 0;
m: INT;
FOR m IN [0..MaxFact) DO
IF exp[i] [m] = exp[j] [m] THEN exp[k] [m] ← exp[i] [m] ELSE
IF exp[i] [m] = DontCare THEN exp[k] [m] ← exp[j] [m] ELSE
IF exp[j] [m] = DontCare THEN exp[k] [m] ← exp[i] [m] ELSE {
ncomps ← ncomps + 1;
exp[k] [m] ← DontCare;
};
ENDLOOP;
RETURN[ncomps = 1];
};
Addcon: PROC [nt: INT] RETURNS [BOOL] = {
i: INT;
FOR i IN [0..nt) DO
IF Subsume[nt,i] THEN RETURN[FALSE];
ENDLOOP;
RETURN[TRUE];
};
Compact: PROC [nterms: INT] RETURNS [INT] = {
i: INT;
j: INT;
i ← 0;
WHILE i < (nterms-1) DO
j ← i+1;
WHILE j < nterms DO
IF Subsume[j,i] THEN {
Remove[j,nterms];
j ← j-1;
nterms ← nterms-1;
}
ELSE IF Subsume[i,j] THEN {
Remove[i,nterms];
nterms ← nterms-1;
i ← i-1;
EXIT;
};
j ← j+1;
ENDLOOP;
i ← i+1;
ENDLOOP;
RETURN[nterms];
};
Combine: PROC [i,j: INT] RETURNS [INT] = {
k,ksave: INT;
ncomps: INT ← 0;
FOR k IN [0..MaxFact) DO
IF exp[i] [k] # exp[j] [k] THEN {
IF (exp[i] [k] = TrueTerm AND exp[j] [k] = FalseTerm) OR (exp[i] [k] = FalseTerm AND exp[j] [k] = TrueTerm) THEN {
ksave ← k;
ncomps ← ncomps+1;
}
ELSE RETURN[NoMerge];
};
ENDLOOP;
IF ncomps = 1 THEN RETURN[ksave];
RETURN[NoMerge];
};
Subsume: PROC [i,j: INT] RETURNS [BOOL] = {
k: INT;
FOR k IN [0..MaxFact) DO
IF (exp[i] [k] # exp[j] [k]) AND (exp[j] [k] # DontCare) THEN RETURN[FALSE];
ENDLOOP;
RETURN[TRUE];
};
Add: PROC [k,nterms: INT] RETURNS [INT] = {
i: INT;
IF nterms >= (MaxTerm-1) THEN {
IO.PutF[viewerout, "Too many terms: %g\n", IO.int[nterms]];
ERROR;
};
FOR i IN [0..MaxFact) DO
exp[nterms] [i] ← exp[k] [i];
ENDLOOP;
RETURN[1];
};
Remove: PROC [k,nterms: INT] = {
i,j: INT;
FOR i IN [k..(nterms-1)) DO
FOR j IN [0..MaxFact) DO
exp[i] [j] ← exp[i+1] [j];
ENDLOOP;
ENDLOOP;
};
Selectprimes: PROC [nprimes: INT] RETURNS [INT] = {
ncore: INT;
ncore ← Findcore[nprimes];
IF nprimes = ncore THEN RETURN[ncore];
nprimes ← Tossaepi[nprimes,ncore];
nprimes ← Pickrest[nprimes,ncore];
RETURN[nprimes];
};
Findcore: PROC [nprimes: INT] RETURNS [INT] = {
i: INT;
ncore: INT ← 0;
k: INT;
FOR i IN [0..ninpterms) DO
IF (k ← Essentialpi[i,nprimes]) # NotCore THEN {
IF k > ncore THEN Swapprime[k,ncore];
IF k >=ncore THEN ncore ← ncore+1;
};
ENDLOOP;
RETURN[ncore];
};
Swapprime: PROC [i,j: INT] = {
temp,k: INT;
FOR k IN [0..MaxFact) DO
temp ← exp[i] [k];
exp[i] [k] ← exp[j] [k];
exp[j] [k] ← temp;
ENDLOOP;
};
Essentialpi: PROC [inpterm,nprimes: INT] RETURNS[INT] = {
i,k: INT;
ncover: INT ← 0;
FOR i IN [0..nprimes) DO
IF Subsume[MaxTerm+inpterm,i] THEN {
ncover ← ncover+1;
k ← i;
};
ENDLOOP;
IF ncover = 1 THEN RETURN[k];
RETURN[NotCore];
};
Tossaepi: PROC [nprimes,ncore: INT] RETURNS [INT] = {
i: INT;
j: INT;
corecovered,covers: BOOL;
i ← 0;
WHILE i < ninpterms DO
corecovered ← FALSE;
FOR j IN [0..ncore) DO
corecovered ← corecovered OR Subsume[MaxTerm+i,j];
ENDLOOP;
IF corecovered = TRUE THEN {
Remove[MaxTerm+i,MaxTerm+ninpterms];
ninpterms ← ninpterms-1;
i ← i-1;
};
i ← i+1;
ENDLOOP;
i ← ncore;
WHILE i < nprimes DO
covers ← FALSE;
FOR j IN [0..ninpterms) DO
covers ← covers OR Subsume[MaxTerm+j,i];
ENDLOOP;
IF covers = FALSE THEN {
Remove[i,nprimes];
nprimes ← nprimes-1;
i ← i-1;
};
i ← i+1;
ENDLOOP;
RETURN[nprimes];
};
Pickrest: PROC [nprimes,ncore: INT] RETURNS[INT] = {
i,j,k,min: INT;
more: BOOL;
save,used: ARRAY [0..MaxPI) OF BOOL;
FOR i IN [0..ninpterms) DO
k ← 0;
FOR j IN [ncore..nprimes) DO
IF Subsume[MaxTerm+i,j] THEN {
prodofsums[i] [k] ← j;
k ← k+1;
};
ENDLOOP;
IF k = 0 THEN {
IO.PutF[viewerout, "Input term %g not covered by PI\n", IO.int[i]];
ERROR;
};
prodofsums[i] [k] ← EndList;
ENDLOOP;
more ← TRUE;
min ← MaxPI;
FOR i IN [0..ninpterms) DO
ptr[i] ← 0;
ENDLOOP;
WHILE more = TRUE DO
FOR i IN [ncore..nprimes) DO
used[i] ← FALSE;
ENDLOOP;
k ← 0;
FOR i IN [0..ninpterms) DO
IF used[prodofsums[i] [ptr[i]]] = FALSE THEN {
used[prodofsums[i] [ptr[i]]] ← TRUE;
k ← k+1;
};
ENDLOOP;
IF k < min THEN FOR i IN [ncore..nprimes) DO
save[i] ← used[i];
min ← k;
ENDLOOP;
more ← Stepptr[ninpterms];
ENDLOOP;
k ← ncore;
FOR i IN [ncore..nprimes) DO
IF save[i] = TRUE THEN k ← k+1 ELSE Remove[k,nprimes];
ENDLOOP;
RETURN[k];
};
Stepptr: PROC [n: INT] RETURNS [BOOL] = {
i: INT;
FOR i IN [0..n) DO
IF prodofsums[i] [(ptr[i] ← ptr[i]+1)] # EndList THEN RETURN[TRUE] ELSE ptr[i] ← 0;
ENDLOOP;
RETURN[FALSE];
};
Report: PROC [nstart,nstop,nout: INT] = {
i: INT;
IO.PutF[results,"\n/%g ^ \n", IO.rope[vnames[nout]]];
FOR i IN [nstart..nstop) DO
Printterm[i];
IF i # (nstop-1) THEN IO.PutF[results," +\n"];
ENDLOOP;
IO.PutF[results,";\n\n"];
};
Printterm: PROC [i: INT] = {
j: INT;
first: BOOLTRUE;
FOR j IN [0..MaxFact) DO
IF exp[i] [j] = TrueTerm THEN {
IF first = TRUE THEN first ← FALSE ELSE IO.PutF[results," "];
IO.PutF[results,"%g",IO.rope[vnames[j]]];
};
IF exp[i] [j] = FalseTerm THEN {
IF first = TRUE THEN first ← FALSE ELSE IO.PutF[results," "];
IO.PutF[results,"/%g",IO.rope[vnames[j]]];
};
ENDLOOP;
};
Commander.Register[key: "///Commands/FSMTool", proc: MakeFSMTool,
doc: "Create a Finite State Machine tool" ];
[ ] ← MakeFSMTool[NIL]; -- and create an instance
END.