使用C语言实现PL/0的词法分析器


一、实验目的和要求

设计、编写、调试一个具体的词法分析程序,加深对词法分析原理的理解。

二、算法描述

先将文件a.txt按字符顺序读入,先判断读入的字符ch是否为数字,字母。如果是,再判断key是否为0如果是,判断是否为数字,如果是数字,将temp设为1,如果不是temp保持0;如果key不为0,判断temp是否为1,如果为1,说明这个单词是数字开头,要检测单词后面是否会出现字母,出现报错。如果读入的字符ch是换行或回车,要将行数lineNum++,然后将word_temp[]数组的值复制到word[].w中,将key置为0;如果读入的是空格或tab键,将word_temp[]数组的值复制到word[].w中,将key置为0;如果ch的值为':'或'>'或'<'将ch放入word_temp[]数组中,并判断下一个ch是否为'=',是将ch放入word_temp[]数组中,将word_temp[]数组的值复制到word[].w中。 最后将word[]数组的所有值输出。程序运行结束。

三、代码


#include<stdio.h>
#include<stdlib.h>
#include<string.h>
/*
  code类别表: 
    1 : 关键字 
    2 : 标识符
	3 : 常量
	4 : 运算符 
    5 : 对应的是界符中元素的位置
 */
 
typedef struct Word
{
	int num;//词所属类型 SYM
	char w[20];//词的标识识别符的值  ID 
	int lineNum;
}Word;

char ktt[42][20]=
{
    "begin","call","const","do","end","if","odd","procedure",
    "read","then","var","while","write",",",";",":","(",")","[","]",
    "{","}","+","-","*","/","=","<",">","<=",">=",":=","0","1","2","3",
    "4","5","6","7","8","9"
};  //SYM用户关键字,运算符,界符 
 
int main()
{
	char ch,word_temp[20]="" ;  //缓存区 
	int i=0,j=0,k=0,key=0,chioce,temp=0, lineNum=1,WordTemp=0;
	
	FILE *fp;
	Word word[100];

	printf("1:输入源程序保存成文件\n");
	printf("2:打开文件进行词法分析\n");
	fp=fopen("a.txt","r");
	if(!fp)
	{
		printf("文件打开失败\n");
		exit(1);
	}

// 源文件输出
	printf("源程序如下:\n");
	while((ch=fgetc(fp))!=EOF)
	{
		putchar(ch);
	}
	fclose(fp);

// 重新打开文件,进行词法分析
	printf("\n词法分析结果如下:\n");
	fp=fopen("a.txt","r");
	if(!fp)
	{
		printf("文件打开失败\n");
		exit(1);
	}

	while((ch=fgetc(fp))!=EOF)
	{   
		if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')||(ch>='0'&&ch<='9'))
		{
			if(!key){
				if(ch>='0'&&ch<='9'){
					temp = 1;
				}
			}
			else{
				if(temp){
					if((ch>='a'&&ch<='z') || (ch>='A'&&ch<='Z')){
						printf("\n\n发现错误,错误出现在%d行---->", lineNum);
						WordTemp=1;
					}
				}
			}
			word_temp[key++]=ch;//连续几个字母,数字的连成单词
			word_temp[key]='\0';
			continue;
		}
		else
		{   if(strcmp(word_temp,"")!=0)
			{
				strcpy(word[i].w,word_temp);    //将单词拷贝到结构数组中
				word[i].lineNum = lineNum;
				strcpy(word_temp,"");
				key=0;                          //回到临时数组的开始位置
				if(WordTemp){
					printf("%s错误,不能以数字加字母的方式命名标识符\n\n\n",word[i].w);
					WordTemp=0;
				}
				i++;                            //结构数组的下标加1
				temp=0;
			}
			if(ch==' '||ch==10||ch==13||ch=='	')//去掉空格、回车和tab键
			{	
				// 换行,回车,所在行数增加
				if(ch=='\n'){
					lineNum++;
				}
				continue;
			}			
			else
			{
				word_temp[0]=ch;
                if(word_temp[0]==':'||word_temp[0]=='>'||word_temp[0]=='<')
				{
					ch=fgetc(fp);
					if(ch=='=')
					{
						word_temp[1]=ch;
						word_temp[2]='\0';
					}
                	
				}else{
					word_temp[1]='\0';
				}
				strcpy(word[i].w,word_temp);//将非字母数字符号拷贝到结构数组中
				word[i].lineNum = lineNum;
				strcpy(word_temp,"");
				key=0;//回到临时数组的开始位置
				i++;
			}
		}
	}
	
	for(j=0;j<i;j++)
	{
		for(k=0;k<43;k++)
		{
			if((strcmp(word[j].w,ktt[k]))==0)
			{
				if(k>=0&&k<13)
					word[j].num=1;//保留字
				else if(k>=13&&k<21)
					word[j].num=5;//分隔符
				else if(k>=21&&k<32)
					word[j].num=4;//运算符
				else if(k>=32&&k<43)
					word[j].num=3;//数字
				break;
			}
			else 
				word[j].num=2;//变量
		}
	}
    printf("code类别表:\n");
    printf("1 : 关键字 \n");
    printf("2 : 标识符\n");
    printf("3 : 常量\n");
    printf("4 : 运算符 \n");
    printf("5 : 对应的是界符中元素的位置\n");
    for(j=0;j<i;j++)//按格式要求打印输出
	{
		printf("类别:%d, 单词:'%s', 所在行数:%d\n",word[j].num,word[j].w,word[j].lineNum);
	} 
    fclose(fp);
	
	return 0;
}


// a.txt文件
const a=10;
var b,c;
procedure p;
    begin
        c:=b+a;
    end;
begin
    read(b);
    while b#0 do
        begin
            call p;
            write(2*c);
            read(b);
        end;
var 4a = 5;
end.

四、输出结果

在这里插入图片描述

  • 21
    点赞
  • 118
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值