Reputation: 25
accent {a1} {Z} {f[1]}
accent {a2} {C} {f[2]}
module c2
accent {a3} {Z} {f[3]}
accent {a4} {C} {f[4]}
I want to manipulate this input file and get the output file fO as follows:-
accord [get_nets c1/f[1]] [get_pins c1/a1/Z]
accord [get_nets c1/f[2]] [get_pins c1/a2/C]
accord [get_nets c2/f[3]] [get_pins c2/a3/Z]
accord [get_nets c2/f[4]] [get_pins c2/a4/C]
I tried this in tcl,
accent {
if {[regexp {{(\w+)}.+{(\w+)}.+{(\w+)}} $line -> a b c]} {
chan puts $fo "accord \[get_nets $module/$c] \[get_pins $module/$a/$b]"
}
}
But it does not work. What could be the issue here?
Upvotes: 0
Views: 175
Reputation: 13282
It's just a minor problem in the third capture group. Rewritten accent
clause:
accent {
if {[regexp {{(\w+)}.+{(\w+)}.+{([][\w]+)}} $line -> a b c]} {
chan puts $fo "accord \[get_nets $module/$c] \[get_pins $module/$a/$b]"
}
}
The word character escape \w
won't match the brackets in {f[1]}
etc. The regular expression fragment [][\w]
means "match a right bracket, a left bracket, or a word character". It looks a bit confusing since brackets are used in two senses: to signify a class match, and as literal brackets.
Note that if you run accord
as a Tcl command, the interpreter will try to evaluate 1, 2, 3, and 4 as commands, since they are enclosed in brackets.
accent {
if {[regexp {{(\w+)}.+{([01])}} $line -> a b]} {
chan puts $fo "create \$mod/tie$b"
}
}
If you're going to use regular expressions, you need to learn regular expression syntax. If you're going to use Tcl, you need to learn Tcl syntax. Explanations and a bit of an apology follows.
You were matching the strings a1
and a2
with the regular expression [][\w]+
meaning "one or more of right bracket, left bracket, or any word character". If there are no brackets, don't match them: use \w+
, i.e. "one or more word character".
You were matching the strings 1
and 0
with the regular expression \d[0-1]+.
, i.e. "one digit, and then one or more characters in the range 0-1". Unless the examples you gave weren't representative, [01]
would suffice ("match one character that is 0 or 1").
This matters, because regular expression matching is a wonderful tool for shooting your own foot to bloody tatters. If you use it, you need to be quite sure you aren't matching anything you shouldn't match, as well as sure that you're matching everything you should match.
This is of course assuming that what's in the strings matters at all. If you know you can build a valid accord
/create
/whatever line out of every given accent
line, skip regular expression matching and just use Donal Fellows' solution. If you still want to use switch
constructs, rip out your regexp
s and use code like
accent {
lassign $line -> a b c
chan puts $fo "accord \[get_nets $module/$c] \[get_pins $module/$a/$b]"
}
And yes, I know, I was the one who suggested REs in my earlier answer: it seemed they were called for, but now that I see you struggling with them I'm beginning to think I did you a major disservice. (I don't usually recommend REs unless I think they're absolutely necessary: validating data is one such application.)
Oh, and if you want a literal $
in your output, you need to escape it as \$
. Otherwise the Tcl interpreter tries to replace the $
and the following substring with the value of a variable named like the substring.
Upvotes: 0
Reputation: 137787
The easiest way to do this is with some procedures and then to just evaluate the input file as a Tcl script, which it looks like it already is. You define those with the proc
command. Also remember that global variables need to be explicitly brought into scope with the global
command in procedures; variables are local by default.
# Initialise the state
set moduleName c1
proc module {name} {
global module
set module $name
}
# No regexp to parse this! No need.
proc accent {a b c} {
global fo module
chan puts $fo "accord \[get_nets $module/$c] \[get_pins $module/$a/$b]"
}
Be aware, if you're generating Tcl commands there for later evaluation (it looks like it!) then the get_nets
calls that you are creating will be “surprising” because c1/f[1]
(for example) will attempt to call a command 1
and substitute its result in the resulting word when evaluating it. That's usually an error. If that's what is going on, you need a little more care when doing the building of the output. The list
command is perfect for this sort of work:
proc accent {a b c} {
global fo module
# Generate the calls we want to do, without any brackets around it
set nets_call [list get_nets $module/$c]
set pins_call [list get_pins $module/$a/$b]
# I like to put \] instead of ] in these situations, even if it isn't necessary here
chan puts $fo "accord \[$nets_call\] \[$pins_call\]"
}
In your examples, this will actually generate:
accord [get_nets {c1/f[1]}] [get_pins c1/a1/Z]
accord [get_nets {c1/f[2]}] [get_pins c1/a2/C]
accord [get_nets {c2/f[3]}] [get_pins c2/a3/Z]
accord [get_nets {c2/f[4]}] [get_pins c2/a4/C]
Upvotes: 1