(RJM) Here some code is presented that can be used to read C-header files. This should apparently aid in developing and managing less error-prone bilingual C/Tcl projects. Further comments is in the code below. Extensions and ideas are welcomed.
New: Modifications resulting in usage of command aliases instead of global variables, according to an idea from constants (modified "def" approach).
# C-header file parser # will parse simple #define commands and enums as long as these are in a section # that act as a parse delimiter areas as well as a comment in C as to indicate # that sections are also used by tcl programs. # Using C macros aid in readability of Tcl/C-projects as well as reduce potential # error sources. # Delimiters: //tcl on and //tcl off (yet not /*tcl on*/) # all #defines are stored in ordinary variables in order to keep accesses as # straightforward as possible. Normally no conflicts occurs when #defines are # capitalized. In procs, defines shall be dereferenced with prefixed ::, which # aid also in quick visual recognition besides not needing 'global' commands. proc h-parse {filename} { global _H_PARSE_ set _H_PARSE_ off set fid [open $filename r] set line_tcl "" set multiline 0 while {![eof $fid]} { set line [gets $fid] # ToDo: /*...*/ comment remover if {[regexp ^//tcl $line]} { set _H_PARSE_ [lindex $line 1] continue } regsub //(.*?)$ $line "" line if {$_H_PARSE_ != "on"} continue append line_tcl [string trimright $line \;] if {[regexp \{ $line]} {set multiline 1} if {[regexp \} $line]} {set multiline 0} if {$multiline} continue eval _C_$line_tcl set line_tcl "" } } proc def {name args} { if {[catch {set value [expr $args]}]} { set value $args } interp alias {} $name {} CONST $value } proc CONST {a} { return $a } proc _C_ {} { } # assign enums as macros (alternatively consider storage in array because it # corresponds to its nature in C. However this compromises readability # of typical enum usage in switch statements) proc _C_enum {name ids} { # name ignored # ids: do assignments in enums without spaces! set index 0 foreach element [split [regsub -all { |\t} $ids ""] ,] { lassign [split $element =] name value if {$value != ""} { set index $value } def $name $index incr index } } proc _C_#define {args} { lassign $args name value def $name $value } if 0 { proc test {} { h-parse test.h puts "===== list of globals with \"A\" =====" foreach var [info globals *A*] { puts $var\t\t[set ::$var] } puts "===== some usage examples =====" for {set i 0} {$i < 25} {incr i} { # note the omission of outer brackets - command substitution! switch -- $i default { puts -nonewline . } [ALPHA] { puts alpha } [GAMMA] { puts gamma } [OMEGA] { puts omega } [LAMBDA] { puts lamda } } if {[MACRO_EMPTY] == "" } {puts "empty macro"} if {[MACRO_VALUE] != "" } {puts "macro: [MACRO_VALUE]"} if {[MACRO_STRING] != "" } {puts "macro: [MACRO_STRING]"} } }
And here a sample header file is quoted that is used for the test case above:
//tcl on enum hallo { ALPHA, BETA, GAMMA=6, ETA , OMEGA = 21 }; //tcl off /* stuff that tcl ignores */ blah, blah //tcl on -- copy this file to the tcl-project when modified! enum shortenum {KAPPA = 10, LAMBDA}; #define MACRO_EMPTY #define MACRO_COMMENT // test comment // here a line with some whitespaces #define MACRO_STRING "TESTVAL" #define MACRO_VALUE 123