Issue
I am writing a utility script to fix a Verilog code using sed
. What I'm trying to do is converting code as follows
input file
my_instance_name
(
.port1 (port1 )
.port2 (port2 ) // comment for port line 2
.port3 (port3 )
.port4 (port4 ) // comment for port line 4
);
What I want
my_instance_name
(
.port1 (port1 ),
.port2 (port2 ), // comment for port line 2
.port3 (port3 ),
.port4 (port4 ) // comment for port line 4
);
The points are
- Append comma just after the closing parenthesis of each 'port' lines
- Do not append comma for the last 'port'
- Preserve the comments if exist (comment starts with double-slash like C)
- Whitespaces (except the line breaks) are not important. it is only for human readability.
- There can be multiple linebreaks after the last port line
If the sed
script becomes too complicated, it is also OK to just prepend the comma just before the dot, except the first port line. i.e, the following code is OK although it is not pretty.
my_instance_name
(
.port1 (port1 )
,.port2 (port2 ) // comment for port line 2
,.port3 (port3 )
,.port4 (port4 ) // comment for port line 4
);
I could only manage appending commas to all 'port' lines via the following two line
sed -i /^\s*my_instance_name.*/,/);/{s/^\(\s*\..*)\)\(\s*\/\/.*\)/\1,\2/} my_verilog.txt
sed -i /^\s*my_instance_name.*/,/);/{s/^\(\s*\..*)\)\s*\$/\1,/} my_verilog.txt
It detects the code scope from "my_instance_name" to ");". The first line insert comma between the closing parenthesis and comment. The second line is for port lines without comments.
But I have no idea how to exclude the last line.
Solution
You may use this gnu-awk
solution using custom RS
to split shown block on header and footer:
awk -i inplace -v RS='my_instance_name\\s*\\(\\s*' '
NF {
$0 = gensub(/(\n\s*)([^)])/, "\\1,\\2", "g")
}
{ORS=RT} 1' file
cat file
my_instance_name
(
.port1 (port1 )
,.port2 (port2 ) // comment for port line 2
,.port3 (port3 )
,.port4 (port4 ) // comment for port line 4
);
Note that due to use of -i inplace
changes will be saved inline in same input file.
Breakdown:
-v RS='my_instance_name\\s*\\(\\s*'
splits input data bymy_instance_name
followed by 0 or more whitespaces then(
and again followed by 0 or more whitespaces.gensub
function matches newline followed by 0 or more whitespaces and captures in a group #1. It matches any character that's not)
(to avoid matching);
line) and captures in a group #2. In replacement we insert a comma between these 2 values.{ORS=RT}
populatesORS
same as the text matched byRS
pattern i.e.RT
1
prints all records
For appending commas in the end use similar awk:
awk -v RS='my_instance_name\\s*\\(\\s*' '
NF {
$0 = gensub(/\)([^\n]*\n[^)])/, "),\\1", "g")
}
{ORS=RT} 1' file
my_instance_name
(
.port1 (port1 ),
.port2 (port2 ), // comment for port line 2
.port3 (port3 ),
.port4 (port4 ) // comment for port line 4
);
Answered By - anubhava Answer Checked By - Clifford M. (WPSolving Volunteer)