【问题标题】:Distinguishing between right shift (>>) and Java generics区分右移 (>>) 和 Java 泛型
【发布时间】:2020-01-26 13:52:06
【问题描述】:

我正在为 flex 中的 java 编写一个词法分析器。 java规范说:

“在每一步都使用尽可能长的翻译,即使结果最终不会产生正确的程序,而另一个词法翻译会。有一个例外:如果词法翻译发生在类型上下文中(第 4.11 节) ) 并且输入流有两个或多个连续的 > 字符后跟一个非 > 字符,则每个 > 字符必须转换为数字比较运算符 > 的标记。”

那么如何区分右移运算符和 <List<List>> 中的类似运算符?

【问题讨论】:

  • "那么我如何区分右移运算符和<List<List>> 中的类似内容?" - 根据上下文。右移是算术表达式的一部分,而泛型是构造函数调用、方法签名、类型或类定义的一部分。
  • 这里我问的是如何在我的词法分析器(lex 代码)中区分它们。
  • 如果您的扫描仪只标记化,那么遇到哪个> 是无关紧要的。 >>,没有区别。然后由解析器确保语法正确性。但是,如果扫描器确实有评估器,那么扫描器需要上下文信息,因为 the grammar of Java is context-sensitive
  • @Turing85:不是这样。在大多数语言中,>> 是单个标记(如 >=)。如果>> 是两个标记,则语法将接受像2> >3 甚至2 >/* This is a right shift* /> 3 这样的表达式,这通常是不被接受的。

标签: java compiler-construction flex-lexer lexer


【解决方案1】:

最初的 Java 泛型提案 (JSR-14) 要求修改参数化类型的 Java 语法,以便在可以使用多个右尖括号的上下文中接受 >>>>>。 (我找不到 JSR-14 的有用权威链接,但 Gilad Bracha 的 GJ specification 仍然可以在他的网站上找到;语法修改见第 2.3 节。)

据我所知,这些修改从未正式纳入任何 Java 标准;最终,JLS8 将更改合并到您在问题中引用的词法分析描述中。 (见JDK-8021600,也复现了最初提出的复杂语法。)

Bracha 等人提出的语法修改会起作用,但您可能会发现它们使合并其他语法更改变得更加复杂。 (我还没有真正深入研究过这个问题,所以它对于当前的 Java 语言规范实际上可能不是问题。但它仍然可能是未来版本的问题。)

虽然上下文词法分析确实允许在 JLS 中实际使用更简单的语法,但它肯定会给词法分析带来困难。一种可能的方法是使用scannerless parser 完全放弃词法分析;这肯定会奏效,但您将无法在 Bison/Flex 模型中实现这一点。此外,您可能会发现支持无扫描仪解析所需的一些修改还需要对已发布的语法进行重大更改。

另一种可能性是使用来自解析器的词法反馈,方法是结合中间规则操作 (MRA),在输入和退出类型上下文时打开和关闭“类型上下文”标志。 (第 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 运算符优先级机制配合使用,因为你不能为非终端声明优先级。因此,您需要使用具有显式运算符优先规则的表达式语法,而不是使用优先声明增强的模棱两可的语法。

【讨论】:

  • long_shift_op 应该是CONJUNCTIVE_GT CONJUNCTIVE_GT INDEPENDENT_GT,对吧?
猜你喜欢
  • 1970-01-01
  • 2014-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多