Richard Suchenwirth: This is part 3 of the series that began with
Playing APL and
APLish - a partial parser
apl2t that converts a string in sub-APL to a string that can be eval'ed by Tcl (call
apl).
It is partial in two ways: it does not attempt to build a complete parse tree, and it does not cover more than a tiny subset of APL, but some already:
% apl2t {N N rho 1,N rho 0}
rho "$N $N" [, "1" [rho "$N" "0" ]]
% set N 5
5
% apl {N N rho 1,N rho 0}
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1
% apl N+2*0.5
6.414213562373095
Still a lot to do (quoted strings, compound operators like -:..), but it's tremendous fun...;-)
namespace eval APL {
namespace export apl apl2t
proc apl s {uplevel [apl2t $s]}
proc apl2t list {
set res ""
#---------- insert potential blanks everywhere, then reduce
set list [join [split $list ""] \x81]
foreach i {1 2} {
regsub -all "(\[_A-Z0-9\])\x81(\[_A-Z0-9\])" $list {\1\2} list
regsub -all "(\[a-z0-9\])\x81(\[a-z0-9\])" $list {\1\2} list
}
regsub -all "(\[.\])\x81(\[0-9\])" $list {\1\2} list
regsub -all "(\[0-9\])\x81(\[.\])" $list {\1\2} list
regsub -all \x81 $list " " list
set op ""
set last ""
#---------- walk the list from back
for {set n [llength $list]} {$n>0} {incr n -1} {
set it [lindex $list [expr $n-1]]
if [regexp {^[A-Z_]} $it] {
if {$last!="val"} {set it "$it\""}
set res "\$$it $res"
set last val
} elseif {[regexp {^-?[0-9.]} $it]} {
if {$last!="val"} {set it $it\"}
set res "$it $res"
set last val
} elseif {$it==")"} {
if {$last=="val"} {set res \"$res}
set last embed
set open [lsearch $list "("]
if {$open<0} {error "unmatched paren"}
set embed [lrange $list [incr open] [incr n -2]]
set res "\[[apl2t $embed]\] $res"
set n $open
} else {
if {$last=="val"} {set res \"$res}
set last op
if [llength $op] {
set res "$op $res"; set op ""
if {$n>2} {set res "\[$res\]"}
}
set op $it
}
}
if {$last=="val"} {set res \"$res}
if [llength $op] {set res "$op $res"}
set res
}
}