Is there a way to split a string into parts the same way as eval would
do?
Example:
set cmd "set a 1; set b {hello bello}; puts gaga"
eval $cmd
Here, eval splits the list at the semicolons and then evaluates one
command after another. If $cmd would contain newlines, those would also
be points to split for eval.
Now suppose I want better control over the eval. In may particular case,
I want to add an additional parameter to each of the commands,
e.g. something similar to
foreach x [commandsplit $cmd] {
puts "running `$x' with additional arg blabliblu"
eval "$cmd blabliblu"
}
Is there a thing like `commandsplit' available?
Harald Kirsch
P.S.: [split $cmd ";\n"] does not work, of course.
--
-------------------------------------------------+------------------
Harald Kirsch, k...@iitb.fhg.de, +49 721 6091 369 | Now I rebooted.
FhG/IITB, Fraunhoferstr.1, 76131 Karlsruhe | --- Jerry Pournelle
It is quite complicated but [info complete] should be a big help.
--
Paul Duffin
DT/6000 Development Email: pdu...@hursley.ibm.com
IBM UK Laboratories Ltd., Hursley Park nr. Winchester
Internal: 7-246880 International: +44 1962-816880
Complicated, yes.
This might be a hint at an interesting feature for future Tcl:
bidirectional trace.
By this, I mean the equivalent at Tcl command level of {/proc,ptrace()}
(in strace/truss/trace) at system call level.
Of course, there is $::tcl_traceExec, but it is "read-only" in the sense
that executed instructions are just written to stdout (and not to any
other stream, to my great disappointment, Grrr...). What would be
useful, is to add a backwards path, so that the 'tracer' explicitly
allows the traced interp to go on, just like /proc and ptrace(). With
this, step-by-step debuggers *without* instrumentation would be
possible, which is a great step towards debugger transparency.
Reactions ?
-Alex
> With
> this, step-by-step debuggers *without* instrumentation would be
> possible, which is a great step towards debugger transparency.
Yes, I recognized that this feature would easily allow for running
a tcl-script step-by-step when I prepared my message and expected
pointers Tcl-Pro or this other debugger (Tuba ?) annonced recently.
Nevertheless I wanted it for something different. And I was really
irritated to find out that it is not at all simple to do.
Harald Kirsch
--
---------------------+------------------+--------------------------
Harald Kirsch (@home)| | Now I rebooted.
k...@iitb.fhg.de | | --- Jerry Pournelle, BYTE
gegen Punktfilitis hilft nur `chmod u-w ~'
[cut]
> foreach x [commandsplit $cmd] {
> puts "running `$x' with additional arg blabliblu"
> eval "$cmd blabliblu"
> }
>
> Is there a thing like `commandsplit' available?
>
> Harald Kirsch
>
> P.S.: [split $cmd ";\n"] does not work, of course.
> --
> -------------------------------------------------+------------------
> Harald Kirsch, k...@iitb.fhg.de, +49 721 6091 369 | Now I rebooted.
> FhG/IITB, Fraunhoferstr.1, 76131 Karlsruhe | --- Jerry Pournelle
What about
proc commandsplit {mylist} {
regsub -all -- {;} $mylist \n foo
return [split $foo \n]
}
GordonJ
Simon
proc commandsplit {CommandList} {
set PossibleCommand {}
set OutputList {}
set RealOutputList {}
while 1 {
set Rc [regexp -indices -- "\[;\n\]" $CommandList Indices]
if {$Rc} {
set Index [lindex $Indices 0]
set PossibleCommand \
"$PossibleCommand[string range $CommandList 0 $Index]"
set CommandList [string range $CommandList [expr $Index + 1] end]
if {[info complete $PossibleCommand]} {
lappend OutputList [string trim $PossibleCommand " \t\n;"]
set PossibleCommand {}
}
} else {
set CommandList "$PossibleCommand$CommandList"
if {[info complete $CommandList]} {
lappend OutputList [string trim $CommandList " \t\n;"]
break
} else {
error "Not a well formed command"
}
}
}
foreach command $OutputList {
if {$command != {}} {
lappend RealOutputList $command
}
}
return $RealOutputList
}
Harald Kirsch wrote:
>
> Is there a way to split a string into parts the same way as eval would
> do?
>
> Example:
>
> set cmd "set a 1; set b {hello bello}; puts gaga"
> eval $cmd
>
> Here, eval splits the list at the semicolons and then evaluates one
> command after another. If $cmd would contain newlines, those would also
> be points to split for eval.
>
> Now suppose I want better control over the eval. In may particular case,
> I want to add an additional parameter to each of the commands,
> e.g. something similar to
>
Tricky. What follows is a first hack at it. It returns a list of
commands, but it does not try to trim any trailing spaces from the
commands (not exactly trivial that...)
proc cmdsplit {script} {
set cmds {}
set cmd {}
for {set i 0} {$i<[string length $script]} {incr i} {
set c [string index $script $i]
switch -exact -- $c {
"\n" - ";" {
if {[info complete $cmd]} {
# The next line is not strictly necessary...
if {[string length $cmd]} {
lappend cmds [string trimleft $cmd]
}
set cmd {}
} else {
append cmd $c
}
}
default {
append cmd $c
}
}
}
if {[string length $cmd]} {
if {[info complete $cmd]} {
lappend cmds [string trimleft $cmd]
} else {
return -code error "Not a well-formatted Tcl script"
}
}
return $cmds
}
Donal.
--
Donal K. Fellows http://www.cs.man.ac.uk/~fellowsd/ fell...@cs.man.ac.uk
Department of Computer Science, University of Manchester, U.K. +44-161-275-6137
--
If you staple a penguin to the head of a gnu, the result won't catch herring...
Autsch!
What will this return for
set cmd "puts {;;;;;;;}; puts {;;}"
[script deleted]
> Harald Kirsch wrote:
> >
> > Is there a way to split a string into parts the same way as eval would
> > do?
Thank you for your solution. It survived at least the following
quick&dirty test:
------------------------------------------------------------
set cmd {
puts "\{"
puts hallo
puts "hallo;ballo"
set a \
bbb
set a "adfadfasdf
asdfadsf"
set b "adfadfadf \
adfadfasdf"
puts {
eins zwei ;
drei
}
}
set res [$cmdsplit $cmd]
foreach cmd $res {
puts ">>$cmd<<"
}
puts [time {$cmdsplit $cmd} 100]
------------------------------------------------------------
The time was 1560 microseconds per iteration which is about 4 times
faster than Mr. Fellows entry :-)
> In article <KIR.98Se...@neptun.iitb.fhg.de>,
> Harald Kirsch <k...@iitb.fhg.de> wrote:
> > Is there a way to split a string into parts the same way as eval would
> > do?
>
Thank you for your solution. It survived the following quick&dirty test:
------------------------------------------------------------
set cmd {
puts "\{"
puts hallo
puts "hallo;ballo"
set a \
bbb
set a "adfadfasdf
asdfadsf"
set b "adfadfadf \
adfadfasdf"
puts {
eins zwei ;
drei
}
}
set res [$cmdsplit $cmd]
foreach cmd $res {
puts ">>$cmd<<"
}
puts [time {$cmdsplit $cmd} 100]
------------------------------------------------------------
However I am sorry to say that it is about four times slower than
Mr. King's solution ;-)
Thanks again to both of you. Although in the meantime thought I came up
with a solution which does not need a `cmdsplit', I might now consider
this approach again, because the solution I have involves quite some
trickery which I might not understand again in a month.
Simon
.
.
.
Here's a routine I wrote to support parsing of class bodies in an
itcl-like, pure Tcl, OO framework into Tcl commands. I've modified
the interface to match yours. It handles the "semicolon in a comment"
problem.
proc cmdSplit {body} {
set commands {}
set chunk ""
foreach line [split $body "\n"] {
append chunk $line
if {[info complete "$chunk\n"]} {
# $chunk ends in a complete Tcl command, and none of the
# newlines within it end a complete Tcl command. If there
# are multiple Tcl commands in $chunk, they must be
# separated by semi-colons.
set cmd ""
foreach part [split $chunk ";"] {
append cmd $part
if {[info complete "$cmd\n"]} {
set cmd [string trimleft $cmd]
# Drop empty commands and comments
if {![string match {} $cmd] \
&& ![string match #* $cmd]} {
lappend commands $cmd
}
if {[string match #* $cmd]} {
set cmd "#;"
} else {
set cmd ""
}
} else {
# No complete command yet.
# Replace semicolon and continue
append cmd ";"
}
}
set chunk ""
} else {
# No end of command yet. Put the newline back and continue
append chunk "\n"
}
}
if {![string match {} [string trimright $chunk]]} {
return -code error "Can't parse body into a\
sequence of commands.\n\tIncomplete\
command:\n-----\n$chunk\n-----"
}
return $commands
}
--
| Don Porter, D.Sc. Mathematical and Computational Sciences Division |
| donald...@nist.gov Information Technology Laboratory |
| http://math.nist.gov/mcsd/Staff/DPorter/ NIST |
|______________________________________________________________________|