📄 bianyi1.cpp
字号:
//编写一个词法分析程序,对给出的程序段进行词法分析,
//要求输出以文件形式存放的TOKEN串和符号表
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#define FILENAMELEN 20
void scanner(FILE* fp);
void intdeal(char *buffer);
void errordeal(char error,int lineno);
int search(char *buf,int type,int command);
int searchID(char* buffer);
int main(void)
{
FILE* rdfp;
FILE* wrfp;
int i;
char fileName[FILENAMELEN];
char *key[]={"", "do", "else", "if", "and", "int", "then", "while"}; //关键字
char *limit[]={" ", "(", ")", ":", ";", "{", "}", ">", "=", "<", "+"};//运算、限界符
wrfp = fopen("keyword.txt", "w");
for (i = 0; i < 8; i++)
fprintf(wrfp, "%s\n", key[i]);
fclose(wrfp);
wrfp = fopen("limit.txt", "w");
for (i = 0; i < 11; i++)
fprintf(wrfp, "%s\n", limit[i]);
fclose(wrfp);
printf("请输入文件名:\n");
scanf("%s", fileName);
rdfp = fopen(fileName, "r");
scanner(rdfp);
return 0;
}
void scanner(FILE* fp)
{
int i;
char array[30];
int line = 0; //记录行数
int errorno = 0;
int result; //搜索结果
int count;
char ch;
char* word;
char filename[FILENAMELEN];
FILE* outputfp = fopen("token.txt", "w"); //输出的文件的文件指针,初始化一下
fclose(outputfp);
FILE* outputfp1 = fopen("identifier.txt", "w"); //输出的文件的文件指针,初始化一下
fclose(outputfp1);
while (!fp){
printf("不能打开指定的文件,请确认输入的文件名正确!\n");
putchar('\n');
printf("请重新输入文件名:");
scanf("%s", filename);
fp = fopen(filename, "r");
}
ch = (unsigned char)fgetc(fp);
while (ch != EOF) {
//按字符依次扫描源程序,直至结束
i=0;
//以字母和下划线开头
if (((ch >= 'A') && (ch <= 'Z')) || ((ch >= 'a') && (ch <= 'z')) || (ch == '_')){
while(((ch >= 'A') && (ch <= 'Z')) || ((ch >= 'a') && (ch <= 'z')) || (ch == '_') || ((ch >= '0') && (ch <= '9'))){
array[i++]=ch;
ch = fgetc(fp);
}
word=(char*)malloc((i + 1) * sizeof(char));
memcpy(word, array, i);
word[i] = '\0';
intdeal(word);
if (ch != EOF){
fseek(fp, -1, SEEK_CUR);
}
}
//以数字开头
else if ((ch >= '0') && (ch <= '9')){
while ((ch >= '0') && (ch <= '9')){
array[i++]=ch;
ch = fgetc(fp);
}
word=(char*)malloc((i + 1) * sizeof(char));
memcpy(word, array, i);
word[i] = '\0';
intdeal(word);
if (ch != EOF){
fseek(fp, -1, SEEK_CUR); //to do
}
}
//消除空格和制表符
else if((ch == ' ') || (ch == '\t'))
;
//消除回车并记录行数
else if(ch == '\n')
line++;
//消除注释
else if (ch == '/'){
ch = fgetc(fp);
if (ch == '='){ //判断是否为‘/=’号
outputfp = fopen("token.txt", "a");
fprintf(outputfp, "/=\t4\t\t\t13\n");
fclose(outputfp);
}
else if (ch != '*'){ //若为除号,写入输出文件
outputfp = fopen("token.txt", "a");
fprintf(outputfp, "/\t4\t\t\t13\n");
fclose(outputfp);
fseek(fp, -1, SEEK_CUR);
}
else if (ch == '*'){ //若为注释的开始,则忽略注释内容
count=0;
ch = fgetc(fp);
while(count!=2){ //当扫描到‘*’且紧接着下一个字符为‘/’才是注释的结束
count=0;
while(ch != '*')
ch = fgetc(fp);
count++;
ch = fgetc(fp);
if(ch=='/')
count++;
else
ch = fgetc(fp);
}
}
}
//消除包含在双引号中的字符串常量
else if (ch == '"'){
outputfp = fopen("token.txt", "a");
fprintf(outputfp, "%c\n", ch);
fclose(outputfp);
while (ch != '"')
ch = fgetc(fp);
fprintf(outputfp, "%c\n", ch);
fclose(outputfp);
}
//首字符为其它字符,即运算限界符或非法字符
else {
errorno = 0;
array[0] = ch;
ch = fgetc(fp); //再读入下一个字符,判断是否为双字符运算、限界符
if (ch != EOF){
array[1]=ch;
word = (char*)malloc(3 * sizeof(char));
memcpy(word, array, 2);
word[2] = '\0';
//先检索是否为双字符运算、限界符
result = search(word, 2, 1);
if (result == 0){ //若不是
word = (char*)malloc(2 * sizeof(char));
memcpy(word, array, 1);
word[1] = '\0';
result = search(word, 2, 1); //检索是否为单字符运算、限界符
if (result == 0){ //若还不是,则为非法字符
errordeal(array[0], line);
errorno++;
fseek(fp, -1, SEEK_CUR);
}
else { //若为单字符运算、限界符,写入输出文件并将扫描文件指针回退一个字符
outputfp = fopen("token.txt", "a");
fprintf(outputfp, "%d\n", result);
fclose(outputfp);
fseek(fp, -1, SEEK_CUR);
}
}
else { //若为双字符运算、限界符,写入输出文件
outputfp = fopen("token.txt", "a");
fprintf(outputfp, "%d\n", result);
fclose(outputfp);
}
}
else { //若读入的下一个字符为文件结束符
word = (char*)malloc(2 * sizeof(char));
memcpy(word, array, 1);
word[1] = '\0';
result = search(word, 2, 1); //只考虑是否为单字符运算、限界符
if (result == 0) //若不是,转出错处理
errordeal(array[0], line);
else { //若是,写输出文件
outputfp = fopen("token.txt", "a");
fprintf(outputfp, "%d\n", result);
fclose(outputfp);
}
}
}
ch = fgetc(fp);
}
fclose(fp);
}
void intdeal(char *buffer)
{
FILE* fp1;
FILE* fp2;
int result;
result = search(buffer, 1, 1); //先查关键字表
fp1 = fopen("token.txt", "a");
fp2 = fopen("identifier.txt", "a");
if (result != 0) //找到了,是关键字
fprintf(fp1, "%d\n", result);
else{ //若找不到,则非关键字
if ((buffer[0] >= '0') && (buffer[0] <= '9'))
fprintf(fp1, "%d\t%d\n", result + 1, buffer);
else
fprintf(fp1, "%d\t%d\n", result, buffer);
//以下代码建立符号表
if((((buffer[0] >= 'A') && (buffer[0] <= 'Z')) || ((buffer[0] >= 'a') && (buffer[0] <= 'z')) || (buffer[0] == '_')) && (searchID(buffer) != 0) )
fprintf(fp2, "%s\t%d\n", buffer, result);
}
fclose(fp1);
fclose(fp2);
}
void errordeal(char error,int lineno)
{
printf("\nerror: %c, line: %d", error, lineno);
}
int search(char *buf,int type,int command)
{
int number = 0;
FILE* fp;
char ch;
char temp[30];
int i = 0;
switch (type){
case 1: //打开关键字表供查阅
fp = fopen("keyword.txt", "r");
break;
case 2: //打开限界符、运算符表供查阅
fp = fopen("limit.txt", "r");
break;
}
ch = fgetc(fp);
while (ch != EOF){
while (ch != '\n'){
temp[i++] = ch;
ch = fgetc(fp);
}
temp[i] = '\0';
i = 0;
number++;
if (strcmp(temp, buf) == 0){
fclose(fp);
return number; //若找到,返回在相应表中的序号
}
else
ch = fgetc(fp);
} //外层while循环
if (command == 1){
fclose(fp);
return 0; //找不到
}
switch (type){
case 1:
fp = fopen("keyword.txt", "r");
break;
case 2:
fp = fopen("limit.txt", "r");
break;
}
fclose(fp);
return (number + 1);
}
int searchID(char* buffer) //搜索符号表看标识符是否已经存在
{
int i;
char id[20] = {'\0'};
char temp[20] = {'\0'};
FILE* fp = fopen("identifier.txt", "r");
strcpy(temp, buffer);
while(fscanf(fp, "%s %d", id, &i) != EOF){
if (strcmp(id, temp) == 0)
return 0; //find
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -