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

Embedding a Tclinterp : some pointers requested !

26 views
Skip to first unread message

Nicolas Castagne

unread,
Apr 12, 2005, 11:34:46 AM4/12/05
to
Hi all !

In our app (writen in C++), various script files using Tcl syntax will
be executed. Some of them will be writen by the users.


While a script is executed, in the GUI, we have to :
- let the user know the level of completion of the execution (ie, for
example, let him know which line of the file is currently "executed") ;
- let the user cancel the execution, when needed ;
- let the user do other tasks.

From these specifications, we are experimenting a conception as following :
- all the execution of the script files are fired from a C++ "working
thread"
- the working thread creates a Tcl_Interp, loads the appropriates
context-dependant proc. and packages
- the working thread then executes the script, by calling Tcl_Eval, or
Tcl_EvalFile


Then, we encounter some diffuculties with :
- retriving the current line executed
- canceling the execution


To that aim, an idea (often implemented, as far as we checked) would be
to execute the script line-per-line :
- the thread reads the file line-per-line, calls Tcl_CommandComplete to
check wether the command is complete or not, reads other lines as needed
- when the current command is complete, the threads calls Tcl_Eval

That way the wotrking thread knows which line is currently processed
When we need to cancel the execution, we just stop sending lines to the
TclInterp..
Well, that is OK most often... But :
- it is very slow, since we have to pre-parse the script for extracting
lines.
- it does not allow to stop the interpretation in case of an infinite
loop within the current command given to Tcl_Eval

Now, the questions !

1 --> is there a way to ask TclInterp to 'execute' only a given number
of lines, or of commands, in a script file ? Something like
"Tcl_ExecuteOneCommand(file *)" ?

2 --> is there a way to retrieve the current line which is executed on a
TclInterp object by Tcl_EvalFile - that is : to let another thread
request this value.

3 --> what should we do to cancel in a nice way the intepretation of a file
For example, a Tcl_Eval may be looping infinitely... So that, to stop
the interpretation, we have to find a way to 'cancel' it from another
thread !


Thx in advance,
All the best,
Nicolas

Michael Schlenker

unread,
Apr 12, 2005, 12:45:42 PM4/12/05
to
Nicolas Castagne wrote:
> Hi all !
>
> In our app (writen in C++), various script files using Tcl syntax will
> be executed. Some of them will be writen by the users.
>
>
> Now, the questions !
>
> 1 --> is there a way to ask TclInterp to 'execute' only a given number
> of lines, or of commands, in a script file ? Something like
> "Tcl_ExecuteOneCommand(file *)" ?
>
> 2 --> is there a way to retrieve the current line which is executed on a
> TclInterp object by Tcl_EvalFile - that is : to let another thread
> request this value.

The concept of which line is 'executed' is a bit complex. With the
dynamic nature of Tcl and dynamic code creation there may be no line
associated with a given command.

Think about something like:

set _matcher 0
proc create_matcher {string} {
global _matcher
incr _matcher
set name matcherproc$_matcher
proc $name txt "string match *$string* \$txt"
return $name
}

set test1 [create_matcher foo]
set test2 [create_matcher bar]

set fd [open somefile.txt]
set data [read $fd]
close $fd

if {[$test1 $data] && [$test2 $data]} {
# do something
}

And this is an easy case..., gets much harder once you start fiddling
with info body and proc rewriting.

> 3 --> what should we do to cancel in a nice way the intepretation of a file
> For example, a Tcl_Eval may be looping infinitely... So that, to stop
> the interpretation, we have to find a way to 'cancel' it from another
> thread !

The interp limit support in Tcl 8.5 may be what you want.
http://www.tcl.tk/cgi-bin/tct/tip/143.html

With threads you always have the option to trash the Tcl interp running
the script with brute force.

Michael

David Gravereaux

unread,
Apr 12, 2005, 11:58:23 PM4/12/05
to
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1


Be the parser. Sounds like you're writing a debugger, not just asking
to Tcl to eval some code. You need a lower level than what Tcl_Eval
provides you. It's all there, but you'll need to do some reading of the
source to figure it out.

The old TclPro debugger called it 'instrumenting', where it parsed the
script(s) into it's own framework, then had control of its evaluation.

You'll first need to start with the parser, and parse it just like
Tcl_Eval would do.

Have a look at generic/tclBasic.c for Tcl_EvalEx(). See the way it
starts the parsing? The general look is:

int
Tcl_EvalEx(..)
{
do {
Tcl_ParseCommand(..);
TclEvalObjvInternal(..);
} while (bytesLeft);
}

There's your split point right there between the two.


> 2 --> is there a way to retrieve the current line which is executed on a
> TclInterp object by Tcl_EvalFile - that is : to let another thread
> request this value.

I think it's an entry in the Interp struct that the parser places there.
See the errorLine member.

> 3 --> what should we do to cancel in a nice way the intepretation of a file
> For example, a Tcl_Eval may be looping infinitely... So that, to stop
> the interpretation, we have to find a way to 'cancel' it from another
> thread !

Either set [interp recursionlimit ...] or whatever the C version of the
same is. There's no generalized way to unwind from any point within an
active eval that I know of. Using Tcl_AsyncMark and returning TCL_ERROR
from the Tcl_AsyncProc might be 60% effective.

But.. if you do some reading of the source and whole lot of hacking on
the innards, I'm sure you could set yourself up so that you have to do
all the 'churning' for the system to run, thus if you use a
Tcl_AsyncProc to set a flag to indicate to the thread that acts as
'churner' to unwind, you could probably cause a clean and absolute
command boundary unwind.

- --
David Gravereaux <davy...@pobox.com>
[species:human; planet:earth,milkyway(western spiral arm),alpha sector]

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.0 (MingW32)

iD8DBQFCXJjflZadkQh/RmERAvXyAJwPUyGNqxuRpyM5z8IR58uX5YkZ7gCg8IyB
jtTaC1Rh7B2kKKoFPbkW2cI=
=xOLG
-----END PGP SIGNATURE-----

Ramon Ribó

unread,
Apr 13, 2005, 4:17:57 AM4/13/05
to
Hello,

If you need an example code for parsing TCL, RamDebugger
(http://wiki.tcl.tk/RamDebugger)
has the code both in TCL and in C.

Regards,

--
Ramon Ribó
http://gatxan.cimne.upc.es/ramsan

"David Gravereaux" <davy...@pobox.com> escribió en el mensaje
news:0sadne-NV7N...@speakeasy.net...

Nicolas Castagne

unread,
Apr 14, 2005, 11:20:07 AM4/14/05
to
Hi all,

a few more precise things in this post.

***reminder of previous post
In a C++ program, we wanna set up a way to execute a script command per
command, but still in an optimized manner, in order to :
1) be able to know, from another thread, which line is currently executed
2) stop the execution nicely when the user requests so


***Now, our plans
In order to execute a file command-per-command, we now plan do the
following in a loop :

while(notEnded AND stopNotRequested){
1) extract the next command thanks to Tcl_ParseCommand
2) eval the command
}

***Now, the problem
However, we do not find a While function tha evals the command WITHOUT
REPARSING IT (for optimizing the process).

For example, Tcl_EvalObjv does eval a TclObject, but there is no command
to build this TclObject from our TclParser.
Convesely, there is no command that would eval directely from a
TclParser (ie, a command that could be called "Tcl_EvalParsedCommand")


Are our plans bad ?
Or do we have to write the command we need ourselves ?
If so, perhaps it would be a good idea to add such a command to Tcl ?

Thx
Nicolas

Don Porter

unread,
Apr 14, 2005, 11:44:02 AM4/14/05
to
Nicolas Castagne wrote:
> ***Now, the problem
> However, we do not find a While function tha evals the command WITHOUT
> REPARSING IT (for optimizing the process).

What evidence do you have that such "optimization" is necessary
or helpful?

