Удаление строк из исходного кода C

Может ли кто-нибудь указать мне на программу, которая удаляет строки из исходного кода C? Пример

#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;
}

становится

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

Я ищу программу, очень похожую на stripcmt, только то, что я хочу разделить строки а не комментарии.

Причина, по которой я ищу уже разработанную программу, а не просто какое-то удобное регулярное выражение, заключается в том, что, когда вы начинаете рассматривать все угловые случаи (кавычки в строках, многострочные строки и т. Д.), Вещи обычно начинают быть (намного) более сложными, чем они впервые появляется. И есть ограничения на то, чего могут достичь RE, я подозреваю, что это невозможно для этой задачи. Если вы действительно считаете, что у вас чрезвычайно надежное регулярное выражение, не стесняйтесь отправлять, но, пожалуйста, никаких наивных sed 's/"[^"]*"//g' советов.

(Нет необходимости в специальной обработке (возможно, незавершенных) строк в комментариях, они будут удалены первыми)

Поддержка многострочных строк со встроенными символами новой строки не важна (не допустимо для C), но должны поддерживаться строки, охватывающие несколько строк, заканчивающихся символом \ в конце.

Это почти то же самое, что и некоторые другое questions, но я не нашел ссылок на какие-либо инструменты.


person hlovdal    schedule 18.08.2009    source источник
comment
Чисто для интереса, зачем вам такой инструмент? Другими словами, что вы собираетесь делать с результатами работы инструмента?   -  person    schedule 18.08.2009
comment
Это для поиска токенов. Например, в каких файлах вызываются функции x, y и z. Путем предварительной обработки, удаления комментариев и строк я получу точный результат. В настоящее время струны создают шум.   -  person hlovdal    schedule 18.08.2009
comment
Не лучше ли использовать инструмент анализа кода, который понимает C? Их очень много.   -  person    schedule 18.08.2009
comment
Я хочу использовать find + xargs вместе со сценарием проверки (без необходимости настройки), где этот сценарий проверки сначала удаляет комментарии и строки, прежде чем выполнять настоящую работу (что, например, может быть проверка того, что если файл вызывает printf, ‹ stdio.h ›должен быть включен).   -  person hlovdal    schedule 18.08.2009


Ответы (4)


Вы можете загрузить исходный код для StripCmt (. tar.gz - 5кБ). Он банально мал, и его не должно быть слишком сложно адаптировать к чередованию строк (он выпущен под лицензией GPL).

Вы также можете изучить правила официального лексического языка для строк C. Я нашел это очень быстро, но может и не быть окончательным. Он определяет строку как:

stringcon ::= "{ch}", where ch denotes any printable ASCII character (as specified by isprint()) other than " (double quotes) and the newline character.
person Mark Pim    schedule 18.08.2009
comment
Не думал проверять источник stripcmt. Доработать было несложно. - person hlovdal; 18.08.2009

Все токены в C (и большинстве других языков программирования) являются «обычными». То есть им можно сопоставить регулярное выражение.

Регулярное выражение для строк C:

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

Регулярное выражение не так уж сложно понять. В основном строковый литерал представляет собой пару двойных кавычек, окружающих кучу:

  • не специальные (без кавычек / обратной косой черты / новой строки) символы
  • escapes, which start with a backslash and then consist of one of:
    • a simple escape character
    • От 1 до 3 восьмеричных цифр
    • x и 1 или более шестнадцатеричных цифр

Это основано на разделах 6.1.4 и 6.1.3.4 спецификации C89 / C90. Если что-то еще закралось в C99, это не поймает этого, но это не должно быть сложно исправить.

Вот сценарий python для фильтрации исходного файла C, удаляющего строковые литералы:

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'))

РЕДАКТИРОВАТЬ:

После того, как я опубликовал вышеизложенное, мне пришло в голову, что, хотя это правда, что все токены C являются обычными, из-за того, что мы не токенизируем все, у нас есть возможность для неприятностей. В частности, если в другом токене появляется двойная кавычка, нас могут вести по садовой дорожке. Вы упомянули, что комментарии уже удалены, поэтому единственное, о чем нам действительно нужно беспокоиться, - это символьные литералы (хотя подход, который я собираюсь использовать, можно легко расширить для обработки комментариев). Вот более надежный сценарий, который обрабатывает символьные литералы:

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'))

По сути, мы находим токен строкового и символьного литерала, а затем оставляем только символьные литералы, но удаляем строковые литералы. Регулярное выражение символьного литерала очень похоже на строковое литерал.

person Laurence Gonsalves    schedule 18.08.2009
comment
В этом случае, думаю, будет лучше: ([^ \\\ n] | \\.) * - person hiena; 18.08.2009
comment
Регулярное выражение не может обрабатывать ‹< char * str = one \ ‹eol› two \ ‹eol› three \ n; ››, где ‹eol› указывает на наличие новой строки. Вот что я имел в виду под угловыми корпусами :) - person hlovdal; 18.08.2009
comment
Использование \ для соединения строк является частью предварительной обработки, и я игнорировал это. (например: что, если код - ‹< char * a = MACRO_THAT_EXPANDS_TO_STRING_LITERAL; ›› - что вы хотите делать тогда?) Если все, что вас волнует, это соединение строк, вы можете добавить \ n в класс символов abfnrtv и замените цикл for на sys.stdout.write (regex.sub (repl, sys.stdin.read ()). Вам также потребуется настроить chr_re, если вы беспокоитесь о соединении строк внутри символьных литералов . - person Laurence Gonsalves; 18.08.2009
comment
Другой вариант, в зависимости от того, для чего вы этого хотите, - сначала запустить весь код через препроцессор. - person Laurence Gonsalves; 18.08.2009

В рубине:

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

выводит на стандартный вывод

person hiena    schedule 18.08.2009

В Python с использованием pyparsing:

from pyparsing import dblQuotedString

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

Также выводится на стандартный вывод.

person PaulMcG    schedule 04.09.2009