语法分析——简单判断条件语句,赋值语句,循环语句

语法分析小程序。简单判断赋值、条件、循环,代码块开始,结束

二、     实验要求

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()函数示意图

语法分析——简单判断条件语句,赋值语句,循环语句_第1张图片

2).main()函数示意图

语法分析——简单判断条件语句,赋值语句,循环语句_第2张图片

3)block()函数示意图

语法分析——简单判断条件语句,赋值语句,循环语句_第3张图片

3).error()函数示意图

错误序号

出错原因

1

没有检测到语句期望begin符号

2

没有检测到赋值语句的 := 符号

3

没有检测到条件语句的 then 符号

4

没有检测到循环语句的 do 符号

5

错误的句子!

6

你写了数字!

7

没有检测到 '(' 的 ')' 符号

8

没有检测到因子

9

没有检测到关系运算符

11

没有检测到语句期望 end 符号


4). statement ()函数示意图

语法分析——简单判断条件语句,赋值语句,循环语句_第4张图片

二、     实验截图

 

输入  begin a:=2*3 end.

输出  syntax parses success!

语法分析——简单判断条件语句,赋值语句,循环语句_第5张图片

 

输入  begin x=4 end.

输出  Error 11: 没有检测到赋值语句的:=符号

语法分析——简单判断条件语句,赋值语句,循环语句_第6张图片

输入 begin x:=2;while x>0 do if x/2=0 then x:=(x/2) end.

输出  syntax parses success!

语法分析——简单判断条件语句,赋值语句,循环语句_第7张图片

 

   实验总结

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




你可能感兴趣的:(编译原理)