> Are our plans bad ?
> Or do we have to write the command we need ourselves ?
> If so, perhaps it would be a good idea to add such a command to Tcl ?

There is work in a feature branch that keeps parse results around
better than the default Tcl sources do. If you really think you need
to look at that, post again and I'll provide a pointer to it.

More likely, you're just worrying about things you don't need to
worry about.

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

miguel sofer

unread,
Apr 14, 2005, 1:07:17 PM4/14/05
to
I think you might be looking for Tcl_EvalObjv
http://www.tcl.tk/man/tcl8.5/TclLib/Eval.htm

Miguel

Nicolas Castagne

unread,
Apr 15, 2005, 6:20:27 AM4/15/05
to
Hi all, thx for your answers.

miguel sofer a écrit :


> I think you might be looking for Tcl_EvalObjv
> http://www.tcl.tk/man/tcl8.5/TclLib/Eval.htm

Indeed, we planed on using one of Tcl_GlobalEvalObj, Tcl_EvalObjEx and
Tcl_EvalObjv.

The question is then :
By executing Tcl_ParseCommand, we will extract the "next command". Then
we have a Tcl_Interp, and a Tcl_Parse which know the "next command".

But how should we build the "Obj" (to call one of the Tcl_EvalObj*)
after having extracted the "next" command ?

So far, we did not find a function to build such an "Obj" from a
Tcl_Parser and a Tcl_Interp.

Should we copy the corresponding code from Tcl_EvalEx (for example) in a
hand-made function ?

If yes, perhaps, it would be an idea to add such a feature in the Tcl_
commands, so that it would become possible to make a whole execution
process step by step :
while (...) {
//parse a command,
//build an obj,
//eval it
}.


Don Porter a écrit :


> Nicolas Castagne wrote:
>>***Now, the problem
>>However, we do not find a While function tha evals the command WITHOUT
>>REPARSING IT (for optimizing the process).

> What evidence do you have that such "optimization" is necessary
> or helpful?

Basically, I suppose that reparsing the command (for example by calling
Tcl_EvalEx after having extracted the 'next command' thanks to a
Tcl_Parser) would not be optimized, since it would redo the parsing.

However, I really don't know how efficient the parsing is, so that I
really don't know if doing the parsing twice would slow down the whole
process in any perceptible manner.

Do you mean that doing the parsing twice would not be a problem at all,
in terms of optimisation ?
(well, wish so :p)


>>Are our plans bad ?
>>Or do we have to write the command we need ourselves ?
>>If so, perhaps it would be a good idea to add such a command to Tcl ?

> There is work in a feature branch that keeps parse results around
> better than the default Tcl sources do. If you really think you need
> to look at that, post again and I'll provide a pointer to it.
> More likely, you're just worrying about things you don't need to
> worry about.

Well, let's wait for your answers first!
Sure we don't want to make pple work and borry them - and work ourselves
- if it is not needed :=)

Thx
Nicolas

Don Porter

unread,
Apr 15, 2005, 10:13:02 AM4/15/05
to
Nicolas Castagne wrote:
> By executing Tcl_ParseCommand, we will extract the "next command". Then
> we have a Tcl_Interp, and a Tcl_Parse which know the "next command".
> But how should we build the "Obj" (to call one of the Tcl_EvalObj*)
> after having extracted the "next" command ?

Since you're concerned about re-parsing cost, go with
Tcl_EvalTokensStandard(). Here's the basic parse and eval loop:

Tcl_Parse parse;
int code = Tcl_ParseCommand(interp, script, numBytes, 0, &parse);
while (code == TCL_OK) {
code = Tcl_EvalTokensStandard(interp, parse.tokenPtr,
parse.numTokens);
if (code != TCL_OK) break;
nextCmdStart = parse.commandStart + parse.commandSize;
numbytes -= (nextCmdStart - script);
script = nextCmdStart;
code = Tcl_ParseCommand(interp, script, numBytes, 0, &parse);

0 new messages