[AMG]: This procedure converts a Tcl script to a list of commands. While there are many possible uses for this functionality, I think one of its most frequently useful practical applications is for reading configuration or database files. The configuration file is written according to the [Dodekalogue], so comments, quoting, whitespace, semicolon, and other goodies can be used to spruce up the formatting. More interesting possibilities arise when variables and commands are thrown into the mix, but the basic functionality is quite useful all by itself. ====== package require Tcl 8.6 proc parse {script} { set int [interp create -safe] $int eval {unset {*}[info vars]} foreach command [$int eval {info commands}] {$int hide $command} $int invokehidden namespace delete {*}[$int invokehidden namespace children] $int invokehidden namespace unknown `addline $int alias `addline apply {{args} {upvar 1 result r; lappend r $args; list}} set result {} $int eval $script interp delete $int return $result } ====== The only validation this code does is to make sure that its input satisfies the [Dodekalogue]. It doesn't attempt to interpret the meaning of its input. That is left to the code that calls [[parse]]. When the data has a nested structure, [[parse]] can be called repeatedly to pull it apart. For example, if the configuration file has a "command" that takes an argument which itself is structured like a Tcl script, just call [[parse]] on its argument to turn it into an easily-processed list. This code works very well with a templating system, so you can write templates with variables that are filled in with data from user-supplied Tcl-like configuration files. I do this at work, with great results. I made a "compiler.tcl" script which (repeatedly) calls [[parse]], analyzes the results, checks syntax (e.g. invalid commands), then prints a [dict] that is accepted by the '''-file''' argument of my [Templates and subst] script. ---- This alternate formation of '''`addline''' changes the output to be a [dict]-like alternating list of commands and argument lists, such as is described above. Merge this into the above script to make it capable of producing output that is directly compatible with the '''-file''' argument of my [Templates and subst] script. ====== $int alias `addline apply {{name args} {upvar 1 result r; lappend r $name $args; list}} ====== Or instead use code similar to the following to format and print the output of [[parse]]: ====== foreach line [parse [read stdin]] { puts [list [lindex $line 0] [lrange $line 1 end]] } ====== ---- One interesting possibility is to selectively expose Tcl commands (or custom [proc]s) to the child interpreter so that the configuration files can use them. For example, if [[[foreach]]] is exposed, then this configuration file: ====== # First specify the foo. foo bar bas # Use lots of quux! foreach a {1 2 3} b {7 8 9} {c d} {p q r s t u} { quux $a$b $c$d } ====== "compiles" into this list: ====== {foo bar bas} {quux 17 pq} {quux 28 rs} {quux 39 tu} ====== ---- A drawback of my approach is that anything can be put into square brackets with nonsensical results: ====== [] [foo [bar]] [bas] ====== results in the following: ====== {bar} {foo ""} {bas} {"" "" ""} ====== At least this clearly demonstrates Tcl's substitution order rules. :^) Plus I bet you didn't know that [[]] is yet another way to obtain the empty string. <>Category File | Category Parsing