Pergunta

Pode alguém me aponte para um programa que retira cordas de código-fonte C? Exemplo

#include <stdio.h>
static const char *place = "world";
char * multiline_str = "one \
two \
three\n";
int main(int argc, char *argv[])
{
        printf("Hello %s\n", place);
        printf("The previous line says \"Hello %s\"\n", place);
        return 0;
}

se torna

#include <stdio.h>
static const char *place = ;
char * multiline_str = ;
int main(int argc, char *argv[])
{
        printf(, place);
        printf(, place);
        return 0;
}

O que eu estou procurando é um programa muito parecido com stripcmt só isso que eu quero tira cordas e não de comentários.

A razão que eu estou procurando um programa já desenvolvido e não apenas alguns expressão regular calhar é porque quando você começar a considerar todos os casos de canto (aspas dentro cordas, multi-linha etc) coisas geralmente começam a ser (muito) mais complexa do que parece à primeira vista. E há limites para o que REs pode conseguir, eu suspeito que não é possível para esta tarefa. Se você acha que tem um extremamente robusta sensação expressão regular livre para enviar, mas por favor não sed 's/"[^"]*"//g' ingênuo como sugestões.

(Não há necessidade de um tratamento especial do (possivelmente cordas un-terminados) dentro de comentários, estes serão removidos primeiro)

O suporte para cordas de várias linhas com novas linhas incorporadas não é importante (não C legal), mas cordas distribuída em várias linhas que terminam com \ no final deve ser apoiado.

Isso é quase o mesmo que o alguns < a href = "https://stackoverflow.com/questions/676296/how-to-tokenize-parse-string-literals-from-javascript-source-code"> outro questions , mas eu não encontrei nenhuma referência a quaisquer ferramentas.

Foi útil?

Solução

Você pode baixar o href="http://www.bdc.cx/download/stripcmt/stripcmt-0.1.2.tar.gz" rel="nofollow noreferrer"> código fonte (.tar.gz - 5kB). É trivialmente pequeno, e não deve ser muito difícil de se adaptar a striping cordas em vez (é lançado sob a GPL ).

Você também pode querer investigar as normas linguísticas lexicais oficiais para strings C. Eu encontrei este muito rapidamente, mas não pode ser definitiva. Ele define uma string como:

stringcon ::= "{ch}", where ch denotes any printable ASCII character (as specified by isprint()) other than " (double quotes) and the newline character.

Outras dicas

Todos os tokens em C (e mais outras linguagens de programação) são "regular". Ou seja, eles podem ser combinados por uma expressão regular.

A expressão regular para strings C:

"([^"\\\n]|\\(['"?\\abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]+))*"

O regex não é muito difícil de entender. Basicamente, um literal de cadeia é um par de aspas duplas em torno de um monte de:

  • não-específicas (não orçamento / barra invertida / nova linha) caracteres
  • escapes, que começam com uma barra invertida e, em seguida, consistem em um dos seguintes:
    • um personagem simples fuga
    • 1 a 3 octal dígitos
    • x e 1 ou mais dígitos hexadecimais

Isto é baseado em seções 6.1.4 e 6.1.3.4 da especificação C89 / C90. Se qualquer outra coisa rastejou em no C99, isso não vai pegar isso, mas isso não deve ser difícil de corrigir.

Aqui está um script python para filtrar um arquivo de origem C removendo strings literais:

import re, sys
regex = re.compile(r'''"([^"\\\n]|\\(['"?\\abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]+))*"''')
for line in sys.stdin:
  print regex.sub('', line.rstrip('\n'))

EDIT:

Ocorreu-me depois que eu postei que precede que, embora seja verdade que todos os tokens C são regular, por não tokenizing tudo o que temos uma oportunidade para o problema. Em particular, se uma aspa aparece no que deveria ser outro sinal que pode ser chumbo pelo caminho do jardim. Você mencionou que os comentários já foram retirados, então a única outra coisa que realmente precisa se preocupar com são literais de caracteres (embora a abordagem Im indo para uso pode ser facilmente estendido aos comentários punho bem). Aqui está um script mais robusto que literais de caracteres identificadores:

import re, sys
str_re = r'''"([^"\\\n]|\\(['"?\\abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]+))*"'''
chr_re = r"""'([^'\\\n]|\\(['"?\\abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]+))'"""

regex = re.compile('|'.join([str_re, chr_re]))

def repl(m):
  m = m.group(0)
  if m.startswith("'"):
    return m
  else:
    return ''
for line in sys.stdin:
  print regex.sub(repl, line.rstrip('\n'))

Essencialmente nós estamos encontrando corda e caráter literal forma, e depois deixando literais de char sozinho, mas que eliminasse strings literais. A regex literal char é muito semelhante ao literal string.

Em Ruby:

#!/usr/bin/ruby
f=open(ARGV[0],"r")
s=f.read
puts(s.gsub(/"(\\(.|\n)|[^\\"\n])*"/,""))
f.close

imprime na saída padrão

Em Python utilizando pyparsing:

from pyparsing import dblQuotedString

source = open(filename).read()
dblQuotedString.setParseAction(lambda : "")
print dblQuotedString.transformString(source)

Também imprime na saída padrão.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top