不包括限定词重复的语法
Grammar excluding repetition of qualifiers
我目前正在通读 Compiler Design in C. 我不太熟悉语法的概念,但第一个练习要求我编写一个识别 C 变量声明的语法。
我的问题是,我如何防止(在语法中)signed 和 unsigned 的重复?我对产品的熟悉程度(如书所教)在左侧有一个非终结符,指向最多两个终结符/非终结符。我只是不确定如果已经使用了另一个符号,该语言如何用于 "see"。!
到目前为止我的语法是:
Declaration -> Attributes Identifier
Attributes -> Prefix Type
Prefix ->
有没有比"qualifier > unsigned long | signed long | unsigned "等更简洁的方法呢?当您包括所有可能的组合时,它会变得很长,即使这样也不会作为前缀出现,因为可以将限定符放在任何地方。
您可以使用一系列产生式对表达式的 "state" 进行编码。类似于:
Expr -> "unsigned" AfterSignExpr
Expr -> "signed" AfterSignExpr
Expr -> AfterSignExpr
AfterSignExpr -> "char" AfterTypeExpr
AfterSignExpr -> "short" AfterTypeExpr
AfterSignExpr -> "int" AfterTypeExpr
AfterSignExpr -> "long" AfterTypeExpr
AfterTypeExpr -> Identifier "," AfterTypeExpr
AfterTypeExpr -> Identifier ";"
尽管 C 声明要复杂得多,因为它允许在所有地方使用修饰符,以不同的顺序、函数声明、结构声明等。
剧透警报:here 是实际的 C11 YACC 语法(和关联的词法分析器)。尽情享受吧!
您可以通过编写不允许重复的语法规则的组合枚举集来防止重复。您可以对非常小的可选或无序项目集执行此操作,例如 "signed" 和 "unsigned",有点实际。
不值得这么麻烦。
您还可以考虑编写语法以防止给定的变量声明在同一范围内出现两次。这本质上是同一个问题,但应该很清楚,仅仅靠大量的语法规则来解决这个问题是没有希望的。
问题在于大多数语言都是上下文相关的,例如,您可以在一个地方写什么,取决于您在其他地方写什么,也许在源文本中很远。 (您的签名和未签名问题 "far away" 小到 1 个令牌)。但是我们的语法形式主义主要用于上下文无关(事实上,对于许多解析器生成器,甚至更少,例如 LL 或 LALR)语言。因此,它们的表现力不足以描述所有语言对您编写的文本的限制。
对此有标准的治疗方法。您编写了一个接受 "too much" 的语法,并实现了一个检查附加约束的程序化 post 解析过程。由于 "procedural" 部分通常是用传统编程语言实现的,因此它具有强大的图灵功能,因此如果可以检查的话,您始终可以对上下文敏感度进行代码检查。
要进行 post 解析,您的解析器必须记住它看到的内容。因此,您需要解析捕获,通常使用抽象语法树完成。检查范围内名称的有效性需要您有符号表。验证 Java 程序的各个部分是否始终可访问至少需要简单的流分析。
底线:简单地写下你的语法。不要担心这样的重复;它很容易检查 post-解析。通过解析位;这是问题中最简单的部分。准备好添加更多的机制以使语法处理变得实用。大多数人似乎不明白这一点。 (查看我的简历以了解 "Life After Parsing" 的讨论)。
我目前正在通读 Compiler Design in C. 我不太熟悉语法的概念,但第一个练习要求我编写一个识别 C 变量声明的语法。
我的问题是,我如何防止(在语法中)signed 和 unsigned 的重复?我对产品的熟悉程度(如书所教)在左侧有一个非终结符,指向最多两个终结符/非终结符。我只是不确定如果已经使用了另一个符号,该语言如何用于 "see"。!
到目前为止我的语法是:
Declaration -> Attributes Identifier
Attributes -> Prefix Type
Prefix ->
有没有比"qualifier > unsigned long | signed long | unsigned "等更简洁的方法呢?当您包括所有可能的组合时,它会变得很长,即使这样也不会作为前缀出现,因为可以将限定符放在任何地方。
您可以使用一系列产生式对表达式的 "state" 进行编码。类似于:
Expr -> "unsigned" AfterSignExpr
Expr -> "signed" AfterSignExpr
Expr -> AfterSignExpr
AfterSignExpr -> "char" AfterTypeExpr
AfterSignExpr -> "short" AfterTypeExpr
AfterSignExpr -> "int" AfterTypeExpr
AfterSignExpr -> "long" AfterTypeExpr
AfterTypeExpr -> Identifier "," AfterTypeExpr
AfterTypeExpr -> Identifier ";"
尽管 C 声明要复杂得多,因为它允许在所有地方使用修饰符,以不同的顺序、函数声明、结构声明等。
剧透警报:here 是实际的 C11 YACC 语法(和关联的词法分析器)。尽情享受吧!
您可以通过编写不允许重复的语法规则的组合枚举集来防止重复。您可以对非常小的可选或无序项目集执行此操作,例如 "signed" 和 "unsigned",有点实际。
不值得这么麻烦。
您还可以考虑编写语法以防止给定的变量声明在同一范围内出现两次。这本质上是同一个问题,但应该很清楚,仅仅靠大量的语法规则来解决这个问题是没有希望的。
问题在于大多数语言都是上下文相关的,例如,您可以在一个地方写什么,取决于您在其他地方写什么,也许在源文本中很远。 (您的签名和未签名问题 "far away" 小到 1 个令牌)。但是我们的语法形式主义主要用于上下文无关(事实上,对于许多解析器生成器,甚至更少,例如 LL 或 LALR)语言。因此,它们的表现力不足以描述所有语言对您编写的文本的限制。
对此有标准的治疗方法。您编写了一个接受 "too much" 的语法,并实现了一个检查附加约束的程序化 post 解析过程。由于 "procedural" 部分通常是用传统编程语言实现的,因此它具有强大的图灵功能,因此如果可以检查的话,您始终可以对上下文敏感度进行代码检查。
要进行 post 解析,您的解析器必须记住它看到的内容。因此,您需要解析捕获,通常使用抽象语法树完成。检查范围内名称的有效性需要您有符号表。验证 Java 程序的各个部分是否始终可访问至少需要简单的流分析。
底线:简单地写下你的语法。不要担心这样的重复;它很容易检查 post-解析。通过解析位;这是问题中最简单的部分。准备好添加更多的机制以使语法处理变得实用。大多数人似乎不明白这一点。 (查看我的简历以了解 "Life After Parsing" 的讨论)。