我正在尝试为搜索引擎查询构建一个简单的语法。 到目前为止我已经有了这个 -
options {
STATIC=false;
MULTI=true;
VISITOR=true;
}
PARSER_BEGIN(SearchParser)
package com.syncplicity.searchservice.infrastructure.parser;
public class SearchParser {}
PARSER_END(SearchParser)
SKIP :
{
" "
| "\t"
| "\n"
| "\r"
}
<*> TOKEN : {
<#_TERM_CHAR: ~[ " ", "\t", "\n", "\r", "!", "(", ")", "\"", "\\", "/" ] >
| <#_QUOTED_CHAR: ~["\""] >
| <#_WHITESPACE: ( " " | "\t" | "\n" | "\r" | "\u3000") >
}
TOKEN :
{
<AND: "AND">
| <OR: "OR">
| <NOT: ("NOT" | "!")>
| <LBRACKET: "(">
| <RBRACKET: ")">
| <TERM: (<_TERM_CHAR>)+ >
| <QUOTED: "\"" (<_QUOTED_CHAR>)+ "\"">
}
/** Main production. */
ASTQuery query() #Query: {}
{
subQuery()
( <AND> subQuery() #LogicalAnd
| <OR> subQuery() #LogicalOr
| <NOT> subQuery() #LogicalNot
)*
{
return jjtThis;
}
}
void subQuery() #void: {}
{
<LBRACKET> query() <RBRACKET> | term() | quoted()
}
void term() #Term:
{
Token t;
}
{
(
t=<TERM>
)
{
jjtThis.value = t.image;
}
}
void quoted() #Quoted:
{
Token t;
}
{
(
t=<QUOTED>
)
{
jjtThis.value = t.image;
}
}
看起来它像我想的那样有效,例如它可以处理AND, OR, NOT/!
,单个术语和引用文本。
但是我不能强迫它处理术语之间的空格OR
运算符。 E.g hello world
应视为hello OR world
我已尝试过所有明显的解决方案,例如<OR: ("OR" | " ")>
,从" "
移除SKIP
等等。但它仍无效。
答案 0 :(得分:2)
也许您不希望将空格视为OR,也许您希望OR关键字是可选的。在这种情况下,您可以使用这样的语法
query --> subquery (<AND> subquery | (<OR>)? subquery | <NOT> subquery)*
然而,这个语法不是作为中缀操作符。它也没有反映出优先权。通常NOT优先于AND和AND优先于OR。你的主要制作也应该寻找一个EOF。为此你可以尝试
query --> query0 <EOF>
query0 --> query1 ((<OR>)? query1)*
query1 --> query2 (<AND> query2)*
query2 --> <NOT> query2 | subquery
subquery --> <LBRACKET> query0 <RBRACKET> | <TERM> | <QUOTED>
答案 1 :(得分:1)
确定。假设您确实希望要求任何丢失的OR被至少一个空格替换。换句话说,如果有一个或多个空格允许使用OR,那么该空格将被视为OR。
正如在我的另一个解决方案中,我将NOT视为一元运算符,并且优先于AND和AND优先于任何一种OR。
更改
SKIP : { " " | "\t" | "\n" | "\r" }
到
TOKEN : {<WS : " " | "\t" | "\n" | "\r" > }
现在使用这样的语法
query() --> query0() ows() <EOF>
query0() --> query1()
( LOOKAHEAD( ows() <OR> | ws() (<NOT> | <LBRACKET> | <TERM> | <QUOTED>) )
( ows() (<OR>)?
query1()
)*
query1() --> query2() (LOOKAHEAD(ows() <AND>) ows() <AND> query2())*
query2() --> ows() (<NOT> query2() | subquery())
subquery() --> <LBRACKET> query0() ows() <RBRACKET> | <TERM> | <QUOTED>
ows() --> (<WS>)*
ws() --> (<WS>)+