Однажды я написал свою собственную версию Flex, которая генерировала набор классов вместо всей программы. Во-первых, мне пришлось разбирать регулярные выражения вручную, но когда я наконец его написал, я заменил механизм синтаксического анализа регулярных выражений на механизм, сгенерированный самой программой.
Анализировать регулярное выражение вручную на самом деле довольно просто. Во-первых, вы должны указать результат, которого хотите достичь. Например, в моем случае:
[abc]+test
Интерпретируется как:
[abc]@[abc]*@[t]@[e]@[s]@[t]
Что на самом деле эквивалентно (@ - это искусственно добавленный оператор конкатенации).
Затем вам нужно создать набор правил, например.
'[' spotted:
- (optionally) expect '^' character;
- repeat:
- expect a non-special character;
- If it is not last character and is succeeded by '-', expect another character
- until `]` is spotted
- Return a character set
'(' spotted:
- Return a block-begin
')' spotted:
- Return a block-end
'*' spotted:
- Return a star-operator
'+' spotted:
- Return a plus-operator
'.' spotted:
- Return a whole character set
Any other char spotted:
- Return a character set consisting of this single character
Написанный таким образом алгоритм даст вам токенизатор - процедуру, которая разбивает элементы на логические токены. Затем вам придется преобразовать их в дерево выражений, и это можно решить, реализовав алгоритм обратной польской записи < / а>.
Вы можете проверить мой генератор синтаксического анализатора здесь, хотя он генерирует код Delphi. К сожалению, файл readme на польском языке, но внутри есть несколько примеров. Попробуйте, например:
Number=[0-9]+
Operator=[\+\-\*/]
И
SpkParserGenerator -i myfile.regex -mc -sg
Кстати, вы можете сгенерировать парсер для себя, а затем просто перевести его с Delphi на C ++, на самом деле это довольно просто, даже если вы плохо знаете Delphi.
Это набор правил, которые я использовал для создания парсера для генератора парсеров:
SetRange=\{([0-9]*,[0-9]+)|([0-9]+,[0-9]*)|([0-9]+)\}
Star=\*
Plus=\+
QMark=\?
CharRange=\[\^?((\\.)|(\#[0-9]{3})|([^\\\#\]]))+\]
AnyChar=\.
EscapedChar=\\.
AsciiChar=\#[0-9]{3}
Char=[^\[\]\{\}\.\(\)\#\*\+\?\|\\]
OpenParenthesis=\(
CloseParenthesis=\)
Alternative=\|
person
Spook
schedule
18.03.2014
if
илиswitch
утверждений. - person Barmar   schedule 18.03.2014if
иswitch
, как это предлагает Бармар. :) - person freakish   schedule 18.03.2014