编译原理:flex与bison--从0到1完成一个编译器(sample语言)②

相关链接

编译原理:flex与bison–从0到1完成一个编译器(sample语言)〇
编译原理:flex与bison–从0到1完成一个编译器(sample语言)①
编译原理:flex与bison–从0到1完成一个编译器(sample语言)②
编译原理:flex与bison–从0到1完成一个编译器(sample语言)③
代码Github链接

前言

本系列文章共三部分,记述了我完成编译器的过程,供后来的学弟学妹参考借鉴。
(时隔三年,我终于想起更新第二部分了。)
本项目是我的编译原理作业,文章是由实验报告整理而来的,重在阐述,如果没有学习编译原理的相关知识,还要结合一些教程来看。
本项目实现的编译器包括词法分析,语法分析,语义分析与中间代码生成,目标代码生成共四个阶段,能将sample语言翻译成可执行的汇编语言。使用flex与bison工具辅助,通过C语言实现。本人能力有限,项目有许多不足和值得改进的地方,也请读者多多指正。

一、实验目的和要求

编写一个程序对 Sample 语言书写的源代码进行语法分析,并且打印分析结果。实验要求使用语法分析工具 Bison,结合 C 语言共同来完成。通过本次实验。实现以下几个功能:
(1)语法成分识别扫描源程序:根据文法规则,使用基于自底向上 LALR 分析工具 BISON 识别语法成分,输出语法分析树。
(2) 错误处理:如果产生语法错误,则输出出错的位置(源程序行号)以及相关的说明文字。程序要能够查出源代码中可能包含的语法错误。
除此之外,程序可能还需要完成以下要求: 联合词法分析器 LEX共同完成语法分析(需要在 lex 源文件中包含 bison 头文件;在 bison 源文件中包含 lex 文件;修改 lex 的单词返回值)。

二、实验原理与内容

YACC(Yet Another Compiler-Compiler) 是美国贝尔实验室开发的语法分析程序自动生成器,输入是某个语言的语法规则,输出是该语言的语法分析器。
多数程序设计语言的语法分析都采用LALR(1)分析法,YACC也正是以LALR(1)文法为基础。它通过对输入的形式文法规则进行分析,产生LALR(1)分析表,输出以该分析表驱动的语法分析器C语言源程序。
本实验要求基于lex和bison,完成以下两项工作:
(1)输出表达式的语法树
设计语法分析器,能够输出正确的语法分析树。比如输入:3+5*7,输出:其语法分析树如下图所示:
在这里插入图片描述

(2)Sample语言语法分析器的实现
设计语法分析器,能够识别Sample程序的语法成分。

三、实验步骤

3.1 表达式语法树的生成

本程序将实现对于算术表达式的词法与语法分析,生成并输出语法树。

1)词法分析

算数表达式的词法简单,包括数字和运算符号。
对于数字的识别,本程序只识别0~9的数字。即只能识别一位数字。识别后对bison程序返回数字类别。
对于运算符号的识别,本程序识别 + , - , * , / 四个运算符号,并对bison程序返回数字类别。
此外,程序还对\n符号进行识别,作为表达式的终止。

2)文法设计以及语义子程序

本文设计了算术表达式的文法。由于*/与±的运算优先级不同,体现到文法中就是:自下而上分析时,要先规约乘除再规约加减。最终设计出本程序的文法如下。
算术表达式的文法

Line -> ‘\n’ | exp ‘\n’
Exp -> exp ± T | T
T -> T * F | T / F | F
F -> 0~9

由于本程序需要建立语法树,对于每个规则,需要在语法树中新建并连接节点。比如识别到” T * F”,就应该在语法树中新建 ”” 节点和一个父节点,将T节点、”” 节点和F节点连接到父节点上,向上返回父节点的地址。用bison的代码实现如下(newNode()是新建节点,linkNode()是连接节点)在这里插入图片描述

对于其他规则的语义子程序,亦可如法炮制。可查看trans.y程序。

3) 语法树的生成与输出

由于语法树会存在多个孩子节点,用二叉树不足以将其表示。此外,用前序遍历来表示语法树不够具体,不同的树可能对应同一个前序遍历。因此本程序用邻接表实现了树的构造与输出。相关代码在GrammarTree.h中。
邻接表可以看作是将多个链表用一个数组串联起来,在使用临界表表示树的时候,可以用串联多个链表的数组表示一个点,用数组某一位置的一条链表表示这个点引出的所有边。
从树的根节点开始,使用顺序表依次存储树中各个节点,给各个节点配备一个链表,用于存储各节点的孩子节点位于顺序表中的位置。如果节点没有孩子节点(叶子节点),则该节点的链表为空链表。
如下图所示,右为左树的邻接表表示。
在这里插入图片描述

代码实现上,本程序定义了两个类ArcNode和Node,分别对应链表和树的节点。定义了五个方法来实现树的初始化、添加节点、连接、遍历和输出等操作。对其实现本文不作具体阐述。
对于语法树的输出,由于前序遍历不能得到具体而确定的树,本程序使用html内置的树形标签,对树进行了输出。对于一些文法规则进行了简化(如F->0~9)。
对于表达式 “3 + 5 * 7” 输出的语法树如下
在这里插入图片描述
虽然树的输出结果并不很美观,但输出正确,且能够表示语义分析过程。

3.2 Sample语言的语法分析

对于Sample语言的语法分析,利用到了实验一的词法分析程序。在实验一的基础上,为bison程序返回了单词的名称。
本程序单词的名称用大写英文或拼音命名,如单词program在bison中的名称为 PROGRAM.在lex程序中部分代码实现如下。
在这里插入图片描述
对于bison程序,首先根据文档将文法整理并输入。每一个规则的语义子程序为对当前规则的输出,如对“<因子> ::= <算术量>|(<算术表达式>)”这一规则的语义子程序的定义如下。在这里插入图片描述
类似地为所有规则添加语义子程序。运行程序即可输出整个SLR语义分析过程。对样例程序的语义分析过程如下:

Sample源代码语法分析过程
program example;
var
a:integer;
begin
x:=3+3.5+3.5e4+0x3f;
end.
在这里插入图片描述

在错误处理上,本程序利用了lex程序中的外部变量row。在实验一中有过介绍,此变量用来记录当前单词的行数。当程序发现源代码中含有语法错误的时候,会调用yyerror()函数。在yyerror()函数中会输出语法错误和行号。结合语义子程序的输出,就可以看到哪里出现了语法错误。
对于一个错误源代码进行分析,输出如下。

Sample源代码语法分析过程
program example;
var
a:integer;
begin
a
x:=3+3.5+3.5e4+0x3f;
end.
在这里插入图片描述

本程序对文档中的文法有一些勘误和修改,在实验三的报告中详述。

  • 18
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值