我目前正在阅读Compiler Design in C.我对语法概念不太熟悉,但第一个练习要求我写一个识别C变量声明的语法。
我的问题是,我如何防止(在语法中)重复签名和未签名?我对作品的熟悉程度(如本书所述)左侧有一个非终结符号,指向最多两个终端/非终结符。我只是不确定该语言如何用于"参见"如果已经使用了另一个符号。!
到目前为止,我的语法是:
Declaration -> Attributes Identifier
Attributes -> Prefix Type
Prefix ->
是否有比#34;限定符>更简洁的方式?无符号长|签名长|未签名"等等?当你包含所有可能的组合时,它会变得很长,即使这样,它也不会作为前缀转移,因为可以将限定符放在任何地方。
答案 0 :(得分:1)
你可以编码"状态"你的表达通过使用一系列的作品。类似的东西:
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语法(和相关的词法分析器)。试着把头包裹起来玩得开心!
答案 1 :(得分:1)
您可以通过编写不允许它的组合枚举语法规则集来防止重复。您可以为非常小的可选或无序项目(如“已签名”和“无符号”)执行此操作,实际上类似。
这不值得麻烦。
您还可以考虑编写语法,以防止给定的变量声明在同一范围内发生两次。这基本上是同样的问题,但应该非常清楚的是,通过大量的语法规则来做这件事是没有希望的。
问题是大多数语言都是上下文敏感的,例如,你可以在一个地方写的东西,取决于你在其他地方写的东西,也许远在源文本中。 (你的签名和无符号问题“远远”只有1个令牌)。但是我们的语法形式主要用于无上下文(事实上,对于许多解析器生成器,甚至更少,例如LL或LALR)语言。因此,他们只是表达不足以描述所有语言对您所写文本的约束。
有一个标准的治疗方法。你编写了一个接受“太多”的语法,并实现了一个检查附加约束的过程后解析过程。由于“程序”部分通常以传统的编程语言实现,因此它具有图灵功能,因此如果可以检查,您可以始终对上下文敏感度进行编码检查。
要进行解析后传递,解析器必须记住它看到的内容。因此,您需要进行解析捕获,通常使用抽象语法树。检查作用域中名称的有效性需要您有符号表。验证Java程序的各个部分始终可以访问,至少需要简单的流程分析。
底线:简单地写你的语法。不要担心这种重复;它很容易在解析后检查。通过解析位;这是问题中最容易的部分。准备添加更多的机器,使语法处理变得切实可行。大多数人似乎都不明白这一点。 (查看我的简历,讨论“解析后的生活”)。