I finally got really interested in this, and against my better judgement coded up a complete answer. I'm not going to document it in any way. Read it, read the docs for commands you don't understand, then come and ask questions.
Looking at your liberty file, I see it's very close to native Tcl syntax. So you can create a few procedures named "timing", "rise_constraint", etc, and you can basically run it as a script.
package require struct::list
######################################################################
proc main {libfile} {
global lines idx3 vals
set lines [list]
set idx3 [list]
set vals [list]
evaluate_liberty $libfile
set idx [get_choice "select an index_3 value: " $idx3]
set column [struct::list mapfor elem $vals {lindex $elem $idx}]
set newvalues [list]
for {set i 0} {$i < 5} {incr i} {
lappend newvalues [lrange $column [expr {5*$i}] [expr {5*($i+1)-1}]]
}
print_liberty $newvalues
}
######################################################################
proc evaluate_liberty {libfile} {
set fh [open $libfile r]
# handle known syntax error in liberty file
set contents [string map {\", \"} [read -nonewline $fh]]
regsub -all -line {\s+$} $contents {} contents
close $fh
uplevel #0 $contents
}
proc get_choice {prompt values} {
while {1} {
for {set i 0} {$i < [llength $values]} {incr i} {
puts stderr [format "%2d. %s" $i [lindex $values $i]]
}
puts -nonewline stderr $prompt
gets stdin answer
if {[string is integer -strict $answer]} {
if {0 <= $answer && $answer < [llength $values]} {
return $answer
}
}
}
}
proc print_liberty {newvalues} {
global lines close_braces
puts [join $lines \n]
puts "values ( \\"
foreach elem $newvalues {
puts [format "\"%s\", \\" [join $elem {, }]]
}
puts ");"
for {set i 1} {$i <= $close_braces} {incr i} {
puts [format %c 125]
}
}
######################################################################
# define DSL
proc timing {label script} {
lappend ::lines [format "timing %s %c" $label 123]
incr ::close_braces
uplevel 1 $script
}
proc rise_constraint {label script} {
lappend ::lines [format "rise_constraint %s %c" $label 123]
incr ::close_braces
uplevel 1 $script
}
proc index_3 {args} {
global idx3
foreach item $args {
lappend idx3 [string map {( "" \" "" , "" ) ""} $item]
}
}
proc values {args} {
global vals
foreach set [lrange $args 1 end-1] {
lappend vals [split [regsub -all {\s*,\s*} $set { }]]
}
}
rename unknown system_unknown
proc unknown args {
lappend ::lines "[join $args];"
}
######################################################################
if {$argc == 0} {
puts "usage: $argv0 filename.lib"
exit
}
set libfile [lindex $argv 0]
if {![file exists $libfile]} {
error "no such file: $libfile"
}
main $libfile
Running it:
$ tclsh liberty.tcl test.lib > newlib.lib
0. 0.084
1. 0.84
2. 3.36
3. 8.4
4. 13.44
select an index_3 value: 0
$ cat newlib.lib
timing () {
related_pin : clk;
timing_type : setup_rising;
rise_constraint (constraint_template_5X5) {
index_1 ("0.01, 0.05, 0.12, 0.2, 0.4");
index_2 ("0.005, 0.025, 0.06, 0.1, 0.3");
values ( \
"1.1, 2.1, 3.1, 4.1, 5.1", \
"6.1, 7.1, 8.1, 9.1, 10.1", \
"11.1, 12.1, 13.1, 14.1, 15.1", \
"16.1, 17.1, 18.1, 19.1, 20.1", \
"21.1, 22.1, 23.1, 24.1, 25.1", \
);
}
}
You do lose all your nice indentation, but you get the values you want.