【问题标题】:How C/C++ parser/lexer makes the difference between '*' of pointer and '*' of multiplication?C/C++ 解析器/词法分析器如何区分指针的“*”和乘法的“*”?
【发布时间】:2016-12-26 13:15:46
【问题描述】:

C/C++ 标记器/解析器如何不误解“*”的用法,因为它可以用于乘法和指针类型。 例如:。

... {
    ...
    obj *var1; // * used to make var1 as pointer to obj
    var1 * var2; // * used to multiply var1 and var2
}

更新 1:在进行标记/解析时,我们还无法区分引用变量的标识符和引用类型的标识符。

更新 2:(问题上下文)我正在设计和实现 C/C++ 系列的编程语言,其中指针声明为 Pointer<int>,并且我想改用 C 指针样式。

更新 32016 年 12 月 30 日): 这个stackoverflow question about LR(1) parser and C++ 的一些答案似乎解决了我的问题。

【问题讨论】:

  • "obj *var1;":将一个类型和一个未定义的标记相乘没有意义,所以它可能是一个变量定义。
  • 通过知道什么是obj/var1...但确实解析C++很复杂。
  • 这就是我们有关键字和标识符的原因。
  • C++ 不是上下文无关可解析的。
  • @WaelBoutglay:为了简化语法,您可以添加关键字来声明变量,从而避免这些歧义。 (如let <type> <var> = <expr>)。

标签: c++ c parsing tokenize lexer


【解决方案1】:

标记器不区分两者。它只是将其视为令牌*

解析器知道如何查找名称。它知道obj 是一个类型,因此可以解析<type> * <identifier><non-type> * <non-type> 不同。你的直觉是:在不实现任何语义的情况下,不可能只解析 C 的语法。获得正确解析 C 语法的唯一方法需要解释声明并跟踪哪些名称名称类型和哪些名称非类型。您的更新:

在进行标记/解析时,我们还无法区分引用变量的标识符和引用类型的标识符。

不太正确,因为它假定标记化/解析是作为一个单独的步骤一次性完成的。事实上,解析和语义分析是交错的。当typedef int obj; 被解析时,它被解释并被认为意味着obj 现在命名了一个类型。继续解析,看到obj * var1;,就可以使用前面语义分析的结果了。

【讨论】:

  • 您关于“获得正确的解析...”的说法是完全错误的! C 是上下文无关文法。解析器仅在解析后查找类型。类型不影响解析(上下文无关!)。在这种情况下,用作 unary 运算符的* 是取消引用,因此a**b 表示取消引用b 并将其与a 相乘,a*b 只能表示乘法。
  • 参见例如gist.github.com/codebrainz/2933703 用于上下文无关的 C99 语法。
  • @PaulOgilvie a*b; 的解析方式完全不同,具体取决于 a 是否为类型名称。你错了a*b; 只能表示乘法,它也可以表示“将b 声明为指向a 类型的指针”。您链接到的语法显示了一个未实现的 check_type 函数,该函数需要添加到词法分析器以返回 TYPE_NAMEIDENTIFIER,以适当的为准。实现它需要部分实现 C 的语义,就像我在回答中指出的那样。
  • 我明白了。我站得更正了。如果您对您的答案进行小修改,我将撤消我的反对票。
  • @hvd,你说的完全正确,我刚刚检查了 Clang 源代码,发现 lexer/tokeniser 返回了一个tok::star
猜你喜欢
  • 1970-01-01
  • 2011-03-12
  • 2013-01-31
  • 1970-01-01
  • 2022-10-22
  • 1970-01-01
  • 2011-04-07
  • 2020-01-17
  • 1970-01-01
相关资源
最近更新 更多