【开发语言及实现平台或实验环境】
C++/Clion
【实验目的】
(1)理解语法分析在编译程序中的作用,以及它与词法分析程序的关系
(2)加深对递归下降语法分析原理的理解
(3)掌握递归下降语法分析的实现方法
【实验内容】
编制一个递归下降分析程序,实现对词法分析程序提供的单词序列的语法检查和结构分析。
【实验要求】
(1)待分析的简单语言的词法同实验1
(2)待分析的简单语言的语法
用扩充的BNF表示如下:
1)<程序>::=begin<语句串>end
2) <语句串>::=<语句>{;<语句>}
3) <语句>::=<赋值语句>
4) <赋值语句>::=ID:=<表达式>
5) <表达式>::=<项>{+<项>|-<项>}
6) <项>::=<因子>{*<因子>|/<因子>}
7) <因子>::=ID|NUM|(<表达式>)
(3)语法分析程序的功能
输入单词串以”#”结束,如果是文法正确的句子,输出成功信息;否则输出错误信息。
例如:
输入 begin a:=9; x:=2 * 3; b:=a + x end #
输出 success
输入 x:=a + b * c end #
输出 error
【实验步骤】
(1)根据图2.1递归下降分析程序示意图构建主程序框架
(2)编写各语法单位分析函数
1)编写语句串及语句分析函数
代码提示:
yucu()//语句串分析函数
{
调用statement();//语句分析函数
while(syn=26){
读入下一个单词符号;
调用statement();
}
return;
}
statement()
{
if(syn=10){
读入下一个单词符号;
if(syn=18)
{
读入下一个单词符号;
调用expression函数;//表达式分析函数
}
else{输出赋值号错误;kk=1//出错标记}
}
else{输出语句号错误;kk=1;}
return;
}
2)编写表达式分析过程
3)编写项分析过程
4)编写因子分析过程
(3)调试程序,验证输出结果
【实验代码】
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
char prog[80], token[8];
char ch;
int syn, p, m, n, sum, kk;
char *pString[6] = {"begin", "if", "then", "while", "do", "end"};
int scanner(); //调用scanner函数
int lrparscr(); //调用lrparscr函数
int yucu(); //调用yucu函数
int statement(); //调用statement函数
int expression(); //调用expression函数
int term(); //调用term函数
int factor(); //调用factor函数
int main() {
p = 0;
cout << "\nPlease input string:" << endl;
do {
cin.get(ch);
prog[p++] = ch; //输入源程序字符串,送到缓冲区prog[p++]中
} while (ch != '#');
p = 0;
kk = 0;
scanner();
lrparscr();
getchar();
getchar();
return 0;
}
int lrparscr() {
if (syn == 1) {
scanner(); //读下一个单词符号
yucu();
if (syn == 6) { //syn=6 对应单词符号end
scanner(); //读下一个单词符号
if ((syn == 0) && (kk == 0))
printf("success!\n");
} else if (kk != 1) {
cout << "出现缺end错误!" << endl;
kk = 1;
}
} else {
cout << "出现缺begin错误!" << endl;
kk = 1;
}
return 0;
}
int yucu() { //语句串分析函数
statement();
while (syn == 26) {
scanner(); //读下一个单词符号
statement(); //调用statement函数
}
return 0;
}
int statement() {
if (syn == 10) {
scanner(); //读下一个单词符号
if (syn == 18) {
scanner(); //读下一个单词符号
expression();
} else {
cout << "出现赋值号错误!" << endl;
kk = 1;
}
} else {
cout << "出现语句错误!" << endl;
kk = 1;
}
return 0;
}
int expression() {
term();
while ((syn == 13) || (syn == 14)) {
scanner(); //读下一个单词符号
term();
}
return 0;
}
int term() {
factor();
while ((syn == 15) || (syn == 16)) {
scanner(); //读下一个单词符号
factor();
}
return 0;
}
int factor() {
if ((syn == 10) || (syn == 11)) //是否是标识符或整型常数
scanner(); //读下一个单词符号
else if (syn == 27) { // 是否是 (
scanner(); //读下一个单词符号
expression();
if (syn == 28) // 是否是 )
syn = scanner(); //读下一个单词符号
else {
cout << "出现 ) 错误!" << endl;
kk = 1;
}
} else {
cout << "出现表达式错误!" << endl;
kk = 1;
}
return 0;
}
int scanner() {
for (n = 0; n < 8; n++) token[n] = '\0';
ch = prog[p++]; //读下一个单词符号并赋给ch
while (ch == ' ') { //如果是空格,读下一字符
ch = prog[p];
p++;
}
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) { //如果是字母字符
m = 0;
while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) { //如果是字母字符
token[m++] = ch; //当前字符送入token
ch = prog[p++]; //读下一个单词符号并赋给ch
}
token[m++] = '\0'; //单词结束
p--; //回退一个字符
syn = 10; //标识符
for (n = 0; n < 6; n++) //与关键字表进行比较,确定syn的值
if (strcmp(token, pString[n]) == 0) {
syn = n + 1; //给出syn值
break;
}
} else if ((ch >= '0' && ch <= '9')) { //如果是数字字符
{
sum = 0;
while ((ch >= '0' && ch <= '9')) { //如果是数字字符
sum = sum * 10 + ch - '0'; //ch送入sum,并更新数字
ch = prog[p++]; //读下一个单词符号并赋给ch
}
}
p--; //回退一个字符
syn = 11; //数字字符
if (sum > 32767)
syn = -1; //出现错误
} else
switch (ch) { //其他字符时
case '<':
m = 0;
token[m++] = ch;
ch = prog[p++]; //读下一个单词符号并赋给ch
if (ch == '>') {
syn = 21; //不等于
token[m++] = ch;
} else if (ch == '=') {
syn = 22; //小于等于
token[m++] = ch;
} else {
syn = 23; //大于
p--; //回退一个字符
}
break;
case '>':
m = 0;
token[m++] = ch;
ch = prog[p++]; //读下一个单词符号并赋给ch
if (ch == '=') {
syn = 24; //大于等于
token[m++] = ch;
} else {
syn = 20; //小于
p--; //回退一个字符
}
break;
case ':':
m = 0;
token[m++] = ch;
ch = prog[p++]; //读下一个单词符号并赋给ch
if (ch == '=') {
syn = 18; //等于
token[m++] = ch;
} else {
syn = 17; //冒号:
p--;
}
break;
case '+':
syn = 13;
token[0] = ch;
break;
case '-':
syn = 14;
token[0] = ch;
break;
case '*':
syn = 15;
token[0] = ch;
break;
case '/':
syn = 16;
token[0] = ch;
break;
case '=':
syn = 25;
token[0] = ch;
break;
case ';':
syn = 26;
token[0] = ch;
break;
case '(':
syn = 27;
token[0] = ch;
break;
case ')':
syn = 28;
token[0] = ch;
break;
case '#':
syn = 0;
token[0] = ch;
break;
case '\n':
syn = -2;
break;
default:
syn = -1;
break;
}
return syn;
}
【运行结果】