我正在为一种虚构的编程语言编写一个递归的解析器。这是一种C样式的语言,具有==,<,>,<=和> =等常见运算符,并且还具有通用功能(如C#中的功能)。
在C#之类的语言中,要调用通用函数,您可以编写:
someFunction<T>(x);
我的问题是,解析器如何区分通用参数与比较运算符(<和>)。
从我的角度来看,以上代码可能具有以下两种含义之一:
解析器如何知道要使用哪种解释?
答案 0 :(得分:5)
您100%正确地认为,泛型函数调用语法在包括该功能的许多语言中都是模棱两可的。
并非所有语言都使用歧义语法。在Java中,因为类型参数放在方法名称的之前,并且必须在其后加上.
:SomeClass.<ArgType>genericMethod()
,所以没有歧义。其他可能性包括对类型括号使用不同的符号,例如[]
,::<>
或!
。 (分别为Scala,Rust和D。Scala对数组下标使用括号。)
但是许多语言确实使用C ++ / C#语法,这是模棱两可的。每种语言都有其自己的歧义消除规则,据我所知,关于如何做到这一点尚无跨语言共识。特别是:
C ++要求编译器确定函数/方法/类名称是否(或可能)模板化。 (ADL使这一点有些棘手,在C ++ 18中,规则进行了更改,以包括未模版的函数/方法名称可能仍被解释为已模版的情况。)
C#要求编译器在可能的情况下找到尖括号模板参数的末尾,然后检查下一个输入标记。如果下一个标记是开放括号或不能在语法上遵循>
的一组标记中的一个(例如,分号),则将模板参数照原样处理;如果没有匹配的>
或匹配的>
后跟42
之类的东西,则将其作为比较。
据我所知,使用C#定义的递归下降解析器必须能够回溯。另一方面,C ++定义要求将名称解析与语法分析相结合,这是一个不同的丑陋之处。
据我所知,您可以自由提出自己的解决方案。如果您希望其他人使用您的语言,我鼓励您完全清楚地记录下来。 (例如,我找不到用于打字稿的此类文档,但我没有使用过。)如果我要设计具有泛型的语言,我想我会使用明确的语法。但这就是我。