语法分析小程序。简单判断赋值、条件、循环,代码块开始,结束
二、 实验要求
1.待分析的简单语言的语法
用扩充的EBNF表示如下:
<程序块>::= begin<语句>{;<语句>} end.
<语句>::= <赋值语句>|<条件语句>|<循环语句>
<赋值语句>::= IDENT:=<表达式>
<条件语句>::= if <条件>then <语句>
<循环语句>::= while <条件> do <语句>
<表达式>::= [+|-]<项>{(+|-)<项>}
<项>::= <因子>{(*|/)<因子>}
<因子>::= IDENT | NUMBER |‘(’<表达式>‘)’
<条件>::= <表达式><关系运算符><表达式>
<关系运算符>::= <>|=|<|<=|>|>=
2. 实验要求说明
输入单词串,以“.”结束,如果是文法正确的句子,则输出成功信息,否则输出失败信息,指出错误原因。需要系统地规划错误码。 例如:
输入 begina:=2*3 end.
输出 syntaxparses success!
输入 beginx=4 end.
输出 Error 11: 没有检测到赋值语句的:=符号
输入 beginx:=2;while x>0 do if x/2=0 then x:=(x/2) end.
输出 syntaxparses success!
3. 语法分析设计说明
采用递归下降分析程序。为每个非终结符编写一个子过程。
设计思路
1.变量说明
line 从终端读入的字符串;
p 当前所指位置在计数器,
ch 字符为
token 正在识别的单词字符串;
m 当前所指位置在计数器
num 整型常数
sym 每个单词符号种类
word 保留字表
Err 错误类型标记
flag 出错标记
2.函数说明
void getsym(); //判断输入字符类型
int block(); //程序快分析函数
void error(int i); //出错处理函数
void statement(); //语句处理函数
void expression(); //表达式处理函数
void term(); //项处理函数
void factor(); //因子处理函数
void condition(); //条件处理函数
void Relational_operator(); //表达式处理函数
void printSym(int i) //打印输入字符的类型
接下来举例说明几个重要函数
1).getsym()函数示意图
2).main()函数示意图
3)block()函数示意图
3).error()函数示意图
错误序号 |
出错原因 |
1 |
没有检测到语句期望begin符号 |
2 |
没有检测到赋值语句的 := 符号 |
3 |
没有检测到条件语句的 then 符号 |
4 |
没有检测到循环语句的 do 符号 |
5 |
错误的句子! |
6 |
你写了数字! |
7 |
没有检测到 '(' 的 ')' 符号 |
8 |
没有检测到因子 |
9 |
没有检测到关系运算符 |
11 |
没有检测到语句期望 end 符号 |
4). statement ()函数示意图
二、 实验截图
输入 begin a:=2*3 end.
输出 syntax parses success!
输入 begin x=4 end.
输出 Error 11: 没有检测到赋值语句的:=符号
输入 begin x:=2;while x>0 do if x/2=0 then x:=(x/2) end.
输出 syntax parses success!
实验总结
1.这个结合上次作业增加了对注释部分的语句处理
2.为解决出错就直接函数返回增加了flag布尔型变量,处理出错的及时报错,函数返回
3.在出错处理上参考了现在主流的编译器gcc,g++,发现他们是遇到出错的点直接报错,递归不返回。
例如:begin x=4end.
这句话,缺少:=符号,但是编译器只报赋值符号缺少,不会返回报错赋值语句出错,语句出错,程序块出错这种错误。
但是如果有这个需求,只需要把flag一个一个递归返回传值就好
代码:
#include
using namespace std;
/*
变量说明:
line 从终端读入的字符串; 当前所指位置在计数器 p
token 为存放的单词自身字符串;当前所指位置在计数器 m
number 整型常数
sym 每个单词符号种类
*/
enum symbol
{
period=0,
ident=1,
number=2,
Plus=3,
Minus=4,
times=5,
slash=6,
eql=7,
neq=8,
lss=9,
leq=10,
gtr=11,
geq=12,
lparen=13,
rparen=14,
semicolon=15,
becomes=16,
beginsym=17,
endsym=18,
ifsym=19,
thensym=20,
whilesym=21,
dosym=22,
note=23,
nil=24,
};
char line[100],token[10],ch;
char s2[10];
enum symbol sym;
int p,m, num;
char *word[6]= {"begin","end", "if","then","while","do"};
int Err;
bool flag=true;
bool flag2=false;
bool flag3=false;
void getsym();
int block();
void error(int i);
void statement();
void expression();
void term();
void factor();
void condition();
void Relational_operator();
int main()
{
freopen("t1.txt","r",stdin);
//读了字符串, 直到遇.结束
p=0;
printf("\n please input a string(end with '.'): ");
do
{
scanf("%c",&ch);
line[p++]=ch;
}
while(ch!='.');
line[p++]='\0';
//逐个单词扫描;
Err = 0;
p=0;
getsym(); //当前扫描的单词存放在sym中
block();
if ((sym==0)&&(Err==0))
printf("syntax parses success!\n");
return 0;
}
void printSym(enum symbol sym)
{
/************************************************
**** ****
**** TODO: 输出单词 ****
**** ****
*************************************************/
switch(sym)
{
case period:
return;
case number:
printf("%d ",num);
break;
case nil:
printf("you have input a wrong string\n");
break;
case note:
//printf("this is notes\n");
break;
case Plus:
printf("+");
break;
case Minus:
printf("-");
break;
case times:
printf("*");
break;
case slash:
printf("/");
break;
case eql:
printf("=");
break;
case neq:
printf("><");
break;
case lss:
printf("<");
break;
case leq:
printf("<=");
break;
case gtr:
printf(">");
break;
case geq:
printf(">=");
break;
case lparen:
printf("( ");
break;
case rparen:
printf(") ");
break;
case semicolon:
printf("; ");
break;
case becomes:
printf(":= ");
break;
case beginsym:
printf("\nbegin ");
break;
case endsym:
flag3=true;
printf("print( %s ) ",s2);
printf("end\n");
break;
case ifsym:
printf("if ");
break;
case thensym:
printf("then ");
break;
case whilesym:
printf("while ");
break;
case dosym:
printf("do ");
break;
case ident:
printf("%s ",token);
break;
default:
break;
}
}
void getsym()
{
for(m=0; m<8;m++) token[m++]=NULL;
ch=line[p++];
m=0;
/************************************************
**** ****
**** TODO: 单词识别 ****
**** ****
*************************************************/
while((ch==' '||ch=='\n')) ch=line[p++];
//字母打头的字符串;标识符
if((ch<='z'&&ch>='a')||(ch<='Z'&&ch>='A'))
{
do
{
token[m++]=ch;
ch=line[p++];
}while((ch<='z'&&ch>='a')||(ch<='Z'&&ch>='A')||(ch<='9'&&ch>='0'));
sym=ident;
token[m++]='\0';
ch=line[p--];
for(int n=0;n<6;n++)
{
if(strcmp(token,word[n])==0)
{
if(n==0) sym=beginsym;
else if(n==1) sym=endsym;
else if(n==2) sym=ifsym;
else if(n==3) sym=thensym;
else if(n==4) sym=whilesym;
else if(n==5) sym=dosym;
break;
}
}
/*TODO识别标识符IDENT和保留字*/
}
else if((ch<='9'&&ch>='0'))
{
num=0;
do{
num=num*10+ch-'0';
ch=line[p++];
}while((ch<='9'&&ch>='0'));
ch=line[p--];
sym=number;
/*TODO识别数字NUMBER*/
}
else {
switch(ch)
{
case ':': //赋值符号
token[m++]=ch;
ch=line[p++];
if(ch=='=')
{
sym=becomes;
token[m++]=ch;
}
else{
sym=nil;
}
break;
case '<': //<=和<符号
token[m++]=ch;
ch=line[p++];
if(ch=='=')
{
token[m++]=ch;
sym=leq;
}
else if(ch=='>'){
token[m++]=ch;
sym=neq;
}
else{
sym=lss;
p--;
}
break;
case '>': //>=和>符号
token[m++]=ch;
ch=line[p++];
if(ch=='=')
{
sym=geq;
token[m++]=ch;
}
else{
sym=gtr;
p--;
}
break;
case '+':
sym=Plus;
token[m++]=ch;
break;
case '-':
sym=Minus;
token[m++]=ch;
break;
case '*':
sym=times;
token[m++]=ch;
break;
case '/':
ch=line[p++];
if(ch=='*'){
//cout<<"in\n";
char fr;//前面的一个符号
fr='*';
ch=line[p++];
while(1){
fr=ch;
ch=line[p++];
if(fr=='*'&&ch=='/') break;
}
sym=note;
token[m++]=ch;
}
else
{
sym=slash;
token[m++]=ch;
p--;
}
break;
case '=':
sym=eql;
token[m++]==ch;
break;
case '(':
sym=lparen;
token[m++]=ch;
break;
case ')':
sym=rparen;
token[m++]=ch;
break;
case ';':
sym=semicolon;
token[m++]=ch;
break;
case '.':
sym=period;
token[m++]=ch;
break;
case ' ':
token[m++]=ch;
break;
default:
sym=nil;
break;
}
}
token[m++]='\0';
//如果想看分析的每一个sym,请打开这个注释
printSym(sym);
//处理语句分析中的注释
if(sym==note) getsym();
}
void error(int i)
{
switch (i)
{
case 1:
printf("Error %d: 没有检测到语句期望begin符号\n", i);
break;
case 2:
printf("Error %d: 没有检测到赋值语句的 := 符号\n",i);
break;
case 3:
printf("Error %d: 没有检测到条件语句的 then 符号\n",i);
break;
case 4:
printf("Error %d: 没有检测到循环语句的 do 符号\n",i);
break;
case 5:
printf("Error %d: 错误的句子!\n",i);
break;
case 6:
printf("Error %d: 你写了数字!\n",i);
break;
case 7:
printf("Error %d: 没有检测到 '(' 的 ')' 符号\n",i);
break;
case 8:
printf("Error %d: 没有检测到因子\n",i);
break;
case 9:
printf("Error %d: 没有检测到关系运算符\n",i);
break;
case 11:
printf("Error %d: 没有检测到语句期望 end 符号\n", i);
break;
default:
break;
}
flag=false;
Err++;
}
int block()
{
//cout<<"程序块分析\n";
if (sym != beginsym)
{
error(1);
}
else
{
getsym();
statement(); //语句处理
while (sym == semicolon)
{
getsym();
statement(); //语句处理
}
if (sym != endsym&&flag)
{
error(11);
}
getsym();
}
return 0;
}
void statement()
{
/********************************************
**** TODO: 语句处理(赋值/条件/循环) *****
*******************************************/
flag2=false;
//cout<<"语句处理\n";
if(sym==ident)
{
flag2=true;
flag3=false;
for(int i=0;i