JAVACC 如何为 1 个或多个传递令牌

JAVACC How to pass token for 1 or more

最近开始学习javacc解析器。我被要求编写一个解析器,其中一个令牌采用从 1 到多个的数字,另一个令牌采用从 2 到多个的数字 因此我想到了这样的事情:

TOKEN : {
<NUM1: <NUM> (<NUM>)* > //for one or more
<NUM2: (<NUM>)+> //for two or more
<NUM :(["0"-"9"])+>





 // and in the function
    void calc():
    {}
    {
     (
      (<NUM1>)+
     (<NUM2>)+
     )* <EOF>
    }

然而,即使我传递一个没有数字的文本值,它也会成功传递。我做错了什么?

词法标记的 JavaCC 语法允许您重复包含在范围 () 中的元素,后跟以下之一:

? - zero or one time
* - zero or more times
+ - one or more times

在您的情况下,您需要两个令牌:

TOKEN: 
{
  <NUM2: ["0"-"9"] (["0"-"9"])+> // for two or more
  <NUM1:           (["0"-"9"])+> // for one or more
}

您读作:

  • 名为 NUM1 的令牌匹配从一到无穷大的数字
  • 名为 NUM2 的令牌匹配从两位到无穷大的数字

JavaCC 中的词法机制使用输入字符流中的一个字符并尝试识别标记。两个自动机如下:

lexer 在两个自动机中针对两个标记同时进行。在无法取得更多进展后,识别出 latest 找到的令牌。如果 一个 令牌类型是可能的,那么声明的 第一个 被识别。因此 NUM2NUM1 之前声明。这意味着对于输入 1,令牌 NUM2 而不是 将被识别,因为它需要不止一位数。在这种情况下,NUM1 将是唯一与此输入匹配的标记类型。对于输入 12 两种标记类型都会接受它,但是 NUM2 会被识别,因为它首先声明。这意味着如果您先订购它们 NUM1,然后订购 NUM2,您将永远不会收到 NUM2 令牌,因为 NUM1 将始终以最高优先级“获胜”。

要使用它们,您可以拥有如下两个解析器函数:

void match_one_to_many_numbers() : {} { <NUM1> (" " <NUM1>)* <EOF> }
void match_two_to_many_numbers() : {} { <NUM2> (" " <NUM2>)* <EOF> }

您读作:

  • function match_one_to_many_numbers 接受从 oneinfinity 数量的令牌 NUM1,由 [= 分隔77=],然后输入流必须以 EOF 系统标记
  • 结束
  • 功能match_two_to_many_numbers相同,只是来自token NUM2

因为这两个标记都接受无限数量的数字,所以如果没有非数字的分隔符,就不能拥有这些标记的序列。