Compiler construction 在JavaCC中,如何降低正则表达式的优先级?

Compiler construction 在JavaCC中,如何降低正则表达式的优先级?,compiler-construction,javacc,Compiler Construction,Javacc,让我用一个具体的例子来澄清我的问题: 首先,我有一个令牌: <T_SELECT:"SELECT"> 我的问题是: JavaCC不再使用SELECT然后使用TABLE1,而是将SELECT TABLE1作为 显然,我希望它会非常消耗SELECT,因为我已经定义了一个名为 我该怎么做才能让JavaCC使用我定义的确切字符串而不是正则表达式呢?这几乎肯定不是您想要做的,因为它会将selection转换为selection ~[”,“]将匹配除逗号以外的任何字符,包括空格和换行符。这也不可

让我用一个具体的例子来澄清我的问题:

首先,我有一个令牌:

<T_SELECT:"SELECT">
我的问题是: JavaCC不再使用
SELECT
然后使用
TABLE1
,而是将
SELECT TABLE1
作为

显然,我希望它会非常消耗
SELECT
,因为我已经定义了一个名为


我该怎么做才能让JavaCC使用我定义的确切字符串而不是正则表达式呢?

这几乎肯定不是您想要做的,因为它会将
selection
转换为
select
ion

~[”,“]
将匹配除逗号以外的任何字符,包括空格和换行符。这也不可能是正确的,因为表名不以(或包含)空格字符开头


您需要匹配并忽略空白,并将名称限制为合法的名称字符。

这几乎肯定不是您想要做的,因为它会将
选择
变成
选择
离子

~[”,“]
将匹配除逗号以外的任何字符,包括空格和换行符。这也不可能是正确的,因为表名不以(或包含)空格字符开头


您需要匹配并忽略空白,并将名称限制为合法的名称字符。

我假设您只有这些词汇规则

TOKEN { <T_SELECT:"SELECT"> }
TOKEN { <T_TABLE_NAME:~[","]> }
TOKEN { <T_COMMA: "," > }
该序列将按如下方式进行词法分析

State          Token Produced
------------------------------
DEFAULT        T_SELECT("SELECT")
S_TABLE_NAME   T_TABLE_NAME( " ABC" )
S_TABLE_NAME   T_COMMA( "," )
S_TABLE_NAME   T_TABLE_NAME( " DEF" )
S_TABLE_NAME   T_NEWLINE( "\n" )
DEFAULT        EOF.
  • 首先找到一个T_SELECT
  • 然后是7个表名标记
  • 然后是一个EOF令牌
即:

如果你的语法只有一条规则

void select() : {} {
    <T_SELECT>
    <T_TABLE_NAME>
    (<T_COMMA> <T_TABLE_NAME>)* 
}   ,
void select() : {} {
    <T_SELECT>
    <T_TABLE_NAME>
    (<T_COMMA> <T_TABLE_NAME>)* 
    <EOF>   // I added an <EOF>
}   ,
现在会发生什么?再次假设输入字符串是

"SELECT TABLE1"    ,
有一个长度为6的前缀与规则匹配

<T_SELECT:"SELECT">
没有办法关闭最大数量规则。你赢不了这场比赛。你必须作弊


作弊的方法就是淘汰对手。将
T_TABLE_NAME
规则移动到不同的词法状态

您希望在lexer看到SELECT关键字后切换状态

写下你的lexer规则如下:

TOKEN : { <T_SELECT: "SELECT"> : S_TABLE_NAME } 

<S_TABLE_NAME> TOKEN :
    { <T_TABLE_NAME:(~[",","\n","\r"])*> : S_TABLE_NAME 
    | <T_COMMA: "," } : S_TABLE_NAME
    | <T_NEWLINE: ("\n" | "\n\r" | "\r") : DEFAULT }
它将被简化如下

State          Token Produced
------------------------------
DEFAULT        T_SELECT("SELECT")
S_TABLE_NAME   T_TABLE_NAME( " ABC" )
S_TABLE_NAME   T_COMMA( "," )
S_TABLE_NAME   T_TABLE_NAME( " DEF" )
S_TABLE_NAME   T_NEWLINE( "\n" )
DEFAULT        EOF.

它将无错误地解析。

我假设您仅有的词汇规则是

TOKEN { <T_SELECT:"SELECT"> }
TOKEN { <T_TABLE_NAME:~[","]> }
TOKEN { <T_COMMA: "," > }
该序列将按如下方式进行词法分析

