Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Definition of 'Tcl script'

303 views
Skip to first unread message

Aidan Hobson Sayers

unread,
Feb 11, 2015, 8:09:15 AM2/11/15
to
The Dodekalogue (`man tcl`/http://wiki.tcl.tk/10259) says:

> [1] Commands
>
> A Tcl script is a string containing one or more commands. [...]

and

> [7] Command substitution
>
> If a word contains an open bracket ("[") then Tcl performs command substitution. To do this it invokes the Tcl interpreter recursively to process the characters following the open bracket as a Tcl script. The script may contain any number of commands and must be terminated by a close bracket ("]"). [...]

While the latter says "The script may contain any number of commands", since it is being interpreted "as a Tcl script", maybe there is a constraint of "one or more commands"?

```
% puts []

%
```

Apparently not. Let's look at eval, where the docs restate the note that a 'Tcl script' is >= 1 command.

> Eval takes one or more arguments, which together comprise a Tcl script containing one or more commands.

```
% eval ""
%
```

So eval takes arguments which can actually result in zero commands. So I guess the definition of 'Tcl script' is incorrect and a string containing zero commands is also acceptable?

Uwe Klein

unread,
Feb 11, 2015, 9:50:04 AM2/11/15
to
Am 11.02.2015 um 14:09 schrieb Aidan Hobson Sayers:
> So eval takes arguments which can actually result in zero commands.
> So I guess the definition of 'Tcl script' is incorrect and a string
> containing zero commands is also acceptable?
>
But then it is not a "script" ;-)

due to "a script is a string containing 1 or more commands".

This is obviously splitting hairs ;-)

uwe

pooryorick

unread,
Feb 11, 2015, 9:51:37 AM2/11/15
to
On Wednesday, February 11, 2015 at 8:09:15 AM UTC-5, Aidan Hobson Sayers wrote:
>
> So eval takes arguments which can actually result in zero commands. So I guess the definition of 'Tcl script' is incorrect and a string containing zero commands is also acceptable?

This came up recently in the Tcl chatroom, and led to the interesting
observation by dgp (I think) that in the current implementation there is always
actually at least one command in a script, even if that command is the empty
string. A command that is the empty string has no name, therefore is not
resolved to any routine, and therefore no routine is invoked. This is a
different scenario than a command that has the empty string for a name, which
of course is a legal name for a command.

I guess that means that technically there are empty commands between the
characters in every sequence of newlines or semicolons in a script.


--
Yorick

Christian Gollwitzer

