Nisha John
Nisha John

Reputation: 25

Editing file in TCL and adding the revised contents to a file - 2

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

Answers (2)

Peter Lewerin
Peter Lewerin

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.


addition to answer follow-up question on 2015-08-03

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 regexps 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

Donal Fellows
Donal Fellows

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

Related Questions