Как очистить комментарии и промежуточные пробелы в строке, содержащей объявление функции C? - PullRequest
0 голосов
/ 06 ноября 2011

В моей программе, написанной на C ++, мне нужно взять набор строк, каждая из которых содержит объявление функции C, и выполнить с ними ряд операций.

Одна из операций заключается всравните, равна ли одна функция другой.Для этого я планирую просто удалить комментарии и промежуточные пробелы, которые не влияют на семантику функции, а затем выполнить сравнение строк.Тем не менее, я хотел бы сохранить пробел в строке как удаление, которое изменило бы выходные данные, создаваемые функцией.

Я мог бы написать некоторый код, который перебирает строковые символы и входит в «строковый режим» всякий раз, когда кавычка (") встречаются и распознаются экранированные кавычки, но мне интересно, есть ли лучший способ сделать это.Идея состоит в том, чтобы использовать полноценный синтаксический анализатор C, запустить его над строкой функции, игнорировать все комментарии и лишние пробелы, а затем снова преобразовать AST в строку.Но, оглядываясь на какой-то синтаксический анализатор C, я чувствую, что большинство из них - сука, чтобы интегрироваться с моим исходным кодом (докажи, что я ошибаюсь).Возможно, я мог бы попытаться использовать yacc или что-то еще и использовать существующую грамматику C и сам реализовать синтаксический анализатор ...

Итак, есть какие-нибудь идеи о наилучшем способе сделать это?

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

Программа, которую я пишу, берет абстрактную модель и преобразует ее в C-код.Модель состоит из графа, где узлы могут содержать или не содержать сегменты кода C (точнее, определение функции C, где ее выполнение должно быть полностью детерминированным (то есть без глобального состояния) и операции с памятью не допускаются).Программа выполняет сопоставление с образцом на графе и объединяет и разделяет определенные узлы, которые придерживаются этих шаблонов.Однако эти операции могут выполняться только в том случае, если узлы демонстрируют одинаковую функциональность (то есть, если их определения функций C одинаковы).Эта «проверка того, что они одинаковы», будет выполнена путем простого сравнения строк, которые содержат объявления функции C.Если они посимвольно идентичны, то они равны.

Из-за характера генерации моделей, это вполне разумный метод сравнения при условии , что комментариии лишние пробелы удаляются, так как это единственный фактор, который может отличаться.Это проблема, с которой я сталкиваюсь - как сделать это с минимальными затратами на реализацию?

Ответы [ 3 ]

4 голосов
/ 06 ноября 2011

Что вы подразумеваете под сравните, равна ли одна функция другой ? Имея достаточно точное значение, эта проблема известна как неразрешимая !

Вы не сказали, что на самом деле делает ваша программа. Правильный синтаксический анализ всех реальных программ на Си не тривиален (поскольку синтаксис и семантика языка Си не так просты!).

Рассматривали ли вы использовать существующие инструменты или библиотеки, чтобы помочь вам? LLVM Clang - это возможность или расширение GCC через плагины, или даже лучше с расширениями, кодированными в MELT .

Но мы не сможем вам больше помочь без понимания вашей настоящей цели. А синтаксический анализ кода на C, вероятно, сложнее, чем вы себе представляете.

1 голос
/ 09 ноября 2011

Похоже, вы можете обойтись без простой грамматики острова, удаляя комментарии, строковые литералы и сворачивая пробелы (табуляции, '\ n'). Поскольку я работаю с AX & dagger; , я написал для вас быструю грамматику & Dagger; . Вы можете написать аналогичный набор правил, используя Boost.Spirit.

#include <axe.h>
#include <string>

template<class I>
std::string clean_text(I i1, I i2)
{
    // rules for non-recursive comments, and no line continuation
    auto endl = axe::r_lit('\n');
    auto c_comment = "/*" & axe::r_find(axe::r_lit("*/"));
    auto cpp_comment = "//" & axe::r_find(endl);
    auto comment = c_comment | cpp_comment;

    // rules for string literals
    auto esc_backslash = axe::r_lit("\\\\");
    auto esc_quote = axe::r_lit("\\\"");
    auto string_literal = '"' & *(*(axe::r_any() - esc_backslash - esc_quote) 
        & *(esc_backslash | esc_quote)) & '"';

    auto space = axe::r_any(" \t\n");
    auto dont_care = *(axe::r_any() - comment - string_literal - space);

    std::string result;
    // semantic actions
    // append everything matched
    auto append_all = axe::e_ref([&](I i1, I i2) { if(i1 != i2) result += std::string(i1, i2); });
    // append a single space
    auto append_space = axe::e_ref([&](I i1, I i2) { if(i1 != i2) result += ' '; });

    // island grammar for text
    auto text = *(dont_care >> append_all 
        & *comment
        & *string_literal >> append_all
        & *(space % comment) >> append_space)
        & axe::r_end();

    if(text(i1, i2).matched)
        return result;
    else
        throw "error";
}

Итак, теперь вы можете выполнить очистку текста:

std::string text; // this is your function
text = clean_text(text.begin(), text.end());

Вам также может понадобиться создать правила для лишних ';', пустых блоков {} и т. П. Вам также может понадобиться объединить строковые литералы. То, как далеко вы должны зайти, зависит от того, как были сгенерированы функции. В конечном итоге вы можете написать значительную часть грамматики Си.

& dagger; Библиотека AX скоро будет выпущена под ускоренной лицензией.
& Dagger; Я не проверял код.

0 голосов
/ 06 ноября 2011

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

Вы могли бы подумать о том, чтобы что-то делать наоборот :

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

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

(Подумайте, что многие генераторы парсеров, такие как ANTLR, YACC или Bison, основаны на схожей идее).

Я действительно сделал нечто очень похожее в MELT (читай, в частности, мою DSL2011 бумагу ). Вы можете найти несколько полезных советов по проектированию DSL с переводом на C.

...