home *** CD-ROM | disk | FTP | other *** search
- module shell () {
-
- -----------------------------------------------------------------------
- -----------------------------------------------------------------------
- -- --
- -- An interactive top-level for use with OPS83 programs --
- -- --
- -----------------------------------------------------------------------
- -----------------------------------------------------------------------
-
-
- --
- -- DEFINITIONS
- --
-
- global
- &RUNFLG : logical, -- set to 0B to halt firings
- &LINE : name, -- the current input line
- &LNDX : integer, -- next char in &LINE to process
- &COM : char, -- the current command
- &ARGS : array(20 : name), -- the arguments
- &ACNT : integer, -- how many arguments there are
- &TLEV : integer; -- current trace level
-
-
- type start = element(task:integer);
-
-
- --
- -- FIRING RULES
- --
-
-
- procedure wmtrace()
- -- print trace info about wm changes
- {
- if (wmcadd())
- write() |=>wm:|
- else
- write() |<=wm:|;
- write() wmctype(), '\n';
- };
-
- procedure notrace()
- -- print no trace information
- {
- };
-
-
- function select():integer
- -- select the dominant instantiation and return its number; return 0 if
- -- there are no unfired instantiations
- {
- local
- &C:integer, -- current best choice
- &CTAG:integer, -- time tag of goal of &C
- &CLEN:integer, -- length of inst &C
- &CUSE:integer, -- number of times &C has fired
- &CRANK:real, -- rank order of &C
- &CCNT:integer, -- number of CEs in &C
- &N:integer, -- next inst to look at
- &NTAG:integer, -- time tag of goal of &T
- &NLEN:integer, -- length of inst &N
- &NUSE:integer, -- number of times &C has fired
- &NRANK:real, -- rank number for &N
- &NCNT:integer, -- number of CEs in &N
- &CSS:integer; -- CS size
-
- -- get the first unfired inst
- &CSS = cssize();
- &C=0;
- &N=&CSS;
- while (&C=0)
- {
- if (instance(&N,&CTAG,&CUSE,&CRANK,&CLEN,&CCNT) = 0b)
- return(0);
- if (&CUSE=0)
- &C=&N
- else
- &N=&N-1;
- };
-
- -- check the rest to find the dominant one
- &N = &C-1;
- while(1b)
- {
- if (instance(&N,&NTAG,&NUSE,&NRANK,&NLEN,&NCNT) = 0b)
- return(&C);
- if (&NUSE = 0)
- {
- if (&NTAG>&CTAG \/ (&NTAG=&CTAG /\ &NLEN>&CLEN))
- {&C=&N; &CLEN=&NLEN; &CTAG=&NTAG;};
- };
- &N = &N-1;
- };
- };
-
-
-
-
- procedure run(&L:integer)
- -- fire rules for up to &L cycles. if &L is less than 0, run for an
- -- indeterminate number of cycles.
- {
- local &I:integer,&C:integer,&NL:integer,&N:name,&TMP:integer;
-
- &RUNFLG = 1B;
- &I = 1;
- while(&L < 0 \/ &I <= &L)
- {
- &C = select();
- if (&C < 1) return;
- if (&TLEV > 0)
- {
- write() |fire:|;
- &NL = irule(&N,&C);
- for &TMP = (1 to &NL) write() &N[&TMP];
- write() '\n';
- };
- fire &C;
- if (&RUNFLG = 0B) return;
- &I = &I + 1;
- };
- };
-
-
- --
- -- UTILITIES
- --
-
- procedure error(&MSG:symbol)
- -- writes out an error message and sets the value of &COM to null
- -- to cause this input line to be ignored
- {
- write() '?', &MSG, '\n';
- &COM = '\0';
- };
-
-
-
- function printing(&C:char):logical
- -- returns 1B if its argument is a printing character
- {
- local &O:integer;
-
- &O = ord(&C);
- if (&O > 32 /\ &O < 127) return(1B);
- };
-
-
-
- procedure span()
- -- skip over blanks, tabs, etc in the input line
- {
- while (1B)
- {
- if (&LINE[&LNDX] = '\0')
- return
- else if (printing(&LINE[&LNDX]))
- return
- else
- &LNDX = &LNDX + 1;
- };
- };
-
-
-
-
- procedure getarg()
- -- read the next argument from the command line
- {
- local
- &C:char,
- &J:integer;
-
- &ACNT = &ACNT + 1;
- if (&ACNT > 20)
- {call error(|too many arguments|); return};
- &J = 1;
- while (1B)
- {
- &C = &LINE[&LNDX];
- if (~printing(&C))
- {&ARGS[&ACNT][&J] = '\0'; return};
- &ARGS[&ACNT][&J] = &C;
- &J = &J + 1;
- &LNDX = &LNDX + 1;
- };
- };
-
-
-
- function getline(&FILE:integer):logical
- -- read in the next command line from &FILE
- -- return 0B if the file was empty
- {
- local &Z, &EOL:integer, &C:char;
-
- --
- -- get prepared for errors
- --
- &COM = '\0'; &ACNT = 0;
-
- --
- -- read the input line
- --
- if (&FILE = 0) write() |>> |;
- &C = '\0';
- while (~printing(&C))
- {
- if (peek(&FILE) < 0) return(0B);
- read(&FILE) &C;
- };
- &LNDX = 1; &LINE[1] = &C;
- &Z = 0; &EOL = ord('\n');
- while ((&Z <> &EOL) /\ (&Z >= 0))
- {
- &Z = peek(&FILE);
- if ((&Z = &EOL) \/ (&Z < 0))
- &C = '\0'
- else
- read(&FILE) &C;
- &LNDX = &LNDX + 1;
- if (&LNDX > 127)
- {
- call error(|input line is too long|);
- while (1B)
- {
- if (peek(&FILE) < 0) return(1B);
- read(&FILE) &C;
- if (&C = '\n') return(1B);
- };
- };
- &LINE[&LNDX] = &C;
- };
-
- --
- -- find the command
- --
- &LNDX = 1;
- call span();
- if (&LINE[&LNDX] = '\0')
- {&COM = ' '; return(1B)}
- else
- &COM = &LINE[&LNDX];
- &LNDX = &LNDX + 1;
-
- --
- -- get the individual arguments if this is not a comment
- --
- if (&COM <> ';')
- {
- while (1B)
- {
- call span();
- if (&LINE[&LNDX] = '\0') return(1B);
- call getarg();
- };
- };
- return(1B);
-
- };
-
-
-
- --
- -- ROUTINES TO PROCESS INDIVIDUAL COMMANDS
- --
-
- procedure comsemi()
- {
- };
-
-
- procedure comx()
- {
- local
- &X:integer;
-
- if (&ACNT = 0)
- call run(1)
- else if (&ACNT > 1)
- call error(|x command takes only one argument|)
- else if (&ARGS[1][1] = 'x' /\ &ARGS[1][2] = '\0')
- call run(-1)
- else if (cvinteger(&X, &ARGS[1]) = 0B)
- call error(|illegal argument|)
- else
- call run(&X);
- };
-
-
-
- procedure comf()
- {
- local
- &FLDS:array(20:symbol),
- &FLG:logical,
- &TYP:symbol,
- &FN:symbol,
- &X,&Y:integer;
-
- --
- -- get the list of types
- --
- for &X = (1 to &ACNT)
- if (cvsymbol(&FLDS[&X], &ARGS[&X]) = 0B)
- {call error(|illegal argument|); return};
-
- --
- -- loop through wm printing the requested information
- --
- for &X = (1 to wsize())
- {
- &TYP = wtype(&X);
- if (&ACNT = 0)
- &FLG = 1B
- else
- &FLG = 0B;
- &Y = 1;
- while (&FLG = 0B /\ &Y <= &ACNT)
- {
- if (&FLDS[&Y] = &TYP) &FLG = 1B;
- &Y = &Y + 1;
- };
- if (&FLG)
- write() &X, |. |, &TYP, '\n';
- };
- };
-
-
-
- procedure comw()
- {
- local
- &WNDX:integer,
- &Z:integer;
-
- if (&ACNT = 0)
- {
- for &Z = (1 to wsize()) call wput(1, &Z);
- return;
- };
- for &Z = (1 to &ACNT)
- {
- if (cvinteger(&WNDX, &ARGS[&Z]) = 0B)
- {call error(|illegal argument|); return};
- if (&WNDX < 1 \/ &WNDX > wsize())
- {call error(|working memory index out of bounds|); return};
- call wput(1, &WNDX);
- };
- };
-
-
-
- procedure comd()
- {
- local
- &FILE:integer,
- &FNAME:symbol,
- &Z:integer;
-
- if (&ACNT = 0)
- &FILE = 1
- else if (&ACNT > 1)
- {call error(|wrong number of arguments|); return}
- else
- {
- if (cvsymbol(&FNAME, &ARGS[1]) = 0B)
- {call error(|illegal argument|); return};
- &FILE = create(&FNAME);
- if (&FILE < 0)
- {call error(|could not open file|); return};
- };
- for &Z = (1 to wsize())
- call wput(&FILE,&Z);
- if (&FILE <> 1)
- call close(&FILE);
- };
-
-
- procedure toplev(&FILE:integer) forward;
-
- procedure comat()
- {
- local
- &FILE:integer,
- &FNAME:symbol;
-
- if (&ACNT <> 1)
- call error(|wrong number of arguments|)
- else
- {
- if (cvsymbol(&FNAME, &ARGS[1]) = 0B)
- {call error(|illegal argument|); return};
- &FILE = open(&FNAME);
- if (&FILE < 0)
- {call error(|could not open file|); return};
- call toplev(&FILE);
- call close(&FILE);
- };
- };
-
-
- procedure comm()
- {
- local
- &RULE:symbol,
- &M:integer,
- &Z:integer,
- &C:integer;
-
- for &Z = (1 to &ACNT)
- {
- if (cvsymbol(&RULE, &ARGS[&Z]) = 0B)
- {call error(|illegal argument|); return};
- write() &RULE, ':', '\n';
- write() |....:....1....:....2....:....3....:|, '\n';
- &C = 0; &M = 0;
- while (&M >= 0)
- {
- &C = &C + 1;
- &M = cmatches(&RULE, &C);
- if (&M > 0)
- write() '*'
- else
- write() ' ';
- };
- write() '\n';
- &C = 0; &M = 0;
- while (&M >= 0)
- {
- &C = &C + 1;
- &M = pmatches(&RULE, &C);
- if (&M > 0)
- write() '*'
- else
- write() ' ';
- };
- write() '\n', '\n';
- };
- };
-
-
- procedure comc()
- {
- local
- &SIZE:integer,
- &NAME:name,
- &LEN:integer,
- &T:integer,
- &NDX:integer,
- &Z:integer;
-
- &SIZE = cssize();
- if (&SIZE = 0) return;
- for &Z = (1 to &SIZE)
- {
- write() &Z, |. |;
- &LEN = irule(&NAME, &Z);
- for &T = (1 to &LEN)
- write() &NAME[&T];
- write() | |;
- &T = 0; &NDX = 0;
- while (&NDX >= 0)
- {
- &T = &T + 1;
- &NDX = iindex(&Z, &T);
- if (&NDX >= 0) write() ' ', &NDX;
- };
- write() '\n';
- };
- write() '[', select(), | dominates]|, '\n';
- };
-
-
- procedure domods(&WMNDX:integer, &NXT:integer)
- -- make the modifications required for "+" and "#" commands
- -- &WMNDX : the wme to modify
- -- &NXT : the next attribute to process
- {
- local
- &FN:symbol,
- &R:real,
- &C:char,
- &L:logical,
- &S:symbol;
-
- --
- -- do initial checks
- --
- if (&NXT > &ACNT) return;
- if (&NXT + 1 > &ACNT)
- {call error(|no value provided for attribute|); return};
- if (&WMNDX < 1 \/ &WMNDX > wsize())
- {call error(|working memory index out of bounds|); return};
- if (cvsymbol(&FN, &ARGS[&NXT]) = 0B)
- {call error(|illegal argument|); return};
- --
- -- change the specified values
- --
- if (wextract(&S, &WMNDX, &FN))
- {
- if (cvsymbol(&S, &ARGS[&NXT+1]) = 0B)
- {call error(|illegal value|); return};
- if (wstore(&S, &WMNDX, &FN) = 0B)
- {call error(|could not store value|); return};
- }
- else if (wextract(&R, &WMNDX, &FN))
- {
- if (cvreal(&R, &ARGS[&NXT+1]) = 0B)
- {call error(|illegal value|); return};
- if (wstore(&R, &WMNDX, &FN) = 0B)
- {call error(|could not store value|); return};
- }
- else if (wextract(&L, &WMNDX, &FN))
- {
- if (cvlogical(&L, &ARGS[&NXT+1]) = 0B)
- {call error(|illegal value|); return};
- if (wstore(&L, &WMNDX, &FN) = 0B)
- {call error(|could not store value|); return};
- }
- else if (wextract(&C, &WMNDX, &FN))
- {
- &C = &ARGS[&NXT+1][1];
- if (wstore(&C, &WMNDX, &FN) = 0B)
- {call error(|could not store value|); return};
- }
- else
- {call error(|illegal field name|); return};
-
- --
- -- do the rest of the mods (note that the wme is now the last one in
- -- wm because it was just modified)
- --
- call domods(wsize(), &NXT+2);
- };
-
-
- procedure commod()
- {
- local
- &WMNDX:integer;
-
- if (&ACNT < 1)
- {call error(|# command requires at least one argument|); return};
- if (cvinteger(&WMNDX, &ARGS[1]) = 0B)
- {call error(|illegal argument|); return};
- call domods(&WMNDX, 2);
- };
-
-
- procedure comadd()
- {
- local
- &TYPE:symbol;
-
- if (&ACNT < 1)
- {call error(|+ command requires at least one argument|); return};
- if (cvsymbol(&TYPE, &ARGS[1]) = 0B)
- {call error(|illegal argument|); return};
- if (make(&TYPE) = 0B)
- {call error(|not a working memory type|); return};
- call domods(wsize(), 2);
- };
-
-
-
- procedure comrem()
- {
- local &WMNDX,&Z:integer;
-
- if (&ACNT <> 1)
- {call error(|- command requires one argument|); return};
- if (&ARGS[1][1] = '-' /\ &ARGS[1][2] = '\0')
- {
- for &Z = (wsize() downto 1)
- call wremove(&Z);
- }
- else
- {
- if (cvinteger(&WMNDX, &ARGS[1]) = 0B)
- {call error(|illegal argument|); return};
- if (wremove(&WMNDX) = 0B)
- {call error(|working memory index out of bounds|); return};
- };
- };
-
-
- procedure comt()
- {
- local &Z:integer;
-
- if (&ACNT < 1)
- {write() |Current trace level: |, &TLEV, '\n'; return;};
- if (cvinteger(&Z, &ARGS[1]) = 0B)
- {call error(|illegal argument|); return};
- if (&Z < 0 \/ &Z > 2)
- {call error(|illegal argument|); return};
- &TLEV = &Z;
- if (&TLEV = 2)
- on wmchange call wmtrace
- else
- on wmchange call notrace;
- };
-
-
- procedure comhelp()
- {
- write() |? Display this information|, '\n';
- write() |@ <file> Read commands from a file|, '\n';
- write() |+ <type> { <att> <val> }... Make a wme|, '\n';
- write() |# <index> { <att> <val> }... Modify a wme|, '\n';
- write() |- <index> Remove a wme|, '\n';
- write() |- - Remove all wmes|, '\n';
- write() |; Comment|, '\n';
- write() |c Display the conflict set|, '\n';
- write() |d Display the contents of wm|, '\n';
- write() |d <file> Dump wm to a file|, '\n';
- write() |f Display types of all wmes|, '\n';
- write() |f <type>... Find wmes of specified types|, '\n';
- write() |m <rule>... Display the lhs matches|, '\n';
- write() |Q Quit|, '\n';
- write() |t Display current trace level|, '\n';
- write() |t <level> Set the new trace level|, '\n';
- write() |w Print all wmes|,'\n';
- write() |w <index>... Print specified wmes|,'\n';
- write() |x Execute one rule|, '\n';
- write() |x <count> Execute <count> rules|, '\n';
- write() |x x Execute rules until system halts|, '\n';
- };
-
-
-
- --
- -- TOP LEVEL ROUTINES
- --
-
-
- procedure shellinit()
- -- must be called to initialize the shell variables
- -- before toplev() is called the first time
- {
- &TLEV = 0;
- };
-
-
-
- body toplev
- -- the top level of the interactive shell
- {
- if (status(&FILE) <> |read|)
- {call error(|illegal input file|); return};
- if (&FILE = 0)
- write() |OPS83 interactive top level. Type '?' for help|, '\n', '\n';
- while (1B)
- {
- if (~getline(&FILE)) return;
- if (&COM = ';')
- call comsemi()
- else if (&COM = 'x')
- call comx()
- else if (&COM = '+')
- call comadd()
- else if (&COM = '-')
- call comrem()
- else if (&COM = '#')
- call commod()
- else if (&COM = '@')
- call comat()
- else if (&COM = 'f')
- call comf()
- else if (&COM = 'w')
- call comw()
- else if (&COM = 'd')
- call comd()
- else if (&COM = 'm')
- call comm()
- else if (&COM = 'c')
- call comc()
- else if (&COM = 't')
- call comt()
- else if (&COM = '?')
- call comhelp()
- else if (&COM = 'Q')
- return
- else if (&COM <> '\0')
- write() |Enter ? for help|, '\n'
- };
- };
- }
-