Как стать автором
Обновить

Императивный RegExp. Нотация

Время на прочтение5 мин
Количество просмотров2.2K
Regular Expressions For All (REFA)

Основная идея


Существует множество систем для поиска подстрок отвечающих определенной маске. К сожалению они теряют свою мощь как только приходится учитывать многие факторы. Конструкции становятся громозкими, непонятными и трудноподдерживающими.
Именно для этого я попытался создать аналог – REFA. Регулярные выражения для всех.
Его идея в следующем. Как только регулярное выражение перестает быть очевидным – разбить его на два. Оптимизатор при возможности все равно сведет его в одно, таким образом в скорости потерь не будет, но зато код станет яснее.

Для удобного чтения ge.tt/9snPkzG/v/0 (формат \.odt)

Примеры


Поиск функций С++

Найти реализацию всех методов класса dummy.

Считается что на вход подается большая строка со всем кодом проекта. Можно сделать чтение из файла, но это затруднит понимание примера.
PROGRAM “FindMethods”
^name^ = ~\w?[\w|\d]*~
BLOCK “FindClass” // поиск декларации класса
PUSH
  BLOCKVAR $regexp = “class ”+%classname%+”\s*\{.*\}.*;”
  MATCH $regexp
  CATCH MATCH_FAIL
    RETURN array() AS $list;
    RETURN array() AS $result;
  FINISH
  BLOCKVAR $class_code = MATCHED
  INCOMING = $class_code
  BLOCKVAR $method = ^name^+~\w*~+^name^+~\([\^name\^\w*\^name\^\w*\,?]*\)\w*~
  BLOCKVAR $declarations = array();
  BLOCKVAR $realisations = array();
  TRY
    WHILE 1  
      MATCH PASS LIMIT 1 $method
      IF select(0,1) INCOMING != “;”
        CALL “SearchEndOfFunction” REMAINED
        $realisations ADD (MATCHED + RESULT $body)
      ELSE
        $declarations ADD MATCHED
      ENDIF
    END
  ON MATCH_FAIL OR END_OF_STRING
    RETURN $declarations AS $list
    RETURN $realisations AS $result
  FINISH  
POP
ENDBLOCK

BLOCK “SearchEndOfFunction”
  BLOCKVAR UINT $level = 0
  MATCH ~[\{|\}]~
  FOREACH ALL_MATCHED AS $t
    IF $t == “{}
      $level++;
    ELSE
      $level--;
    ENDIF
    IF $level == 0
      BLOCKVAR STRING $ret = select(ALL_MATCHED[0], ALL_MATCHED[ITERATION]) INCOMING_BLOCK
      RETURN $ret AS $body
    ENDIF
  END
ENDBLOCK

BLOCK “AddClassName”
MATCH PASS LIMIT 1 ^name^+”\w*”
BLOCKVAR $ret = MATCHED
$ret += “[\^name\^\w*::\w*]*”+%classname%+”\w*::\w*”
$ret += REMAIN
RETURN $ret
ENDBLOCK

BLOCK “SearchDeclaredFunctions”
BLOCKVAR $dec = %declared%
IMPLODE ($dec, “|”) $string
$string = “[“+$string+”]”
MATCH $string
BLOCVAR $realistaions = array()
FOREACH ALL_TILES as $tile
  IF ITERATION % 2 == 1
      IF select(0,1) INCOMING != “;”
        CALL “SearchEndOfFunction” ALL_TILES[ITERATION + 1]
        $realisations ADD (ALL_TILES[ITERATION] + RESULT $body)
      ENDIF
  ENDIF
END
RETURN $realisations AS $result
ENDBLOCK

// код программы
BLOCKVAR $classname = $arg1
CALL “FindClass”
BLOCKVAR $ret = RESULT $result
BLOCKVAR $declared = RESULT $list
CALL “SearchDeclaredFunctions”
$ret ADD RESULT $result
RETURN $ret
ENDPROGRAM


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

Документация


Типы данных

INT

Тип по умолчанию. Целочисленный. Диапазон −2^31 до +2^31-1. Значение по умолчанию 0.
LONG

Целочисленный. Диапазон −2^63 до +2^63-1. Значение по умолчанию 0
UINT

ULONG

STRING

Строка. Максимальная длина UINT. Приватные поля START и COUNT.
Значение по умолчанию не существует и вызывает исключительную ситуацию.
TILE

Часть строки. Приватные поля START, END, COUNT, PARENT_STRING.
Предопределенные переменные

INCOMING

Строка для обработки. Подставляется если никакая переменная не указана.
ICOMING это синоним INCOMING_CURRENT
  • INCOMING_PROGRAM – пришедшее в программу
  • INCOMING_BLOCK – пришедшее в блок
  • INCOMING_CURRENT – актуальная строка
  • INCOMING_LAST – до последнего изменения

MATCHED

Первое совпадение подошедшее в последнем match.
ALL_MATCHED

Массив со всеми совпадениями последнего выражения.
REMAINED

Первый символ после MATCHED
ALL_REMAINED

Первые символы после каждого в ALL_MATCHED
ALL_TILES

Все нечетные это ALL_MATCHED. Остальное – недостающие строки, в правильном порядке до строки.
ITERATION

