Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/308.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在不使用标记器状态的情况下消除标记的歧义_Java_Parsing_Tokenize_Javacc - Fatal编程技术网

Java 在不使用标记器状态的情况下消除标记的歧义

Java 在不使用标记器状态的情况下消除标记的歧义,java,parsing,tokenize,javacc,Java,Parsing,Tokenize,Javacc,我无法让JavaCC通过标记在语法中的位置来正确地消除歧义。我有以下JJTree文件(我将其称为bug.jjt): 现在,在编译完这个之后,您可以从命令行为runmyparser提供一个要解析的字符串作为参数。如果成功,它将打印生产,如果失败,它将输出错误 我尝试了两种简单的输入:foo state和state state。第一个解析,但第二个不解析,因为两个状态字符串都标记为。当我将LOOKAHEAD设置为3时,我希望它使用语法并看到一个字符串state必须是,另一个必须是,LOOKAHEAD

我无法让JavaCC通过标记在语法中的位置来正确地消除歧义。我有以下JJTree文件(我将其称为
bug.jjt
):

现在,在编译完这个之后,您可以从命令行为runmyparser提供一个要解析的字符串作为参数。如果成功,它将打印
生产
,如果失败,它将输出错误


我尝试了两种简单的输入:
foo state
state state
。第一个解析,但第二个不解析,因为两个
状态
字符串都标记为
。当我将
LOOKAHEAD
设置为3时,我希望它使用语法并看到一个字符串
state
必须是
,另一个必须是
LOOKAHEAD
选项仅适用于解析器(生成规则)。标记器不受此影响:它将生成标记,而不必担心生成规则试图匹配什么。输入
“状态”
将始终标记为
状态
,即使解析器试图匹配
产品名称

您可以这样做(未经测试,前面是伪语法代码!):


LOOKAHEAD
选项仅适用于解析器(生成规则)。标记器不受此影响:它将生成标记,而不必担心生成规则试图匹配什么。输入
“状态”
将始终标记为
状态
,即使解析器试图匹配
产品名称

您可以这样做(未经测试,前面是伪语法代码!):


当lexer将字符组合成令牌时,Lookahead并不涉及lexer。解析器在匹配由终端(令牌)组成的非终端时使用它

如果您定义“状态”以产生令牌状态,那么这就是它

我同意你的观点,对于允许关键字用作标识符,标记器状态不是一个好的解决方案。这真的有必要吗?HLL有充分的理由不允许这样做


OTOH,如果您可以只使用
重写语法,您可能会在语义分析过程中推迟对关键字的识别。

先行词在将字符组合为标记时不涉及词法。解析器在匹配由终端(令牌)组成的非终端时使用它

如果您定义“状态”以产生令牌状态,那么这就是它

我同意你的观点,对于允许关键字用作标识符,标记器状态不是一个好的解决方案。这真的有必要吗?HLL有充分的理由不允许这样做

OTOH,如果你可以只使用
重写语法,你可能会在语义分析过程中推迟对关键词的识别。

这将在下面的问题4.19中讨论

这里概述了三种战略

在语法中添加选项。参见巴特·基尔斯的答案

使用语义前瞻。对于这种方法,您摆脱了产品定义的
状态
,并像这样编写语法

void SimpleNode production():
{}
{
    (
        <PROD_NAME>
        ( LOOKAHEAD({getToken(1).kind == PROD_NAME && getToken(1).image.equals("state")})
         <PROD_NAME>
         ...
        |
         ...other choices...
        )
    )
    {return jjtThis;}
}
name  state  : "a" | "b" name ;
|__||______||_________________||_________
DEF-   S0             S1                    DEFAULT
AULT
<*> SKIP: { " " }

<S0> TOKEN: { <STATE: "state"> : S1 }

<DEFAULT> TOKEN:{ <PROD_NAME: (["a"-"z"])+ >  : S0 }
<S0,S1> TOKEN:{ <PROD_NAME: (["a"-"z"])+ >  }

