Below find a cut/plaste of a Wiki article contributed by TV (ast least
this appears to be the initials).
So far this is the only document that directly addresses my primary
concern of evoking Maxima functionality from a TCL interactive or batch
type program using MS XP OS. This document does a good job of
explaining my concerns. What worries me is that the solutions provided
are of the nature of a prototype and testing has not been exhaustive.
My question on this document (actually an extract of the original and
some small edits) is as follows:
(1) Has no one taken this prototype and integrated (compiled into) it
into the TCL package provided with the Maxima installation on MS XP OS????
(2) Given the information found in the attachments (and if they get
filtered from the list try the below text version cut and pasted from
the (txt) attachment - format with word wrap) what special
considerations would be required in doing this compile to ensure that
the functions created by TV in an interactive TCL session (with some
complications) functions the same way as the his interactive session..
HERE IS THE CUT AND PASTE
I've thus far tested Maxima on windows (XP), and it proved to be useful
and useable, not in the least because of its integration with tcl,
though maybe that isn't perfect from a strict programmer's point of view.
The mechanism which is used in maxima to interface between the Tcl and
Tk supplied user interface (at least on windows) is that a maxima
process communicates with the Tcl/Tk interface process over a socket,
over which mainly text is being sent back and forth containing
mathematica statements/commands/formulas and the answers from the maxima
'engine', a technique succesfully used in professional software of
various kinds.
The possible disadvantage is that for each communication, process change
is needed in the process time slicer, which probably works with at most
a granularity of a millisecond or so. Most maxima commands aren't
executed blazing fast, and usually don't really need to, so that in
practice (process change) is probably not a granularity problem.
As stated on the maxima page, the way normally the tcl/tk + maxima
'program' maxima.exe communicates the user input to the maxima lisp
based core (is) primarily by reading from and outputting to a text
widget, which from a UI perspective is not a bad idea. In fact it
appears the maxima.exe is a tclkit (tcl+tk+incrtcl+metakit) apparently
calling some scripts, and in the same dir with as.exe, gcc.exe, and some
dlls.
This is not very handy in my opinion, I'd prefer a few script files
which simply normally start up tcl/tk of which I control the
installation, which works fine for me, and would seem to require less
files, and be more overseeable.
Maybe I'll try, and in the process see if that way a more recent tcl/tk
can be
used
The maxima tcl procedure to make user interactions work is that somehow
pressing return in the .maxima.text widget invokes the routine CMeval
with (normally) the window name .maxima.text as only argument. This
procedure does some regexpr stuff and basically pushes the maxima input
line where the cursor is through the maxima command socket stream to the
engine.
The socket of this non-blocking connection has a fileevent readable
routine scheduled to activate when data arrives back from the engine:
maximaFilter .maxima.text sock156 (second argument depending on session
of course).
There seem to be various return kinds, and it could be data can be multi
line and maybe even intra-line split up in seperate return packets.
Below is a first very prototypical hack to make a (TCL) proc that
executes maxima commands and returns 'clean' results, which I made by
starting maxima, loading bwise034.tcl in the opened console (not needed
to run the below), somehow redefining the below proc (source in console
or as I did edit the
bwise procedure window), and of course loading the domax proc.
I've come up with a first simple (read not too tested, subjected to the
above considerations of possible failure) way to have a procedure to
give a expression to maxima, and have the return value return to the tcl
caller. I've changed the following proc:
proc maximaFilter { {win} {sock} } {
linkLocal $win plotPending
global pdata
#TV added:
global passres
###
if { [eof $sock] } {
# puts "at end"
close $sock
return ""
}
set it [read $sock]
# puts "read=<$it>"
if { [string first "\032\032" $it] >= 0 &&
[regexp -indices "\032\032(\[^:]+):(\[0-9]+):\[^\n]*\n" $it junk
file line] } {
dblDisplayFrame [getMatch $it $file] [getMatch $it $line]
append res [string range $it 0 [expr { [lindex $junk 0] -1 } ]]
append res [string range $it [expr { 1+[lindex $junk 1]}] end]
set it $res
}
if { [string first "\032\031tcl:" $it] >= 0 && [regexp -indices
"\032\031tcl:(\\[^\n]*)\n" $it junk com]} {
eval $com
append res [string range $it 0 [expr { [lindex $junk 0] -1 } ]]
append res [string range $it [expr { 1+[lindex $junk 1]}] end]
set it $res
}
# puts it=<$it>
if { [regexp -indices "\{plot\[d23]\[fd]" $it inds] } {
set plotPending [string range $it [lindex $inds 0] end]
set it ""
if { [regexp {\(C[0-9]+\) $} $it ff] } {
regexp "\{plot\[d23]\[df].*\}" $ff it
# set it $ff
}
}
if { [info exists plotPending] } {
#puts "plotPending=<$plotPending>,it=<$it>"
append plotPending $it
set it ""
if { [regexp -indices "\n\\(D\[0-9\]+\\)" $plotPending inds] } {
set it [string range $plotPending [lindex $inds 0] end]
set plotPending [string range $plotPending 0 [lindex $inds 0]]
set data $plotPending
unset plotPending
#puts itplot=<$it>,$inds
#puts plotdata=<$data>
doShowPlot $win $data
}
}
$win insert end $it "output"
$win mark set lastStart "end -1char"
#TV added:
if [string compare -length 2 $it "(D"] {
################## here you want to get the first characters of the next
prompt, for Maxima 5.9.1 on Windowa,
################## that has become "\n(%i" (otherwise your output contains
the next prompt).
set i [string first "\n(C" $it];
if {$i <= 0} {set i end-1} {incr i -1}
set passres [string range $it [expr [string first )\ $it]+2] $i]
}
###
if { [regexp {\(C[0-9]+\) $|\(dbm:[0-9]+\) $|([A-Z]+>[>]*)$} $it junk
lisp] } {
#puts "junk=$junk, lisp=$lisp,[expr { 0 == [string compare $lisp {}]
}]"
#puts "it=<$it>,pdata={[array get pdata *]},[$win index end],[$win
index insert]"
if { [info exists pdata($sock,wait) ] && $pdata($sock,wait) > 0 } {
#puts "it=<$it>,begin=$pdata($sock,begin),end=[$win index {end
linestart}]"
#puts dump=[$win dump -all "insert -3 lines" end]
setAct pdata($sock,result) [$win get $pdata($sock,begin) "end -
1char linestart" ]
#puts result=$pdata($sock,result)
set pdata($sock,wait) 0
}
$win mark set lastStart "end -1char"
$win tag add input "end -1char" end
oset $win atMaximaPrompt [expr { 0 == [string compare $lisp ""] }]
}
$win see end
return
}
Now the routine (proc domax) to do the maxima calling from tcl:
proc domax {e} {
global passres;
.maxima.text insert insert "$e;\n" ;
CMeval .maxima.text;
set passres {};
while {$passres == ""} {vwait passres};
return $passres
}
And it's needed to set maxima's reply mode to 1 dimensional, so that
formatting is simple formula return which can be fed back even to a new
evaluation by maxima, and so that my output line parse finds the number
of the result (DXX) at the beginning, and not in the middle line of the
output:
domax "display2d:false"
Now we can use:
domax 1+5
6
domax "solve(x^2+x+1=0,x)"
[x = -(SQRT(3)*%I+1)/2,x = (SQRT(3)*%I-1)/2]
Note that at this moment, there is no real error handling, and the domax
proc can hang (leaving the maxima console running, type a ; on a new
prompt to mostly make domax return...),
I've had a few wrong responses (missing first part of reply) though I'm
not sure in the latest version, but the principle appears to work.
Important note is that I didn't contentwise think at all what might
happen when calling domax recursively...
Meanwhile I've tried using domax in recursive calls, which appears to
workright, but the above remark still holds....
Possible/needed improvements:
maybe join the return lines into one line for long return values as the
'solve' example indicated, return values can be lists
certain integrate() and probably other commands require the user to add
input, which could be done in the text widget, but that makes domax at
least no normal proc anymore (possibly there are settable options to
prevent this)
for certain cases maybe it is desirable to be able to change back and
forth to tcl expr syntax
for higher speed, possibly it would be better to batch commands
the stream setup should be able to work fine, but as it is, it may be
not to good how domax works, but that would require alternatives like
stream based processing to be used instead of a proc.
Multiple line responses are not really dealt with by me, so when the
socket starts buffering, I might not get the whole response line and
mess up the interaction.
Anyone from the maxima scene follow the wiki? Or: maybe someone wants to
make a touch more decent 'domax'? And maybe a Tk based pretty printer ?
Just askin' ...
Attached file: TCL_to_Maxima_interfacing.doc
Attached file: TCL_to_Maxima_interfacing.html
Attached file: TCL_to_Maxima_interfacing.txt