Version 0 of A partial APL parser

Updated 2001-01-18 21:21:32

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
    }
 }

Arts and crafts of Tcl-Tk programming