tcl script to filter the data lines consist of keyword with maximum index - tcl

I am trying to fetch keyword with Maximum index number.
In the below code puts $line getting few data i.e
pin ("DCC_SEL[0]") {
pin ("DCC_SEL[1]") {
pin ("DCC_SEL[2]") {
pin ("DCC_SEL[3]") {
pin ("DCC_SEL[4]") {
pin ("DCC_SEL[5]") {
pin ("DCC_SEL[6]") {
pin ("NDE_DLY_SEL[0]") {
pin ("NDE_DLY_SEL[1]") {
pin ("NDE_DLY_SEL[2]") {
pin ("NDE_DLY_SEL[3]") {
pin ("NDE_DLY_SEL[4]") {
pin ("NDE_DLY_SEL[5]") {
pin ("NDE_DLY_SEL[6]") {
pin ("NDE_DLY_SEL[7]") {
pin ("NDE_DLY_SEL[8]") {
pin ("PCLK_PH_SEL[0]") {
pin ("PCLK_PH_SEL[1]") {
pin ("PCLK_PH_SEL[2]") {
pin ("PCLK_PH_SEL[3]") {
pin ("PI_SEL[0]") {
pin ("PI_SEL[1]") {
pin ("PI_SEL[2]") {
pin ("PI_SEL[3]") {
pin ("PI_SEL[4]") {
pin ("PI_SEL[5]") {
pin ("PI_SEL[6]") {
pin ("PI_SEL[7]") {
pin ("PI_SEL[8]") {
pin ("PI_SEL[9]") {
pin ("SCLK_DLY_SEL[0]") {
pin ("SCLK_DLY_SEL[1]") {
pin ("SCLK_DLY_SEL[2]") {
pin ("SCLK_DLY_SEL[3]") {
pin ("SCLK_DLY_SEL[4]") {
pin ("SCLK_DLY_SEL[5]") {
pin ("SPARE[0]") {
pin ("SPARE[1]") {
pin ("SPARE[2]") {
pin ("SPARE[3]") {
when i tried to debug my code somewhere near regexp is not working,
proc parse_pins {filename} {
set filedata [open $filename "r"]
set file [read $filedata]
close $filedata
set pins {}
# create a dictionary to store the largest index seen for each pin name
set largest_indices {}
set regex {pin\s*\(\s*"(.*?)"\s*\)\s*\{\s*\[\s*(\d+)\s*\]\s*\}}
foreach line [split $file \n] {
if {[string match "*pin*]*" $line]} {
puts $line
if {[regexp $regex $line extracted_data pin_name index]} {
if {![info exists largest_indices($pin_name)] || $index > $largest_indices($pin_name)} {
# update the largest index for this pin name
set largest_indices($pin_name) $index
}
}
}
}
foreach pin_name [array names largest_indices] {
set index $largest_indices($pin_name)
set new_pin "pin (\"$pin_name\[$index]\")"
lappend pins $new_pin
}
puts [join $pins "\n"]
return $pins
}
set filename "rx_clkgen_tdl_ss_0.675v_m40c.lib"
set pins [parse_pins $filename]
puts $pins
where the expected output is at $pins is
pin ("DCC_SEL[6]") {
pin ("NDE_DLY_SEL[8]") {
pin ("PCLK_PH_SEL[3]") {
pin ("PI_SEL[9]") {
pin ("SCLK_DLY_SEL[5]") {
pin ("SPARE[3]") {
can anyone debug my code and let me know the changes.

I modified the regexp command to capture only the index, and then used string match and string map commands to extract the pin name from the line and remove any unwanted characters. I also changed the string match command in the foreach loop to match lines that start with "pin (". Finally, I removed the extracted_data and pin_name variables from the regexp command, since they are not used.
proc parse_pins {filename} {
set filedata [open $filename "r"]
set file [read $filedata]
close $filedata
set pins {}
# create a dictionary to store the largest index seen for each pin name
set largest_indices {}
set regex {pin\s*\(\s*"\S+"\s*\)\s*\{\s*\[\s*(\d+)\s*\]\s*\}}
foreach line [split $file \n] {
if {[string match "pin (*" $line]} {
puts $line
if {[regexp $regex $line extracted_data index]} {
set pin_name [string match {pin (*"*) $line]
set pin_name [string map {{"} "" {[} "" {]} ""} $pin_name]
if {![info exists largest_indices($pin_name)] || $index > $largest_indices($pin_name)} {
# update the largest index for this pin name
set largest_indices($pin_name) $index
}
}
}
}
foreach pin_name [array names largest_indices] {
set index $largest_indices($pin_name)
set new_pin "pin (\"$pin_name\[$index]\")"
lappend pins $new_pin
}
puts [join $pins "\n"]
return $pins
}
set filename "rx_clkgen_tdl_ss_0.675v_m40c.lib"
set pins [parse_pins $filename]
puts $pins
Based on the input you provided, the expected output of the script would be:
pin ("DCC_SEL[6]")
pin ("NDE_DLY_SEL[8]")
pin ("PCLK_PH_SEL[3]")
pin ("PI_SEL[9]")
pin ("SCLK_DLY_SEL[5]")
pin ("SPARE[3]")

Related

How to break a single TCL list into multiple sublists and easily searchable?

I have single TCL list that is extracted from a text file.
{ First Name = John
Last Name = Doe
Country = USA
Hello;
World;
Hello;
World;
First Name = Dwayne
Last Name = Jhonson
Country = USA
DoYou;
Smellwhatthe;
RockisCooking;
First Name = Harry
Last Name = Potter
Country = UK
The;
BoyWHo;
Lived; }
I want to be able to have the user input the text file(list), First name,last name and country. The code needs to dump out the remaining information for further post processing.
The way I am thinking of coding it right now is with multiple FOR loops, but I am sure there is a more efficient way to do this. Any tips?
proc display_name_information {text_file first_name last_name country} {
set fid [open $text_file r]
set filecontent [read $fid]
set input_list [split $filecontent "\n"]
foreach elem $input_list{
set first_word [lindex $line 0]
set second_word [lindex $line 1]
set third_Word [lindex $line 2]
if {[expr {$first_word== "First"}] && [expr {$third_word== "$first_name"}]}
*Then similarly check last name and country*
*and then output everything until I reach the keyword "First Name" again*
This feels very inefficient for large files.
A generic method of processing a text file is using a state machine. In the following example, each time a text line matches the expected pattern, the state machine goes to the next state. In each state, you may do further processing, such as extracting data from the text line. Until all lines are done.
set state 0
set chn1 [open input_file r]
array set record [list]
while { [gets $chn1 s1] >= 0 } {
set s1 [string trim $s1]
switch -- $state {
0 - 3 {
if { [regexp {^First Name\s*=\s*(.*)$} $s1 match data] } {
set first_name $data
set state 1
} elseif { $state == 3 } {
append record($key) $s1 { }
}
}
1 {
if { [regexp {^Last Name\s*=\s*(.*)$} $s1 match data] } {
set last_name $data
set state 2
}
}
2 {
if { [regexp {^Country\s*=\s*(.*)$} $s1 match data] } {
set country $data
set key ${first_name},${last_name},${country}
set state 3
}
}
}
}
append record($key) $s1 { }
close $chn1
parray record
exit

Tcl code to fetch pin details and compare with another file pins

I have two files and I am comparing specific lines between two files using the def function. python and I am trying to write same code on tcl
The file data is given below
PIN i_hbmc_ieee1500_sel_wir
DIRECTION INPUT ;
USE SIGNAL ;
PORT
LAYER K3 ;
RECT 2090.163000 3265.856000 2090.476000 3265.920000 ;
END
END i_hbmc_ieee1500_sel_wir
PIN i_hbmc_ieee1500_cap_wr
DIRECTION INPUT ;
USE SIGNAL ;
PORT
LAYER K3 ;
RECT 2090.163000 3265.984000 2090.476000 3266.048000 ;
END
END i_hbmc_ieee1500_cap_wr
PIN i_hbmc_ieee1500_shft_wr
DIRECTION INPUT ;
USE SIGNAL ;
PORT
LAYER K3 ;
RECT 2090.163000 3265.728000 2090.476000 3265.792000 ;
END
END i_hbmc_ieee1500_shft_wr
The python code to fetch pin details of both files and compare between files
def readPinFile(filename):
result = None
with open(filename, "r") as file:
result = {}
lastPin = None
for line in file:
lines = line.strip()
if lines[:3] == "PIN":
lastPin = lines.split(" ")[1]
result[lastPin] = {"LAYER": None, "RECT": None}
if lines[:5] == "LAYER":
result[lastPin]["LAYER"] = lines.split(" ")[1]
if lines[:4] == "RECT":
result[lastPin]["RECT"] = lines.split(" ")
return result
pin_of_file1 = readPinFile("osi_hbmp_top_briscm_1.lef") #lef file1
pin_of_file2 = readPinFile("osi_hbmp_top_briscm_2.lef")#lef file2
with open("file04.txt", "r+") as output_file4: #compare same pins with layer and location
for pin, pin_data in pin_of_file1.items():
if pin in pin_of_file2:
if pin_of_file2[pin]["LAYER"] == pin_data["LAYER"] and pin_of_file2[pin]["RECT"] == pin_data["RECT"]:
output_file4.write(pin + "\n\n")
The TCL code I tried to get the same output
proc fileinput {filename} {
set filedata [open filename r]
set file1 [ read $filedata ]
foreach line [split $file1 \n] {
set pindata { PIN { LAYER {} RECT {} }}
if {[string match *PIN* $line]} {
dict lappend pindata PIN $line
}
if {[string match *LAYER* $line]} {
dict lappend pindata PIN {LAYER{$line}}
}
if {[string match *RECT* $line]} {
dict lappend pindata PIN {RECT{$line}}
}
}
return $pindata
}
set fileinput1 [fileinput osi_hbmp_top_briscm_1.txt]
set fileinput2 [fileinput osi_hbmp_top_briscm_2.txt]
In tcl I am trying to write comparing between the pins section (last 4-5 lines on python code), but I am stuck in the middle. I am fully confused to continue this code. can anyone help me to complete this code(mainly last 2 lines of python code)
foreach $pin, $pin_data [gets $fileinput1]
if{[string match $pin $fileinput2]}
This is the code I tried
Your code is using a proc called fileinput but you didn't include the proc definition. It actually looks like you are including the body of the proc, you didn't include the proc command at the beginning.
I will assume you want to do this (I also changed how the pindata dictionary is set)
proc fileinput {filename} {
set filedata [open $filename r]
set file1 [ read $filedata ]
close $filedata
set pindata [dict create]
foreach line [split $file1 \n] {
if {[string match "PIN*" $line]} {
set pin [lindex $line 1]
}
if {[string match "LAYER*" $line]} {
set layer [lindex $line 1]
dict lappend pindata $pin layer $layer
}
if {[string match "RECT*" $line]} {
set rect [lrange $line 1 4]
dict lappend pindata $pin rect $rect
}
}
return $pindata
}
Now the proc returns a dictionary with a top key set to the pin name and nested keys called "layer" and "rect".
To compare the pin layer of two different files:
# Parse each file and return a dict
set pin_data1 [fileinput osi_hbmp_top_briscm_1.txt]
set pin_data2 [fileinput osi_hbmp_top_briscm_2.txt]
# Iterate over the keys and compare layers:
foreach pin_name [dict keys $pin_data1] {
set layer1 [dict get $pin_data1 $pin_name layer]
# Check that the pin_name is in the second file
if {![dict exists $pin_data2 $pin_name]} {
puts "$pin_name exists in pin_data1 but not pin_data2"
continue
}
# If we get this far, then $pin_name appears in both files.
set layer2 [dict get $pin_data2 $pin_name layer]
if {$layer1 ne $layer2} {
puts "Layer mismatch for $pin_name:"
puts " 1: $layer1"
puts " 2: $layer2"
}
}
By the way, your example input file is incomplete. There is an END for a pin name that was never declared earlier.

How to access .txt file using tcl PROC function

I have two files and I am comparing specific lines between two files using the def function.
def readPinFile(filename):
result = None
with open(filename, "r") as file:
result = {}
lastPin = None
for line in file:
lines = line.strip()
if lines[:3] == "PIN":
lastPin = lines.split(" ")[1]
result[lastPin] = {"LAYER": None, "RECT": None}
if lines[:5] == "LAYER":
result[lastPin]["LAYER"] = lines.split(" ")[1]
if lines[:4] == "RECT":
result[lastPin]["RECT"] = lines.split(" ")
return result
pin_of_file1 = readPinFile("osi_hbmp_top_briscm_1.lef") #lef file1
pin_of_file2 = readPinFile("osi_hbmp_top_briscm_2.lef")#lef file2
comparing between pins
with open("file04.txt", "r+") as output_file4: #compare same pins with layer and location
for pin, pin_data in pin_of_file1.items():
if pin in pin_of_file2:
if pin_of_file2[pin]["LAYER"] == pin_data["LAYER"] and pin_of_file2[pin]["RECT"] == pin_data["RECT"]:
output_file4.write(pin + "\n\n")
The TCL code I tried to get the same output
proc fileinput {filename} {
set filedata [open filename r]
set file1 [ read $filedata ]
foreach line [split $file1 \n] {
set pindata { PIN { LAYER {} RECT {} }}
if {[string match *PIN* $line]} {
dict lappend pindata PIN $line
}
if {[string match *LAYER* $line]} {
dict lappend pindata PIN {LAYER{$line}}
}
if {[string match *RECT* $line]} {
dict lappend pindata PIN {RECT{$line}}
}
}
return $pindata
}
set fileinput1 [fileinput osi_hbmp_top_briscm_1.txt]
set fileinput2 [fileinput osi_hbmp_top_briscm_2.txt]
In tcl I am trying to write comparing between the pins section, but I am stuck in the middle. i am fully confused to continue this code
foreach $pin, $pin_data [gets $fileinput1]
if{[string match $pin $fileinput2]}
This is the code I tried
The error trace tells you the immediate problem:
couldn't open "filename": no such file or directory
while executing
"open filename r"
(procedure "fileinput" line 2)
You need to give the name of the file, not the name of the variable containing the file name. Tcl cares about whether things are uses or references/names a lot. You fix this by using:
set filedata [open $filename r]
in the procedure; the added $ is vital as it says "read from the variable and use its value here".

Tcl How to sort certain words in the text and take the last one

I have a text and contains
#AA_VERSION = Aa/10.10-d87_1
#AA_VERSION = Aa/10.10-d887_1
#AA_VERSION = Aa/10.10-d138_1
#AA_VERSION = Aa/10.10-d82_1
How can I sort all the #AA_VERSION = beginning and print the last one?
And if the text don't have the # beginning ,how to show space or don't have version.
Thanks for your kindly help !!
Assuming you've already got a list of the contents of the lines, what you need to do is iterate over that list and test whether the line in question matches your critera; if it does, you store that matched information in a variable. At the end of the loop, the variable will contain the last such info that was matched.
set version ""
set current ""
foreach line $lines {
if {[regexp {^(#?)AA_VERSION *= *(.+)} $line -> commented info]} {
if {$commented eq "#"} {
set version [string trim $info]
} else {
if {$current ne ""} {
puts stderr "WARNING: multiple current versions"
}
set current [string trim $info]
}
}
}
# All lines scanned; describe what we've found
if {$version eq ""} {
puts "no #AA_VERSION line"
} else {
puts "#AA_VERSION is $version"
}
if {$current eq ""} {
puts "no current AA_VERSION"
} else {
puts "current AA_VERSION is $current"
}
The classic way to get a list of all lines in a file is this procedure:
proc linesOf {filename} {
set f [open $filename]
set data [read $filename]
close $f
return [split $data "\n"]
}
set lines [linesOf "mydata.txt"]

File Read and Write in tcl

I saw some previous posts related to opening a file to perform read and write operations but I din't get an answer for my task. I want to append some results to a file (should create a new file if it does not exist).
However, if the file already has result then append should be skipped and move on to next search for next result. I wrote a script for this and I have problem in reading the file.
The script is something like this:
proc example {} {
set a [result1 result2 ... result n]
set op [open "sample_file" "a+"]
set file_content ""
while { ![eof $op] } {
gets $op line
lappend file_content $line
}
foreach result $a {
if {[lsearch $file_content $result] == -1} {
puts $op $result
}
}
close $op
}
Note: In this script I find variable "line" to be empty {""}. I guess I have trouble in reading the file. Please help me with this
What you forgot, is to seek to the beginning of the file before reading:
proc example {} {
set a {result1 result2 ... result n}; # <== curly braces, not square
set op [open "sample_file" "a+"]
set file_content ""
seek $op 0; # <== need to do this because of a+ mode
while { ![eof $op] } {
gets $op line
lappend file_content $line
}
foreach result $a {
if {[lsearch $file_content $result] == -1} {
puts $op $result
}
}
close $op
}
Update
You can simplify the reading (while loop and all), with one single read statement:
proc example {} {
set a {result1 result2 result3}
set op [open "sample_file" "a+"]
seek $op 0
set file_content [read $op]
foreach result $a {
if {[lsearch $file_content $result] == -1} {
puts $op $result
}
}
close $op
}
example