Действительно ли ANTLR подходит для этого проекта?
Я ищу для обработки и преобразования строки, введенной пользователем, которая может включать пользовательские функции. Например, пользователь может написать что-то вроде $ CAPITALIZE ("слово") в строке, и я хочу выполнить фактическое преобразование в фоновом режиме с помощью StringUtils.
Я бы предположил, что пользователи иногда будут писать вложенные функции, такие как:
$ RIGHT_PAD ($ ПРАВЫЙ ($ прописными буквами ( 'a123456789'), 6), 3, '0')
Где ожидаемый результат будет строковым значением "A12345000".
Я попытался использовать регулярное выражение для разделения функций отдельно, но после вложенности это было не так просто. Я решил, что могу попробовать написать свой собственный парсер, и во время исследования я наткнулся на статью, которая предложила использовать ANTLR.
Является ли это чем-то ANTLR правильным? Если да, есть ли подобные примеры, которые уже доступны для просмотра? Или кто-то будет достаточно любезен, чтобы дать мне пример того, как я могу записать это в ANTLR, чтобы у меня были обе пользовательские функции, которые можно обрабатывать индивидуально и вложенным образом.
Функции:
Основные примеры:
Вложенные примеры
Фактический пример: я имею в виду, например, что это то, что я ожидаю, что значение строки может выглядеть. Вы заметите, что есть переменные, написанные как $ {var}. Эти переменные будут заменены фактическими строковыми значениями, используя Apache Commons StringSubstitutor перед передачей String в ANTLR (если окажется, что я должен его использовать)
Начальная строка, написанная пользователем\HomeDir\Students\$ RIGHT ($ {graduation.year}, 2)\$ LEFT_PAD ($ LEFT ($ {state.id}, 6), 3, '0')
Строка после обработки StringSubstitutor\HomeDir\Students\$ RIGHT ('2020', 2)\$ LEFT_PAD ($ LEFT ('123456789', 6), 3, '0')
Строка после обработки ANTLR (И мой окончательный результат)
\HomeDir\Студенты\20\000123456
Кажется ли ANTLR чем-то, что я должен использовать для этого проекта, или что-то еще лучше подходит?
Да, ANTLR будет хорошим выбором. Имейте в виду, что ANTLR выполняет только синтаксический анализ для вас и предоставляет вам механизм для перемещения сгенерированного дерева синтаксического анализа. Вам нужно будет написать код для оценки выражений.
В вашем случае ваш лексер должен быть запущен, когда он наткнется на '$'
, нажав лексическое состояние как "in-a-function-mode". И когда он видит ')'
, один такой "in-a-function-mode" должен быть удален из лексического стека.
Читайте все о лексических режимах/стеках в вики-базе ANTLR: https://github.com/antlr/antlr4/blob/master/doc/lexer-rules.md
Вот быстрая демонстрация того, как это может работать для ANTLR4 (ANTLR3 не поддерживает лексические режимы):
lexer grammar TLexer;
TEXT
: ~[$]
;
FUNCTION_START
: '$' -> pushMode(IN_FUNCTION), skip
;
mode IN_FUNCTION;
FUNTION_NESTED : '$' -> pushMode(IN_FUNCTION), skip;
ID : [a-zA-Z_]+;
PAR_OPEN : '(';
PAR_CLOSE : ')' -> popMode;
NUMBER : [0-9]+;
STRING : '\'' ( ~'\'' | '\'\'' )* '\'';
COMMA : ',';
SPACE : [ \t\r\n]-> skip;
parser grammar TParser;
options {
tokenVocab=TLexer;
}
parse
: atom* EOF
;
atom
: text
| function
;
text
: TEXT+
;
function
: ID params
;
params
: PAR_OPEN ( param ( COMMA param )* )? PAR_CLOSE
;
param
: NUMBER
| STRING
| function
;
С плагином ANTLR4 от IntelliJ вы можете легко протестировать метод parse
из анализатора и foo $RIGHT_PAD($RIGHT($CAPITALIZE('a123456789'), 6), 3, '0') bar
ему следующий вход: foo $RIGHT_PAD($RIGHT($CAPITALIZE('a123456789'), 6), 3, '0') bar
, который будет генерировать следующий образ дерева разбора: