ANTLR4: Как разобрать строку многоугольника WKT?

Я использую ANLTR4 в Java, и я мог бы разобрать строку многоугольника WKT, как это

polygon((20 30, 30 40, 50 60, 20 30)) 

с этим лексером:

POLYGON: ('polygon'|'POLYGON')'(('[0-9:,-.eTZ" ]+'))';

поскольку числа внутри многоугольника (()) могут быть datetime или float, то он содержит несколько символов.

Тем не менее, я не мог разобрать многоугольник с внутренним многоугольником, как это

polygon((20 30, 30 40, 50 60, 20 30), (20 30, 30 40, 50 60, 20 30), (20 30, 30 40, 50 60, 20 30))

когда я пытался добавить () в Lexer, например:

POLYGON: ('polygon'|'POLYGON')'(('[0-9:,-.eTZ" \(\)]+'))';

Java выдает исключение, не может найти ")" с.

Что я могу сделать, чтобы ANTLR4 мог анализировать полигон ((), (), (), ...)?

2 ответа

Решение

Лексер должен определять только основные строительные блоки языка. Полигон, список и т. Д. Должны быть определены как правила синтаксического анализа.

Примерно так должно начаться:

grammar WKT;

parse
 : polygon EOF
 ;

polygon
 : POLYGON '(' ( points ( ',' points )* )? ')'
 ;

points
 : '(' ( value value ( ',' value value )* )? ')'
 ;

value
 : INT
 | FLOAT
 | DATE_TIME
 ;

POLYGON
 : [pP] [oO] [lL] [yY] [gG] [oO] [nN]
 ;

INT
 : DIGITS
 ;

FLOAT
 : DIGITS '.' DIGITS
 ;

DATE_TIME
 : D D D D '-' D D '-' D D 'T' D D ':' D D ':' D D [+-] D D ':' D D
 | D D D D '-' D D '-' D D 'T' D D ':' D D ':' D D 'Z'
 | D D D D D D D D 'T' D D D D D D 'Z'
 ;

SPACES
 : [ \t\r\n]+ -> skip
 ;

fragment DIGITS
 : D+
 ;

fragment D
 : [0-9]
 ;

Следующий вход: POLYGON ((35 10, 45 45, 15 40, 10 20, 35 10), (20 30, 35 35, 30 20, 20 30)) будет проанализирован следующим образом:

Я думаю, что вы не должны делать это только с лексером. Вы должны использовать свой лексер, чтобы разделить на символы; например 'polygon', '(', ')', ',', <number>, <date> и так далее. Затем реализуйте грамматику, чтобы иметь дело с синтаксисом большого масштаба; например

<polygon> ::= 'polygon' '(' <list> ')'

<list> ::= '(' ')' |
           '(' <element> ( ',' <element> ) * ')'

<element> ::= <number> | <date>

(Я использую метасинтаксис вроде EBNF ....)

Проблемы с использованием только основанного на регулярных выражениях лексера без грамматики:

  • регулярное выражение трудно читать / трудно проверить
  • вы не получите дерево разбора
  • вы не получаете никаких значимых ошибок парсера
  • чем сложнее регулярное выражение, тем больше вероятность возникновения проблем с производительностью; например, https://www.regular-expressions.info/catastrophic.html
Другие вопросы по тегам