2014-12-22 1 views
7

В модерировании игры с закрытым исходным кодом я изменяю машинный код во время выполнения до jmp в свой собственный код. Чтобы сделать это в общем виде, я использую сопоставление шаблонов, чтобы найти коды, которые я хочу изменить. (Шаблоны состоят только из символов/байтов и подстановочных знаков, где байты могут меняться.) Путем построения детерминированного конечного автомата из всех моих шаблонов я могу искать в линейном времени.Может ли компилятор правильно вычислить DFA из регулярного выражения?

Однако я обнаружил, что для создания DFA требуется больше времени, чем при его запуске, особенно в отладочных сборках (что я, конечно, хочу, во время разработки), и это только ухудшится, когда я добавлю больше шаблонов. Но это легко можно было сделать в автономном режиме. Я сейчас думаю о том, как; может ли компилятор сделать это?

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

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

+5

Другое дело: вы можете создать DFA для регулярного выражения с помощью специального инструмента, который вы пишете и сериализуете его в некоторый двоичный файл. Затем во время выполнения вам просто нужно импортировать DFA вместо того, чтобы строить его с нуля. Он должен быть быстрее, чем просто строить DFA во время выполнения. – bialpio

+1

Я предполагаю, что я просто незнаю, но почему DFA, построенный во время компиляции, и зная, что его размер потребует распределения памяти? Конечно, каждая конструкция будет иметь другой тип, но это не должно быть проблемой. Я подозреваю, что глубина рекурсии является более вероятным ограничением (хотя я не пробовал создавать DFA во время компиляции). –

+4

Я не уверен, действительно ли он генерирует DFA или NFA, но [Boost Xpressive] (http: //www.boost.org/doc/libs/1_57_0/doc/html/xpressive.html) (только для одного примера), по крайней мере, преобразует регулярное выражение в * некоторый * вид FSM во время компиляции (а также ряд других аналогичных вещей) , –

ответ

2

Да, это возможно. Конструкцию можно выполнить с помощью одного из стандартных алгоритмов, таких как Thompson's construction algorithm, чтобы получить NFA, а затем построить DFA. Проблема в том, что при преобразовании NFA в DFA возможно экспоненциальное раздутие числа состояний.

Как справиться с необходимой глубиной рекурсии обсуждается в answers to this question.

Возможно реализовать алгоритм с использованием метапрограммирования шаблонов. Список основных строительных блоков можно найти here, что позволяет хранить значения, реализовывать ветви и функции.

Ниже приведен пример для функции от linked page:

template<int X, int Y> 
struct Adder 
{ 
    enum { result = X + Y }; 
}; 

Это функция, которая добавляет свои два параметра и сохраняет результат в элементе результата перечисления. Вы можете назвать это во время компиляции с чем-то вроде Adder < 1, 2> :: result, который будет расширен при компиляции и действовать точно так же, как буква 3 в вашей программе.

Поскольку алгоритм Томпсона основан на рекурсии, здесь пример для оценки рекурсии:

template <unsigned n> 
struct factorial 
{ 
    enum { value = n * factorial<n-1>::value }; 
}; 

Это реализует факториал во время компиляции. Это можно было бы использовать во время выполнения, например, factorial<5>::value.

+0

Я просто не понимаю, как бы я представлял и вычислял произвольно большой набор состояний, указывающих друг на друга в TMP. Но я, вероятно, не собираюсь делать это с помощью TMP, вместо этого кэшируя результат онлайн-вычисления в файле, это намного проще. –