Training, Open Source computer languages
PerlPHPPythonMySQLApache / TomcatTclRubyJavaC and C++LinuxCSS 
Search for:
Home Accessibility Courses Diary The Mouth Forum Resources Site Map About Us Contact
 
For 2023 (and 2024 ...) - we are now fully retired from IT training.
We have made many, many friends over 25 years of teaching about Python, Tcl, Perl, PHP, Lua, Java, C and C++ - and MySQL, Linux and Solaris/SunOS too. Our training notes are now very much out of date, but due to upward compatability most of our examples remain operational and even relevant ad you are welcome to make us if them "as seen" and at your own risk.

Lisa and I (Graham) now live in what was our training centre in Melksham - happy to meet with former delegates here - but do check ahead before coming round. We are far from inactive - rather, enjoying the times that we are retired but still healthy enough in mind and body to be active!

I am also active in many other area and still look after a lot of web sites - you can find an index ((here))
Dynamic switch statements

Posted by ShipConner (ShipConner), 1 June 2005
Hello all  

<using tcl 8.4.9 & expect 5.41 on Suse 9.3>

I am trying to get my script  to dynamically write a proceedure and then source and use that proceedure all while my script is executing.

I use the following code in my script to write the proceedure file:
---------------------------------------------
set lookatthis "lotsOstufftomatch"

set dynamic_switch_file [open /dynamic_switch_file.tcl {RDWR CREAT}]

puts $dynamic_switch_file "proc dynamic_switch_proc { lookatthis } {"
puts $dynamic_switch_file "switch -glob -- \$lookatthis \\ "
puts $dynamic_switch_file "pattern1 {puts HIpat1} \\ "
puts $dynamic_switch_file "pattern2 {puts HIpat2} \\ "
puts $dynamic_switch_file "default {puts HIdefault}"
puts $dynamic_switch_file ""
puts $dynamic_switch_file "}"
close $dynamic_switch_file
---------------------------------------------

Then I source and try to use it:
----------------------------------------
source /dynamic_switch_file.tcl
dynamic_switch_proc $lookatthis
-----------------------------------------

And I keep getting this in exp_internal 1:
-----------------------------------------
wrong # args: should be "switch ?switches? string {pattern body ... ?default body?}"
   while executing
"switch -glob -- $lookatthis \ "
   (procedure "dynamic_switch_proc" line 2)
----------------------------------------

The dynamic_switch_file.tcl gets built and looks like this:
------------------------------------
badmachine#cat dynamic_switch_file.tcl
proc dynamic_switch_proc { lookatthis } {
switch -glob -- $lookatthis \
pattern1 {puts HIpat1} \
pattern2 {puts HIpat2} \
default {puts HIDEFAULT}

}
------------------------------------

When I copy out the contents of this file and put it into a "normal" script as a proceedure it works perfectly. So it would seem the syntax is correct despite the usage error I keep getting...

I have been working on this for two days straigh and am at witts end ! Any ideas would be GREATLY appreciated !

p.s. prehaps there is a better way to  match unknown patterns and in unkown amounts at the time of script execution

Posted by admin (Graham Ellis), 1 June 2005
on 06/01/05 at 01:02:21, ShipConner wrote:
Hello all  

I am trying to get my script  to dynamically write a proceedure and then source and use that proceedure all while my script is executing.

etc

puts $dynamic_switch_file "switch -glob -- \$lookatthis \\ "

etc

And I keep getting this in exp_internal 1:
-----------------------------------------
wrong # args: should be "switch ?switches? string {pattern body ... ?default body?}"
   while executing
"switch -glob -- $lookatthis \ "
   (procedure "dynamic_switch_proc" line 2)


You appear to have a spare space character after the \\ at the end of the put statement here, so that you're protecting the space from the Tcl interpretter rather than the new line.  Rewrite this line as

puts $dynamic_switch_file "switch -glob -- \$lookatthis \\"

(and correct the other lines with the same problem) and I think you'll be OK.

Posted by admin (Graham Ellis), 1 June 2005
P.S. You ask about a better way.  

YES PLEASE - self-modifying code is nearly never a good idea.

Try something like:

Code:
# Set up the options

set patterns(tom) {puts "Tom Smith"}
set patterns(dick) {puts "Richard Head"}
set patterns(harry) {puts "Harold Lemon"}

set teststring dick

# Loop to find a matching options

set matched 0
foreach name [array names patterns] {
       if {$name == $teststring} {
               eval $patterns($name)
               set matched 1
               break
               }
       }

# Default action if no match

if {$matched == 0} {puts "default action"}


Posted by ShipConner (ShipConner), 1 June 2005
I am not a religous man...

But Jesus Graham, you pulled that out of your hat at 5:10am !

Its late here and I am not even close to being as as tclsh as you but I think  you addressed my problem perfectly. My main reason for writing a self-modifying program was to avoid being locked into a hard coded number of patterns in my switch statement and becuase at the start of the program I don't know how many switch statements will really be needed therefore I wanted to make it into a proc and call it recursively as I needed it.

If I understand your example... I am no longer confined by a fixed number of pattern matches that a static switch statement would have becuase the array can absorb any number of patterns. So I should just be able to do this:
--------------------------------
proc patterns_actions_proc { pat_act_list } {
foreach line $pat_act_list {
set pat_act_array([lindex $line 0]) {[lindex $line1]}
}
set teststring thingy

# Loop to find a matching options

set matched 0
foreach name [array names pat_act_array] {
  if {$name == $teststring} {
     eval $pat_act_array($name)
     set matched 1
     break
     }
  }

# Default action if no match

if {$matched == 0} {puts "default action"}
}
# end of proc
----------------------------------------------------------

Hoping I understood you correctly. By the way removing the space worked perfectly  

Posted by admin (Graham Ellis), 1 June 2005
Yes that looks fine except you'll have to fix the scope of pat_act_array using global, upvar or uplevel if you want to set it inside a proc then use it outside.

Posted by ShipConner (ShipConner), 1 June 2005
Thank you Graham.



This page is a thread posted to the opentalk forum at www.opentalk.org.uk and archived here for reference. To jump to the archive index please follow this link.

You can Add a comment or ranking to this page

© WELL HOUSE CONSULTANTS LTD., 2024: Well House Manor • 48 Spa Road • Melksham, Wiltshire • United Kingdom • SN12 7NY
PH: 01144 1225 708225 • FAX: 01144 1225 793803 • EMAIL: info@wellho.net • WEB: http://www.wellho.net • SKYPE: wellho