NB. Evaluation in Slow Motion  rev: 7 sep 01

NB. This script defines an adverb EVM which evaluates an expression.
NB. The argument of EVM is an expression as character-string, 
NB. for example '2+2' EVM .
NB. EVM also produces global variables which, when displayed,
NB. show the stages in the evaluation process.

NB. The main function:

EVM =: 1 : 0
setup x.
done  =: 0
while. not done  do.
   r =: inspect ''          NB. look for applicable rule
   update (<Q),(<S), <<r    NB. update history

   if.     not r -: 'none'  NB. some rule applies
       do. execute r , ' 0' NB. execute the rule

   elseif. (#Q) > 0         NB. no rule, some Q
       do. transfer ''      NB. get a word from Q

   elseif. 1
       do. done =: 1
   end.
end.

". 'zz =: ',  ; }. S
((5 !: 1) <'zz') (5 !: 0)    NB. deliver the result
)


NB.  Utility Functions and Constants

wordform =: ;:
unwordfm =: ;: ^: _1
print    =: (1 !: 2 ) & 2
First    =: {.
Last     =: {:
Most     =: }:
jclass   =: 4 !: 0
T1       =: 1 & {.  NB. Take 1 (first)
T2       =: 2 & {.
T3       =: 3 & {.  NB. Take 3
T4       =: 4 & {.  NB. Take 4
D3       =: 3 & }.  NB. Drop 3
D4       =: 4 & }.  NB. Drop 4
and      =: *.
or       =: +.
not      =: -.
rep      =: 5 !: 6  NB. representation-function
execute  =: ".

mark     =: 'mark'
letters  =:  ((65 + i. 26), (97 + i. 26)) { a.
digits   =: (48 + i. 10) { a.
nchars   =:  letters,digits,'_'

NB. A scheme for classifying the objects of the stack. We assign a number
NB. for each kind of object. Following the built-in J classification scheme, 
NB. nouns are class-0 objects, adverbs are class-1 objects and  so on.

Noun =: 0
Adv  =: 1
Conj =: 2
Verb =: 3
Name =: _1  NB. a name with no assigned value

NB. Also in the stack will be objects which are punctuation rather
NB. than values. We have the "mark" (marking the beginning of the expression), left and right
NB. parentheses and the symbol for assignment, ([=:] or [=.]). We give arbitrary numbers 
NB. to encode these classes.

Mark =: 99
Rpar =: 98
Lpar =: 97
Asgn =: 96

NB. Next some larger classes, represented by lists. 

VN   =: Verb, Noun
AVN  =: Adv,  Verb, Noun
CAVN =: Conj, Adv,  Verb, Noun
EDGE =: Mark, Asgn, Lpar
EAVN =: EDGE, AVN
NN   =: Noun, Name

NB. A pattern is a sequence of classes. Here is a verb to match the stack 
NB. against a pattern and identify the corresponding rule.

inspect =: 3 : 0
   if.     S match EDGE; Verb; Noun       do. 'monad'  
   elseif. S match EAVN; Verb; Verb; Noun do. 'monad2'  
   elseif. S match EAVN; Noun; Verb; Noun do. 'dyad'
   elseif. S match EAVN; VN;   Adv        do. 'adv'
   elseif. S match EAVN; VN;   Conj; VN   do. 'conj' 
   elseif. S match EAVN; Verb; Verb; Verb do. 'fork' 
   elseif. S match EDGE; CAVN; CAVN; CAVN do. 'trident' 
   elseif. S match EDGE; CAVN; CAVN       do. 'bident'  
   elseif. S match NN;   Asgn; CAVN       do. 'assign'  
   elseif. S match Lpar; CAVN; Rpar       do. 'paren'  
   elseif. 1                              do. 'none' 
   end.
)

setup =: 3 : 0
NB. set up global variables
Q   =: mark ; wordform y.  NB. a list of boxed strings
S   =: 0 $ < ' '           NB. a list of boxed strings
Qh  =: (0 , (#Q)) $ Q      NB. Q history
Sh  =: 0 1 $ Q             NB. Stack history
Rh  =: (0,1) $ < '  '      NB. Rule history
)


NB. verb to transfer a word from end of Q to front of S, 
NB. evaluating names which are nouns and not about to be assigned-to 

transfer =: 3 : 0
a =. > Last Q
if. isname a do. 
   if.  (classify a) = Noun  do.
         if. 1 - S match < Asgn  do.
             a =. > Eval < a 
end. end. end. 

S =: (<a) , S
Q =: Most Q
)

NB. A verb to test whether the stack matches a pattern of object-classes.
NB. The left argument x. is the stack, and the right argument y.
NB. is a pattern, a list of (sets of) classes.

match =: 4 : 0
if.   (# x.) < (# y.) do. 0       NB. stack too short
else. x. =. (# y.) {. x.
      *. / x. (match1 &: > " 0 0) y.
end.
)

NB. a verb to match a single stack item against a classification.
NB. case [q] catches reassigning to existing name
NB. case [r] embodies the assumption that an unassigned name denotes a verb

match1 =: 4 : 0
c =. classify x.
p =.  c e. y. 
q =. (y. -: NN)   and (isname x.) 
r =. (Verb e. y.) and (c -: Name) 
or/p,q,r
)

NB. A verb which tests whether a string is a name , that is,
NB. begins with a letter and contains only letters or digits or underscores.

isname  =: 3 : '((0 { y.) e. letters) and (*./  y. e. " 0 1 nchars)'

NB. A verb to classify a stack-item (a string). 

classify =: 3 : 0
if.     y. -: mark          do. Mark
elseif. y. -: 1 $ ')'       do. Rpar
elseif. y. -: 1 $ '('       do. Lpar
elseif. y. -: '=:'          do. Asgn
elseif. y. -: '=:'          do. Asgn
elseif. Name = jclass < y.  do. Name  NB.  an unused name !
elseif. 1                   do. 
                                ". 'x =. ' , y.
                                jclass < 'x'
end.
)


NB. Now the functions for the rules. Each computes a new value of S. 

monad  =: 3 : 'S =: (T1 S), (Eval 1 2 { S),   (D3 S) '
monad2 =: 3 : 'S =: (T2 S), (Eval 2 3 { S),   (D4 S) '
bident =: 3 : 'S =: (T1 S), (Eval 1 2 { S),   (D3 S) '
trident=: 3 : 'S =: (T1 S), (Eval 1 2 3 { S), (D4 S) '
dyad   =: 3 : 'S =: (T1 S), (Eval 1 2 3 { S), (D4 S) '
adv    =: 3 : 'S =: (T1 S), (Eval 1 2   { S), (D3 S) '
conj   =: 3 : 'S =: (T1 S), (Eval 1 2 3 { S), (D4 S) '
fork   =: 3 : 'S =: (T1 S), (Eval 1 2 3 { S), (D4 S) '
assign =: 3 : 'S =: (Is 0 1 2 { S), (D3 S)           '
paren  =: 3 : 'S =: (1&{ , D3) S                     '

NB. Each of these rule-functions needs to perform some actual computation.
NB. The computations are done by the Eval verb, or in case
NB. of assignments, by the Is verb.

NB. The argument of Eval is a sequence of stack items.
NB. After parenthesizing each item they are run together  
NB. to form a single string.  This string is executed. 
NB. The resulting value (of whatever kind) is turned back into a string with 
NB. the representation-function and boxed to give a single 
NB. stack-item, which is the result of Eval. 

Paren   =:  (('('&,) @ (, & ')')) &. >

Eval =: 3 : 0
execute 'z=. ' , ; Paren y.
< rep < 'z'
)

NB. The Is verb executes assignments. 
NB. Note that, for the purpose of the modelling, it is convenient 
NB. to force the assignment to be global. Otherwise, a local assignment would be
NB. buried inside the model itself. 

Is =: 3 : 0
execute 'z=. ', (> 0 { y.), '=:', (> 2} y.) 
< rep < 'z'
)

NB. function to record one stage, adding it to the history

update =: 3 : 0
'Q S R' =. y.
Qh =: Qh,Q
Sh =: Sh,S
if. R -: <'none' do. R =. <'    ' end.
Rh =: Rh,R
''
)

NB.  End of definition of modelling-adverb EVM.

NB. display of history: functions to generate an HTML table
NB. from the global variables Qh, Sh, Rh



td  =: 3 : '''<TD>'', y. , ''</TD>'''
TD  =: td @: ('<TT>' & ,)
b   =: ' '
bl  =: td b


show =: 3 : 0
print '<TABLE BORDER=1 CELLPADDING=4>'
print '<TR>'
print bl,bl,(td 'queue'),bl, ('<TD COLSPAN='),(": # 0{Sh), '> stack </TD>',bl ,(td 'rule')
i =. _1
while. (i =. i+1) < # Sh do. showrow i end.
print '</TABLE> <BR>'
''
)


showrow =: 3 : 0
i =. y.       NB. row-number
print '<TR>'
print TD ": i                         NB. stage
print bl, TD b, rmark unwordfm  i { Qh   NB. queue
print bl 
s =. i { Sh
j =. _1
while. (j =. j+1) < # s do. 
 print TD b, rmark > j { s           NB. stack item
end.
r =. i { Rh
print bl, TD b, > r                      NB. rule
''
)

NB. replace mark with HTML symbol in string y.
HTMLmark =: 38 35 49 54 55 59 { a.

rmark =: 3 : 'if. (T4 y.) -: mark do. HTMLmark, D4 y. else. y. end.'

NB.   -------  e n d ----------    last updated  7 sep 01
#
#

last updated 7 Sep 01