编译原理C语言实现词法和语法分析器

实验一:词法分析器

词法分析器的思路:

1.首先是对关键词的识别
可以做一个数组存放关键词的所有单词,例如下列程序的

char *rwtab[6]={"begin","if","then","while","do","end"};

2.然后是主程序的逻辑:
* 循环输入缓存中的字母放进输入数组中
* 调用scaner函数对每一个词进行分析
* 为数字则拼在一起作为一个数输出
* 为关键字符或者变量时,拼成字符串输出

3.scaner函数的思路:
* token临时数组存放完成后的数字或字符串
* prog数组存放输入的所有内容
* p用来保存识别的所有进度,m为token的偏移量,n用来判断是哪个关键词,num用来保存最后的数字
* 首先初始化token数组
* 跳过所有空格和回车
* 先判定字母,然后把数字判断也包含进来,组成了含数字的变量名或者关键词,再判断是不是关键词
* 再判定数字,最后组成数字
* 最后是各种符号

#include <stdio.h>
#include <string.h>
 
char prog[80],token[8],ch;  //prog数组用来存放输入的字符串 ,token数组用来存放字符,ch用来表示输入缓存的移动标志 
int syn,p,m,n,num;//标识码 
char *rwtab[6]={"begin","if","then","while","do","end"};//关键字数组,由1到6 

void scaner(void);//扫描输入后的字符串,识别关键字、字母和数字 
 
int main()
{
	p=0;                        //用p来表示输入字符串数组的偏移量 
 	printf("\nplease input a string(end with '#'):\n");//提示字符 
 	
 	do{                         //用循环来读取输入缓冲区的字符串 
	        scanf("%c",&ch);    //读取单个字符 
    		prog[p++]=ch;
	}while(ch!='#');//用#来表示结束 
 	
 	p=0;
	do{
			scaner();
			switch(syn)//用syn来分辨不同种情况 
	 		{
	 			case 11://如果syn是11就是数字 
	 				printf("< %-5d%8d >\n",syn,num);
	      		break;
	      		
	  			case -1://如果是-1则是错的 
	  				printf("you have input a wrong string\n");
	      			//getch(); 
	      			return 0;
	      		break;
	      		
	  			default://默认就是字符 
	  			printf("< %-5d%8s >\n",syn,token);
	      		break;
	  		}
    	}while(syn!=0);
    //getch();
 }
 
void scaner(void)
{  
	num=0;
	
    for(m=0;m<8;)
    	token[m++]= NULL;    //初始化token数组 
	
    ch=prog[p++];      //p从0开始判断 
    m=0;
		
    while((ch==' ')||(ch=='\n'))        //跳过空格和回车 
	  		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--;                           //p减一回到上一个字符进行判断 
      	syn=10;
	  	for(n=0;n<6;n++)               //循环识别关键字 
    	if(strcmp(token,rwtab[n])==0)
       	{ 
       		syn=n+1;                   //由1到6 
        	break;
       	}
     }
	 else if((ch>='0')&&(ch<='9'))         //识别数字 
     { 
      	while((ch>='0')&&(ch<='9'))
    	{
    		num=num*10+ch-'0';             //将多个单个数字组合成一个数字 
      		ch=prog[p++];
    	}
    	p--;
   		syn=11;
    }
    else                                   //剩下就是各种运算符 
    {
		switch(ch)
		{
		case '<':                           
			token[m++]=ch;
			ch=prog[p++];
			if(ch=='=')                    //识别为小于号 
			{ 
				syn=22;
				token[m++]=ch;
			}
			else                           //识别为小于等于号 
			{  
				syn=20;
				p--;
			}
		break;
		case '>':
			token[m++]=ch;
			ch=prog[p++];
			if(ch=='=')                    //识别为大于等于号 
			{
				syn=24;
				token[m++]=ch;
			}
			else                           //识别为大于号 
			{ 
				syn=23;
				p--;
			}
		break;
 
		case '+':
			token[m++]=ch;
			ch=prog[p++];
			if(ch=='+')                    //识别为++号 
			{
				syn=17;
				token[m++]=ch;
			}
			else                           //识别为+号 
			{
				syn=13;
				p--;
			}
		break;
 
		case '-':                         
			token[m++]=ch;
			ch=prog[p++];
			if(ch=='-')                    //识别为--号 
			{
				syn=29;
				token[m++]=ch;
			}
			else                           //识别为-号 
			{ 
				syn=14;
				p--;
			}
		break;
 
		case '!':
			ch=prog[p++];
			if(ch=='=')                    //识别为!=号 
			{ 
				syn=21;
				token[m++]=ch;
			}
			else                           //识别为错误 
			{ 
				syn=31;
				p--;
			}
		break;
 
		case ':':
			token[m++]=ch;
			ch=prog[p++];
			if(ch=='=')                    //识别为==号 
			{
				syn=18;
				token[m++]=ch;
			}
			else                           //识别为=号 
			{
				syn=17;
				p--;
			}
		break;
 
		case '*':                          //识别为* 
			syn=15;
			token[m++]=ch;
		break;
 
		case '/':                          //识别为/ 
			syn=16;
			token[m++]=ch;
		break;
 
		case '(':                          //识别为( 
			syn=27;
			token[m++]=ch;
		break;
 
		case ')':                          //识别为) 
			syn=28;
			token[m++]=ch;
		break;
 
		case '{':                          //识别为{ 
			syn=5;
			token[m++]=ch;
		break;
 
		case '}':                          //识别为} 
			syn=6;
			token[m++]=ch;
		break;
 
		case ';':                          //识别为; 
 			syn=26;
			token[m++]=ch;
		break;
 
		case '\"':                         //识别为” 
			syn=30;
			token[m++]=ch;
		break;
 
		case '#':                          //识别为# 
			syn=0;
			token[m++]=ch;
		break;
 
 
		default:                           //识别为错误 
			syn=-1;
		break;
		}
	}
    	token[m++]='\0';
}

重要的点

  1. 循环的问题
for(m=0;m<8;)
    	token[m++]= NULL;

这个位置for循环的第三个参数不要写,有些人习惯就直接写m++。或者可以:

for(m=0;m<8;m++)
    	token[m]= NULL;
  1. 识别字母
if(ch>='A'&&ch<='z')//当识别字母时可以直接使用这个
{

}

因为ascii码中字母的顺便是从A~Z a~z变大的,可以一次性整合在一块。

  • 7
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值