unread,
Feb 11, 2015, 2:16:33 PM2/11/15
to
Am 11.02.15 um 14:09 schrieb Aidan Hobson Sayers:
> The Dodekalogue (`man tcl`/http://wiki.tcl.tk/10259) says:
>
>> [1] Commands
>> A Tcl script is a string containing one or more commands. [...]
>
> and
>
>> [7] Command substitution
>>
>> If a word contains an open bracket ("[") then Tcl performs command substitution. To do this it invokes the Tcl interpreter recursively to process the characters following the open bracket as a Tcl script. The script may contain any number of commands and must be terminated by a close bracket ("]"). [...]
>
> While the latter says "The script may contain any number of commands", since it is being interpreted "as a Tcl script", maybe there is a constraint of "one or more commands"?
>
> ```
> % puts []
> %
> ```
> Apparently not. Let's look at eval, where the docs restate the note that a 'Tcl script' is >= 1 command.

My wishlist for Tcl 9, maybe earlier: somebody please rewrite the
dodekalogue in machine-readable form as an EBNF or PEG grammar. Then
these things would be unambiguously specified, and a parser and code
generator is "trivially" constructed from a compiler toolkit.


Christian

Prof Craver

unread,
Feb 11, 2015, 3:02:27 PM2/11/15
to
On Wednesday, February 11, 2015 at 5:09:15 AM UTC-8, Aidan Hobson Sayers wrote:

> % puts []
>
> %

Interestingly, while the empty string is a valid input for bracket substitution, a comment doesn't seem to be unless it is terminated by a newline---at least on my system:

% puts [#] ;# hangs forever

% puts [expr 1 ;# comment] ;# also hangs forever

% puts [# this is not a problem
]

...however, a comment string that is not new-line terminated doesn't seem to be a problem for [eval], or for [source] if the script is stored in a file.

--S

pooryorick

unread,
Feb 11, 2015, 3:18:32 PM2/11/15
to
On Wednesday, February 11, 2015 at 3:02:27 PM UTC-5, Prof Craver wrote:
>
> Interestingly, while the empty string is a valid input for bracket substitution, a comment doesn't seem to be unless it is terminated by a newline---at least on my system:
>
> % puts [#] ;# hangs forever
>

That's the shell waiting for the closing bracket that ends the script
substitution, since the "#" character commented out everything up to the next
newline. If you put that same line in a file and feed the file to tclsh, the
result will be "missing close bracket".

--
Yorick

Prof Craver

unread,
Feb 13, 2015, 9:47:32 PM2/13/15
to
On Wednesday, February 11, 2015 at 3:18:32 PM UTC-5, pooryorick wrote:

> That's the shell waiting for the closing bracket that ends the script
> substitution, since the "#" character commented out everything up to the next
> newline. If you put that same line in a file and feed the file to tclsh, the
> result will be "missing close bracket".

Ah, of course. How silly of me.

--S

Aidan Hobson Sayers

unread,
Feb 19, 2015, 9:02:08 PM2/19/15
to
On Wednesday, 11 February 2015 14:50:04 UTC, Uwe Klein wrote:
> Am 11.02.2015 um 14:09 schrieb Aidan Hobson Sayers:
> > So eval takes arguments which can actually result in zero commands.
> > So I guess the definition of 'Tcl script' is incorrect and a string
> > containing zero commands is also acceptable?
> >
> But then it is not a "script" ;-)
>
> due to "a script is a string containing 1 or more commands".

But if it's not a script, eval should not accept it as an argument. Which isn't the case in practice.

> This is obviously splitting hairs ;-)

Of course :) I'm just entertaining myself with Tcl corner cases.

On Wednesday, 11 February 2015 14:51:37 UTC, pooryorick wrote:
> This came up recently in the Tcl chatroom, and led to the interesting
> observation by dgp (I think) that in the current implementation there is always
> actually at least one command in a script, even if that command is the empty
> string. A command that is the empty string has no name, therefore is not
> resolved to any routine, and therefore no routine is invoked. This is a
> different scenario than a command that has the empty string for a name, which
> of course is a legal name for a command.

Yes, I have observed that the Tcl parser (when playing with it in C) always gives me one empty command at the end of a script.

It's unclear that this is acceptable:

> [2] Evaluation.
> [...] The first word is used to locate a command procedure to carry out the command [...]

Note 'is'. I think someone reading that description would be forgiven for thinking that a command is at least one word.

Aidan

heinrichmartin

unread,
Feb 20, 2015, 3:23:36 AM2/20/15
to
On Friday, February 20, 2015 at 3:02:08 AM UTC+1, Aidan Hobson Sayers wrote:
> Of course :) I'm just entertaining myself with Tcl corner cases.
> [...]
>
> Yes, I have observed that the Tcl parser (when playing with it in C) always gives me one empty command at the end of a script.
>
> It's unclear that this is acceptable:
>
> > [2] Evaluation.
> > [...] The first word is used to locate a command procedure to carry out the command [...]
>
> Note 'is'. I think someone reading that description would be forgiven for thinking that a command is at least one word.
>
> Aidan

Entertaining not only yourself ...

expect:~$ [lindex {} 0]
empty command name ""
while evaluating {[lindex {} 0]}
expect:~$ ;# empty command
expect:~$ proc {} {} {;# empty}
expect:~$ [lindex {} 0]
expect:~$ {}
expect:~$

The error message should definitely be changed to invalid command name "".
But on the other hand: when someone is challenging the spec, then he is fluent enough to find it out by himself.

Rich

unread,
Feb 20, 2015, 6:35:20 AM2/20/15
to
heinrichmartin <martin....@frequentis.com> wrote:
> On Friday, February 20, 2015 at 3:02:08 AM UTC+1, Aidan Hobson Sayers wrote:
> > Of course :) I'm just entertaining myself with Tcl corner cases.
> > [...]
> >
> > Yes, I have observed that the Tcl parser (when playing with it in
> > C) always gives me one empty command at the end of a script.
> >
> > It's unclear that this is acceptable:
> >
> > > [2] Evaluation.
> > > [...] The first word is used to locate a command procedure to
> > > carry out the command [...]
> >
> > Note 'is'. I think someone reading that description would be
> > forgiven for thinking that a command is at least one word.
> >
> > Aidan

> Entertaining not only yourself ...

