Encontre strings que começam com #define e terminam com \

2

Estou tentando realizar a otimização da definição de macros no meu código em C. Para o mesmo, preciso extrair todas as macros presentes nos arquivos C e preciso descobrir quantas vezes essa definição de macro específica está presente.

O formato das minhas definições de macro é de tal forma que

#define MACRO_NAME DEFN_LINE1\
DEFN_LINE2\
DEFN_LINE3

Então eu pensei que minha lógica seria para

  1. use expressão regular para encontrar a lista de linhas que começa com "#define" e termina com "\" redireciona a saída acima para um arquivo, como diz MacroLineExtract.txt
  2. remover todos os "#define" de MacroLineExtract.txt == > MACRO_NAME DEFN_LINE1 \
  3. remova as strings finais após o espaço === > MACRO_NAME
  4. salve a saída acima no arquivo Macros.txt, que agora conterá apenas a lista de MACROS presentes no meu código
  5. Escreva um script bash para obter uma linha após a outra do Macros.txt e descubra quantas vezes MACRO_NAME apareceu no meu código.

Você pode por favor me ajudar a escrever um regex / awk para encontrar todas as macros em meus arquivos c que começam com "#define" e terminam com "\". Se você tem uma lógica melhor, por favor, sugira o mesmo.

    
por Sakthi Kumar Chandrabose 04.05.2017 / 17:01

5 respostas

2

Usando ctags exuberantes :

$ ectags --c-kinds=d *.[ch]

ectags é uma versão aprimorada de ctags e etags usada para criar um "arquivo de tags" que pode ser usado por editores como Vi / Vim ou Emacs para facilitar a navegação do código-fonte. Ele conhece as regras de gramática C, então é capaz de analisar o código C para você (para que você não precise se preocupar com expressões regulares).

Com --c-kinds=d informamos que ectags só se preocupa com #define linhas no código C.

Agora você tem um arquivo chamado tags no diretório atual com o seguinte tipo de conteúdo:

DEVELOPER       bayes.h 225;"   d
DIFFERENT       bayes.h 227;"   d
DIR_MIN bayes.h 338;"   d
DNA     bayes.h 242;"   d
DOLLAR  bayes.h 309;"   d
DOLLO   bayes.h 276;"   d
DOWN    bayes.h 215;"   d

Ou seja, cada linha (exceto algumas linhas de cabeçalho) identifica o nome de uma macro, o arquivo de origem em que foi encontrado e o número da linha. Se uma macro for definida em vários arquivos, ela será listada uma vez para cada ocorrência. O último d é um indicador de tipo de tags (todos são #define s).

Se você quiser apenas a contagem de quantas vezes cada macro foi definida:

$ cut -f 1 tags | uniq -c
    
por 04.05.2017 / 19:50
1

awk pode fazer a análise e contando em uma única operação, supondo que você possa passar todos os nomes de arquivos desejados sem exceder ARG_MAX:

awk '$1=="#define"&&/\$/ {n[$2]++} END {for(i in n) print n[i],i}' *.[ch]

# this includes #define's that are indented with whitespace,
# which the C language allows. If you really want only #defines 
# that start exactly in column 1, use /^#define /&&/\$/ 

# if you want the columns to line up change the print to something like
#   printf "%6d %s\n",x[i],i
    
por 04.05.2017 / 21:39
0

Se as linhas estiverem como estas no seu arquivo:

#define MACRO_NAME DEFN_LINE1 \

então, isso receberá os valores exclusivos de MACRO_NAME:

cat yourCfile | grep '#define' | awk '{print $2}' | sort -u > macro_names

O grep está recebendo as linhas contendo '#define'

o awk trata cada string em uma linha como um novo campo, usando espaço / espaços como o separador de campo padrão. Então, aqui, usamos apenas o awk para imprimir o segundo campo em "#define MACRO_NAME DEFN_LINE1", que é "MACRO_NAME".

classifique -u > O macro_names apenas remove quaisquer duplicados e envia tudo para um arquivo.

e para percorrer sua lista de nomes de macro e descobrir quantas linhas contêm esse nome de macro:

for macro in $(cat macro_names); do
count=$(cat yourCfile | grep $macro | wc -l);
echo $macro appears $count times
done

o comando "wc" com o sinalizador "-l" imprime o número de linhas que recebe do stdin.

    
por 04.05.2017 / 19:28
0

Muito obrigado às pessoas. Eu usei as soluções fornecidas por você para criar minhas necessidades. :)

awk '/#define.*\/$/{cnt[$2]++}END{for(i in cnt)print i}' > macro_names

#!/usr/local/bin/bash -x
TotalCount=0
CurrFileTotalCount=0
#takes One $macro after other from macro_names.txt file
for macro in $(cat macro_names); 
do
    #Takes $files from the current path in a recursive manner 
    #<$(find . -type f -name "*.c" -o -name "*.h")
    for files in $(find . -type f -name "*.c" -o -name "*.h")
    do
        #Counts the number of times $macro is present in $files
         CurrFileTotalCount=$(grep -c $macro "${files}");
         #Adds the Current file count to $TotalCount
         TotalCount=$(($TotalCount+$CurrFileTotalCount));
         #print the $CurrFileTotalCount and $TotalCount PROPERLY
    done 
    #Expected to print how many times that $macro is present in the files -- BUT PRINTS $TotalCount AS 0
    echo $macro appears_3 TotalCount $TotalCount
    TotalCount=0;
done
    
por 08.05.2017 / 16:04
-2
sed '/#define/,\
        /^\(.*[^\]\)*$/N
        /\n\/P;D'
    
por 08.05.2017 / 17:13