tclparser, a component of
Tcl Dev Kit written in
C, parses Tcl scripts.
Attributes edit
- repository
- Tcl Dev Kit
- repository
- https://chiselapp.com/user/aspect/repository/tclparser/, which is just tclparser.
See Also edit
- parsetcl
- pure-Tcl alternative, different API
- scriptSplit
- Sses introspection to get a similar result
Synopsis edit
package require parser
Description edit
The module originated in
TclPro, whose source code is available from
sourceforge CVS or
https://github.com/ActiveState/teapot/tree/master/lib/tclparser Building edit
fossil clone https://chiselapp.com/user/aspect/repository/tclparser tclparser.fossil
mkdir -p tclparser/build
cd tclparser
fossil open ../tclparser.fossil
cd build
../configure --prefix=/home/tcl --with-tcl=/home/tcl/lib
make all install
cvs -d:pserver:anonymous@tclpro.cvs.sourceforge.net:/cvsroot/tclpro login
cvs -z3 -d:pserver:anonymous@tclpro.cvs.sourceforge.net:/cvsroot/tclpro co tclparser
mkdir tclparser/build
cd tclparser/build
../configure --prefix=/home/tcl --with-tcl=/home/tcl/lib
make
make install
Despite CVS history showing no activity since 2007, this builds cleanly against 8.6.4. That's a stable interface!
As the
manual explains, it exposes one command
parse $type $text $range, which returns a structure similar to
tcltest's
[testparser
], but a bit more convenient for script manipulation. Like
tcltest::testparser, this is a lightweight wrapper around
functions in tclParse.c.
Parsing Expressions edit
A simple example to turn an
expression into
namespace evalable code:
package require parser
proc expr2tcl {expr {parse ""}} {
if {$parse eq ""} {
set parse [parse expr $expr {0 end}]
}
lassign $parse type range parts
lassign $range min max
incr max $min
incr max -1
set text [string range $expr $min $max]
set result ""
switch $type {
subexpr {
set result [join [lmap part $parts {expr2tcl $expr $part}] " "]
if {[lindex $parts 0 0] eq "operator"} {
return \[$result\]
} else {
return $result
}
}
default {
return $text
}
}
}
# % puts [expr2tcl {sin($x)+4*$x-$x**(pow($x,2))}]
# [- [+ [sin $x] [* 4 $x]] [** $x [pow $x 2]]]
Parsing Scripts and Commands edit
To parse a script, repeatedly call
parse command. Its result is a 4-tuple
{commentRange commandRange restRange parseTree}.
parseTree is an interesting structure that breaks down the words in the command, and the rest are just index pairs as illustrated in the below work-alike of
scriptSplit.
package require parser
proc stringRange {string start step} {
tailcall string range $string $start [expr {$start+$step}]
}
proc ss {script} {
set restRange {0 end}
while {1} {
lassign [parse command $script $restRange] commentRange commandRange restRange tree
set comment [stringRange $script {*}$commentRange]
set command [stringRange $script {*}$commandRange]
if {$command eq ""} break
#puts "Parsed a command {$tree} {$command}"
lappend result $command
}
return $result
}
Note that the command terminator (newline or semicolon) is included in
commandRange. But only if it is present. This is discussed somewhere else.
APN: Minor comment on the above use of string range. The expr is not needed as string range arguments can include + and - arithmetic operators. Also, the use of tailcall here does nothing useful other than slow down the procedure.