| top | | 68. Derive the attribute evaluation machine ::
The attribute rules are stored in the grammar. For the production
production: member,member,...,
the Horn clauses defining the attributes is stored as symbol string sets
in the property cs: production.member,member,....
- context-sensitive-value ::=
[ rule|rule... ]
- rule ::=
head [ ,term ] ...
| %query,query-name,term...
- head ::= term
- term ::=
<TERM,functor [ ,term ] ...>
| <VAR,variable>
| <NIL>
| <LIST,term...>
| <ANTIUNIFY,term,term>
| <FOREIGN,language, [ ,foreign-var ] ...,code>
| <FAILURE,_RECOVERY,_LOC>
| <SUCCESS,_RECOVERY>
| <ITREE,hypernotion,list>
| <OTREE,hypernotion,list>
- functor ::= production | %eq%
- foreign-var ::= +metanotion | -metanotion
Notation
In Prolog notation, a rule which could be written 'abc(X) :- pqr(X).'
is represented as a parsed, Cambridge notation symbols string
'<TERM,abc,<VAR,X>>,<TERM,pqr,<VAR,X>>'.
(except the commas and other punctuation between <...> are
hex escaped #hh). In these notes, TERM and VAR are omitted, and
lists are indicated by [a,b,...,z] instead of <LIST,a,b,...,z>.
Rather than using traditional attribute grammars, the context constraints
is handled with logic programmming techniques. More specifically the attribute
processing is the resolution of one query within a database of Horn clauses,
a Prolog-ish program which operates on the concrete
parse tree. However unlike Prolog the order of rules cannot be
significant. Also, though the not-equal relation can be used, there is no
cut.
The parse tree is tree is built of terms of lists:
<p ,
[P1 ,
P2 ,
... ,
Pm ,LOC]>
is the parse tree node labelled with hypernotion p ,
daughter parse trees P1 , P2 , and so on to Pm ,
and the implementation defined source location LOC.
The goal, then, is given the concrete parse tree of the entire input to return the
the attributed tree
- %query,%start,%start,<P_0,A_0>
The P_0 tree will be bound before starting the querying, the resulting
bound value of A_0, if any, is the attributed tree.
| ^ | | | | | | section top | | 69. Using not-equals with partially defined terms ::
Because the attributes can be partially defined, it is problematic
what not-equals actually means. If two partially defined terms are
checked for equality, if the defined parts are the same, the undefined
parts are linked so that they must also be the same; equals handles
past, present, and future equality. Not-equals also checks if the defined
parts of both terms are equal, but what should it do about undefined
parts? Does their potential equality mean
a future equality, or must the decision wait until the terms are
fully defined? The latter presents a difficult backtrack
problem: potentially an entire parse will have to backtrack if the
first predicate is not-equals. The former means adding time to
the logic, and then the orderring of clauses becomes important.
The former is adopted with this caveat.
Members within an alternative are not rearranged if not-equals is used
in that alternative or any predicate it calls.
Not-equals is verified by a failure to unify. Fully defined different
terms will not unify; partially defined terms might unify at the time
of the not-equals, even though subsequent predicates would unify them to
different terms.
It is the grammar writer's responsibility to use not-equals at a time
when the terms are as fully defined as the grammar needs them to be.
In a real vW2 grammar, inequality checks are on protonotions only,
which correspond to fully defined terms. The correct protonotions
are automagically guessed. cow grammars cannot rely on this magic
and be efficient.
| ^ | | | | | | section top | | | ^ | | | | | | section top | |
$grammar action: $pn $alt := [sym nest reduce_parse,[compileWAMConstant $pn 1],[sym length $alt]]
| ^ | | | | | | section top | |
if {[sym empty $alt]} {
foreach foreign [sym decode [hr::if foreign: $pn := {}]] {
setp {language output input code} [sym decode string $foreign]
if {[string match *immediate $language] && [string length $code]} {
if {![string equal $output -]} {
report E immediate foreign text has output: $pn: $output
}
if {![string equal $input -]} {
report E immediate foreign text has input: $pn: $input
}
if {[string match *immediate $language]} {
set language [string range $language 0 end-[string length immediate]]
}
symr0 action: $pn $alt := [sym nest [sym encode string foreign_immediate $language $code]]
}
}
}
| ^ | | | | | | section top | | | ^ | | | | | | section top | |
set rule [sym choose $rules]
set head [sym unnest [sym first $rule]]
set symbol [sym index $head 1]
set attribute [sym range $head 2 end]
$grammar action: $pn %shift := [sym nest [sym concat shift_lexeme \
[compileWAMConstant $symbol 1] \
[expr {![sym empty $attribute] || [sym contains [hr::if namedsymbols: := {}] $symbol]}] \
]]
| ^ | | | | | | section top | | | ^ | | | | | | section top | | | ^ | | | | | | section top | | | ^ | | | | | | section top | | | ^ | | | | | | section top | | | ^ | | | | | | section top | | | ^ | | | | | | section top | | 81. A database production rule ::
The vW1 separator writes the attribute evaluator for an
alternative pi of the production p as
- p: r1, ... , rn
-
<p,F1,...,Fm>
- <r1,...,V_1k,...>,
- ... ,
- <r_n,...,V_nl,...>
The concrete parse and attributed parse trees are created by adding variables and
terms to analyze the concrete parse tree P and synthesise the
attributed tree A.
-
<p,
-
- [<r1,P1>,<r2,P2>,...,<rn,Pn>,LOC],
- <p,F1,...,Fm,[A1,A2,...,An,LOC]>,
- F1,...,F_m>,
- <r1,P1,A1,...,V1k,...>,
- ...
- <rn,Pn,An,...,Vnl,...>,
LOC is the source file location, encoded in an implementor specific fashion.
(It would seem that the individually alternatives could be indexed explicitly,
something like
-
<pi+r1+r2+...+rn,
-
- [<r1,P1>,<r2,P2>,...,<rn,Pn>,LOC],
- <p,F1,...,Fm,[A1,A2,...,An,LOC]>,
- F1,...,F_m>,
- <r1,P1,A1,...,V1k,...>,
- ...
- <rn,Pn,An,...,Vnl,...>,
and avoid having to choose which alternative. But then the choice gets pushed into
the ri terms, where instead of single functor, all the possible parses
of ri+t1+t2+ have to be considerred, with combinatorial
explosion in the number of disjunctions. Instead of that
indexing can be done implicitly
as part of the logic machine optimisation.)
Predicates are deleted from the context free grammar, and so do not show
up in the parse tree, the Pi and Ai parameters, but they are still present
in the attribute analysis. Predicates have a different editted calling sequence:
they receive the parse tree location and name of calling production instead
of parse trees. These parameters are discussed next.
-
- ...
- <rn,...,Vnl,...,caller,LOC>,
- ...
Symbol have no parse tree, but they still have LOC; the calling sequence
is similar enough to productions that they need not be handled differently
at this moment.
set n [sym length $alt]
set newrules {}
sym each rule $rules {
set head [sym rest [sym unnest [sym first $rule]]]
set Plist [sym nest [sym concat LIST [sym nest VAR,_LOC] NIL]]
set Alist [sym nest [sym concat LIST [sym nest VAR,_LOC] NIL]]
for {set i $n} {$i>=1} {incr i -1} {
set Plist [sym nest [sym concat LIST [sym nest VAR,_P$i] $Plist]]
set Alist [sym nest [sym concat LIST [sym nest VAR,_A$i] $Alist]]
}
<Generated command: term_production>
if {[rew::if :[sym first $head]]} {
<Redirect production tree construction to the rewriting rules>
} else {
set Alist [sym nest [sym concat TERM $head $Alist]]
set newrule [sym nest [sym concat TERM [sym first $head] $Plist $Alist [sym rest $head]]]
}
set i 1
sym enum term [sym rest $rule] {
set term [sym unnest $term]
if {[sym contains [$grammar predicates:] [sym index $term 1]]} {
set term [sym concat \
$term \
[sym nest [sym encode string [list TERM "[sym index $term 1] in $pn"]]] \
[sym nest VAR,_LOC]
]
} else {
set term [sym concat \
[sym range $term 0 1] \
[sym nest VAR,_P$i] \
[sym nest VAR,_A$i] \
[sym range $term 2 end] \
]
incr i
}
set newrule [sym concat $newrule [sym nest $term]]
}
set newrules [sym union $newrules $newrule]
}
$grammar cs: $pn $alt := $newrules
| ^ | | | | | | section top | | 82. A database predicate rule ::
Predicates are inaccessible in the context free grammar; they are still
defined to an empty string. All the interesting stuff is the disjunction
of clauses in the cs: property.
- p: #NS
-
<p,F1,...,Fm>
- <r1,...,V_1k,...>,
- ... ,
- <r_n,...,V_nl,...>
Recovery and location parameters are added to the predicates. If the predicate is called
from a predicate, these will be unbound. If called from a production,
these parameters will be the production name and location.
The predicate body is patched to produce an error message
if all alternatives fail and its recovery parameter is bound.
-
<p,F1,...,Fm,RECOVERY,LOC>
- <r1,...,V_1k,...,RECOVERY,LOC>,
- ... ,
- <r_n,...,V_nl,...,RECOVERY,LOC>
set newrules {}
set head "#NS"
sym each rule $rules {
set head [sym unnest [sym first $rule]]
set newrule [sym nest [sym concat \
$head \
[sym nest VAR,_RECOVERY] \
[sym nest VAR,_LOC] \
]]
sym enum term [sym rest $rule] {
set term [sym nest [sym concat [sym unnest $term] [sym nest VAR,_] [sym nest VAR,_]]]
set newrule [sym concat $newrule $term]
}
set newrule [sym concat $newrule [sym nest SUCCESS,_RECOVERY]]
set newrules [sym union $newrules $newrule]
}
$grammar cs: $pn $alt := $newrules
<Define predicate recovery term>
| ^ | | | | | | section top | |
set database [concat $database $predicaterecoveries]
| ^ | | | | | | section top | |
if {[sym length $head]>=2} {
set n [expr {[sym length $head]-2}]
set predicaterecovery [sym range $head 0 1]
for {set i 2} {$i<$n} {incr i} {
set predicaterecovery [sym concat $predicaterecovery [sym nest VAR,_]]
}
set predicaterecovery [sym concat $predicaterecovery [sym nest VAR,_RECOVERY]]
set predicaterecovery [sym concat $predicaterecovery [sym nest VAR,_LOC]]
set predicaterecovery [sym concat [sym nest $predicaterecovery] [sym nest FAILURE,_RECOVERY,_LOC]]
lappend predicaterecoveries $predicaterecovery
}
| ^ | | | | | | section top | |
set head [sym first $clause]
set tail [sym rest $clause]
set queryvar 0
| ^ | | | | | | section top | |
set QUERY %query,%start,[sym nest TERM,%start,[sym nest VAR,P_0],[sym nest VAR,A_0]]
| ^ | | | | | | section top | |
set head "#NS"
set queryname [sym index $clause 1]
set tail [sym range $clause 2 end]
if {[string equal $queryname %start]} {
set querystart [llength $C]
set Y(a.[llength $C]) %query
} else {
<Record the subquery address>
}
| ^ | | | | | | section top | | | ^ | | | | | | section top | |
lappend C [list query_start C.$querystart $variableAssignments]
| ^ | | | | | | section top | |
lappend C [list subquery_start $queryname C.$querystart $variableAssignments]
| ^ | | | | | | section top | |
set EQFACT [sym nest TERM,%eq%,[sym nest VAR,ATTRIBUTE],[sym nest VAR,ATTRIBUTE],[sym nest VAR,_]]
| ^ | | | | | | section top | |
set newrules {}
sym each rule $rules {
set head [sym unnest [sym first $rule]]
set symbol [sym index $head 1]
set attribute [sym range $head 2 end]
if {[sym empty $attribute] && [sym contains [hr::if namedsymbols: := {}] $symbol]} {
set attribute [sym nest VAR,_NAME]
}
set core [sym nest LIST,[sym nest VAR,_LOC],NIL]
if {![sym empty $attribute]} {
set core [sym nest LIST,$attribute,$core]
gen term_production $symbol 2
}
set newrules [sym concat $newrules [
sym nest [sym concat \
TERM \
$symbol \
$core \
[sym nest [sym concat TERM $symbol $attribute $core]] \
$attribute \
] \
]]
}
$grammar cs: $pn $alt := $newrules
| ^ | | | | | | section top | |
set head [sym first $clause]
set choices "#NS"
set queryvar 0
| ^ | | | | | | section top | | 94 ::
The memory used by the WAM is divided into eight zones: integers, registers,
constant, heap, list, environment stack, trailback, and foreign. The operand in WAM
instructions are prefixed with a letter and full stop which indicate which
zone the operand is in.
- J
-
Integer. No memory is actually allocated in this zone: the offset
is the integer. It encodes negative and positive integers.
- X and A
-
Global register. Offset i is the register
A.i or X.i.
- C
-
Constant arity. A constant c/0 or
structure functor f/n is encoded in the C zone
with offset i: the value at
C.i is the arity, 0 or n, and
F[i] is the string, c or f.
The WAM does not itself interrogate the F vector, but this is
needed to construct a readable representation from the heap. After
machine intialisation F and the C zone are not modified
by the machine.
-
Constant operands are written C.i.f [ /n ] .
C.i is the tagged offset; the remainder is presented
to document the code.
- H
-
The heap. If the cell is the start of a structure, its tag has the modifier
bit set.
- list
-
The heap again. This is mapped into the H zone. Offsets to list cells are tagged
to be in the list zone instead of heap zone (for structure pointers and ref cells)
because of how tag bits are allocated.
- S and Y
-
Environment stack. Y.i is a permanent register,
relative to the E register (environment stack pointer).
- trail
-
The trail stack.
- foreign
-
Foreign. WAM does not create or interpret the foreign zone. This zone can be used
to store foreign values and give them a tagged address.
- L or R
-
WAM instruction are not stored in the memory and not in any zone.
Instruction offsets are labelled
L.o [ .f/n ] or
R.o where o is the code offset. A procedure name
may be included as commentary. Some addresses must be somehow tagged
because they are stored in the environment stack; these
are the offset labelled with R instead of L. How the addresses are encoded
depends upon the implementation.
| ^ | | | | section top | | | ^ | | | | | | section top | |
lappend C [list allocate $allocate]
| ^ | | | | | | section top | |
lappend C [list get_constant [compileWAMConstant $f 0] A.$r]
| ^ | | | | | | section top | |
lappend C [list get_list $tr]
| ^ | | | | | | section top | |
lappend C [list get_structure [compileWAMConstant $f $n] $tr]
| ^ | | | | | | section top | |
lappend C [list get_value $map($f) A.$a]
| ^ | | | | | | section top | |
lappend C [list get_variable $map($f) A.$a]
| ^ | | | | | | section top | | | ^ | | | | | | section top | | | ^ | | | | | | section top | | | ^ | | | | | | section top | | | ^ | | | | | | section top | |
lappend C [list unify_constant [compileWAMConstant $f 0]]
| ^ | | | | | | section top | |
lappend C [list unify_local_value $map($f)]
| ^ | | | | | | section top | |
lappend C [list unify_value $map($f)]
| ^ | | | | | | section top | |
lappend C [list unify_variable $tr]
| ^ | | | | | | section top | |
lappend C [list unify_void 1]
| ^ | | | | | | section top | |
set flattenned {}
vprioq new work 0 [list 0 $head]
while {[vprioq dequeue work task est; set est]} {
setp {d list} $task
if {[sym nested $list]} {set list [sym unnest $list]}
switch [sym first $list] {
TERM {
set functor [sym index $list 1]
set terms [sym range $list 2 end]
lappend flattenned $d [sym length $terms] $functor
incr d
while {![sym empty $terms]} {
vprioq enqueuebefore work [list $d [sym last $terms]]
set terms [sym front $terms]
}
}
VAR {
lappend flattenned $d -1 [sym last $list]
}
NIL {
lappend flattenned $d 0 %nil
}
LIST {
set list [sym rest $list]
lappend flattenned $d 2 LIST
incr d
while {![sym empty $list]} {
vprioq enqueuebefore work [list $d [sym last $list]]
set list [sym front $list]
}
}
}
}
| ^ | | | | | | section top | | | ^ | | | | | | section top | |
lappend C [list anti_get_value A.1 A.2]
| ^ | | | | | | section top | |
lappend C [list call $f/$n $n 0]
| ^ | | | | | | section top | | | ^ | | | | | | section top | |
lappend C [list execute $f/$n 0 $n]
| ^ | | | | | | section top | |
if {[string equal $language %symbol]} {
<ref tag='%symbol table foreign text inserted in the grammar'/>
} else {
lappend C [list foreign_text $language $no $ni $varnames $foreigntext]
}
| ^ | | | | | | section top | |
lappend C [list if_bound A.$i]
| ^ | | | | | | section top | |
lappend C [list on_failure A.1 A.2]
| ^ | | | | | | section top | |
lappend C [list on_failure A.1]
| ^ | | | | | | section top | |
lappend C [list put_constant [compileWAMConstant $f 0] A.$r]
| ^ | | | | | | section top | |
lappend C [list put_list $tr]
| ^ | | | | | | section top | |
lappend C [list put_structure [compileWAMConstant $f $n] $tr]
| ^ | | | | | | section top | |
lappend C [list put_unsafe_value $map($f) A.$a]
| ^ | | | | | | section top | |
lappend C [list put_value $map($f) A.$a]
| ^ | | | | | | section top | |
lappend C [list put_variable $map($f) A.$a]
| ^ | | | | | | section top | |
lappend C [list put_void A.$a]
| ^ | | | | | | section top | |
lappend C [list set_constant $r]
| ^ | | | | | | section top | |
lalappend C [list set_local_value $r]
| ^ | | | | | | section top | |
lappend C [list set_value $r]
| ^ | | | | | | section top | |
lappend C [list set_variable $r]
| ^ | | | | | | section top | |
lappend C [list set_void 1]
| ^ | | | | | | section top | |
lappend C [list trim_environment $le]
| ^ | | | | | | section top | |
set flattenned {}
vprioq new work 0 [list 0 0 $term]
while {[vprioq dequeue work task est; set est]} {
setp {out d list} $task
if {[sym nested $list]} {set list [sym unnest $list]}
if {$out} {
setp {d n f} $list
lappend flattenned $d $n $f
} else {
switch [sym first $list] {
TERM {
set functor [sym index $list 1]
set terms [sym range $list 2 end]
vprioq enqueuebefore work [list 1 0 [list $d [sym length $terms] $functor]]
incr d
while {![sym empty $terms]} {
vprioq enqueuebefore work [list 0 $d [sym last $terms]]
set terms [sym front $terms]
}
}
VAR {
lappend flattenned $d -1 [sym last $list]
}
NIL {
lappend flattenned $d 0 %nil
}
LIST {
set list [sym rest $list]
vprioq enqueuebefore work [list 1 0 [list $d 2 LIST]]
incr d
while {![sym empty $terms]} {
vprioq enqueuebefore work [list 0 $d [sym last $terms]]
set terms [sym front $terms]
}
}
ANTIUNIFY {
set list [sym rest $list]
vprioq enqueuebefore work [list 1 0 [list $d -2 ANTIUNIFY]]
incr d
while {![sym empty $terms]} {
vprioq enqueuebefore work [list 0 $d [sym last $terms]]
set terms [sym front $terms]
}
}
FAILURE {
set list [sym rest $list]
vprioq enqueuebefore work [list 1 0 [list $d -3 FAILURE]]
incr d
while {![sym empty $terms]} {
vprioq enqueuebefore work [list 0 $d [sym last $terms]]
set terms [sym front $terms]
}
}
SUCCESS {
set list [sym rest $list]
vprioq enqueuebefore work [list 1 0 [list $d -6 SUCCESS]]
incr d
while {![sym empty $terms]} {
vprioq enqueuebefore work [list 0 $d [sym last $terms]]
set terms [sym front $terms]
}
}
FOREIGN {
set code [sym last $list]
set language [sym index $list 1]
set list [sym range $list 2 end-1]
set vars {}
set d0 $d; incr d
set m 0
set n 0
sym enum var $list {
if {[string match +* $var]} {
incr m
set var [string range $var 1 end]
lappend vars $var
lappend flattenned $d -1 $var
}
}
foreach var $list {
if {[string match -* $var]} {
incr n
set var [string range $var 1 end]
lappend vars $var
lappend flattenned $d -1 $var
lappend flattenned $d -5 $var
}
}
lappend flattenned $d0 -4 [list $language $m $n $vars $code]
}
}
}
}
| ^ | | | | | | section top | |
set MZ {
{initialise_memory C.0 J.0}
{initialise_memory C.1 J.0}
{initialise_constant C.0 %nil 0}
{initialise_constant C.1 %undefined 0}
}
set F {%nil %undefined}
| ^ | | | | | | section top | | | ^ | | | | | | section top | |
gen term_vars $pn/[sym length $vars] $vars
| ^ | | | | | | section top | |
gen term_production [sym first $head] [sym length $head]
| ^ | | | | | | section top | |
lappend MZ [list initialise_constant C.[llength $F] [list $f] $arity]
| ^ | | | | | | section top | |
lappend MZ [list initialise_memory C.[llength $F] J.$arity]
| ^ | | | | | | section top | | | ^ | | | | | | section top | | | ^ | | | | | | section top | |
array set Y {c.%nil/0 0 c.%undefined/0 0}
| ^ | | | | | | section top | |
unset -nocomplain peuse
unset -nocomplain pecount
unset -nocomplain peclient
array set peuse {}
array set pecount {}
array set peclient {}
vprioq new work
set i 1
if {[sym length $head]} {vprioq enqueue work [list 1 $head]}
sym enum term $tail {
vprioq enqueue work [list $i $term]
incr i
}
while {[vprioq dequeue work task est; set est]} {
setp {i list} $task
if {[sym nested $list]} {set list [sym unnest $list]}
switch [sym first $list] {
VAR {
set var [sym last $list]
lappend peuse([list $var $i]) $i
set pecount($var) 0
}
TERM {
sym enum term [sym range $list 2 end] {vprioq enqueue work [list $i $term]}
}
LIST - ANTIUNIFY - FAILURE - SUCCESS {
sym enum term [sym range $list 1 end] {vprioq enqueue work [list $i $term]}
}
FOREIGN {
sym enum term [sym range $list 2 end-1] {
set var [string range $term 1 end]
lappend peuse([list $var $i]) $i
set pecount($var) 0
}
}
}
}
foreach v [array names peuse] {
setp {v c} $v
incr pecount($v)
lappend peclient($v) $c
}
set permanent0 {}
foreach {v k} [array get pecount] {
if {$k>1} {
lappend permanent0 [list $v [lindex [lsort -integer $peclient($v)] end]]
}
}
set permanent0 [lsort -integer -decreasing -index 1 $permanent0]
| ^ | | | | | | section top | |
unset -nocomplain ulvar
array set ulvar {}
vprioq new work
if {[sym length $head]} {vprioq enqueue work $head}
sym enum term $tail {vprioq enqueue work $term}
while {[vprioq dequeue work list est; set est]} {
if {[sym nested $list]} {set list [sym unnest $list]}
switch [sym first $list] {
VAR {
set v [sym last $list]
if {![info exists ulvar($v)]} {set ulvar($v) 0}
incr ulvar($v)
}
TERM {
sym enum term [sym range $list 2 end] {vprioq enqueue work $term}
}
LIST - ANTIUNIFY - FAILURE - SUCCESS {
sym enum term [sym range $list 1 end] {vprioq enqueue work $term}
}
FOREIGN {
sym enum term [sym range $list 2 end-1] {
set v [string range $term 1 end]
if {![info exists ulvar($v)]} {set ulvar($v) 0}
incr ulvar($v)
}
}
}
}
set useless {}
foreach {v k} [array get ulvar] {
if {$k<2} {lappend useless $v}
}
| ^ | | | | | | section top | |
foreach {procname aentry} [array get Y e.*] {
set procname [lindex [split $procname .] 1]
if {[string equal [lindex $C $aentry 0] nop]} {
unset Y(a.$aentry); incr aentry; set Y(a.$aentry) $procname; set Y(e.$procname) $aentry
}
if {[string equal [lindex $C $aentry 0] try_me_else]} {
<Index WAM/cow procedure>
}
}
| ^ | | | | | | section top | |
set arity [lindex $C $aentry 2]
if {![string length $arity]} {error null-arity}
array set procindex {V {} C {} L {} S {}}
for {set aclause $aentry} {$aclause!=0} {set aclause $anextclause} {
if {[string equal [lindex $C $aclause 0] trust_me]} {
set anextclause 0
} else {
set anextclause [lindex $C $aclause 1]
}
set asubclause $aclause; incr asubclause; set afirstget $asubclause
while 1 {
switch [lindex $C $afirstget 0] {
allocate {
incr afirstget
}
get_structure {
lappend procindex(S) [lindex $C $afirstget 2] $asubclause
break
}
get_constant {
lappend procindex(C) [lindex $C $afirstget 2] $asubclause
break
}
get_list {
lappend procindex(L) $asubclause
break
}
default {
lappend procindex(V) $aclause
break
}
}
}
}
foreach x {C S} y {switch_on_constant switch_on_structure} {
if {[llength $procindex($x)]==2} {
set procindex($x) [thirdlevel [concat [lindex $procindex($x) 1] $procindex(V)]]
} elseif {[llength $procindex($x)]==0} {
set procindex($x) [thirdlevel $procindex(V)]
} else {
unset -nocomplain H
foreach {symbol address} $procindex($x) {lappend H($symbol) $address}
set switch {}
foreach {symbol addresses} [array get H] {
set addresses [thirdlevel [concat $addresses $procindex(V)]]
lappend switch $symbol $addresses
}
set procindex($x) [llength $C]
lappend C [list $y $switch]
}
}
set procindex(L) [thirdlevel $procindex(L)]
set asegment [llength $C]
unset Y(a.$aentry); set Y(a.$asegment) $procname
set Y(e.$procname) $asegment
<Generated command: switch_on_term>
| ^ | | | | | | section top | |
proc thirdlevel {addresses} {
upvar 1 arity arity C C
if {[llength $addresses]==1} {
return $addresses
} elseif {[llength $addresses]>1} {
set aswitch [llength $C]
for {set i 0; set n [llength $addresses]} {$i<$n} {incr i} {
set a [lindex $addresses $i]
if {$i==0} {
<Generated command: try>
} elseif {$i+1==$n} {
<Generated command: trust>
} else {
<Generated command: retry>
}
}
return $aswitch
} else {
return 0
}
}
| ^ | | | | | | section top | |
lappend C [list retry $a]
| ^ | | | | | | section top | | | ^ | | | | | | section top | | | ^ | | | | | | section top | |
lappend C [list switch_on_term $aentry $procindex(C) $procindex(L) $procindex(S)]
| ^ | | | | | | section top | |
lappend C [list trust $a]
| ^ | | | | | | section top | |
lappend C [list try $a $arity]
| ^ | | | | | | section top | |
foreach {e addr} [array get Y e.*] {
set e [lindex [split $e .] 1]
foreach ref $Y(f.$e) {
lset C $ref 2 $addr
}
}
| ^ | | | | | | section top | |
set p 0
set sections {}
set section L.0
array set target {}
foreach instruction $C {
switch [lindex $instruction 0] {
switch_on_constant {
foreach {c L} [lindex $instruction 1] {
set target($L) 1
}
}
call - execute {
set target([lindex $instruction 2]) 1
}
try - retry - trust {
set target([lindex $instruction 1]) 1
}
}
}
set o 0
foreach instruction $C {
if {[info exists target($p)] && [llength $section]>1} {
lappend section [list continue_at L.$p]
lappend sections $section
set section L.$p
}
incr o
set p1 [expr {$p+1}]
if {[info exists Y(a.$p)]} {
lappend section [list entry_point $Y(a.$p)]
}
switch [lindex $instruction 0] {
call {
set instruction [
concat call [list L.[lindex $instruction 2].[lindex $instruction 1]] [lrange $instruction 3 end] R.$p1
]
lappend section $instruction
lappend sections $section
set section L.$p1
}
retry - try {
lset instruction 1 L.[lindex $instruction 1]
lappend instruction R.$p1
lappend section $instruction
lappend sections $section
set section L.$p1
}
execute {
set instruction [
concat execute [list L.[lindex $instruction 2].[lindex $instruction 1]] [lrange $instruction 3 end]
]
lappend section $instruction
lappend sections $section
set section L.$p1
}
trust {
lset instruction 1 L.[lindex $instruction 1]
lappend section $instruction
lappend sections $section
set section L.$p1
}
fail - pass - proceed {
lappend section $instruction
lappend sections $section
set section L.$p1
}
switch_on_constant - switch_on_structure {
set op [lindex $instruction 0]
set hash {}
foreach {c l} [lindex $instruction 1] {
lappend hash $c L.$l
}
set instruction [list $op [list $hash]]
lappend section $instruction
lappend sections $section
set section L.$p1
}
switch_on_term {
setp {op v c l s} $instruction
set instruction [list $op L.$v L.$c L.$l L.$v]
lappend section $instruction
lappend sections $section
set section L.$p1
}
try_me_else - retry_me_else {
lset instruction 1 R.[lindex $instruction 1]
lappend section $instruction
}
default {
lappend section $instruction
}
}
set p $p1
}
set code {}
foreach section $sections {
set section [setp name $section]
lappend code [list BEGIN section $name]
foreach instruction $section {
lappend code $instruction
}
lappend code END
}
| ^ | | | | | | section top | |
gen BEGIN attribute_wam [$grammar name:]
gen BEGIN wam_initialisation
gen initialise_register B S.0
gen initialise_register BO S.0
gen initialise_register CP L.1
gen initialise_register E S.1
gen initialise_register H H.0
gen initialise_register HB H.0
gen initialise_register mode READ
gen initialise_register P L.0
gen initialise_register S H.0
gen initialise_register TR T.0
foreach command $MZ {
eval gen $command
}
gen END
gen BEGIN eval_loop
foreach instruction $code {gen $instruction}
gen END
gen END
| ^ | | | | | | section top | | | ^ | | | | | | section top | | | ^ | | | | | | section top | | | ^ | | | | | | section top | | | ^ | | | | | | section top | | | ^ | | | | | | section top | | | ^ | | | | section top | | | ^ | | | | section top | |
proc displayAttribute {parsed} {
if {[sym nested $parsed]} {set parsed [sym unnest $parsed]}
#puts [string repeat . [info level]]$parsed
switch [sym card $parsed] {
0 {return "{}"}
1 {;}
default {
set U ""; set sep ""
sym each term $parsed {append U $sep[displayAttribute $term]; set sep "; "}
return $U
}
}
switch [sym first $parsed] {
%query {
return "[sym index $parsed 1] ?-[displayAttribute [sym range $parsed 2 end]]."
}
TERM {
set args {}
set r [sym index $parsed 1]
sym enum arg [sym range $parsed 2 end] {
append args ",[displayAttribute $arg]"
}
return <$r$args>
}
VAR {
return [sym last $parsed]
}
LIST {
set a [sym index $parsed 1]
set b [sym unnest [sym index $parsed 2]]
set a [displayAttribute $a]
while 1 {
switch [sym first $b] {
LIST {
set x [sym index $b 1]
set b [sym unnest [sym index $b 2]]
append a ,[displayAttribute $x]
}
NIL {
set r \[$a\]
break
}
default {
set r \[$a|[displayAttribute $b]\]
break
}
}
}
return $r
}
NIL {
return {[]}
}
ANTIUNIFY {
set a [sym index $parsed 1]
set b [sym index $parsed 2]
return "<%antiunify%,[displayAttribute $a],[displayAttribute $b]>"
}
FAILURE {
return "%failure-recovery%"
}
SUCCESS {
return "%success%"
}
FOREIGN {
return "<%foreign%,[sym range $parsed 1 end]>"
}
default {
set r ""; set sep1 ""; set sep2 " :- "
sym enum predicate $parsed {
if {[string equal $predicate $parsed]} {error HANG}
append r "$sep1[displayAttribute $predicate]"
set sep1 $sep2
set sep2 ", "
}
return $r.
}
}
}
| ^ | | |
| |