编译原理——基于LR(1)的语法检查器(一)

本文介绍了基于LR(1)的语法检查器的实现,包括理论基础、配置文件解析和处理过程。通过读取BNF范式和正则表达式描述的文法,该检查器能对代码进行错误检查。文章详细阐述了LR语法分析技术的优越性和应用,以及配置文件的特定格式。解析配置文件时采用递归下降分析法,最终将文法结构存储在数据结构中,为构建LR(1)项集族和语法分析表打下基础。
摘要由CSDN通过智能技术生成

前言

  该项目是我在学习编译原理的时候所完成的一个项目,不同于成熟的yacc语法分析器,我的语法检查器通过和一个词法分析器相互配合,启动之前读入由BNF范式和正则表达式所描述的文法与词法,之后根据给定的文法对给出的代码文件进行检查,并指出文件中的错误。整个文法的解析以LR(1)为基础,总共的代码量为800左右(不包括词法分析器),完整的代码请移步Configurable-syntactic-analyzer

正文

理论介绍

  一般说来,常用的语法分析技术有两种,一种是自顶向下的,另一种是自底向上的,对于LL(1)型的文法来说,我们一般使用自顶向下的分析方式例如递归下降或者构造预测分析器的方式进行文法的解析,而其中递归下降分析法经常在手写的语法分析器中用到,这种方式对于大部分比较简单的文法是十分实用的,递归下降写起来也十分的方便。虽然LL(1)的文法足以描述大部分程序设计的构造,但是却无法描述左递归的文法以及二义性的文法,而在程序设计中,左递归的文法是经常出现的,例如S->Sab这样的产生式便是左递归的,因此递归下降的方式在此时并不适用,因此我们需要将左递归的文法经过某些变换,使它变为非递归的文法,但这种变换常常使得文法面目全非,而且实现起来也比较困难,因此我们提出了基于LR(k)的语法分析的概念。
  LR语法分析技术是通过自底向上的方式进行语法分析的,而我们引入这种方法的原因有以下几点(摘自龙书):
- 对于几乎所有的程序设计语言,只要能够写出该构造的上下文无关文法,就能够构造出识别该构造的LR语法分析器。
- LR语法分析方法是已知的最通用的无回溯的移入-规约分析技术。
- 一个LR语法分析器可以在对输入进行从左到右扫描时尽可能早的检测到错误。
- 可以使用LR方法进行语法分析的文法类是可以使用预测方法或LL方法进行语法分析的文法类的真超集。

  由此可见,LR语法分析技术的能力是十分强大的,LR语法分析技术一般来说有三种,一种是SLR(简单LR技术),LR(规范LR技术),LALR(向前看LR技术)。相较之下,规范LR技术的分析能力最强,但是占用的系统资源也最多,鉴于规范LR的典型性,因此我的语法检查器使用的规范LR技术。无论哪一种LR技术,在使用时都要经过如下的几个步骤:
1. 根据给定的文法构造出该文法的规范LR(k)项集族
2. 根据规范LR(k)项集族构造出语法分析表。
3. 在运行时根据语法分析表进行相应的移入,规约操作。

  而本文则会针对以上三个步骤提供一个具体可行的实现方案,从而构造出一个简单的语法检查器。

配置文件

  对于描述文法的配置文件,我以龙书上的文法描述方式为基础,在实际使用的时候做了一些修改,方便我对文法进行解析,首先文法中出现的所有终结符必须在文法之前注明,并且在这些终结符之前写上统一的标识”%token”并在结尾写上分号,所有的产生式需要用’ { ‘以及’ } ‘包裹起来。对于文法来说,文法应该写成增广文法的形式,即第一个产生式写成S'->S的形式,其次产生式的箭头”->”被修改为冒号’ : ‘,符号和或连接符’ | ‘之间无空格,最后在产生式的结尾处应加上分号’ ; ‘。因此,如下的文法格式:

S->L = R | R
L->* R | id
R->L

会被改写为

%token = * id;
{
S':S;
S:L = R|R;
L:* R|id;
R:L;
}

  %token标识符后边的所有符号均应该在词法分析器的配置文件中使用正则表达式进行描述,例如上述的文法在配置文件中就应该被描述为:

id:[_0-9a-zA-Z]+
*:\*
=:=

  由于我的词法分析器具有优先匹配的功能,因此需要优先匹配的需要写在前边。关于词法分析器的相关理论以及具体实现详见正则引擎入门以及Configurable-lexical-analyzer

配置文件的解析

  虽然规范LR技术是本文章的重点,但是在解析配置文件的时候我依旧采用了递归下降的分析方法,这种方法写起来比较方便,也便于理解。我们解析配置文件的目的是要将文法读取进内存,使用某种数据结构将文法中各个符号之间的关系展现出来,便于我们下一步的分析,下面展示的三个结构体可以用来表示一个文法的各个结构:

struct _production          //代表一个产生式
{
    char head[20];          //用于记录产生式的头
    int p_index;            //记录产生式的序号
    struct _
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值