> expect:~$ [lindex {} 0]
> empty command name ""
> while evaluating {[lindex {} 0]}
> expect:~$ ;# empty command
> expect:~$ proc {} {} {;# empty}
> expect:~$ [lindex {} 0]
> expect:~$ {}
> expect:~$

What version of expect is this? My version here gives this instead:

expect1.1> [lindex {} 0]
ambiguous command name "": _close.pre_expect after append apply array
auto_execok auto_import auto_load auto_load_index auto_qualify binary
break case catch cd chan clock close close_on_eof concat continue
coroutine debug dict disconnect encoding eof error eval exec exit
exp_close exp_close_on_eof exp_configure exp_continue exp_debug
exp_disconnect exp_exit exp_fork exp_getpid exp_inter_return
exp_interact exp_internal exp_interpreter exp_log_file exp_log_user
exp_match_max exp_open exp_overlay exp_parity exp_pid exp_remove_nulls
exp_send exp_send_error exp_send_log exp_send_tty exp_send_user
exp_sleep exp_spawn exp_strace exp_stty exp_system exp_timestamp
exp_trap exp_version exp_wait expect expect_after expect_background
expect_before expect_tty expect_user expr fblocked fconfigure fcopy
file fileevent flush for foreach fork format getpid gets glob global
history if incr info inter_return interact interp interpreter join
lappend lassign lindex linsert list llength lmap load log_file log_user
lrange lrepeat lreplace lreverse lsearch lset lsort match_max namespace
open overlay package parity pid proc prompt1 prompt2 puts pwd read
regexp regsub remove_nulls rename return scan seek send send_error
send_log send_tty send_user set sleep socket source spawn split strace
string stty subst switch system tailcall tclLog tell throw time
timestamp trace trap try unknown unload unset update uplevel upvar
variable vwait wait while yield yieldto zlib
while executing
"[lindex {} 0]"

> The error message should definitely be changed to invalid command
> name "".

Why should it be changed? The name "", if defined, is a valid command
name:

% proc "" {args} {puts "Empty command name called, with args '[join $args ", "]'"}
% "" a b c d e f
Empty command name called, with args 'a, b, c, d, e, f'
%
% {} zxy abc
Empty command name called, with args 'zxy, abc'
%

Provided one does not exclude zero length words, a zero length word is
a member of the general set "words". Just as a set of zero elements is
a proper set in mathematics. And a zero length list is also a proper
list to Tcl.

"" is valid to expect as well:

expect1.2> proc "" {args} {puts "Empty command name called, with args '[join $args ", "]'"}
expect1.3> [lindex {} 0]
Empty command name called, with args ''

heinrichmartin

unread,
Feb 20, 2015, 8:35:39 AM2/20/15
to
On Friday, February 20, 2015 at 12:35:20 PM UTC+1, Rich wrote:
>
> > expect:~$ [lindex {} 0]
> > empty command name ""
> > while evaluating {[lindex {} 0]}
> > expect:~$ ;# empty command
> > expect:~$ proc {} {} {;# empty}
> > expect:~$ [lindex {} 0]
> > expect:~$ {}
> > expect:~$
>
> What version of expect is this? My version here gives this instead:

It's 8.6.3, but this is not the problem: The error message comes from tclreadline, sorry for the confusion.

if {[llength $cmds] != 0} {
if {$name == ""} {
return -code error "empty command name \"\""
} else {
return -code error \
"ambiguous command name \"$name\": [lsort $cmds]"
}
}

> > The error message should definitely be changed to invalid command
> > name "".
>
> Why should it be changed? The name "", if defined, is a valid command
> name:

As you can see it in my example. I meant, that it should be changed FROM empty command name TO invalid command name. But tclreadline hid the feature of ::unknown that completes a unique abbreviation for an existing Tcl command.

Don Porter

unread,
Feb 20, 2015, 9:42:55 AM2/20/15
to
On 02/20/2015 08:35 AM, heinrichmartin wrote:
>>> expect:~$ [lindex {} 0]
>>> empty command name ""
>>> while evaluating {[lindex {} 0]}

>... The error message comes from tclreadline, sorry for the confusion.
>
> if {[llength $cmds] != 0} {
> if {$name == ""} {
> return -code error "empty command name \"\""
> } else {
> return -code error \
> "ambiguous command name \"$name\": [lsort $cmds]"
> }
> }

Apparently tclreadline had this cargo-culted over from pre-8.4 Tcl.

>>> The error message should definitely be changed...

Yes. Tcl did change it. Long long ago.

The [rename foo {}] misfeature persists, but that's harder to get
rid of, since there's no alternative access to the functionality in
place, and the established user base is enormous.

Doing sensible things with empty strings is a long term project.

--
| Don Porter Applied and Computational Mathematics Division |
| donald...@nist.gov Information Technology Laboratory |
| http://math.nist.gov/~DPorter/ NIST |
|______________________________________________________________________|

heinrichmartin

unread,
Feb 21, 2015, 4:40:51 PM2/21/15
to
I think I found a real mistake in the dodekalogue:

[2] Evaluation.
A command is evaluated in two steps. First, the Tcl interpreter breaks the command into words and performs substitutions as described below. These substitutions are performed in the same way for all _commands_.

==> substitutions are performed for all _words_

On Wednesday, February 11, 2015 at 3:51:37 PM UTC+1, pooryorick wrote:
> actually at least one command in a script, even if that command is the empty
> string. A command that is the empty string has no name, therefore is not
> resolved to any routine, and therefore no routine is invoked. This is a
> different scenario than a command that has the empty string for a name, which
> of course is a legal name for a command.
>
> I guess that means that technically there are empty commands between the
> characters in every sequence of newlines or semicolons in a script.

And more theoretical, consider the difference between:

puts [subst a;] ;# empty command.
puts [subst a;eval ""] ;# empty command?

heinrichmartin

unread,
Feb 22, 2015, 5:16:12 AM2/22/15
to
On Saturday, February 21, 2015 at 10:40:51 PM UTC+1, heinrichmartin wrote:

puts [subst a;] ;# empty command.
puts [subst a;eval ""] ;# empty command?
puts [subst a;{*}{}] ;# empty command.

Many ideas crossed my mind since my last post. Now I think that the behavior is fine as it is.

[subst a;] must return a. Otherwise most legacy code breaks because many code arguments end in regexp {\n[ \t]*$}. {*}{} is a handled by the parser, the result is expected; but eval "" is a procedure call, which is NOT nothing.

And the doc is fine, too. The behavior of [eval ""] (or [eval "" \t ""]) is not defined: the result might depend on the implementation, maybe even on the platform ... An error message is a bit hard imho, and returning "" is reasonable.

It might be an improvement to make it explicit in the doc, that eval is not defined for empty scripts, or that it is defined to return the empty string (which is different from doing nothing!). If the latter is chosen, then [eval] i.e. without args should be a valid call.

Martin

pooryorick

unread,
Feb 23, 2015, 1:03:52 AM2/23/15
to
The behaviour of [eval] for an argument that contains no commands is defined.
Eval returns the result of the evaluation of a script. When a script contains
only empty commands, no routines are invoked, so the result is nothing, i.e.,
the empty string, and that's what [eval] returns. [eval] always returns
something, so by definition, it *never* does nothing. There's no need for
[eval] without args to be a valid call.


--
Yorick

heinrichmartin

unread,
Feb 23, 2015, 4:16:36 AM2/23/15
to
Yes, it never does nothing. But the behavior is only defined for a "script containing one or more commands" according to the doc.

Aidan suggested that it might be an error to call eval with an empty script. Yorick quoted the idea that there are empty commands everywhere. I pointed out that empty commands do not have a return value at all.

It looks like we agree that the current implementation is reasonable. I support Aidan's idea in this theoretical discourse that the docs could be more explicit and consistent about empty scripts.

Martin

pooryorick

unread,
Feb 23, 2015, 8:12:23 AM2/23/15
to
On Monday, February 23, 2015 at 2:16:36 AM UTC-7, heinrichmartin wrote:
>
> Aidan suggested that it might be an error to call eval with an empty script. Yorick quoted the idea that there are empty commands everywhere. I pointed out that empty commands do not have a return value at all.
>

"They do not have a return value" sort of implies that they're being evaluated
at all, They can't have a return value because they aren't even evaluated,
there being no name of a routine to look up.

In the example,

puts [subst a;]

the value of the substitution is the result of the [subst] command not just so
that "legacy code" doesn't break, but because [subst] is the last command
evaluated.

--
Yorick

pooryorick

unread,
Feb 23, 2015, 8:50:01 AM2/23/15
to
And I mean "evaluated" in the Rule 2 sense, not the [eval] sense. [eval]
requires a value to work with.

--
Yorick

heinrichmartin

unread,
Feb 24, 2015, 3:12:12 AM2/24/15
to
On Monday, February 23, 2015 at 2:12:23 PM UTC+1, pooryorick wrote:
> On Monday, February 23, 2015 at 2:16:36 AM UTC-7, heinrichmartin wrote:
> >
> > Aidan suggested that it might be an error to call eval with an empty script. Yorick quoted the idea that there are empty commands everywhere. I pointed out that empty commands do not have a return value at all.
> >
>
> "They do not have a return value" sort of implies that they're being evaluated
> at all, They can't have a return value because they aren't even evaluated,
> there being no name of a routine to look up.

I didn't mean to imply that. Obviously it is not even a no-op. [eval ""] and [if true {}] both return an empty string, which is very fine.

The point of this thread is that this happens by definition. And this definition is not in the doc. Even worse, the docs allow an interpretation where these corner cases are implied to not be valid code (*).

Martin

(*) reasoning for
eval: "which together comprise a Tcl script containing one or more commands".
if: "body1 is executed by passing it to the Tcl interpreter" > Tcl_12 [1] "A Tcl script is a string containing one or more commands" [7] "The result of the script (i.e. the result of its last command)" > no last command! no canonical preference for "" or error.
0 new messages