<S1> TOKEN: { <SEMICOLON : ";" > : DEFAULT
<S0, DEFAULT> TOKEN : { <SEMICOLON : ";" > }

<*> TOKEN {
     COLON : ":"
|    ...etc...
}
其中,
DUMMY
是一种从未进入的状态

使用词汇状态。OP问题的标题表明他不想这样做,但不是为什么。如果状态切换可以包含在令牌管理器中,则可以执行此操作。假设一个文件是一系列产品,每个产品都是这样的

name state : "a" | "b" name ;
也就是说,它以一个名称开始,然后是关键字“state”一个冒号,一些标记,最后是分号。(我只是在编造,因为我不知道OP试图解析哪种语言。)然后可以使用三种词汇状态DEFAULT、S0和S1

  • 默认情况下,任何字母序列(包括“状态”)都是产品名称。默认情况下,识别产品名称会将状态切换为S0
  • 在S0中,除“状态”外的任何字母序列都是产品名称,“状态”是状态。在S0中,识别状态令牌导致令牌赋予器切换到状态S1
  • 在S1中,任何字母序列(包括“状态”)都是产品名称。在S1中,识别分号会将状态切换为默认状态
我们的例子是这样标记的

void SimpleNode production():
{}
{
    (
        <PROD_NAME>
        ( LOOKAHEAD({getToken(1).kind == PROD_NAME && getToken(1).image.equals("state")})
         <PROD_NAME>
         ...
        |
         ...other choices...
        )
    )
    {return jjtThis;}
}
name  state  : "a" | "b" name ;
|__||______||_________________||_________
DEF-   S0             S1                    DEFAULT
AULT
<*> SKIP: { " " }

<S0> TOKEN: { <STATE: "state"> : S1 }

<DEFAULT> TOKEN:{ <PROD_NAME: (["a"-"z"])+ >  : S0 }
<S0,S1> TOKEN:{ <PROD_NAME: (["a"-"z"])+ >  }

<S1> TOKEN: { <SEMICOLON : ";" > : DEFAULT
<S0, DEFAULT> TOKEN : { <SEMICOLON : ";" > }

<*> TOKEN {
     COLON : ":"
|    ...etc...
}
作品是这样写的

void SimpleNode production():
{}
{
    (
        <PROD_NAME>
        ( LOOKAHEAD({getToken(1).kind == PROD_NAME && getToken(1).image.equals("state")})
         <PROD_NAME>
         ...
        |
         ...other choices...
        )
    )
    {return jjtThis;}
}
name  state  : "a" | "b" name ;
|__||______||_________________||_________
DEF-   S0             S1                    DEFAULT
AULT
<*> SKIP: { " " }

<S0> TOKEN: { <STATE: "state"> : S1 }

<DEFAULT> TOKEN:{ <PROD_NAME: (["a"-"z"])+ >  : S0 }
<S0,S1> TOKEN:{ <PROD_NAME: (["a"-"z"])+ >  }

<S1> TOKEN: { <SEMICOLON : ";" > : DEFAULT
<S0, DEFAULT> TOKEN : { <SEMICOLON : ";" > }

<*> TOKEN {
     COLON : ":"
|    ...etc...
}
跳过:{'}
令牌:{:S1}
令牌:{:S0}
令牌:{}
令牌:{:默认值
令牌:{}
代币{
冒号:“
|……等等。。。
}
解析器可以将状态切换命令发送回标记器,但要使其正确且脆弱是很困难的。参见常见问题解答中的问题3.12。

这将在问题4.19中介绍

这里概述了三种战略

在语法中添加选项。参见巴特·基尔斯的答案

使用语义前瞻。对于这种方法,您摆脱了产品定义的
状态
,并像这样编写语法

void SimpleNode production():
{}
{
    (
        <PROD_NAME>
        ( LOOKAHEAD({getToken(1).kind == PROD_NAME && getToken(1).image.equals("state")})
         <PROD_NAME>
         ...
        |
         ...other choices...
        )
    )
    {return jjtThis;}
}
name  state  : "a" | "b" name ;
|__||______||_________________||_________
DEF-   S0             S1                    DEFAULT
AULT
<*> SKIP: { " " }

<S0> TOKEN: { <STATE: "state"> : S1 }

<DEFAULT> TOKEN:{ <PROD_NAME: (["a"-"z"])+ >  : S0 }
<S0,S1> TOKEN:{ <PROD_NAME: (["a"-"z"])+ >  }

<S1> TOKEN: { <SEMICOLON : ";" > : DEFAULT
<S0, DEFAULT> TOKEN : { <SEMICOLON : ";" > }

<*> TOKEN {
     COLON : ":"
|    ...etc...
}
其中,
DUMMY
是一种从未进入的状态

使用词汇状态。OP问题的标题表明他不想这样做,但不是为什么。如果状态切换可以包含在令牌管理器中,则可以这样做。假设一个文件是一系列产品,每个产品都是这样的

name state : "a" | "b" name ;
也就是说,它从一个名称开始,然后是关键字“state”一个冒号,一些标记,最后是分号。(我只是在编这个,因为我不知道OP试图解析哪种语言。)然后可以使用三种词汇状态DEFAULT、S0和S1

  • 默认情况下,任何字母序列(包括“状态”)都是产品名称。默认情况下,识别产品名称会将状态切换为S0
  • 在S0中,除“state”外的任何字母序列都是产品名称,“state”是状态。在S0中,识别状态标记会导致标记器切换到状态S1<