ANTLR4 - Заменить ошибки границ операций - PullRequest
0 голосов
/ 23 мая 2018

Здравствуйте, создатели / пользователи ANTLR,

Некоторый контекст - я использую синтаксический анализатор PlSql ANTLR4 для упрощенной передачи некоторых запросов из oracle sql в, скажем, spark sql.У меня есть настройка класса слушателя, которая расширяет базовый слушатель.

Пример проблемы - скажем, что-то вроде ввода -

SELECT to_char(to_number(substr(ATTRIBUTE_VALUE,1,4))-3)||'0101') from xyz;

Теперь я хотел бы заменить ||с CONCAT и to_char с CAST в качестве STRING, так что окончательный запрос выглядит следующим образом -

SELECT CONCAT(CAST(to_number(substr(ATTRIBUTE_VALUE,1,4))-3) as STRING),'0101') from xyz;

В моем классе слушателя я переопределяю две функции из базового слушателя, чтобы сделать это - конкатенация и string_function.В них я использую замену tokenStreamRewriter для выполнения необходимых преобразований.Поскольку tokenStreamRewriter оценивается лениво, я работаю над выдачей ->

java.lang.IllegalArgumentException: replace op boundaries of 
<ReplaceOp@[@38,228:234='to_char',<2193>,3:15]..[@53,276:276=')', 
<2214>,3:63]:"CAST (to_number(substr(ATTRIBUTE_VALUE,1,4))-3 as STRING)"> 
overlap with previous <ReplaceOp@[@38,228:234='to_char',<2193>,3:15].. 
[@56,279:284=''0101'',<2209>,3:66]:"CONCAT 
(to_char(to_number(substr(ATTRIBUTE_VALUE,1,4))-3),'0101')">

Очевидно, проблема в том, что две мои функции прослушивателя пытаются заменить / преобразовать текст на перекрывающихся границах.

Есть ли какие-либообойти для перекрытия территории вид вопросов для ANTLR4?Я уверен, что люди сталкиваются с такими вещами, вероятно, все время.

Я был бы признателен за любые обходные пути, даже грязные на данный момент :)

Я понял, что ANTLR4 не делаетПозвольте нам изменить исходный AST, иначе это было бы немного проще решить.

Спасибо!

1 Ответ

0 голосов
/ 23 октября 2018

Взгляд на то, как работает tokenstreamrewriter, приводит к следующему пониманию:

  • сначала создается список всех операций модификации
  • , затем вы вызываете getText ()
  • здесь происходит сокращение операций модификации.Идея, например, состоит в том, чтобы объединить несколько вставок вместе в одном сокращении.Его роль также состоит в том, чтобы избежать многократной замены одних и тех же данных (но об этом я расскажу позже).
  • Затем читается каждый токен, в случае если для указанного индекса токена есть изменения, TokenStreamRewriter делаетоперация, в противном случае она просто извлекает токен чтения.

Давайте посмотрим, как реализованы операции модификации:

  • для вставки, программа переписывания токенов в основном просто добавляет строкучтобы добавить его к текущему индексу токена, а затем выполнить индекс + 1, фактически перейдя к следующему токену
  • для замены, перезаписывающий токен заменяет диапазон токенов новой строкой и задает новый индекс равнымконец этого диапазона.

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

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

Итак, вы пытаетесь сделать следующее (для каждого шага часть между '*' является изменяемой):

*SELECT to_char(to_number(substr(ATTRIBUTE_VALUE,1,4))-3)||'0101')* from xyz;
|
V
CONCAT (*to_char(to_number(substr(ATTRIBUTE_VALUE,1,4))-3)*,'0101') from xyz;
|
V
SELECT CONCAT(CAST(to_number(substr(ATTRIBUTE_VALUE,1,4))-3) as STRING),'0101') from xyz;

чтобы добиться трансформации, вы можете сделать замену:

  • 'to_char' -> 'CONCAT (CAST'
  • '||' -> 'как STRING), '

И, используя немного интеллекта при разборе ваших токенов, можно сказать, что есть' || 'в моих токенах, чтобы знать, если это строка, вы бы знали, что заменить.

regards

...