1. 程式人生 > >編譯原理實驗 —— 語法分析器

編譯原理實驗 —— 語法分析器

/*
待分析的簡單語言的語法
用擴充的BNF表示如下:
⑴<程式>::=begin<語句串>end
⑵<語句串>::=<語句>{;<語句>}
⑶<語句>::=<賦值語句>
⑷<賦值語句>::=ID:=<表示式>
⑸<表示式>::=<項>{+<項> | -<項>}
⑹<項>::=<因子>{*<因子> | /<因子>
⑺<因子>::=ID | NUM | (<表示式>)
*/

#include "stdio.h"
#include "string.h"
char prog[100],token[8],ch;//prog[100],用來儲存要處理的物件,token用來與關鍵字比較,ch用來儲存一個字元
char *rwtab[6]={"begin","if","then","while","do","end"};//關鍵字表
int syn,p,m,n,sum;
/*syn是種別碼,p為prog陣列的指標,m為token陣列的指標,n為rwtab陣列的指標,sum為詞法分析器裡的數字數值大小*/
int flag;//flag與判斷是否end有關

void factor(void);//因式 factor
void expression(void);//表示式 expression
void yucu(void);
void term(void);//項 term
void statement(void);// 語句 statement
void parser(void);
void scaner(void);//掃描器


int main(void)
{
	p=flag=0;
	printf("\nplease input a string (end with '#'): \n");

    /*從命令列讀取要處理的物件,並存儲在prog[]陣列中*/
	do
	{
		scanf("%c",&ch);
		//printf("\n input %c now\n",ch);
		prog[p++]=ch;
	}while(ch!='#');

	p=0;
	scaner();//主要完成賦值種別碼等詞法分析功能
	parser();//呼叫各種遞迴子程式,完成語法分析的過程
	//getch();
}

/*呼叫各種遞迴子程式,完成語法分析的過程*/
void parser(void)
{
	if(syn==1)//begin
	{
		scaner();       /*讀下一個單詞符號*/
		yucu();         /*呼叫yucu()函式;*/

		if(syn==6)//end
		{
			scaner();
			if((syn==0)&&(flag==0))//出現#且flag=0
			printf("success!\n");
		}
		else
		{
			if(flag!=1) printf("the string haven't got a 'end'!\n");//flag來判斷是否end
			flag=1;
		}
	}
	else
	{
		printf("haven't got a 'begin'!\n");
		flag=1;
	}

	return;
}

void yucu(void)
{
	statement();         /*呼叫函式statement();*/

	while(syn==26)//分號
	{
		scaner();          /*讀下一個單詞符號*/
		if(syn!=6)
			statement();         /*呼叫函式statement();*/
	}

	return;
}

void statement(void)
{
	if(syn==10)
	{
		scaner();        /*讀下一個單詞符號*/
		if(syn==18)
		{
			scaner();      /*讀下一個單詞符號*/
			expression();      /*呼叫函式expression();*/
		}
		else
		{
			printf("the sing ':=' is wrong!\n");
			flag=1;
		}
	}
	else
	{
		printf("wrong sentence!\n");
		flag=1;
	}

	return;
}

void expression(void)
{
	term();

  	while((syn==13)||(syn==14))
    {
    	scaner();             /*讀下一個單詞符號*/
      	term();               /*呼叫函式term();*/
    }

 	return;
}

void term(void)
{
	factor();

  	while((syn==15)||(syn==16))
    {
    	scaner();             /*讀下一個單詞符號*/
      	factor();              /*呼叫函式factor(); */
    }

	return;
}

void factor(void)//因式處理函式
{
	if((syn==10)||(syn==11))//識別符號,數字
	{
		scaner();
	}
  	else if(syn==27)//開頭是左括號(
    {
    	scaner();           /*讀下一個單詞符號*/
     	expression();        /*呼叫函式statement();*/

		if(syn==28)//出現右括號)
		{
			scaner();          /*讀下一個單詞符號*/
		}
      	else
	  	{
	  		printf("the error on '('\n");
      		flag=1;
     	}
    }
  	else
	{
		printf("the expression error!\n");
  		flag=1;
    }

  	return;
}

/*主要完成賦值種別碼等詞法分析功能*/
void scaner(void)//掃描器,詞法分析器內容
{
	sum=0;//數字初始化為0

	for(m=0;m<8;m++)//初始化token
		token[m++]=NULL;

	m=0;//m為token的指標
	ch=prog[p++];//陣列指標+1

	while(ch==' ')//遇到空格+1
		ch=prog[p++];

	if(((ch<='z')&&(ch>='a'))||((ch<='Z')&&(ch>='A')))//遇到字母
	{
		while(((ch<='z')&&(ch>='a'))||((ch<='Z')&&(ch>='A'))||((ch>='0')&&(ch<='9')))
		{
			token[m++]=ch;
			ch=prog[p++];//p+1,下次迴圈使用
		}
		p--;//迴圈跳出,要-1
		syn=10;//10,字母開頭
		token[m++]='\0';//\0為字串結束符

		/*判別是否為關鍵字*/
		for(n=0;n<6;n++)//n為rwtab的指標
		if(strcmp(token,rwtab[n])==0)//strcmp返回值為0,則兩個引數大小相同
		{
			syn=n+1;
			break;
		}
	}


	else if((ch>='0')&&(ch<='9'))//遇到數字
	{
		while((ch>='0')&&(ch<='9'))
		{
			sum=sum*10+ch-'0';
			ch=prog[p++];
		}
		p--;//回溯
		syn=11;//11為數字
	}

	/*除數字和字母開頭以外的其他符號*/
	else
	switch(ch)
	{
		case '<':
			m=0;
			ch=prog[p++];
			if(ch=='>')
			{
				syn=21;
			}
			else if(ch=='=')
			{
				syn=22;
			}
			else
			{
				syn=20;
				p--;//回溯
			}
		break;

		case '>':
			m=0;
			ch=prog[p++];
			if(ch=='=')
			{
				syn=24;
			}
			else
			{
				syn=23;
				p--;
			}
		break;

		case ':':
			m=0;
			ch=prog[p++];
			if(ch=='=')
			{
				syn=18;
			}
			else
			{
				syn=17;
				p--;
			}
			break;

		case '+':
			syn=13;
		break;

		case '-':
			syn=14;
		break;

		case '*':
			syn=15;
		break;

		case '/':
			syn=16;
		break;

		case '(':
			syn=27;
		break;

		case ')':
			syn=28;
		break;

		case '=':
			syn=25;
		break;

		case ';':
			syn=26;
		break;

		case '#':
			syn=0;
		break;

		default:
			syn=-1;
		break;
	}
}