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

时间:2019-06-08 20:21:39

标签: c# parsing generics programming-languages recursive-descent

我正在为一种虚构的编程语言编写一个递归的解析器。这是一种C样式的语言,具有==,<,>,<=和> =等常见运算符,并且还具有通用功能(如C#中的功能)。

在C#之类的语言中,要调用通用函数,您可以编写:

someFunction<T>(x);

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

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

  • 使用通用参数“ T”和常规参数“ x”调用“ someFunction”
  • 计算表达式'(someFunction x',将'someFunction','T'和'x'视为常规变量

解析器如何知道要使用哪种解释?

1 个答案:

答案 0 :(得分:5)

您100%正确地认为,泛型函数调用语法在包括该功能的许多语言中都是模棱两可的。

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

但是许多语言确实使用C ++ / C#语法,这是模棱两可的。每种语言都有其自己的歧义消除规则,据我所知,关于如何做到这一点尚无跨语言共识。特别是:

  • C ++要求编译器确定函数/方法/类名称是否(或可能)模板化。 (ADL使这一点有些棘手,在C ++ 18中,规则进行了更改,以包括未模版的函数/方法名称可能仍被解释为已模版的情况。)

  • C#要求编译器在可能的情况下找到尖括号模板参数的末尾,然后检查下一个输入标记。如果下一个标记是开放括号​​或不能在语法上遵循>的一组标记中的一个(例如,分号),则将模板参数照原样处理;如果没有匹配的>或匹配的>后跟42之类的东西,则将其作为比较。

据我所知,使用C#定义的递归下降解析器必须能够回溯。另一方面,C ++定义要求将名称解析与语法分析相结合,这是一个不同的丑陋之处。

据我所知,您可以自由提出自己的解决方案。如果您希望其他人使用您的语言,我鼓励您完全清楚地记录下来。 (例如,我找不到用于打字稿的此类文档,但我没有使用过。)如果我要设计具有泛型的语言,我想我会使用明确的语法。但这就是我。