JavaCC:像对待 <OR> 一样对待白色 space
JavaCC: treat white space like <OR>
我正在尝试为搜索引擎查询构建一个简单的语法。
到目前为止我已经知道了 -
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
运算符一样处理术语之间的空格。例如 hello world
应该被视为 hello OR world
我已经尝试了所有明显的解决方案,例如 <OR: ("OR" | " ")>
、从 SKIP
中删除 " "
等。但它仍然不起作用。
也许您不希望将空格视为 OR,也许您希望 OR 关键字是可选的。在那种情况下,您可以使用这样的语法
query --> subquery (<AND> subquery | (<OR>)? subquery | <NOT> subquery)*
然而,此语法将 NOT 视为中缀运算符。它也不反映优先级。通常 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>
好的。假设您确实需要用至少一个 space 替换任何缺失的 OR。或者换句话说,如果有一个或多个白色 space 允许 OR,则该白色 space 被认为是 OR。
与我的其他解决方案一样,我将 NOT 视为一元运算符,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>)+
我正在尝试为搜索引擎查询构建一个简单的语法。 到目前为止我已经知道了 -
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
运算符一样处理术语之间的空格。例如 hello world
应该被视为 hello OR world
我已经尝试了所有明显的解决方案,例如 <OR: ("OR" | " ")>
、从 SKIP
中删除 " "
等。但它仍然不起作用。
也许您不希望将空格视为 OR,也许您希望 OR 关键字是可选的。在那种情况下,您可以使用这样的语法
query --> subquery (<AND> subquery | (<OR>)? subquery | <NOT> subquery)*
然而,此语法将 NOT 视为中缀运算符。它也不反映优先级。通常 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>
好的。假设您确实需要用至少一个 space 替换任何缺失的 OR。或者换句话说,如果有一个或多个白色 space 允许 OR,则该白色 space 被认为是 OR。
与我的其他解决方案一样,我将 NOT 视为一元运算符,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>)+