编译原理实验五:对算术表达式的递归下降分析

本文档详细介绍了如何根据上下文无关文法,使用C++编程实现构造算术表达式的语法树。程序采用递归子程序法,解析加减乘除运算及括号表达式,并通过输出语法树验证算术表达式的合法性。同时,文章讨论了LL(1)文法的特性,以及在程序中处理算术表达式时避免左递归的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

实验要求

【任务介绍】根据给定的上下文无关文法,分析任意一个算术表达式的语法结构。

【输入】任意的算术表达式。

【输出】与输入对应的一颗语法树或者错误。

【题目】设计一个程序,根据给定的上下文无关文法,构造一颗语法树来表达任意一个算术表达式的语法结构。要求:

1.基础文法:

<Expr> → <Term> <Expr1> 
<Expr1> → <AddOp> <Term> <Expr1> | empty 
<Term> → <Factor> <Term1> 
<Term1> → <MulOp> <Factor> <Term1> | empty 
<Factor> → id |number | ( <Expr> ) 
<AddOp> → + | - 
<MulOp> → * | /

2.语法分析方法采用递归子程序法。

3.输入:形如x*1+2的算术表达式,有+、-、*、/ 四种运算符,运算符的优先级、结合规则和括号的用法遵循惯例,有变量、整数两种运算对象。为简化问题,变量和整数均为只含有1个字符的单词,忽略空格等非必要的字符。

4.输出:输入正确时,输出其对应的语法树,树根标记为;输入错误时,输出error。

编译环境和语言

编程语言:C++

IDE:vs 2019

实验原理分析

对于给定文法定义:

<Expr> → <Term> <Expr1> 
<Expr1> → <AddOp> <Term> <Expr1> | empty 
<Term> → <Factor> <Term1> 
<Term1> → <MulOp> <Factor> <Term1> | empty 
<Factor> → id |number | ( <Expr> ) 
<AddOp> → + | - 
<MulOp> → * | /

起始点为,因为采用的是LL(1)文法,所以需要不断左递归遍历,直到递归到终结字符,才会回溯,继续走另一条路,以此类推,直到最终回溯到。

对于LL(1)文法,即分析表不含多重定义入口的文法,换言之,直到不得不用右部表达式代替左部表达式的时候,再进行替换,形如:

<Expr> → <Expr><Term1> | <Expr><Term2>

就会导致不断的左递归而无法停止,这是因为在右部表达式的最左边,而我们又是使用的左递归,因此这就不是LL(1)文法。

程序关键部分分析

定义

string str = "";  //用来存储算术表达式
int location = 0;  //用来定位算术表达式
bool flag = true;  //用来判断该算术表达式是否合法
string tree_map[100];  //用来存储语法树
const int width = 3;  //设置间隔为3

int draw_line(int row, int num);
void string_out(string s, int row, int column);
void word_out(char ch, int row, int column);
int tree_out(string s, int row, int loc);
void print_tree();
int Expr(int row, int column);
int Expr1(int row, int column);
int Term(int row, int column);
int Term1(int row, int column);
int Factor(int row, int column);
bool AddOp(char ch);
bool MulOp(char ch);

关键部分分析

首先是draw_line(int row, int num)函数,用来画横线隔开兄弟节点,长度为num:

int draw_line(int row, int num) {  //用来画横线,隔开兄弟节点,返回下次开始的起始位置
	int n = tree_map[row].size();
	tree_map[row].append(num, '-');
	return tree_map[row].size();
}

对于string_out(string s, int row, int column),用来将对应的数据存储到对应的位置上,首先需要判断输入的column是否与对应行数的长度相等,若不想等,则由于string数据类型的特性,必须将这中间部分填充上空格:


                
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

花无凋零之时

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值