编译原理---递归下降法---文法设计---LL(1)

时隔这么久,我又回来更新博客了。

编译原理这里本人就是做多少更新多少了,不定期更新,因为时间有时候比较紧,所以就不能按时更新了。

今天看了一下语法分析,要是有需要词法分析的小伙伴们可以在等一等,很快也会更新过来。文章中不免有用词不当的地方,谢谢指正。

        今天我们学习一下语法分析的LL(1)文法,LL(1)文法不是二义性的,也不是左递归的,我们要做确定的自顶向下语法分析,那么当给定一个文法,如下,本着学习并且要体验创造乐趣的我们,干脆自己写一个文法了,我就不直接用书上的例子了,我们要判定一个加,乘,括号和数字的式子是否符合我们的文法,文法如下。

      E\rightarrow E+E|E*E|(E)|a

这个文法粗糙了点,一看就不是LL(1)文法,我们要将其整理成符合LL(1)文法规则的文法,为了不让文章篇幅过大,这里不会展开整理的过程(相关知识会在别的文章里更新出),我直接写出结果。

E\rightarrow iF|(E)F

F\rightarrow +EF|*EF|\varepsilon

整理完之后我也吓一跳,和书上的完全不同,可能是因为我对加,乘,括号之间没定义优先级的原因,不过这个文法还是符合LL(1)文法的。暂时不知道有什么弊端,我觉得可能会导致递归树过深。

现在可以编写代码了。源文件见群文件(qq群:417801511)

#include
using namespace std;
char code[128];//字符串
int i = 0;//字符串下标
bool isError = false;//当有一个位置出错了,则不会显示第二个位置的错误
void GrammarE();
void GrammarF();
/*获取下一个字符*/
char nextSymbol()
{
	return code[++i];
}
/*访问当前的字符*/
char nowSymbol()
{
	return code[i];
}
/*语法E*/
void GrammarE()
{
	switch (nowSymbol())
	{
	case '(':
		nextSymbol();
		GrammarE();
		switch (nowSymbol())
		{
		case ')':
			nextSymbol();
			GrammarF();
			break;
		default:
			if (!isError)
			{
				cout << "error: at col " << i+1 << endl;
				cout << endl;
				isError = true;
			}
			break;
		}
		break;
	case 'a':
		nextSymbol();
		GrammarF();
		break;
	default:
		if (!isError)
		{
			cout << "error: at col " << i+1 << endl;
			cout << endl;
			isError = true;
		}
		break;
	}
}
/*语法F*/
void GrammarF()
{
	switch (nowSymbol())
	{
	case '+':
	case '*':
		nextSymbol();
		GrammarE();
		GrammarF();
		break;
	default:
		break;
	}
}
int main()
{
	while (1)
	{
		cin >> code;
		GrammarE();
		//当分析结束后,测试中途中断说明有错误
		if (strlen(code) != i)
		{
			if (!isError)
			{
				cout << "error: at col " << i+1 << endl;
				cout << endl;
				isError = true;
			}
			isError = true;
		}
		//没有错误,显示成功
		if (!isError)
		{
			cout << "succeed" << endl;
			cout << endl;
		}
		isError = false;
		i = 0;
	}
	return 0;
}
/*
测试数据集:
a
(a)
a+a
(a+a)*a
a+a)
a)
()
aaa
a*a
a+(a+a)*a*(a+a*(a+a))
((((a))))
(((a)))+(((a+a)))*(a+a+(((a))))
a+a+b
a++
a+a++
a+(a+)
a*(a+(+))
)))
(((
((a)
(a))
*/

如果想把减法和除法也加进来,可以修改一下语法F

F\rightarrow +EF|*EF|-EF|/EF|\varepsilon

之后修改代码如下。

/*语法F*/
void GrammarF()
{
	switch (nowSymbol())
	{
	case '+':
	case '*':
	case '-':
	case '/':
		nextSymbol();
		GrammarE();
		GrammarF();
		break;
	default:
		break;
	}
}
/*
a-a
a/a-a
a-a*a
a/(a+a-(a+a)/a)
a//
a++
a--
a/*-+
*/

这样也能识别减法和除法了。

给出一个运行图片。

编译原理---递归下降法---文法设计---LL(1)_第1张图片

我们最后要把零碎的东西组合在一起,会有意想不到的惊喜。

ARTELE

你可能感兴趣的:(编译原理,语法分析,LL(1),编译器,编译原理)