编译原理课程设计——语法分析器

实验目的

  了解掌握算符优先分析的基本方法、内容;学会科学思考并解决问题,提高程序设计能力。

实验内容与要求

  用算符优先分析方法设计一个分析解释程序,对输入的赋值语句、输出语句、清除语句进行词法分析、语法分析、表达式求值并存储于指定变量中;若存在错误,提示错误相关信息。

文法表示  

    S -> v=E | E? | clear

    E -> E+T | E–T | T

    T -> T*F | T/F | F

    F -> (E) | v | c

问题分析

  由于要求用算符优先分析方法来进行程序的语法分析,所以我们要根据给出的文法来设计优先关系表。对每个非终结符,求出:

    FIRSTVT(S) = { v , ? , clear }                 LASTVT(S) = { ? , clear }

    FIRSTVT(F) = { ( , v , c }                       LASTVT(F) = { ) , v , c }

    FIRSTVT(T) = {* , / , ( , v , c }               LASTVT(T) = {* , / , ) , v , c }

    FIRSTVT(E) = {+ , - , * , / , ( , v , c}       LASTVT(E) = {+ , - , * , / , } , v , c}

  符号的种别码如下表所示:

   

  优先关系表如下:

       

先简要分析一下语法分析的大致流程:

当有句子要进行处理时,首先要对其进行词法分析来分解出该句子中的每个符号,然后将该句子按照算符优先算法压入归约栈中,如果可以顺利归约,则说明这是一个合法的句子,否则该句子非法。

这里有一个需要考虑的地方,就是如何进行归约。由于文法已经给定,所以我们考虑设计一个文法表,文法表中的内容就是可归约串的种别码的顺序,比如v=E可以表示为9,1,13。这样的话当我们要进行一次归约时,只用按顺序存储最左素短语中符号的种别码,然后拿这个种别码序列与文法表进行匹配,就可知道当前归约需要执行哪些操作。

还有一点需要注意,就是如何对一个表达式进行求值。这里需要我们设计一个二元组的变量名表,这个变量名表可以根据变量的名称来返回变量的数据。变量名表的具体设计见详细设计部分。

由于是简化分析,所以这个程序只考虑整数的处理。

有了上面的分析,可以构造出算符优先分析算法的流程图,如下图所示。

详细设计

(1)词法分析部分

  由于词法分析的内容在课程设计1中已经介绍,并且这次的状态转换图与课程设计1中的非常相似,所以这里就不过多介绍。

(2)优先关系表

  在程序中我们用一个二维数组priTable[][]来存储算符间的优先关系。priTable[a][b]=1表示a>b; 。priTable[a][b]=0表示a=b; 。priTable[a][b]=-1表示a<b;

(3)归约栈的设计

  由于真正要设计一个栈来处理问题有些麻烦,所以这里可以用一个数组s[]来代替栈,如图2.1所示,i就代表栈顶指针,s[i]就代表栈顶的元素。归约栈中的结点,构造一个数据结构Node来表示,Node中有三个元素,算符的单词名str、算符的种别码type、算符的数值num。当我们词法分析来扫描出一个单词的时候,就可以填充Node结点的单词名、种别码和数值。

(4)归约过程

  在问题分析中我们介绍到用文法表来进行归约,文法表graTable是一个二维数组,保存文法中算符的种别码。归约的时候,只要最左素短语的种别码匹配到文法表中的某一项,就可以按照那个归约操作来进行归约。归约的步骤参照流程图中的操作,设置栈顶指针,将栈顶结点的种别码设为非终结符,并且还要保存这一次归约产生的结果。举个例子,比如E->E+T 这次归约,E+T会产生一个结果,这个结果最终就保存在栈顶结点的数值域中。需要注意的是,Node结点中数值域的主要作用就是在归约中保存结果。

(5)变量名表

  变量名表varTable的作用是根据变量名来返回该变量的数值,是一个二元组的序列,为了方便这里采用STL模板中的map来实现。变量名表的主要用处也就是在赋值语句和表达式求值当中,比如说当有赋值语句a=5需要归约时,检查变量a是否存在于变量名表中,如果不存在就将a和5添加至变量名表,如果a存在那么就可以更新变量名表中a的数值。并且在有F->v这样的归约中,如果查找到v不在变量名表中,说明v就是一个未赋值的变量,这样就产生异常。

输入与输出

  程序的输出有:判断语法是否正确;输出表达式求值的结果;输出错误信息。

样例输入(输入来自文件in.txt):

  a = 5

  b = a + 10

  b?

  b + a * a?

  a = (a + b) * (b - a) + 5 + 4 / 2

  a?

  clear

  ab =

样例输出(输出至文件out.txt):

  a = 5 为合法句子,执行成功

  b = a + 10 为合法句子,执行成功

  b? 为合法句子,执行成功

  b 的值为 15

  b + a * a? 为合法句子,执行成功

  b + a * a 的值为 40

  a = (a + b) * (b - a) + 5 + 4 / 2 为合法句子,执行成功

  a? 为合法句子,执行成功

  a 的值为 207

  clear 为合法句子,执行成功

  ab =  语句出现语法错误!

结语

  寒假在家想尝试着做一个C语言的编译器,这几天在家里研究编译原理的龙书,顺带就把上学期编译原理的课程设计整理下发到BLOG上。

  说实话龙书里面的内容挺难的,我学过编译原理的,但是还在在第二章就卡住了,所以说我们的课程知识还是学得很浅的。这段时间还是先把基础打的牢固些吧,研究龙书一段时间,然后考虑如何做这个编译器。过几天应该就要开始着手做了,到时候开发的文档和学到的一些新知识应该都会更新到BLOG上,也算是对自己的一种总结吧。

