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>)+