''procc'' takes three arguments, a procedure name, an argument list given like (arg1, arg2, arg3) and a script written in [c]-like code. It transforms the script by some simple regexp rules with the following idea: basically any expression x = expression; is replaced by set x [expr { EXPRESSION }] where EXPRESSION is tclified, by sticking a $ sign in front of each variable but leaving math functions unchanged. Other rules deal with transformations of "[for]" and "[if]" statements and a few others. The new script is then concatenated with proc and a minor transformation of the argument list to remove the commas and replace the ()'s by {}, and then evaled to define a new procedure. ====== procc test3 (x,y) { s1 = sin(x+y); s2 = sin(x)*cos(y)+cos(x)*sin(y); return s1-s2; } => proc test3 {x y} { set s1 [expr { sin($x+$y)}] set s2 [expr { sin($x)*cos($y)+cos($x)*sin($y)}] return [expr {$s1-$s2}] } ====== The algorithm for tclifying an expression looks for things that begin with a letter followed by alphanumerics, and adds a $ sign. If it's a math expression, then remove the $ sign. Things that caused me trouble can be seen in trying the following e1=e2+2.*e3-1e6-exp(7.e2)-e89e2; and I had to add extra stuff to deal with scientific notation. It was originally written as an exercise in regexp and regsub and is basically limited by what regular expressions can do. Ultimately I'd like to see it capable of doing a well defined subset of c-like code, suitable for numerics. To do: Incorporate user defined math functions, ie replace myFn(x, y) with [myFn x y], where x and y can generally be expressions. This is straightforward if the arguments are simple, but what if you have nested calls? One limitation of regexps is finding matched parans. Doing this properly will probably require a full tokenizer. ---- WARNING: Thoroughly untested on all but the simplest expressions. However I'd appreciate any improvements, or just let me know where it falls over. ---- ====== # Enable writing of 'c-style' code, primarily for convenience in writing # numerical stuff. # So I write "x=5*y+12.-sin(z)" instead of "set x [expr {5*$y+12.- sin($z)}]" # set mathFns [list abs cosh log sqrt acos double log10 srand \ asin exp pow tan atan floor rand tanh atan2 fmod round \ ceil hypot sin cos int sinh ] set mathRegexp [join $mathFns "|"] set varRegexp {[a-zA-Z_][a-zA-Z0-9_]} # Some regexps # assignmentRe - " x= 3*cos(theta)-5.;" set assRe {^(\s*)([[:alpha:]]\w*) *=([^;]*);?$} # reassRe - reassignment " x += 53*atan2(3.2,8.)-144/y;" set reassRe {^(\s*)([[:alpha:]]\w*) *([-+*/])=([^;]*);?$} # (hey this stuff looks just like TECO...) # forRe - for statement " for (i=0; i<20; i++)" set forRe {^(\s*)for\s*\(([^;]*);([^;]*);(.*)\)\s*\{$} # ifRe - if statement " if ((x<10) || z>tan(theta))" set ifRe {^(\s*)if\s*\((.*)\)\s*\{$} # slifRe - single line if " if (x>2 && t7.e4) x*=3; if ((x>0.0) || f<3) { f*=-2; } else { f+=pow(x2, 2.); } e5=1.; e89e2=0; e3=1e3; e2 = 1.e-3+.1e4*1e4; e1=e2+2.*e3-1e6-exp(7.)-e89e2; e1= .1e-4-e5; } return f; } procc test2 (i) { sum1 = 0; sum2 = 0; sum3 = 0; for (j=0; j<=i; j++) { sum1 += j; sum2 += j*j; sum3 += j*j*j; } return sum3-sum1*sum1; } foreach i {1 2 3 6 10} {puts [test2 $i]} procc test3 (x,y) { s1 = sin(x+y); s2 = sin(x)*cos(y)+cos(x)*sin(y); return s1-s2; } for {set i 0} {$i<10} {incr i} { puts [test3 [expr 5*rand()] [expr 5*rand()]] } ====== ---- [Chang Li] How do you deal with array in it?