解析器如何处理泛型类型参数?

How do parsers handle generic type parameters?

我正在为一种虚构的编程语言编写递归体面的解析器。它是一种 C 风格的语言,具有 ==、<、>、<= 和 >= 等常用运算符,并且还具有通用函数(如 C# 中的函数)。

在 C# 等语言中,要调用泛型函数,您可以编写:

someFunction<T>(x);

我的问题是,解析器如何区分通用参数和比较运算符(< 和 >)。

从我的角度来看,上面的代码可能有以下两种含义之一:

解析器如何知道要进行哪种解释?

您 100% 正确,通用函数调用语法在许多包含该功能的语言中是不明确的。

并非所有语言都使用模棱两可的语法。在 Java 中,没有歧义,因为类型参数放在 方法名称之前 ,并且前面必须有一个 .: SomeClass.<ArgType>genericMethod()。其他可能性包括对类型括号使用不同的符号,例如 []::<>!。 (分别为 Scala、Rust 和 D。Scala 对数组下标使用圆括号。)

但是很多语言确实使用 C++/C# 语法,这是不明确的。每种语言都有自己的消歧规则,据我所知,对于如何做到这一点还没有 cross-language 共识。特别是:

  • C++ 要求编译器确定 function/method/class 名称是否(或可能)模板化。 (ADL 使这有点棘手,在 C++18 中,规则更改为包括 non-templated function/method 名称可能仍被解释为模板化的情况。)

  • C# 要求编译器找到 angle-bracketed 模板参数的末尾,如果可能,然后检查下一个输入标记;如果下一个记号是一个左括号或一组记号中的一个,在句法上不能跟在 > 之后(例如,分号),那么模板参数将被这样处理;如果没有匹配的 > 或匹配的 > 后跟 42 之类的东西,则将其作为比较处理。

据我所知,使用 C# 定义的递归下降解析器需要能够回溯。另一方面,C++ 定义要求将名称解析交织到语法分析中,这是一种不同的丑陋。

据我所知,您可以自由地提出自己的不同解决方案。如果您希望其他人使用您的语言,我确实鼓励您完整而清楚地记录下来。 (例如,我找不到这样的打字稿文档,我不使用它。)如果我正在设计一种带有泛型的语言,我想我会选择明确的语法。但这就是我。