Номер итерации в текущем цикле. Для получения номера итерации в внешнем – сохраняйте в отдельную переменную.
CALLSTACK

Стек вызовов с параметрами
QUERY_LOG

Лог команд, влиявших так или иначе на строки. Обязательно запоминать копирование строк(вдруг была последующая обработка). Входящие данные хранить в единственном экземпляре.
EXCEPTION_STRING

Строка обьясняющая суть ошибки. Место вознекновения, входящие параметры, результат.
Минимальный набор

Необходим для простейшего использования системы
Match

MATCH [IGNORE {ignore_count|FIRST}] [PASS] [LIMIT {limit_count}] reg_exp [processing_string]
Проверить reg_exp, сдвинуть START в processing_string в MATCHED (по умолчанию)
IGNORE – пропустить первые несколько совпадений. По умолчанию IGNORE 0
PASS – передвинуть START в последний ALL_REMAINED
LIMIT – максимальное количество совпадений, после которых подпрограмма оборвется. По умолчанию LIMIT 0, значит будет работать до конца файла.
reg_exp – может быть регулярное выражение заданное между ~, может быть переменной.
processing_string – строка для обработки. По умолчанию INCOMING
Echo

ECHO string
Вывод строки в результат.
Простейший пример замены регулярного выражения:
MATCH PASS ~some_regexp~
FOREACH ALL_TILES AS $tile
IF ITERATION % 2
// все совпавшие кусочки заменим на строку
ECHO “REPLACED”
ELSE
// все куски между совпавшими вернем в неизменном виде
ECHO $tile
ENDIF
END
IF ELSE ENDIF

IF expr then [ELSE else] ENDIF
Если выражение expr не равно нулю, то выполнится код then, иначе else
Расширенный набор

PROGRAM

Программа – атомарный набор исполняемых команд, выполняющих необходимую задачу. Только программы могут иметь параметры отличные от “по умолчанию”.
Вообще говоря это может быть отдельным процессом(или потоком) и выполняться параллельно. Нет никакой возможности обратиться из одной программы к другой. Но можно использовать(если они декларированны) методы соседней программы. Программы могут вызывать программы.
Программа является областью видимости для всех блоков.
По умолчанию все команды заключаются в программу с нулевым именем (ее нельзя вызвать из других программ)
PROGRAM name arg0 [arg1 arg2 … ] code ENDPROGRAM
name – имя программы
arg0 – строка для обработки. Становится INCOMING_PROGRAM
code – код программы, включая декларации.
Доступ к блокам кода осуществляется с помощью конструкции
program_name::block_name.
BLOCK

BLOCK name [string]
Несамостоятельный участок кода. Едентичен двум прыжкам goto. Если указан string – перед запуском происходит смена соответсвующих INCOMING, после возвращение.
PUSH POP

PUSH [var1 var2]
Сохранить состояние системных переменных. Также можно добавить для сохранения локальные переменные (перечислением), и явно исключить некоторые системные с помощью конструкции !var
POP – восстанавливает состояние к моменту до PUSH
BLOCKVAR

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

Служит для возвращения значения временных переменных из блока/программы.
RETURN name
Для доступа к переменной в вызывающей конструкции используется RESULT name
Значение валидно до вызова следующего блока.
Обработка ошибок

Во время исполнения скрипта возможны различные исключительные ситуации, которые не должны влиять на ход исполнения. Для этого существует система исключений.
exceptions: exception_name [OR exception_name … ]
CATCH FINISH

CATCH exceptions code [CATCH exceptions code …] FINISH
Необходим для отлова ошибки произошедшей на строке предыдущей к первому блоку CATCH.
Используется в ситуациях если исключительная ситуация в этом участке ожидаема и подлежит обработке.
TRY ON FINISH

TRY code ON exceptions code [ON exceptions code …] FINISH
THROW

THROW exception
Сгенерировать ошибку вручную
Виды ошибок

  • MATCH_FAIL – не удалось найти ни одного вхождения regexp
  • END_OF_STRING – конец достигнут до того как что то удалось найти(подразумевает под собой MATCH_FAIL)
  • WRONG_REGEXP – не удалось скомпилировать регулярное выражение
  • VARIABLE_OVERFLOW – переполнение переменной
  • UNSIGNED_NEGATIVE – внесение отрицательного значения в беззнаковое число
  • WRONG_STRING_INDEXES – попытка доступа к строке по индексам выходящим за границы строки
  • OUT_OF_ARRAY – попытка доступа к несуществующим элементам массива (вне)


Специальные конструкции

~regexp~

Содержимое – регулярное выражение
%name%

Во время исполнения подменится копией значения переменной $name. (ближайшей по стеку)
#name#

Аналог define
^name^

Ссылка на регулярное выражение. Работает внутри ~~ как \^
^hello^ = ~hel{2}o~
~\^hello\^ world~

Работа с строками

array{tile} SPLIT(delimeter) [string]
tile SELECT(start, end) [string]
PASS(count) [&string]
CUT(count) [&string]
CUT_AFTER(index) [&string]
IMPLODE (array[, delimeter]) &string
Теги:
Хабы:
Всего голосов 13: ↑6 и ↓7-1
Комментарии7

Публикации

Истории

Ближайшие события

15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань