Weird TCL quirk - tcl

So I am very new and inexperienced to the ways of TCL programming. I wrote a script that calls a proc written by someone else, first removing the output file. It then does some additional logic I wrote.
I moved the logic into a second proc and instantly a bunch of it broke (namely the rm commands).
From what I can tell, the first program on a line inside the central execution (the text following proc definitions) executes normally without an "exec" command. However, if you move it inside a proc, it now needs an "exec" command.
Can anyone explain to me why TCL behaves this way?
e.g.
proc helloworld {} {
puts "hi"
}
#works
rm my_file
helloworld
..
proc helloworld {} {
#doesn't work
rm my_file
puts "hi"
}
helloworld
..
proc helloworld {} {
#works
eval rm my_file
puts "hi"
}
helloworld
..
proc helloworld {} {
#works
file delete my_file
puts "hi"
}
helloworld
*Note this weird behavior may be specific to the program I'm feeding the script to vmd, which has its own built in TCL behavior. Perhaps in your responses you can indicate if this is standard for other interpreters as well?

An interactive tclsh session will try to exec an unknown command (such as rm). You cannot count on this behaviour in non-interactive script execution or, as you've discovered, in procs.
I can't see that this is documented in the tclsh man page, but the unknown man page does. See also the tclsh page on the Tcl wiki. In an interactive tclsh session, you can see what unknown does by typing:
info body unknown
[update]
Quoting from "Practical Programming in Tcl and Tk":
The unknown command provides a few other conveniences. These are used only when you typing commands directly. They are disabled once execution enters a procedure or if the Tcl shell is not being used interactively. The convenience features are automatic execution of programs, command history, and command abbreviation. These options are tried, in order, if a command implementation cannot be loaded from a script library.

