Awk на самом деле имеет ассоциативных массивов, поэтому я бы выбрал следующий подход:
Для каждого #ifdef
(или эквивалент, такой как #if 1
),увеличить переменную, затем использовать ее для хранения номера строки if
, задав для номеров строки else
и endif
значение -1.
Для строки #else
используйтетекущая переменная для установки номера строки else
.
Для #endif
выведите все данные, которые у вас есть для номеров строк, затем уменьшите значение переменной.
Для #elif
необходимо объединить действия #else
и #if
и убедиться, что соответствующие #end
закрывают все строки #if/#elif
.
Например, вот автономный скрипт bash
, показывающий, как он может работать:
#!/usr/bin/env bash
# Use this script as input file as well, luckily C preprocessor
# macros look like bash comments.
#ifdef XYZZY
# Some text inside the first ifdef
#if 0
# This is the inner bit.
#endif
#if 1
# blah blah blah
#elif defined TWISTY
# yada yada yada
#elif defined PASSAGES
# run out of phrases
#else
# still got nothing
#endif
#else
#ifdef PLUGH
# This is the plugh stuff
#else
# This is the anti-plugh stuff
#endif
#endif
awk <$0 '
$1 == "#ifdef" || $1 == "#if" {
level++
line_mac[level] = $0
gsub(/^[ \t]+/, "", line_mac[level])
line_if[level] = NR
line_else[level] = "X"
line_end[level] = "X"
typ_elif[level] = 0
next
}
$1 == "#elif" {
line_else[level] = NR
level++
line_mac[level] = $0
gsub(/^[ \t]+/, "", line_mac[level])
line_if[level] = NR
line_else[level] = "X"
line_end[level] = "X"
typ_elif[level] = 1
next
}
$1 == "#else" {
line_else[level] = NR
next
}
$1 == "#endif" {
while (typ_elif[level] == 1) {
printf "if-line %-4s, else-line %-4s, endif-line %-4s, macro '%s'\n", line_if[level], line_else[level], NR, line_mac[level]
level--
}
printf "if-line %-4s, else-line %-4s, endif-line %-4s, macro '%s'\n", line_if[level], line_else[level], NR, line_mac[level]
level--
}
'
Вывод этого (с пронумерованными строками из файла для проверки)это:
1: #!/usr/bin/env bash
2:
3: # Use this script as input file as well, luckily C preprocessor
4: # macros look like bash comments.
5:
6: #ifdef XYZZY
7: # Some text inside the first ifdef
8: #if 0
9: # This is the inner bit.
10: #endif
11: #if 1
12: # blah blah blah
13: #elif defined TWISTY
14: # yada yada yada
15: #elif defined PASSAGES
16: # run out of phrases
17: #else
18: # still got nothing
19: #endif
20: #else
21: #ifdef PLUGH
22: # This is the plugh stuff
23: #else
24: # This is the anti-plugh stuff
25: #endif
26: #endif
if-line 8 , else-line X , endif-line 10 , macro #if 0
if-line 15 , else-line 17 , endif-line 19 , macro #elif defined PASSAGES
if-line 13 , else-line 15 , endif-line 19 , macro #elif defined TWISTY
if-line 11 , else-line 13 , endif-line 19 , macro #if 1
if-line 21 , else-line 23 , endif-line 25 , macro #ifdef PLUGH
if-line 6 , else-line 20 , endif-line 26 , macro #ifdef XYZZY