区分右移运算符 (>>) 和 Java 泛型

5
我正在使用flex为java编写词法分析器。 Java规范指出:
“在每个步骤中,都使用最长可能的翻译,即使结果不会形成正确的程序,而另一个词汇翻译则会。有一个例外:如果词汇翻译发生在类型上下文(§4.11)中,并且输入流具有两个或两个以上连续的">"字符,后面跟着一个非“>”字符,那么必须将每个">"字符转换为数值比较运算符">"的标记。”
那么我如何区分右移运算符和像<List<List>>这样的东西?

6
“那么我如何区分右移运算符和类似于 <List<List>> 的内容呢?” - 通过上下文。右移运算符是算术表达式的一部分,而泛型则是构造函数调用、方法签名、类型或类定义的一部分。 - Turing85
这里我在询问如何在我的词法分析器(lex代码)中区分它们。 - Naman Gupta
如果您的扫描器只进行标记化,则遇到哪个 > 是无关紧要的。> 就是 >,没有区别。语法正确性由解析器保证。但是,如果扫描器具有求值器,则扫描器需要上下文信息,因为 Java 的语法是上下文相关的 - Turing85
3
实际上,在大多数语言中,>>是一个单词(就像>=一样)。如果>>被拆分成两个单词,语法将接受类似2> >3或甚至2 >/* 这是右移* /> 3这样的表达式,这通常是不被支持的。 - rici
1个回答

4
原始的Java泛型提案(JSR-14)要求修改Java语法以接受参数化类型中的>>>>>,使它们能在可能出现多个闭合尖括号的上下文中使用。(我找不到关于JSR-14的有用权威链接,但Gilad Bracha的GJ规范仍可在他的网站上找到;语法修改在第2.3节中显示。)
据我所知,这些修改从未正式纳入任何Java标准;最终,JLS8将更改描述的词法分析方法纳入其中,该方法在您的问题中引用。(请参见JDK-8021600,该文件还复制了最初提出的复杂语法。)
Bracha等人提出的语法修改是可行的,但您可能会发现它们使其他语法修改的整合变得更加复杂。(我没有深入研究过这个问题,因此对于当前的Java语言规范来说可能并不是一个问题。但对于将来的版本可能仍然是一个问题。)
虽然词法分析上下文允许使用在 JLS 中实际使用的简单语法,但它确实给词法分析带来了困难。一种可能的方法是通过使用 无扫描器解析器 放弃词法分析; 这肯定有效,但你将无法在 Bison/Flex 模型内完成。此外,你可能会发现,支持无扫描器解析还需要对已发布的语法进行非平凡的修改。
另一个可能性是从解析器中使用词法反馈,通过合并中间规则动作(MRAs)来开启和关闭“类型上下文”标志,以便当进入或退出类型上下文时使用。( §4.11 中有一个完整的类型上下文列表,可用于查找语法中适当的位置。)如果你尝试这样做,请注意 MRA 的执行与词法分析不完全同步,因为解析器通常需要先行符号来决定是否缩减 MRA。你通常需要在语法中将 MRA 定位得比你想象的早一个符号,以便在需要时它实际上会生效。
另一种可能性是永远不将>>>>>识别为标记。相反,词法分析器可以返回两个不同的>标记,其中一个在紧接着的下一个字符是>时使用:
>/>     { return CONJUNCTIVE_GT; }
>       { return INDEPENDENT_GT; }
  /* These two don't need to be changed. */
>>=     { return SHIFT_ASSIGN; }
>>>=    { return LONG_SHIFT_ASSIGN; }

然后,您可以修改语法以识别>>>>>运算符,同时允许任一形式的>作为闭角括号:

shift_op     : CONJUNCTIVE_GT INDEPENDENT_GT
long_shift_op: CONJUNCTIVE_GT CONJUNCTIVE_GT INDEPENDENT_GT
close_angle  : CONJUNCTIVE_GT | INDEPENDENT_GT
gt_op        : INDENPENDENT_GT /* This unit production is not really necessary */

那应该可以(虽然我没有尝试过),但它与Bison / Yacc运算符优先级机制不兼容,因为你无法为非终端声明优先级。因此,你需要使用具有显式运算符优先级规则的表达式语法,而不是带有优先级声明的模糊语法。

1
long_shift_op 应该是 CONJUNCTIVE_GT CONJUNCTIVE_GT INDEPENDENT_GT,对吗? - sepp2k

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接