我最近了解到C does not have a context-free grammar。我最近还了解到gcc used to use yacc to parse C。 yacc实用程序的手册指出"The class of specifications accepted [by yacc] is a very general one: LALR(1) grammars with disambiguating rules",而维基百科states则指出LALR语法是确定性上下文无关语法的子集,而上下文无关语法是子上下文无关语法的子集。如果C甚至不是上下文无关的(更少是确定性上下文无关的语言),但是yacc可以解析C,那么,如果不是具有LALR(1)的上下文无关语言的子集,则yacc可以解析哪种类型的语言。语法?
答案 0 :(得分:4)
Yacc生成计算机程序,这些程序非常完善。 yacc框架使用LALR(1)框架来触发操作,但是这些操作是任意代码。
此外,yacc的输入是令牌流,而不是直接输入。令牌流是由另一种以图灵完整语言编写的计算机程序生成的,该计算机程序还可以以不限于上下文无关代码转换的方式来操纵其输入。
最后,没有什么可以阻止yacc生成的解析器首先接受目标语言的超集,然后再分析无上下文的解析树,并拒绝基于任意计算的某些构造,例如坚持在使用前声明变量(上下文相关的计算)。
简而言之,现实世界中的解析器是实用的编写程序,而不是理论上的学术练习。由bison / yacc解析的语言通常是“大部分” LALR(1),并且它们的词法分析通常是“大部分”常规的,但是当计算机程序充分利用它们的能力来超越这些限制时,不要感到惊讶。这就是使编程成为有趣的活动的原因。
所有这些都不会使学术理论失去作用。 Bison / yacc和其他解析器生成器从构建解析器中花费了大量精力,因为它们可以处理“大部分”分析。语言越接近可分析的上下文无关模型,就越容易生成(“大多数”)其他有用的工具:lint,语法突出显示,重新格式化,索引器,静态分析器,文档提取器等,等等。更不用说充当语言本身语法的文档了。
答案 1 :(得分:0)
C仅出于琐碎的原因而没有上下文无关的语法,原因很简单:标识符标记的语义分类(其词法类别)有时需要了解如何声明它。 C设计用于一次编译,因此在解析的任何时候,都可以从先前的声明中了解与解析相关的所有内容。作用域中的声明可用于将词法类别分配给令牌。
因此,例如,如果解析器在语句块的中间面向(A)(B)
,则可能是:
表达式(B)
被强制转换为类型A
。
参数列表(B)
应用于函数表达式(A)
。
但是在语法分析器中不必出现这种歧义,因为词法分析器可以窥视范围,并根据名称是A
还是其他名称来对typedef
进行不同的分类,然后可以通过单独的语法规则将这些分类不同的标识符作为目标。就像有一个神奇的预言家用语义信息标记令牌一样,因此可以应用上下文无关技术。
首先,C语言中的另一个问题是它具有预处理器。 C的语法在不同的部分中指定:存在预处理器语法,并且存在用于预处理令牌流的语法。这样的C语言就没有一个上下文无关的语法可以捕获其短语结构的细微差别,因为预处理可以重新定义语法,并且可以在任何地方调用宏,除了注释和字符串文字外。