时间: 2024-10-24 05:37:34

编译原理课程设计——语法分析器的相关文章

【编译原理课程设计】词法分析程序设计

[实验目的] (1)理解词法分析在编译程序中的作用 (2)加深对有穷自动机模型的理解 (3)掌握词法分析程序的实现方法和技术 [实验内容] 对一个简单语言的子集编制一个一遍扫描的词法分析程序. [实验要求] (1)待分析的简单语言的词法 1) 关键字 begin  if  then  while  do  end 2) 运算符和界符 :=  +  -  *  /  <  <=  >  >=  <>  =  ;  (  )  # 3) 其他单词是标识符(ID)和整形常数(

编译原理课程作业1 消除无用产生式

前言: 一年前在知乎上看到一个回答,答主说自己学了两天Python,用十几个小时做完了全部的编译原理课程作业,当时吓傻了我,现在看来,虽然两天学会比不上,但Python做课程作业的速度简直是快,课程作业1里我还傻傻的用list的extend和append,加上set函数,到第二次作业里我才发现, 没有什么结构体是一个list不能解决的,如果有,那就再套一个list 课程作业题: 消除无用产生式 # -*- coding: utf-8 -*- class Solution: def __init_

词法分析器——哈工大编译原理课程(一)

词法分析器——哈工大编译原理课程(一) 程序输入:从code.txt文件中读取内容 程序输出:识别出的单词序列,格式为:(种别码,属性值) ①对于关键字和运算符.分隔符来说,输出格式为(种别码,0),因为每个种别码能唯一地标识出是哪个单词 ②对于标识符来说,输出格式为(id的种别码即36,在哈希桶中的位置) ③对于常量(整数.浮点数.字符串)来说,输出格式为(种别码,在数组中的位置) 1 #include<stdio.h> 2 #include<stdlib.h> 3 #inclu

两周自制脚本语言-第5天 设计语法分析器

第5天 设计语法分析器 5.1 Stone语言的语法 代码清单 5.1 Stone 语言的语法定义 primary : "(" expr ")" | NUMBER | IDENTIFIER | STRING factor : "-" primary | primary expr : factor { OP factor } block : "{" [ statement ] { (";" | EOL) [

0909关于编译原理课程的认识

1.编译原理学什么?编译原理是学习编译技术的基本理论和实现技术,包括语言文法的基本知识.词法分析.语法分析.语义分析及中间代码.目标代码生成等内容: 2.为什么学编译原理?可以使我们学生既掌握编译理论和方法方面的基本知识,而且也获得设计.实现.分析.和移植编译程序方面的初步能力: 3怎么学编译原理?首先要巩固先前所学习的c,数据结构等课程,以及即将要学习的离散数学,多提疑问,多参考有关书籍,借助互联网等工具与人交流. 4.思考:在没有学习本书理论之前,如果让你写一个编译器,你是什么思路?    

自己动手写编译器之Tiny语言语法分析器的实现

接着上一篇文章介绍的Tiny语言的词法分析的实现,本文将介绍Tiny语言的语法分析器的实现. 1 Tiny语言的语法 下图是Tiny在BNF中的文法, 文法的定义可以看出,INNY语言有以下特点: 1 程序共有5中语句:if语句,repea语句,read语句,write语法和assign语句. 2 if语句以end作为结束符号,if语句和repeat语句允许语句序列作为主体. 3 输入/输出由保留字read和write开始.read语句一次只读出一个变量,而write语句一次只写出一个表达式.

哈工大2015秋 编译原理课程实验1:词法分析

经过一年的C#的历练,确实算是挺喜欢C#的了,这次的编译原理尤为用心.既已提交作业,便拿出来共享一下,或许某学弟学妹能看到呢[偷笑]. 图1 项目资源管理器截图 工程: | Class.cs 主要是Record ErrorRecord Data类的定义,存储词法分析的结果 | Form1.cs WinForm窗体 | Program.cs 自动生成的主程序 | test.cs 主要参与运算的类,通过字符的判断将分析结果及错误提示存储到Data类 运行截图: 图2 运行截图 保存文件: 图3 项目

编译原理课程作业2

NFA匹配字符串,突然意识到可以用多层的list,然后整个作业就没有难度了,递归部分一直错我都怀疑人生了,结果发现是类里的递归声明要加类名.. # -*- coding: utf-8 -*- import sys class io(): """read the NFA from file""" def __init__(self,strlist): self.strlist = strlist def i(self): if(len(sys.ar

编译原理-如何使用flex和yacc工具构造一个高级计算器

Flex工具的使用方法 Lex 是一种生成扫描器的工具. Lex是Unix环境下非常著名的工具,主要功能是生成一个扫描器(Scanner)的C源码. 扫描器是一种识别文本中的词汇模式的程序. 这些词汇模式(或者常规表达式)在一种特殊的句子结构中定义.一种匹配的常规表达式可能会包含相关的动作.这一动作可能还包括返回一个标记. 当 Lex 接收到文件或文本形式的输入时,它试图将文本与常规表达式进行匹配. 它一次读入一个输入字符,直到找到一个匹配的模式. 如果能够找到一个匹配的模式,Lex 就执行相关