以 Go 为目标匹配 ANTLR4 中任何可打印的类字母字符
Match any printable letter-like characters in ANTLR4 with Go as target
这把我吓坏了,我就是找不到解决办法。我有一个搜索查询的语法,并且想匹配由可打印字母组成的查询中的任何搜索词,特殊字符“(”,“)”除外。引号中的字符串被单独处理并起作用。
这是一个有点工作的语法:
/* ANTLR Grammar for Minidb Query Language */
grammar Mdb;
start
: searchclause EOF
;
searchclause
: table expr
;
expr
: fieldsearch
| searchop fieldsearch
| unop expr
| expr relop expr
| lparen expr relop expr rparen
;
lparen
: '('
;
rparen
: ')'
;
unop
: NOT
;
relop
: AND
| OR
;
searchop
: NO
| EVERY
;
fieldsearch
: field EQ searchterm
;
field
: ID
;
table
: ID
;
searchterm
:
| STRING
| ID+
| DIGIT+
| DIGIT+ ID+
;
STRING
: '"' ~('\n'|'"')* ('"' )
;
AND
: 'and'
;
OR
: 'or'
;
NOT
: 'not'
;
NO
: 'no'
;
EVERY
: 'every'
;
EQ
: '='
;
fragment VALID_ID_START
: ('a' .. 'z') | ('A' .. 'Z') | '_'
;
fragment VALID_ID_CHAR
: VALID_ID_START | ('0' .. '9')
;
ID
: VALID_ID_START VALID_ID_CHAR*
;
DIGIT
: ('0' .. '9')
;
/*
NOT_SPECIAL
: ~(' ' | '\t' | '\n' | '\r' | '\'' | '"' | ';' | '.' | '=' | '(' | ')' )
; */
WS
: [ \r\n\t] + -> skip
;
问题是搜索词太受限制了。它应该匹配注释掉的 NOT_SPECIAL 中的任何字符,即有效查询将是:
Person Name=%
Person Address=^%Street%%%$^&*@^
但是每当我尝试以任何方式将 NOT_SPECIAL 放入 searchterm 的定义中时,它都不起作用。我也尝试过将它按字面意思放入规则中(注释掉 NOT_SPECIAL)和许多其他内容,但它就是行不通。在我的大多数尝试中,语法只是抱怨“=”之后的无关输入,并表示它期待 EOF。但我也不能将 EOF 放入 NOT_SPECIAL.
有什么方法可以简单地解析规则字段搜索中“=”之后的每个文本,直到出现空格或“)”、“(”?
N.B。 STRING 规则工作正常,但不应要求用户每次都使用引号,因为这是一个命令行工具,需要对其进行转义。
目标语言是 Go。
你可以通过引入一个 lexical mode 来解决这个问题,每当你匹配一个 EQ
标记时你就会输入它。一旦进入该词法模式,您要么匹配 (
、)
或空格(在这种情况下您会跳出词法模式),要么继续匹配您的 NOT_SPECIAL
字符。
通过使用词法模式,您必须在自己的文件中定义词法分析器和解析器规则。请务必使用 lexer grammar ...
和 parser grammar ...
而不是您在组合 .g4
文件中使用的 grammar ...
。
快速演示:
lexer grammar MdbLexer;
STRING
: '"' ~[\r\n"]* '"'
;
OPAR
: '('
;
CPAR
: ')'
;
AND
: 'and'
;
OR
: 'or'
;
NOT
: 'not'
;
NO
: 'no'
;
EVERY
: 'every'
;
EQ
: '=' -> pushMode(NOT_SPECIAL_MODE)
;
ID
: VALID_ID_START VALID_ID_CHAR*
;
DIGIT
: [0-9]
;
WS
: [ \r\n\t]+ -> skip
;
fragment VALID_ID_START
: [a-zA-Z_]
;
fragment VALID_ID_CHAR
: [a-zA-Z_0-9]
;
mode NOT_SPECIAL_MODE;
OPAR2
: '(' -> type(OPAR), popMode
;
CPAR2
: ')' -> type(CPAR), popMode
;
WS2
: [ \t\r\n] -> skip, popMode
;
NOT_SPECIAL
: ~[ \t\r\n()]+
;
您的解析器语法将像这样开始:
parser grammar MdbParser;
options {
tokenVocab=MdbLexer;
}
start
: searchclause EOF
;
// your other parser rules
我的 Go 有点生疏,但是一个小 Java 测试:
String source = "Person Address=^%Street%%%$^&*@^()";
MdbLexer lexer = new MdbLexer(CharStreams.fromString(source));
CommonTokenStream tokens = new CommonTokenStream(lexer);
tokens.fill();
for (Token t : tokens.getTokens()) {
System.out.printf("%-15s %s\n", MdbLexer.VOCABULARY.getSymbolicName(t.getType()), t.getText());
}
打印以下内容:
ID Person
ID Address
EQ =
NOT_SPECIAL ^%Street%%%$^&*@^
OPAR (
CPAR )
EOF <EOF>
这把我吓坏了,我就是找不到解决办法。我有一个搜索查询的语法,并且想匹配由可打印字母组成的查询中的任何搜索词,特殊字符“(”,“)”除外。引号中的字符串被单独处理并起作用。
这是一个有点工作的语法:
/* ANTLR Grammar for Minidb Query Language */
grammar Mdb;
start
: searchclause EOF
;
searchclause
: table expr
;
expr
: fieldsearch
| searchop fieldsearch
| unop expr
| expr relop expr
| lparen expr relop expr rparen
;
lparen
: '('
;
rparen
: ')'
;
unop
: NOT
;
relop
: AND
| OR
;
searchop
: NO
| EVERY
;
fieldsearch
: field EQ searchterm
;
field
: ID
;
table
: ID
;
searchterm
:
| STRING
| ID+
| DIGIT+
| DIGIT+ ID+
;
STRING
: '"' ~('\n'|'"')* ('"' )
;
AND
: 'and'
;
OR
: 'or'
;
NOT
: 'not'
;
NO
: 'no'
;
EVERY
: 'every'
;
EQ
: '='
;
fragment VALID_ID_START
: ('a' .. 'z') | ('A' .. 'Z') | '_'
;
fragment VALID_ID_CHAR
: VALID_ID_START | ('0' .. '9')
;
ID
: VALID_ID_START VALID_ID_CHAR*
;
DIGIT
: ('0' .. '9')
;
/*
NOT_SPECIAL
: ~(' ' | '\t' | '\n' | '\r' | '\'' | '"' | ';' | '.' | '=' | '(' | ')' )
; */
WS
: [ \r\n\t] + -> skip
;
问题是搜索词太受限制了。它应该匹配注释掉的 NOT_SPECIAL 中的任何字符,即有效查询将是:
Person Name=%
Person Address=^%Street%%%$^&*@^
但是每当我尝试以任何方式将 NOT_SPECIAL 放入 searchterm 的定义中时,它都不起作用。我也尝试过将它按字面意思放入规则中(注释掉 NOT_SPECIAL)和许多其他内容,但它就是行不通。在我的大多数尝试中,语法只是抱怨“=”之后的无关输入,并表示它期待 EOF。但我也不能将 EOF 放入 NOT_SPECIAL.
有什么方法可以简单地解析规则字段搜索中“=”之后的每个文本,直到出现空格或“)”、“(”?
N.B。 STRING 规则工作正常,但不应要求用户每次都使用引号,因为这是一个命令行工具,需要对其进行转义。
目标语言是 Go。
你可以通过引入一个 lexical mode 来解决这个问题,每当你匹配一个 EQ
标记时你就会输入它。一旦进入该词法模式,您要么匹配 (
、)
或空格(在这种情况下您会跳出词法模式),要么继续匹配您的 NOT_SPECIAL
字符。
通过使用词法模式,您必须在自己的文件中定义词法分析器和解析器规则。请务必使用 lexer grammar ...
和 parser grammar ...
而不是您在组合 .g4
文件中使用的 grammar ...
。
快速演示:
lexer grammar MdbLexer;
STRING
: '"' ~[\r\n"]* '"'
;
OPAR
: '('
;
CPAR
: ')'
;
AND
: 'and'
;
OR
: 'or'
;
NOT
: 'not'
;
NO
: 'no'
;
EVERY
: 'every'
;
EQ
: '=' -> pushMode(NOT_SPECIAL_MODE)
;
ID
: VALID_ID_START VALID_ID_CHAR*
;
DIGIT
: [0-9]
;
WS
: [ \r\n\t]+ -> skip
;
fragment VALID_ID_START
: [a-zA-Z_]
;
fragment VALID_ID_CHAR
: [a-zA-Z_0-9]
;
mode NOT_SPECIAL_MODE;
OPAR2
: '(' -> type(OPAR), popMode
;
CPAR2
: ')' -> type(CPAR), popMode
;
WS2
: [ \t\r\n] -> skip, popMode
;
NOT_SPECIAL
: ~[ \t\r\n()]+
;
您的解析器语法将像这样开始:
parser grammar MdbParser;
options {
tokenVocab=MdbLexer;
}
start
: searchclause EOF
;
// your other parser rules
我的 Go 有点生疏,但是一个小 Java 测试:
String source = "Person Address=^%Street%%%$^&*@^()";
MdbLexer lexer = new MdbLexer(CharStreams.fromString(source));
CommonTokenStream tokens = new CommonTokenStream(lexer);
tokens.fill();
for (Token t : tokens.getTokens()) {
System.out.printf("%-15s %s\n", MdbLexer.VOCABULARY.getSymbolicName(t.getType()), t.getText());
}
打印以下内容:
ID Person
ID Address
EQ =
NOT_SPECIAL ^%Street%%%$^&*@^
OPAR (
CPAR )
EOF <EOF>