Lex和Yacc从入门到精通(6) 您所在的位置:网站首页 makefile后缀规则 Lex和Yacc从入门到精通(6)

Lex和Yacc从入门到精通(6)

2023-03-14 23:13| 来源: 网络整理| 查看: 265

词法状态

所谓的词法状态就是指对文本进行词法分析的时候,词法分析器当前所处 的状态,默认情况下,词法分析器都处于INITIAL状态,这个INITIAL状态 是Lex内置的状态。用户可以通过%x来重新定义各种各样的状态。

至于为什么要使用状态,我们来看一个实际的例子:上面分析头文件的时候 采用了两个自定义的状态:_INCLUDE_状态和_INCLUDE_FILE_状态, _INCLUDE_状态是当遇到了#include开始的,因为这个状态之后是尖括号或者 是双引号括起来的头文件名,在后面分析模板(使用尖括号)和分析字符串 (使用双引号)的时候也会遇到尖括号和双引号,因而需要区分这两种情况 ,所以才需要使用_INCLUDE_状态,以此来区分是包含文件还是模板或者是字 符串了。这一点非常重要!

同样,状态_INCLUDE_FILE_存在也是为了区分双引号包含的头文件名称的, 因为双引号不同于尖括号,双引号在头文件名的开始和结束都是相同的,因 此为了区分头部和尾部的双引号,必须再增加一个状态。实际上这可以用来 简化词法分析器的编写,当您遇到这种类似的问题的时候可以考虑再增加一 种新的状态,通常来说就可以解决问题啦:)

不过还有一点特别需要强调的是当您感觉所添加的状态太多了,出现了混乱 现象,就说明用Lex状态已经不大适合处理这种问题了,就应该考虑采用Yacc 的一条独立的语法规则来进行处理了:)这也是Yacc语法文件存在的原因,要 不然全部都可以采用词法分析文件来解决啦,还要语法分析文件干什么!

递归表达

这里需要特别注意的是:frame.y文件中program的构成采用了左递归的形 式。从代码中可以看出:program可以是空(什么也没有)也可以是由现有 的program内容再追加一条include_preprocess类构成。当program内容为 空的时候增加一条include_preprocess类就表示program只有一条 include_preprocess内容,当program已经有了一条include_preprocess内 容之后再增加一条include_preprocess内容就可以表示两条 include_preprocess内容了,依次类推,可以表达无数的包含信息,从而 表达了无限的内容了。特别需要注意的是,这里的program表示的仅仅是现 有的内容,包括但不限于include_preprocess内容,还可以有其他的内容 ,这一点可以在增加其他内容的时候体现出来,因为C/C++源代码不仅仅是 由包含信息构成的嘛:)

特别需要注意的是,这里要特表强调一下使用左递归,不是说右递归不行,而 是出于程序运行效率考虑最好使用左递归。具体原因在后续的文档中会有详细 的说明的:)

YYSTYPE, yylval, $$,$1,$2,...$n

因为编写词法分析程序和语法分析程序的目的就是为了操作分析出来的数据 ,所以就需要有一种比较方便的形式来表达这些分析出来的数据。一种是词 法分析程序使用的方式,叫做yylval;一种是语法分析程序使用的,叫做$n ,从上面的词法分析程序和语法分析程序中已经可以看到它们在相应的文件 中的使用了。

至于YYSTYPE那就更简单了,因为要表达词法分析程序和语法分析程序中的数据 ,既然是数据,在C/C++中就有数据类型的概念,这里的YYSTYPE就是yylval和 $n的数据类型。

特别需要注意的是,语法分析程序中每一个语法规则冒号左边的类的值用$$表 示,而冒号右边的第一项用$1表示,第二项用$2表示,依次类推。

标记和值

标记指的是由%token定义的INCLUDE和HEADERFILE,他们都对应着一个具体 值,而且具体值类型还有可能完全不一样。这里需要特别强调的一点是: 每一个标记都对应着一个值,你可以不使用,但是他就是确确实实存在着 ,而且从始至终都保持着这种对应。例如上面的INCLUDE标记的值就没有使 用,但是HEADERFILE标记的值就被使用了。在Lex和Yacc中标记都是用一个 C宏定义的一个整数,而标记的值都是由YYSTYPE定义着的一个变量,这个 变量的名字就是yylval,其中保存着相关的信息,这个信息就是在词法分 析文件中进行设置的,而在语法分析文件中就直接采用了。

实际上%token还可以更进一步的简化Yacc语法程序的编写,从而避免一些不 必要的错误。从上面的语法分析来看,对于不同的$n,还需要记住$n的精确 类型和变量名,这一点其实是不必要的,可以通过%token HEADERFILE来声明标记,那么在Yacc程序的语法规则 中就可以直接使用$3来表示yylval.headerfile了,从而也就不需要记住那 些具体变量名啦:)

值得注意的是,尽管标记是可以用%token来定义,但是并不仅仅限于这种方 式,Yacc中还可以用%type来定义,采用%type来定义的目的就是为那些不是 标记的类也准备一个对应的值的,例如:完全可以为include_preprocess定 义一个值,用来保存一些额外的信息,不过本文中并不需要,后续的文档中 就会需要这个功能了,在此先简单说明一下:)

词法动作

对于词法分析程序中的每一个正则表达式对应的规则,都有相应的C/C++ 语句来做一些额外的处理,这个额外的处理就是词法动作。

语法动作

对于语法分析程序中的每一个语法规则,都有相应的C/C++语句来做一些额 外的处理,这个额外的处理就是语法动作。不过语法动作和词法动作的不同 之处在于,语法动作允许嵌入式的语法动作,而词法动作不行。至于什么是 嵌入式的语法动作,在后续的文档中会有详细的说明的!



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有