Регулярные выражения - древовидная грамматика Antlr Java
Я пытаюсь написать программу на ANTLR (Java), касающуюся упрощения регулярных выражений. Я уже написал некоторый код (содержание файла грамматики ниже)
grammar Regexp_v7;
options{
language = Java;
output = AST;
ASTLabelType = CommonTree;
backtrack = true;
}
tokens{
DOT;
REPEAT;
RANGE;
NULL;
}
fragment
ZERO
: '0'
;
fragment
DIGIT
: '1'..'9'
;
fragment
EPSILON
: '@'
;
fragment
FI
: '%'
;
ID
: EPSILON
| FI
| 'a'..'z'
| 'A'..'Z'
;
NUMBER
: ZERO
| DIGIT (ZERO | DIGIT)*
;
WHITESPACE
: ('\r' | '\n' | ' ' | '\t' ) + {$channel = HIDDEN;}
;
list
: (reg_exp ';'!)*
;
term
: ID -> ID
| '('! reg_exp ')'!
;
repeat_exp
: term ('{' range_exp '}')+ -> ^(REPEAT term (range_exp)+)
| term -> term
;
range_exp
: NUMBER ',' NUMBER -> ^(RANGE NUMBER NUMBER)
| NUMBER (',') -> ^(RANGE NUMBER NULL)
| ',' NUMBER -> ^(RANGE NULL NUMBER)
| NUMBER -> ^(RANGE NUMBER NUMBER)
;
kleene_exp
: repeat_exp ('*'^)*
;
concat_exp
: kleene_exp (kleene_exp)+ -> ^(DOT kleene_exp (kleene_exp)+)
| kleene_exp -> kleene_exp
;
reg_exp
: concat_exp ('|'^ concat_exp)*
;
Моя следующая цель - написать код грамматики дерева, который может упростить регулярные выражения (например, a|a -> a и т. Д.). Я сделал некоторое кодирование (см. Текст ниже), но у меня проблемы с определением правила, которое рассматривает узлы как поддеревья (чтобы упростить следующий вид выражений, например: (a | a) | (a | a) к a и т. Д.)
tree grammar Regexp_v7Walker;
options{
language = Java;
tokenVocab = Regexp_v7;
ASTLabelType = CommonTree;
output=AST;
backtrack = true;
}
tokens{
NULL;
}
bottomup
: ^('*' ^('*' e=.)) -> ^('*' $e) //a** -> a*
| ^('|' i=.* j=.* {$i.tree.toStringTree() == $j.tree.toStringTree()} )
-> $i // There are 3 errors while this line is up and running:
// 1. CommonTree cannot be resolved,
// 2. i.tree cannot be resolved or is not a field,
// 3. i cannot be resolved.
;
Малый класс водителя:
public class Regexp_Test_v7 {
public static void main(String[] args) throws RecognitionException {
CharStream stream = new ANTLRStringStream("a***;a|a;(ab)****;ab|ab;ab|aa;");
Regexp_v7Lexer lexer = new Regexp_v7Lexer(stream);
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
Regexp_v7Parser parser = new Regexp_v7Parser(tokenStream);
list_return list = parser.list();
CommonTree t = (CommonTree) list.getTree();
System.out.println("Original tree: " + t.toStringTree());
CommonTreeNodeStream nodes = new CommonTreeNodeStream(t);
Regexp_v7Walker s = new Regexp_v7Walker(nodes);
t = (CommonTree)s.downup(t);
System.out.println("Simplified tree: " + t.toStringTree());
Может ли кто-нибудь помочь мне с решением этого дела? Заранее спасибо и всего наилучшего.
1 ответ
Теперь я не эксперт, но в вашей древовидной грамматике
- добавлять
filter=true
- изменить вторую строку
bottomup
Правило:^('|' i=. j=. {i.toStringTree().equals(j.toStringTree()) }? ) -> $i }
Если я не ошибаюсь, используя i=.*
вы позволяете i
быть несуществующим, и вы получите NullPointerException
на преобразование в String
,
И то и другое i
а также j
имеют тип CommonTree
потому что вы настроили это так: ASTLabelType = CommonTree
так что вы должны позвонить i.toStringTree()
,
И так как это Java и вы сравниваете строки, используйте equals()
,
Также, чтобы сделать выражение в фигурных скобках предикатом, вам нужен вопросительный знак после заключительного.