Note this is programatically testable too, via the variable tcl_interactive, which is "1" if the Tcl is being run via an interactive shell, and "0" if not. The variable is also settable, so one could start an interactive shell, then [set tcl_interactive 0], and continue on. At this point, one loses such features as the % command prompt proc name / command name completion (i.e.: can't type [pu "xyz"] and get the effect of typing [puts "xyz"], like an interactive shell)automatic "shell-out" to have external commands complete a request (like the "rm" in this original question)and perhaps others...

Related

How to compile and test functions in ocaml?

For my summer programming course I need to compile and test several functions from an ocaml file (a .ml file) our teacher gave us. I've never programmed in ocaml before, but I downloaded it on my ubuntu vm and not I can't figure out how to compile it and test the functions from the terminal.
I'm also curious if I need to add print statements to the code in order to test them, since ocaml doesn't require main methods. If so, how do I print the return value of a function?
Thank you for your help, I apologize if this is a newbie question.
Make sure that you have installed OCaml properly, by running the OCaml interactive toplevel (don't type $ this is a prompt from your shell):
$ ocaml
It should show something like this:
OCaml version 4.07.0
#
The # symbol is a prompt, you can type OCaml definitions there and send them to the interpreter using the ;; terminating sequence (again don't type # it is also a prompt symbol), e.g.,
# print_endline "Hello, world";;
Hello, world
- : unit = ()
#
Hint: to enable history install rlwrap with sudo apt install rlwrap and run the ocaml toplevel as
$ rlwrap ocaml
Now, we are ready to compile our first program. In OCaml, like in Python, all top-level definitions in your program are evaluated in order of their appearance, therefore you don't need to have a special main function. Despite this fact, I'm usually defining one, using the following idiom
let main () =
print_endline "Hello, world"
(* the entry point - just call the main function *)
let () = main ()
Now, create a new folder (make sure it is empty)
$ mkdir my-first-ocaml-program
$ cd my-first-ocaml-program
and put the OCaml code above into a file named test.ml (the filename doesn't have any special meaning for the compiler toolchain, but I will reference this name in the shell commands below).
let's test that everything is correct, by printing the contents of the test.ml file
$ cat test.ml
and the output should be
let main () =
print_endline "Hello, world"
(* the entry point - just call the main function *)
let () = main ()
Now, let's compile and run at the same time,
$ ocamlbuild test.native --
And we should see the "Hello, world",
Finished, 4 targets (4 cached) in 00:00:00.
Hello, world
The first line is the output from the compiler (ignore it, unless it is different). Starting from the second line it is our output. Here are some explanations on the build one-liner, ocamlbuild test.native. It uses ocamlbuild, an easy to use but powerful OCaml build tool. The test.native tells ocamlbuild that you want to build a native (machine code) binary and that test.ml is the main source file. You can also ask to build a bytecode binary, e.g., test.byte. This is called a target in ocamlbuild parlance. The -- is optional, and it tells ocamlbuild to run the built target as soon as it is ready. Any argument past -- is passed to your program as command line arguments.
What about larger programs or programs with dependencies? The good news is that you can put your code in several files in the same folder, and ocamlbuild will be clever enough to build them in the proper order (it will do the dependency analysis, compiling, and linking for you - all seamlessly). If you need to use some external package, then you can specify it via the -pkg option. For example, let's assume that we're using the fileutils package to implement our version of the ls program1. Let's update our test.ml so that it now is having the following contents:
$ cat test.ml
let main () =
FileUtil.ls "." |> List.iter print_endline
(* the entry point - just call the main function *)
let () = main ()
and, as usual, build and print in one
$ ocamlbuild -pkg fileutils test.native --
Finished, 4 targets (4 cached) in 00:00:00.
./test.native
./_build
./test.ml
1) How to install a package is system dependent. E.g., if you're using apt to install OCaml then you can do sudo apt install libfileutils-ocaml-dev. If you're using opam (the recommended way), then it is just opam install fileutils. In any case, package installation is out of the scope of this question, I'm assuming that in your course you would be using some packages pre-installed. We use fileutils here just as an example, which you can easily adapt to your own purposes.

How to pass arguments to tcl script in Vivado GUI tcl console

I am trying to execute a tcl script in Vivado GUI Tcl Console and my script takes an argument to decide which type of run (synth, impl, bitgen etc.) has to be configured.
I know that, using -tclargs one could pass arguments if the script is executed in Vivado command-line mode. Something like:
vivado -mode batch -source <filename> -tclargs <arguments>
I tried the same in Vivado gui mode and got an error.
ERROR: [Common 17-170] Unknown option '-tclargs', please type 'source -help' for usage info.
Running 'source -help':
Syntax:
source [-encoding <arg>] [-notrace] [-quiet] [-verbose] <file>
Usage:
Name Description
------------------------
[-encoding] specify the encoding of the data stored in filename
[-notrace] disable tracing of sourced commands
[-quiet] Ignore command errors
[-verbose] Suspend message limits during command execution
<file> script to source
By looking at -help I am getting a feeling that it is not possible to do so. Also, I can't find any documents for doing so. I would like to know if there is any way of achieving this.
The source command doesn't set up the arguments; it's more like C's #include than anything else really. Because of that, if the script that you are sourceing expects argv and argc to be set — as if the script was run as a program — then you should just set them before the source. They are ordinary variables as far as Tcl's concerned; they just happen to be set up by default.
You might also need to set argv0 to the script. Some programs expect that when running in non-interactive mode.
set argv [list "a b c" foo bar 123]
set argc [llength $argv]
set argv0 theScript.tcl
source $argv0

Loading tcl extension from tclsh

I have a C extension to Tcl where command mytest is defined. The extension is compiled correctly (I am on Linux, extension is *.so). For example, I can start tclsh and use it like this:
$ tclsh
% load /path/extension.so
% mytest abc
...
But, if I create a file myscript.tcl with the following content:
load /path/extension.so
mytest abc
then I get error:
$ tclsh myscript.tcl
invalid command name "mytest"
while executing
"mytest abc"
(file "myscript.tcl" line 2)
I am using bash on Ubuntu 14.04. Tcl 8.6.
EDIT 1: My question/problem is that I want to use tclsh with a script as an argument - this script should properly load extensions in such a way that mytest and other implemented functions are working without error.
EDIT 2: Uhh, If I use command "source myscript.tcl" inside tcl shell the result is the same. If I use absolute path for myscript.tcl the error is still the same --- "load" executes without warning but I am not sure about it because I get invalid command name "mytest". Maybe the problem is with scope, but it is working correctly when tclsh is used interactively.
If you are using the full path of the extension library in both cases, that part should work identically. It probably is doing though; if it couldn't load it, it would generate an error (which might or might not be helpful, as some of the ways that things fail give very little information; Tcl reports what it has got, but that's sometimes not enough, as it is dependent on the OS to tell it some things). Instead, the problem is probably elsewhere.
The main difference between interactive use and scripted use is that in interactive use, the unknown command will expand unknown command names to Tcl commands that the thing you typed is an unambiguous prefix of. This is convenient, but when converting to a script, you should always use the full command name. OK, not the full full command name — you mostly don't want or need the :: namespace on the front — but without abbreviation, so don't use lappe for lappend. (In interactive use, Tcl will also exec things as external programs without requiring you to type the exec explicitly; again, that's turned off in scripts as it is rather fragile.)
Could it be that this is what is going on? You can check by setting the global variable tcl_interactive to 0 before typing in your code (I recommend using cut-n-paste for that typing, so that you know exactly what is going in). If that fails, it's the interactive-mode helpfulness that is tripping you up. Check what commands you might have as an expansion for a prefix with info commands (after the load, of course):
info commands mytest*
If that just reports mytest, my theory is wrong. (Well, if it does that and the length of that string is 6; there could theoretically be extra invisible characters have been put on the command name, which would be legal Tcl but very nasty and DON'T DO THAT!)

Tcl interact after sourcing a file.tcl

I want to interact after sourcing a file in Tcl prompt.
i.e.,
]$ tclsh myCode.tcl
// execute my code
% // Enters Interact mode within myCode.tcl
The simplest way of doing this is to use the commandloop command from the TclX extension.
package require Tclx
#... define things and run things...
# Let the user issue commands
commandloop
The wiki page linked above discusses how to do this without using TclX.
I'm afraid I may be reading too little into this, or over-simplifying it, but... isn't what you need the interact command?
If you want Tcl/Expect to do something, then yield control back to the user, pls check out the interact command in the man page link below:
http://www.tcl.tk/man/expect5.31/expect.1.html
If you'd rather do it in pure tcl without any external packages, the simplest implementation of a tclsh prompt is very simple indeed. Just put this at the end of myCode.tcl:
fileevent stdin readable {
puts [eval [gets stdin]]
}
vwait forever
You can even implement this as a standalone program that sources your other tcl scripts.
Of course, the example code above is so simple it doesn't even print a prompt or handle things like multiline commands but it's a good starting point for you to modify and customize.
You may try tkcon, an interactive tclsh which creates a separate window. I wrote a small shell script mytclsh with the first line
#!/usr/bin/tkcon myscript.tcl
and made it executable (chmod 755 mytclsh). This executes myscript.tcl and then goes interactive. Here's more information on tkcon: https://wuhrr.wordpress.com/2011/01/13/a-solution-for-tclsh-editing-woes/

How to disable a modified tclsh interpreter interactive mode?

Run tclsh command without any tcl file, the interpreter will go into interactive mode.
Can I simply disable this feature by modifying the tclsh source code ?
I can't imagine why you would want to bother doing this, given that supplying any script file will turn off interactive mode. The script you supply will have full access to the additional arguments passed in (a list in the global argv variable) and the standard IO channels (stdin, stdout and stderr). It can exit when it is done. Literally anything you want can be done at that point; you've just got to write a script to do it.
If you're including Tcl in your own program, the behaviour of tclsh is implemented in the C function Tcl_Main. If you never call that — instead just using Tcl_FindExecutable, Tcl_CreateInterp and Tcl_Eval/Tcl_EvalFile — then you never get any of that interactive behaviour. While theoretically you could modify the Tcl source itself to do what you want — it's all open source — why would you bother when you could just not call that code in the first place?