Attempt to create nested for loops generating missing arguments error - tcl

Am attempting to teach myself to program using Tcl. (I want to become more familiar with the language to understand someone else's code - SCID chess)
The task i've set myself to motivate my learing of Tcl is to solve the 8 queens problem.
My approach to creating a program is to sucessively 'prototype' a solution.
So.
I'm up to nesting a for loop holding the q pos on row 2
inside the for loop holding the q pos on row 1
Here is my code
set allowd 1
set notallowd 0
for {set r1p 1} {$r1p <= 8} {incr r1p } {
puts "1st row q placed at $r1p"
;# re-initialize r2 'free for q placemnt' array after every change of r1 q pos:
for {set i 1 } {$i <= 8} {incr i} { set r2($i) $allowd }
for { set r2($r1p) $notallowd ; set r2([eval $r1p-1]) $notallowd ;
set r2([eval $r1p+1]) $notallowd ; set r2p 1} {$r2p <= 8} {
incr r2p ;# end of 'next' arg of r2 forloop
}
;# commnd arg of r2 forloop placed below:
{puts "2nd row q placed at $r2p"
}
}
My problem is that when i run the code the interpreter is aborting with the fatal error:
"wrong #args should be for start test next command.
I've gone over my code a few times and can't see that i've missed any of the for loop arguments.

The carriage return before the command in the last for loop is what's getting you. From the first syntax rule on the Tcl man page, "Semi-colons and newlines are command separators unless quoted as described below." BTW, your eval's should be expr's.
This works for me:
set allowd 1
set notallowd 0
for {set r1p 1} {$r1p <= 8} {incr r1p } {
puts "1st row q placed at $r1p"
;# re-initialize r2 'free for q placemnt' array after every change of r1 q pos:
for {set i 1 } {$i <= 8} {incr i} { set r2($i) $allowd }
for { set r2($r1p) $notallowd ; set r2([expr $r1p-1]) $notallowd ;
set r2([expr $r1p+1]) $notallowd ; set r2p 1} {$r2p <= 8} {
incr r2p ;# end of 'next' arg of r2 forloop
} {
# commnd arg of r2 forloop placed below:
puts "2nd row q placed at $r2p"
}
}

Related

Xcelium simulator in endless loop using Tcl for/while

Could someone help me to understand why the below code hangs (i.e. stuck in an endless loop) in Xcelium simulator, and what should be the correct one?
for {set i 0} {$i < 2} {incr $i} { puts "i is $i"; }
set i 0
while {$i < 2} { puts "i is $i"; incr $1; }
The result for either for or while loop above is just an endless: i is 0
incr takes a variable name as input argument, so it should be incr i.
incr $i increments instead the variable 0. What happens if the variable does not exist depends on Tcl version. From the manual page:
Starting with the Tcl 8.5 release, the variable varName passed to incr may be unset, and in that case, it will be set to the value increment or to the default increment value of 1.

I am trying to execute a code and getting the error"child killed segmentation violation " and the program stopped working

on executing the following code in tcl(opensees) it is showing "child killed segmentation violation" and the program stopped working.
Monte carlo simulation
set Ntrials 10000
set Nfails 0
for {set i 1} {$i <= $Ntrials} {incr i} {
set U '';#initialize list to Null
foreach rv [getRVTags] {
set val [expr rand()]; #random float between 0 and 1
lappend U [getStdNormalInverseCDF $val]
}
set X [transformUtoX $U]
set irv 0
foreach rv "1 2" {
updateParameter $rv[lindex $X $irv]
incr irv
}
set x1 [getParamValue 1]
set X2 [getParamValue 2]
set g [expr $x1*$x1-$x2*$x2];#g=R^2-S^2
if { $g <= 0 } {
incr Nfail
}
}
puts "Monte Carlo Simulation, pf = [expr double($Nfail)/$Ntrials]";

For loop increment by a non-integer in TCL

I want to implement the following C code in TCL:
Float power_pitch = 8
float offset = 7.5
float threshold = 100
for(i=power_pitch+offset ; i<= threshold ; i += power_pitch)
I want to implement above forloop in TCL. I have tried the following code in TCL:
set power_pitch 8
set offset 7.5
set threshold 100
for { set i [expr $power_pitch + $offset] } { $i <= $threshold } { incr i $power_pitch}
but when I execute above code I get the following error:
expected integer but got "15.5 "
while executing incr i $power_pitch
Could you help me to implement above forloop in TCL?
The incr command only works with integers. Otherwise, use:
set i [expr {$i + $power_pitch}]
The for command itself won't mind. (Be aware of float rounding issues; they're not Tcl-specific, but can hit with anything that isn't an integer multiple of a power of 2…)
Donal has already provided the answer to the question, I'd just like to make an observation in two points about the for command.
for is very nearly free-form
while an integral counting loop is a typical use of for, it's by no means the only option
The for command has the synopsis
for start test next body
where start, next, and body are command strings (i.e. appropriate as an argument to eval; they can be empty, contain single commands, or be full scripts) and test is a boolean expression string (i.e. appropriate as an argument to expr and evaluating to something that is or can be coerced into a boolean value).
Usually, start is used to set up for test and body, and next is supposed to bring the state incrementally closer to having test return a false value, but that's just a convention, not a requirement. The following are perfectly valid (but rather smelly) invocations:
for {set n 0 ; puts -nonewline X} {[incr n] < 5} {puts -nonewline X} {
puts -nonewline [string repeat - $n]
}
for {set f [open foo.txt] ; set n 0} {$n >= 0} {puts $line} {
set n [chan gets $f line]
}
Give for any combination of command strings and boolean expression, and it will run. It might execute its body forever or not even once, but it will run. Don't limit yourself to for {set i 0} {$i < 10} {incr i} {...} invocations, that's 1950s thinking.
Even if you just want to use it for counting loops, there are still lots of options, for instance:
for {set i 0} {$i < $limit} {incr i} {...} ;# simple increment
for {set i 0} {$i < $limit} {incr i $n} {...} ;# stepping increment/decrement
for {set i 0} {$i < $limit} {incr i $i} {...} ;# doubling increment
for {set i 0} {$i < $limit} {set i [expr {...}]} {...} ;# arbitrary change
Free your mind, the rest will follow.
Documentation: chan, expr, for, incr, open, puts, set, string

sequential binary TCL

Please suggest improvements to my program. This program gives a 4 bit binary incremental o/p
I am looking for optimizing this where there is unnecessary code.
Please suggest improvements to my program. This program gives a 4 bit binary incremental o/p
I am looking for optimizing this where there is unnecessary code.
Please suggest improvements to my program. This program gives a 4 bit binary incremental o/p
I am looking for optimizing this where there is unnecessary code.
#!/bin/sh
# This
puts "+++++++++++++++++\n"
set ipaddr "0.0.0.0"
set limit 4
set splitip [split $ipaddr "."]
puts "Split ip address = $splitip"
# MAIN ROUTINE
set ilength [llength $splitip]
puts "Length of string is $ilength"
set first [lindex $splitip 0]
set sec [lindex $splitip 1]
set third [lindex $splitip 2]
set four [lindex $splitip 3]
for { set limit 1} { $limit >0} {} {
for { set first $first } { $first <= $limit} {} {
for { set sec $sec } { $sec <= $limit} {} {
for { set third $third } { $third <= $limit} {} {
for { set four $four } { $four <= $limit} {} {
puts " f:$first $sec $third $four"
incr four
}
set four 0
incr third; #puts " t:$four $third $sec $first\n"
}
set third 0
incr sec
}
#puts " f:$four $third $sec $first"
set sec 0
incr first
}
incr limit -1
}
# End Main
puts "\n++++++End Program+++++++++++"
Your program essentially boils down to this, does this do what you intended?
for { set first 0 } { $first <= 1} {incr first} {
for { set sec 0 } { $sec <= 1} {incr sec} {
for { set third 0 } { $third <= 1} {incr third} {
for { set four 0 } { $four <= 1} {incr four} {
puts " f:$first $sec $third $four"
}
}
}
}
Because if so, the primary suggestion is to simply remove everything except this.
Also: [llength $splitip] does not give you the string length of $splitip, but the list length. Those are different.
You're using a very roundabout way to assign values to first et al. Instead, use
lassign $splitip first sec third four
The lassign was added in Tcl 8.5. If you're using an older version of Tcl, use assignment by foreach instead:
foreach {first sec third four} $splitip break
The construct
for { set limit 1} { $limit >0} {incr limit -1} { ... }
simply means "execute ... exactly once": it doesn't affect the program's execution in any way. Even if you remove it (keeping the code inside the body argument), the code that was inside it will still execute exactly once.
For clarity, the incr x invocations should be inside the third argument to for, not inside the fourth, body, argument.
As a final note, if your intent is to print out a sequence of binary numbers, it's a lot easier to do that this way:
for {set i 0} {$i < 16} {incr i} { puts [format %04b $i] }

Is there shorthand in Tcl to get a sequential array of numbers?

For example, in Perl, to get a sequential array of numbers from 1 to 10, you could simply do:
#myArray = (1 .. 10);
The two periods serve as shorthand for this operations instead of making a for loop or writing the whole thing out manually. Other languages I've used have something similar also.
Does a similar shorthand exist in Tcl?
You can define the method:
proc fillArray {a b} {
eval return \[list $a [string repeat "\[incr a\] " [incr b -$a]]\]
}
And use it as:
set myArray [fillArray 1 10]
You even can beautify the call of procedure to make it look as in perl. For that just redefine unknown procedure:
rename unknown __unknown
proc unknown {args} {
if {[llength $args] == 3} {
lassign $args a op b
if {[string is integer $a] && $op == ".." && [string is integer $b]} {
return [fillArray $a $b]
}
}
return [uplevel __unknown {*}$args]
}
After that you can write just simple as:
set myArray [1 .. 10]
:)
Not quite this one, but
% package require struct::list
1.6.1
% struct::list iota 10
0 1 2 3 4 5 6 7 8 9
Also search this for the "iota" keyword to see how this can be done using a one-liner.
With the exception of expressions (which are their own little language) Tcl has no operators and is always a strictly prefix-driven language. This means that there isn't such a convenient shorthand for doing loops. On the other hand, there's nothing particularly special about Tcl's standard commands (apart from some minor efficiency details that don't matter here) so making your own is no problem:
proc .. {from to} {
if {$from >= $to} {
for {set i $from} {$i <= $to} {incr i} {lappend out $i}
} else {
for {set i $from} {$i >= $to} {incr i -1} {lappend out $i}
}
return $out
}
puts [.. 1 10]; # --> “1 2 3 4 5 6 7 8 9 10”
You can fake infix operators by using an unknown handler (as in GrAnd's answer) but that's really quite slow by comparison with the above.
No, a similar shorthand does not exist in tcl.
If you really want shorthand, you can create your own command that looks almost the same. For example:
proc : {start ignore end} {
set result []
for {set i $start} {$i <= $end} {incr i} {
lappend result $i
}
return $result
}
puts "from 1 to 10: [: 1 .. 10]"