文章目录
前言
经过这段时间对编译原理中语法分析的学习,掌握了一定语法分析器设计的理论知识,下面就利用这些理论知识,使用递归下降分析实现一个简单的语法分析器。
一、实验内容
对下列算术表达式的文法编写递归下降分析程序,要求对输入的任意符号串进行语法分析:
(1)E->TE’
(2)E’->+TE’ | —TE’ |ε
(3)T->FT’
(4)T’->*FT’ | /FT’ |ε
(5)F->(E) | id | num
注:文法中id表示标识符(此处标识符的定义与实验一中标识符的定义相同),num表示数字(简单处理可以认为是整数)
二、实验要求
1、 输入/输出格式
输入一个字符串,输出该字符串是否为正确的句子。
例如:输入a+xyz*10+(c/d),输出“正确的表达式”
输入a+*xyz,输出“错误的表达式”
2、上述要求仅为基本要求,可以在此基础上扩充
例如数字可以允许是浮点数,增加错误处理,输出错误信息等。
例:输入a+*xyz,输出“表达式错误:缺少运算数”
进一步可以指出出错的位置。
三、设计
1、首符集(FIRST)
1、定义
2、算法
3、计算上述语法的首符集
2、尾符集(FOLLOW)
1、定义
2、算法
3、计算上述语法的尾符集
3、可选集(SELECT)
1、定义
2、算法
3、计算上述语法的可选集
4、语法分析器类(Parser)设计
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ReDescentAnaly
{
/// <summary>
/// 该类用来描述递归下降法设计的语法分析器
/// </summary>
class Parser
{
char elem; //记录逐个获取的表达式字符
int i = 0; //记录获取的位置
bool err = false; //false正确 true错误
//记录要进行判断的表达式
String express;
public String Express
{
get { return express; }
set { express = value; }
}
//记录错误原因
String errReson;
public String ErrReson
{
get { return errReson; }
}
//记录错误位置
int errLie;
public int ErrLie
{
get { return errLie; }
}
//逐个获取表达式中的字符
public void GetElem()
{
elem = express.ToCharArray()[i];
if (elem != '$')
{
i++;
}
}
//(1)E->TE'
public void E()
{
T();
E1();
}
//(2)E'->+TE' | —TE' |ε
public void E1()
{
if ((elem == '+')||(elem == '-'))
{
GetElem();
T();
E1();
}
}
//(3)T->FT'
public void T()
{
F();
T1();
}
//(4)T'->*FT' | /FT' |ε
public void T1()
{
if ((elem == '*') || (elem == '/'))
{
GetElem();
F();
T1();
}
}
//(5)F->(E) | id | num
public void F()
{
if(elem=='(') //左括号
{
GetElem();
E();
if(elem==')') //判断完'('后,要判断之后之后的串中是否存在')'
{
GetElem();
}
else
{
Error("缺少‘)’");
}
}
else if(elem>='0'&&elem<='9') //数字
{
int flag=0;
for(;(elem>='0'&&elem<='9')||elem=='.';)
{
if(elem>='0'&&elem<='9')
{
GetElem();
}
if(elem=='.')
{
GetElem();
flag++;
}
if(flag>=2)
{
Error("小数点过多");
break;
}
if(elem>='a'&&elem<='z')
{
Error("运算数后不能带有字母");
break;
}
if (elem == '(')
{
Error("运算数后不能直接带上左括号");
break;
}
}
}
else if(elem>='a'&&elem<='z') //字母
{
for(;(elem>='a'&&elem<='z');)
{
GetElem();
}
if (elem == '(')
{
Error("标识符后不能直接带有左括号");
}
}
else
{
Error("缺少运算数");
}
}
///错误处理
public void Error(string reson)
{
if (err == false)
{
err = true;
errReson = reson;
errLie = i;
}
}
//判断语法检验结果是否正确
public bool IsError()
{
return err;
}
//判断表达式是否为空
public bool IsEmpty()
{
return express.ToCharArray()[0]=='$';
}
}
}
5、语法分析器的界面实现
1、界面设计
1、表达式输入框:这是一个TextBox控件,可读可写,然后将其取名为textBox1
2、分析结果输出框:这是一个TextBox控件,设置ReadOnly属性为true,使其成为只读不可写,然后将其取名为textBox2
3、分析按钮:这是一个Button控件,为其绑定点击事件Analy,然后将其取名为AnalyBtn
2、结合Parser类实现语法分析器
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ReDescentAnaly
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Analy(object sender, EventArgs e)
{
string s = textBox1.Text + "$";
Parser parser = new Parser();
parser.Express = s;
parser.GetElem(); //获取表达式的首个字符
if (parser.IsEmpty()) //如果表达式为空
{
textBox2.Text = "表达式不能为空";
}
else //表达式不为空
{
parser.E(); //进行语法分析
if (!parser.IsError())//正确
{
textBox2.Text = "正确的表达式";
}
else //错误
{
textBox2.Text = "表达式错误:" + parser.ErrReson + ",错误位置在第" + parser.ErrLie + "个字符处。";
}
}
}
}
}
四、测试方案及测试结果
1、 测试表达式:a+xyz*10+(c/d)
2、 测试表达式:a+*xyz
3、 测试表达式:3.14*5+(10/b)
结语
本次内容的介绍就到这里,希望这篇文章能够给努力学习的你一些帮助,感谢各位人才的:点赞、收藏和评论,我们下次见。