smilax:: Tcl Hacks : cmacro.tcl | [Changes] [Calendar] [Search] [Index] [PhotoTags] |
[Bedstraw] *smilax* |
# C-like Macro system for Tcl. # # cmacro::reset ?beginChar? ?midChar? ?endChar? # # Delete any existing macro definitions, # and set the special substitution delimiters. # Defaults are "<" "," ">" # # cmacro::define name formal_parameter_list body # # Define a macro named "name" to expand to "body", # substituting occurrances of the formal parameters # with values provided when the macro is used. # Tcl "string map" is used to make the substitutions. # # cmacro::substitute string # # Preform macro substitutions on string # and return the new string. # # cmacro::mproc name params body # # Define a procedure just like "proc" does, # but first preform macro substitutions on the body. # # For examples, see the tests at the end of this file. # To test, run with ::argv set to "--test-cmacro"
Here we define three macros, "hd", "tl", and "tlN". The first two take one parameter, but tlN takes two.
cmacro::define hd X {[lindex X 0]} cmacro::define tl X {[lrange X 1 end]} cmacro::define tlN {N X} {[lrange X N end]}
(* "hd" returns the head of a list, its first element. "tl" returns the tail, the rest of the list. "tlN" returns the tail starting with the Nth element, rather than starting with the second. *)
Now we use them in two proc definitions, but we use "cmacro::mproc" rather than "proc" so macro substitutions will occur.
cmacro::mproc second list { return hd< tl<$list> > } cmacro::mproc tailN {n list} { return tlN<$n, $list> }
(* "second" returns the head of the tail of the list, which is its second item. "tailN" is a simple wrapper around "tlN", demonstrating how a "," is used to separate the arguments to the macro "tlN". *)
Although the C preprocessor uses parentheses "(" ")" to mark macro arguments, we prefer angle brackets "<" ">" so that parentheses may be used for array references. (You may change the special characters with the cmacro::reset command if you don't like angle brackets.)
The "<" must occur immediately after the macro name, followed by one or more arguments separated by ",", and finally the ">" ends the macro arguments. Inner macros substitute before outer ones. There may be no extra "<", ",", or ">" characters inside the macro arguments.
Macro arguments are "string trim"med, so spaces may be used after "<", before ">", and around "," to improve readability, without changing the substitution. This matters when the formal parameters of the macro are used in strings in the macro definition.
Whereas C allows macros with no arguments and no parens, we require the angle brackets to be used.
Here is "second_proc", which is the same as "second" except that it is written using procs instead of macros:
proc hd_proc X {lindex $X 0} proc tl_proc X {lrange $X 1 end} proc second_proc list {hd_proc [tl_proc $list]}And here is a preformance test:
set list {one two three four five} puts fast=[time {second $list} 2000] puts slow=[time {second_proc $list} 2000]And the results:
$ tclsh8.4 perform.tcl fast=7 microseconds per iteration slow=37 microseconds per iteration $
(last modified 2006-05-29) [Login] |