编译原理 实验1《词法分析程序设计与实现》
目录
1、定义目标语言的可用符号表
- 关键字:if,else,for,while,do,int,read,write,return
- 标识符:①标识符由字母、数字组成;②不能把c语言关键字作为标识符;③标识符对大小写敏感;④首字符只能是字母,不能是数字。
- 常数:无符号整数值。
- 运算符:+、-、*、/、==、<=、>=、!=、=
- 界符:,、;、{、}、(、)
2、定义程序输入输出
- 程序输入:依照c语言程序规则输入,以txt文本形式存储;
- 程序输出:程序依照 类型 值 的形式每行一个进行输出,例如 int int。
3、代码
(1)头文件 analysis.h
#include<stdio.h>
#include<ctype.h>
#include<string.h>
//下面定义保留字表,为简化程序,使用字符指针数组保存所有保留字
//如果想增加保留字,可继续添加,并修改保留字数目 keywordSum
#define keywordSum 9
char *keyword[keywordSum] = {"if","else","for","while","do","int","read","write","return"};
//下面定义纯单分界符的首字符
char singleword[50] = "!+-*(){};,:";
//下面定义双分界符的首字符
char doubleword[10] = "><=!&|";
extern char Scanin[300], Scanout[300];
//用于接收输人输出文件名,在 test _ main.c 中定义
extern FILE *fin ,*fout; //用于指向输入输出文件的指针,在 test _ main.c 中定义
int TESTscan () //词法分析函数
{
char ch , token[40]; //ch 为每次读人的字符,token 用于保存识别出的单词
int es = 0,j,n; //es错误代码,0表示没有错误
//j, n为临时变量,控制组合单词时的下标等
printf("请输人源程序文件名(包括路径):");
scanf("%s",Scanin);
printf("请输人词法分析输出文件名(包括路径):");
scanf("%s",Scanout);
if(( fin = fopen(Scanin ,"r")) == NULL) //判断输人文件名是否正确
{
printf("\n打开词法分析输人文件出错!\n");
return (1); //输人文件出错返回错误代码1
}
if (( fout = fopen (Scanout ,"w")) == NULL ) //判断输出文件名是否正确
{
printf("\n创建词法分析输出文件出错!\n");
return(2); //输出文件出错返回错误代码2
}
ch = getc(fin);
while(ch != EOF)
{
while(ch == ' '|| ch == '\n' || ch == '\t') ch = getc(fin);
if(isalpha(ch)) //如果是字母则组合标识符
{
token[0] = ch; j = 1;
ch = getc(fin);
while(isalnum(ch)) //如果是字符数字则组合标识符
//如果不是则标识符组合结束
{
token[j++] = ch; //组合的标识符保存在token中
ch = getc(fin); //都下一个字符
}
token[j] = '\0'; //标识符组合结束
//查保留字
n = 0;
while((n < keywordSum) && strcmp(token,keyword[n])) n++;
if(n >= keywordSum) //不是保留字,输出标识符
fprintf(fout,"%s\t%s\n","ID",token); //输出标识符符号
else //是保留字,输出保留字
fprintf(fout,"%s\t%s\n",token,token); //输出保留字符号
}else if(isdigit(ch)) //数组处理
{
token[0] = ch; j = 1;
ch = getc(fin); //读下一个字符
while(isdigit(ch)) //如果是数字则组合整数;如果不是则整数组合结束
{
token[j++] = ch; //组合整数保存在token中
ch = getc(fin); //都下一个字符
}
token[j] = '\0'; //整数组合结束
fprintf(fout,"%s\t%s\n","NUM",token); //输出整数符号
}else if(strchr(singleword,ch) > 0) //单分界符处理
{
token[0] = ch; token[1] = '\0';
ch = getc(fin); //读下一个字符以便识别下一个单词
fprintf(fout,"%s\t%s\n",token,token); //输出单分界符符号
}else if(strchr(doubleword,ch) > 0) //双分界符处理
{
token[0] = ch;
ch = getc(fin); //读下一个字符判断是否为双分界符
if(ch == '=') //如果是=,组合双分界符 != == >= <=
{
token[1] = ch; token[2] = '\0'; //组合双分界符结束
ch = getc(fin); //读下一个符号以便识别下一个单词
} else if(ch == '&') //判断是否是&&
{
token[1] = ch; token[2] = '\0';
ch = getc(fin);
}
else if(ch == '|') //判断是否是||
{
token[1] = ch; token[2] = '\0';
ch = getc(fin);
} else
token[1] = '\0';
fprintf(fout,"%s\t%s\n",token,token); //输出单或双分界符
}else if(ch == '/') //注释处理
{
ch = getc(fin); //读下一个字符
if(ch == '*') //如果是*,则开始处理注释
{
char ch1;
ch1 = getc(fin); //读下一个字符
do
{
ch = ch1; ch1 = getc(fin); //删除注释
} while((ch != '*' || ch1 != '/')&&ch1 != EOF);
//直到遇到注释结束符 * / 或文件尾
ch = getc(fin); //读下一个字符以便识别下一个单词
}else //不是*则处理单分界符
{
token[0] = '/'; token[1] = '\0';
fprintf(fout,"%s\t%s\n",token,token); //输出单分界符
}
}else //错误处理
{
token[0] = ch; token[1] = '\0';
ch = getc(fin); //读下一个符号以便识别下一个单词
es = 3; //设置错误代码
fprintf(fout,"%s\t%s\n","ERROR",token); //输出错误符号
}
}
fclose(fin); //关闭输入输出文件
fclose(fout);
return(es); //返回主程序
}
(2)测试 main.cpp
#include<stdio.h>
#include<ctype.h>
#include<string.h>
#include"analysis.h"
extern int TESTscan();
char Scanin[300],Scanout[300]; //用于接收输入输出文件名
FILE *fin,*fout; //用于指向输入输出文件的指针
int main() {
int es = 0;
es = TESTscan();
if(es > 0)
printf("词法分析有错,编译停止!");
else
printf("词法分析成功!\n");
}