Lex&Yacc 编译原理课设

本文介绍了如何使用Lex和Yacc进行编译原理课程设计,包括工具Bison、Flex和GCC的介绍,编译器的五个阶段,重点讲解了Lex的消除歧义规则和语法结构,以及Yacc的LALR(1)算法和自动生成分析表的过程,并提供了编译运行的步骤和注意事项。
摘要由CSDN通过智能技术生成

Lex&Yacc

1 知识储备:

1.1 工具

1.1.1 Bison

bison是一个通用解析器生成器,将LALR(1)上下文无关文法转变成一个解析该语法的C程序,可被用于开发各种语言的解析器,向上兼容Yacc,用C开发语法解析器时要安装Bison

1.1.2 Flex

flex是一个高速的词法分析器生成器,可用于对文字(text)进行模式匹配(pattern-matching), 它是lex的众多版本之一,选择flex是因为可以方便的在Windows系统安装

1.1.3 GCC(GNU Compiler Collection)

bison和flex需要的编译包都是GnuWin32,在win环境下,使用MinGW工具安装gcc编译环境

1.2 编译器原理概述

1.2.1 编程语言的编译器通常可被分为五个阶段:
  1. 词法分析:分析源码,扫描字符串,分离出所有语法单位(tokens), 这个任务可由Lex自动化完成
  2. 语法分析:分析词法分析传来的tokens, 找出符合规定的语法,确定整个输入串能否构成语法正确的句子和程序,这个任务可由Yacc自动化完成
  3. 中间代码生成:在语法分析正确的基础上,按照语义规则产生介于源语言和目标代码之间的代码,中间代码不依赖于机器,同时便于产生依赖于机器的代码
  4. 优化:依据等价变换原则,对中间代码进行加工变换,以便在后期生成高效的代码
  5. 目标代码生成:将优化后的中间代码转换成具体机器的指令序列
  • Note:在微、小型机这类对编译质量要求不高的场合,可跳过中间代码生成阶段,语法分析后直接生成目标代码。语义分析在目标代码生成阶段完成。
1.2.2 词法分析
定义

词法分析器以词法定义为基础,词法定义用正则表达式(正规文法)表示

正则表达式 ->NFA(不确定有限自动机)->DFA(确定有限自动机)->DFA最小化

功能

读取源代码,根据定义的词法分析识别单词,构造词法单元(token),检查此法错误,最后输出token序列(用二元组表示)

token
  • 语言中最小的语法单位

  • 分为两部分

    • 种类(类号)

    • 内容(内码)

    • 例如:

      <id,  1>
      
  • token种类

    • 标识符
      变量名、常量名、函数名、数组名…

    • 数字 数值

      整型浮点型布尔型…

    • 特殊种类

      • 保留字(基本字)

        被被语言系统自身定义的有特殊意义的单词,例如int float void null

      • 操作符 + - * /

      • 分隔符(界限符) ; : ( )

1.2.3 语法分析
定义

以语法定义(上下文无关文法)为基础,语法定义用产生式表示

功能

读取词法分析器传来的词法单元序列,根据语法定义生成语法结构(组词成句)

语法结构

描述程序结构,例如:

Program -> Type main() Block
Type -> int | bool
Block -> { Stmts return Num ; }
Decl -> Type Array ;
Array -> Identifier [ Num ] | Identifier [ Identifier ] | Identifier
Stmts -> Stmts M Stmt | Stmt
上下文无关文法(context-free grammar)
  • 文法中所有的产生式左边只有一个非终结符
  • 只要找到符合产生式右边的串,就可以把它归约为对应的非终结符
  • S->ab是一个上下文无关文法
  • aSb->aaSbb是一个上下文有关文法,因为它的第一个产生式左边有不止一个符号,所以你在匹配这个产生式中的S的时候必需确保这个S有正确的“上下文”,也就是左边的a和右边的b

2 Lex

生成词法分析器源码,lex.yy.c

2.1 Lex用于消除歧义的规则:

  1. 优先原则,只匹配字符或字符串一次,如果出现单词与两个规则都匹配,匹配靠前的规则
  2. 最长字串匹配原则,执行能匹配到的最长的匹配对应的action

2.2 lex语法分为三段

每段之间用**%%**隔开

2.2.1 定义部分:
  • 例:

    %{
    /*
    *这是一个Lex的定义部分
    */
    #undef input 
    #undef unput 
    unsigned verbose; 
    char *progName; 
    %}
    
    • 用**%{ %}**包住这块

    • 包裹住的部分会被直接复制粘贴进**.l文件生成的.c**文件

    • 把想要想要粘贴进最终程序的C代码写这

      • 要include的头文件
      • 其他C代码
2.2.2 规则部分:
  • 例:

    int		{ printf("%s: is a verb\n", yytext); }
    
  • 规则由模式(pattern)和与应的操作(action)构成

    • pattern:

      • 字符串
      • 正则表达式
    • action:

      • C代码
      • return的数据将传递给Yacc作为保留字(token)
  • lex生成的词法分析器(lexer)识别出定义的pattern时,将执行对应的action

2.2.3 子程序部分
  • 写C代码

    • 例子:
    main() 
    {
    	yylex();
    }
    

2.3 Lex对比C写出来的词法分析器

  • Lex程序长度比C短很多
  • C需要花接近三倍于Lex的时间来编写和Debug
  • 一些词法用C编写会失败,例如:/** comment **/,C编写的词法分析器可能会识别不出这个注释的结尾

2.4 lex.yy.c中的全局变量和函数

2.4.1 变量
  • yyoutFILE*类型,指向lexer的输出
  • yyinFILE*类型,指向lexer的输入
  • yytext:匹配到的文本存在这个变量里
2.4.2 函数
  • yylex()由lex自动生成,从进入这个函数开始分析

  • yywrap() 批量处理文件,可以配合yyin在子程序部分使用,返回1表示文件读完,返回0继续读文件

  • ECHO输出匹配到的字符串

2.5 flex词法分析产生器实现过程

词法分析器自动生成器的核心是lex编译器,lex编译器的功能是对某语言单词集描述的lex源程序,将其变换为一个能识别该语言单词的词法分析器。而该词法分析器像有限自动机一样取识别处理单词。

基于lex源程序,lex编译器的实现步骤大致是:

  1. 对lex源程序识别规则中的每个pi构造一个相应的NFA Ni
  2. 引入唯一初态S,从初态S通过ε弧将所有NFA Ni(i=1,…,n)连接成新的NFA N’
  3. 对NFA N’确定化,产生DFA N
  4. DFA N 最小化
  5. 给出控制程序。控制程序的作用是激活有限自动机,即控制输入字符串在有限自动机上运行,一旦达到终态,即识别出lex源程序模式描述的某个单词,转去调用相应的动作部分就可以了

3 Yacc

生成语法分析器源码y.tab.c 存放LALR分析表

和包含了token的枚举定义的头文件y.tab.h

3.1 Yacc parser分为三部分

每段之间用**%%**隔开

3.1.1定义部分
  • 和Lex的一样
  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值