State          Token Produced
------------------------------
DEFAULT        T_SELECT("SELECT")
S_TABLE_NAME   T_TABLE_NAME( " ABC" )
S_TABLE_NAME   T_COMMA( "," )
S_TABLE_NAME   T_TABLE_NAME( " DEF" )
S_TABLE_NAME   T_NEWLINE( "\n" )
DEFAULT        EOF.
  • 首先找到一个T_SELECT
  • 然后是7个表名标记
  • 然后是一个EOF令牌
即:

如果你的语法只有一条规则

void select() : {} {
    <T_SELECT>
    <T_TABLE_NAME>
    (<T_COMMA> <T_TABLE_NAME>)* 
}   ,
void select() : {} {
    <T_SELECT>
    <T_TABLE_NAME>
    (<T_COMMA> <T_TABLE_NAME>)* 
    <EOF>   // I added an <EOF>
}   ,
现在会发生什么?再次假设输入字符串是

"SELECT TABLE1"    ,
有一个长度为6的前缀与规则匹配

<T_SELECT:"SELECT">
没有办法关闭最大数量规则。你赢不了这场比赛。你必须作弊


作弊的方法就是淘汰对手。将
T_TABLE_NAME
规则移动到不同的词法状态

您希望在lexer看到SELECT关键字后切换状态

写下你的lexer规则如下:

TOKEN : { <T_SELECT: "SELECT"> : S_TABLE_NAME } 

<S_TABLE_NAME> TOKEN :
    { <T_TABLE_NAME:(~[",","\n","\r"])*> : S_TABLE_NAME 
    | <T_COMMA: "," } : S_TABLE_NAME
    | <T_NEWLINE: ("\n" | "\n\r" | "\r") : DEFAULT }
它将被简化如下

State          Token Produced
------------------------------
DEFAULT        T_SELECT("SELECT")
S_TABLE_NAME   T_TABLE_NAME( " ABC" )
S_TABLE_NAME   T_COMMA( "," )
S_TABLE_NAME   T_TABLE_NAME( " DEF" )
S_TABLE_NAME   T_NEWLINE( "\n" )
DEFAULT        EOF.

它将无错误地进行分析。

您的语法中是否应该允许使用带未转义/未引号空格的表名?是的,在我们的语法中,不带引号的空格是允许的。您是否希望表名只能有一个字符长?在示例中,“TABLE1”是7个字符长。但是正则表达式
~[”,“]
将只匹配一个字符长的字符串。有关详细信息,请参阅我的答案。您的语法中是否允许使用带有未加引号/未加引号的空格的表名?是的,在我们的语法中,允许使用未加引号的空格。是否希望表名只能有一个字符长?在示例中,“TABLE1”是7个字符长。但是正则表达式
~[”,“]
将只匹配一个字符长的字符串。有关详细信息,请参阅我的答案。在我们的sytax中,允许在表名中包含空格。我们已经为自己的系统定义了一种查询语言。@qinqjinlyc即使一个表名由几个单词组成,在
select
my table
之间的空格似乎不太可能是名称的一部分。(如果有人在代码之后放置了两个空格,选择?)通常,允许多单词名称的语言将它们看作是单词列表,而不是空格的字串,因此<代码>我的表和<代码>我的表< /代码>是相同的名称。允许关键字进入下一个符号(我的
选择
示例)更不常见。你是说
select
i
o
n
n
?@theodore:用逗号来分隔标记就是
select
ion
。虽然我假设OP忘记了一个重复运算符,但在我们的sytax中,它允许在表名中包含空格。我们已经为自己的系统定义了一种查询语言。@qinqjinlyc即使一个表名由几个单词组成,在
select
my table
之间的空格似乎不太可能是名称的一部分。(如果有人在代码之后放置了两个空格,选择?)通常,允许多单词名称的语言将它们看作是单词列表,而不是空格的字串,因此<代码>我的表和<代码>我的表< /代码>是相同的名称。允许关键字进入下一个符号(我的
选择
示例)更不常见。你是说
select
i
o
n
n
?@theodore:用逗号来分隔标记就是
select
ion
。虽然我认为OP确实忘记了一个重复操作符。嗨@Norvell,我试过你的建议,它可以解析“selectabc,def”。然而,在我们的语法中,表后面可能有“from”,比如“selectabc,def from”。然后,“from”将被视为“def”的一部分。然而,“from”是关键词,你原来的帖子说“表名是任意长度的字符串
State          Token Produced
------------------------------
DEFAULT        T_SELECT("SELECT")
S_TABLE_NAME   T_TABLE_NAME( " ABC" )
S_TABLE_NAME   T_COMMA( "," )
S_TABLE_NAME   T_TABLE_NAME( " DEF" )
S_TABLE_NAME   T_NEWLINE( "\n" )
DEFAULT        EOF.