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

实验目的

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

实验内容与要求

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

文法表示  

    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上,也算是对自己的一种总结吧。

 

转载于:https://www.cnblogs.com/H-Vking/p/5171374.html

java编程 含有界面 以及完整代码 〈程序〉→ main()〈语句块〉 〈语句块〉→{〈语句串〉} 〈语句串〉→〈语句〉;〈语句串〉|〈语句〉; 〈语句〉→〈赋值语句〉|〈条件语句〉|〈循环语句〉 〈赋值语句〉→ ID =〈表达式〉; 〈条件语句〉→ if〈条件〉〈语句块〉 〈循环语句〉→ while〈条件〉〈语句块〉 〈条件〉→(〈表达式〉〈关系符〉〈表达式〉) 〈表达式〉→〈表达式〉〈运算符〉〈表达式〉|(〈表达式〉)|ID|NUM 〈运算符〉→+|-|*|/ 〈关系符〉→<|<=|>|>=|=|!> word.wordList包(存储了关键字): word:此类是定义了存储关键字的结构:包括String型的关键字,和int型的识别符。 wordList:此类存储了29个关键字,在构造函数中初始化。 2、word包(进行词法分析)中: basicFunction:此类定义了做词法分析的基本函数: GetChar()将下一输入字符读到ch中,搜索知识器前移一个字符位置 GetBC();检查ch中的字符是否为空白。若是,则调用GetChar直至不 是字符为止 Concat();将ch中的字符连接到strToken之后 IsLetter();判断ch中的字符是否为字母 IsDigit();判断ch中的字符是否为数字 Reserve();对strToken中的字符创查找保留字表,若是则返回它的编码,否则返回0 Retract();将搜索指示器回调一个字符位置 RetractStr();将strToken置空 lexAnalysis:此类是用来进行词法分析,将分析后的单词存入word数组中,(注:在词法分析中,若是一串字母,则认为是ID,若是数字,则认为是NUM。存储的时候识别符分别存ID与NUM的识别符,但是内容仍然是自己的内容) 其中的wordAnalysis函数就是词法分析函数(具体实现请看后面的重要函数分析) 3、stack包(定义栈)中: 栈是通过链表来定义的,因此 StringListElement:次类定义了链表的每一个节点 StringStrack:此类定义了栈,其中有长度属性,有函数: Top();用来取得栈顶 Push();压栈 Pop();出栈 4、sentence包(语法分析)中: juzi :定义了文法的句子的结构:key(左边部分) content[](右边推出的部分) lo(长度) grammar :存储了文法的27个关系式 AnalysisFB :定义了分析表的存储结构 AnalysisF :存储分析表 SentenceAnalysis :语法分析 JuProduction(word w):此函数是用来判断在当前栈与输入串的情况下,用哪一个产生式,返回产生式在数组中的下标 若输入串的第一个字符与栈顶字符相同则表示可以规约,则返回-1; 若不能过用产生式,则返回-2; AnalysisBasic(word w):此函数是分布进行语法分析,对栈操作 * 根据所需要的产生式对符号栈进行操作 * 返回0表示规约;返回1表示移进;否则表示输入串不是文法的句子 5.Main包(主界面)中 Main:此类定义了图形界面
这个里面的都是测试数据,总共得分5分。从控制台输入,不能从文件中读取。实现了基本功能,加分项目都没有去实现,没有函数数组这些的实现。这是用C++语言写的,新建parser类别要选C++,其他对于VS的配置和C语言一样。for语句用的是枚举所有情况,你可以自行修改。 对预备工作中自然语言描述的简化C编译器的语言特性的语法,设计上下文无关文法进行描述 借助Yacc工具实现语法分析器 考虑语法树的构造: 1.语法树数据结构的设计:节点类型的设定,不同类型节点应保存哪些信息,多叉树的实现方式 2.实现辅助函数,完成节点创建、树创建等功能 3.利用辅助函数,修改上下文无关文法,设计翻译模式 4.修改Yacc程序,实现能构造语法树的分析器 考虑符号表处理的扩充 1.完成语法分析后,符号表项应增加哪些标识符的属性,保存语法分析的结果 2.如何扩充符号表数据结构,Yacc程序如何与Lex程序交互,正确填写符号表项 以一个简单的C源程序验证你的语法分析器,可以文本方式输出语法树结构,以节点编号输出父子关系,来验证分析器的正确性,如下例: main() { int a, b; if (a == 0) a = b + 1; } 可能的输出为: 0 : Type Specifier, integer, Children: 1 : ID Declaration, symbol: a Children: 2 : ID Declaration, symbol: b Children: 3 : Var Declaration, Children: 0 1 2 4 : ID Declaration, symbol: a Children: 5 : Const Declaration, value:0, Children: 6 : Expr, op: ==, Children: 4 5 7 : ID Declaration, symbol: a Children: 8 : ID Declaration, symbol: b Children: 9 : Const Declaration, value:1, Children: 10: Expr, op: +, Children: 8 9 11: Expr, op: =, Children: 7 10 12: if statement, Children: 6 11 13: compound statement, Children: 3 12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值