📄 scanner.cpp
字号:
// Scanner.cpp : Defines the entry point for the console application.
//
/************************************************************
词法分析程序
*************************************************************/
//#include "stdafx.h"
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define LENGTH 61
#define N 100
/***********************数据存储结构*************************/
//token文件记录结构
typedef struct token
{
int label; //单词序号
char name[30]; //单词自身值
int code; //单词机内码(种别码)
int addr; //单词在符号表中的入口地址,但关键字以-1表示
}token;
//关键字表记录结构
typedef struct KeyWord
{
char name[30];
int code;
}KeyWord;
//符号(标识符/实常数/整常数/字符常量)表记录结构
typedef struct symble
{
int number; //序号
int type; //类型
char name[30]; //名字
}symble;
/*************************************************************/
char ch;
int var_count; //符号表项计数器
int label_count; //单词序号计数器
//int addr_count; //地址计数器
int LineOfCurrent; //当前源码行
int LineOfPro; //已处理的源码行数计数器
int error_count; //错误计数器
char filename[30];
FILE *KeyFin; //指向关键字文件的指针
FILE *SourceFin; //指向源文件的指针
FILE *TokenFout; //指向token输出文件指针
FILE *SymbleFout; //指向符号表输出文件指针
token CurrentToken; //当前单词符号
symble CurrentSymble; //查填符号表时的当前项
symble SymbleList[N]; //符号(变量,常量)表
KeyWord key[LENGTH]; //关键字表
/**********************************************************/
void Scanner();
void ScannerInit();
void IsAlpha();
void IsNumber();
void IsAnotation();
void IsChar();
void IsOther();
void OutPut();
void Error(int a);
int WordHave();
int strcmp(char*s,char *t)/*两个字符串的精确比较,相等时返回0,否则返回1*/
{
for(;*s==*t;s++,t++)
if(*s==0)
return 0;
return 1;
}
/*************************** 主程序 *********************************/
int main()
{
int i=0,j=0;
LineOfPro=0;
var_count=0;
//addr_count=1;
label_count=1;
for(i=0;i<N;i++){
SymbleList[i].number=0;
SymbleList[i].type=0;
for(j=0;j<30;j++)
SymbleList[i].name[j]='\0';
}
Scanner();
return 0;
}
/************************* 扫描程序 *******************************/
void Scanner()
{
int i=0;
error_count=0;
ScannerInit();
printf("**********************************************\n");
printf(" S语言词法分析器 \n");
printf("**********************************************\n");
printf("输入源文件名(提示是s.txt):");
for(;;){
scanf("%c",&filename[i]);
if(filename[i]==10)
break; //回车符
i++;
}
filename[i]='\0'; //最后加上'\0'
strcpy(filename,"s.txt");
if((SourceFin=fopen(filename,"r"))==NULL){
printf("无法打开文件%s.\n",filename);
exit(1);
}
if((TokenFout=fopen("token.txt","w+"))==NULL){
printf("无法打开文件token.txt.\n");
exit(1);
}
if((SymbleFout=fopen("symble.txt","w+"))==NULL){
printf("无法打开文件symble.txt.\n");
exit(1);
}
ch=fgetc(SourceFin); /*读取第一个字符*/
while(ch!=EOF) /*循环处理字符串*/
{
for(i=0;i<30;i++)
CurrentToken.name[i]='\0';
if((ch>47)&&(ch<58)) //判断是否为数字
IsNumber();
else
{
if(((ch>64)&&(ch<90))||((ch>96)&&(ch<123))||ch=='_') //判断是否为大小写字符或者是空格
IsAlpha(); //标识符处理
else
{
if(ch=='/')
IsAnotation(); //注释处理
else
if(ch=='\'') //单引号
IsChar(); //字符串(字符常量)处理
else
IsOther();//算术与关系运算符,(,),:,:=,.,;,逗号处理
}
}
}
fclose(SourceFin);
fclose(TokenFout);
fclose(SymbleFout);
printf("源文件共%d行,现已全部分析完毕.\n",LineOfPro);
}
/******************** 初始化 ************************/
void ScannerInit()
{
int i=1;
int k=0;
if((KeyFin=fopen("key.txt","rb"))==NULL) //预先检查是否存在key.txt文件,即关键字文件
{
printf("cannot open key.txt\n");
exit(1);
}
for(i=0;i<60;i++) { //初始化清空
for(k=0;k<30;k++) {
key[i].name[k]='\0';
}
}
//修改读取操作
/*for(i=0;i<60;i++){ //读入编码表
fread(&key[i],sizeof(struct KeyWord),1,KeyFin);
}*/
//修改如下:
for (i=0;i<60;i++) {
fscanf(KeyFin,"%s",&key[i].name);
fscanf(KeyFin,"%d",&key[i].code);
}
fclose(KeyFin);
}
/**************** 数字处理 **************************/
void IsNumber()
{
int k=0; //索引
int flag=0; //实数标志
char ch1; //保存读取的符号
while(((ch>47)&&(ch<58))) //是否为数字
{
CurrentToken.name[k++]=ch;
ch=fgetc(SourceFin); //读取字符
if(ch=='.')
{
flag=1; //flag=1表示实数
//ch=fgetc(SourceFin);
break;
}
}
if (!flag)
CurrentToken.code=28; //整常数
//CurrentToken.addr=addr_count++;
//CurrentToken.addr=var_count;
CurrentToken.label=label_count++; //单词序号加1
if(flag) //实数
{
ch1=fgetc(SourceFin);
if((ch1>47)&&(ch1<58))
CurrentToken.name[k++]=ch; //记录小数点号
else
Error(2);
ch=ch1;
while((ch>47)&&(ch<58)) //添加小数点后数字
{
CurrentToken.name[k++]=ch;
ch=fgetc(SourceFin);
}
CurrentToken.code=29; //标记为实数
if(ch=='.') //还有小数点,则舍去尾部
{
Error(2);
ch=fgetc(SourceFin);
while((ch>47)&&(ch<58))
ch=fgetc(SourceFin);
}
}
if(((ch>64)&&(ch<90))||((ch>96)&&(ch<123))) //当前字符为字母,舍去尾部
{
Error(2);
while(((ch>64)&&(ch<90))||((ch>96)&&(ch<123)))
{
ch=fgetc(SourceFin);
while((ch>47)&&(ch<58))
ch=fgetc(SourceFin);
}
}
OutPut();
}
/*************** 字母处理 *****************************/
void IsAlpha()
{
int i,h;
h=0;
i=0;
while(((ch>64)&&(ch<90))||((ch>96)&&(ch<123))||((ch>47)&&(ch<58))||(ch=='_'))
{
CurrentToken.name[i++]=ch;
ch=fgetc(SourceFin);
}
for(i=0;i<LENGTH;i++) /*判断输入字符是否为保留字*/
{
h=strcmp(CurrentToken.name,key[i].name);
if(!h)
break; //是保留字
}
if(!h) { //是保留字
CurrentToken.code=key[i].code;
CurrentToken.addr=-1;
}
else {
CurrentToken.code=27;
// CurrentToken.addr=addr_count++;
}
CurrentToken.label=label_count++;
OutPut();
}
/****************** 字符串常量处理 ********************/
void IsChar()
{
int i=0;
for(;;)
{
ch=fgetc(SourceFin);
CurrentToken.code=30;
if(ch!='\'')
CurrentToken.name[i++]=ch;
else
break;
}
//CurrentToken.addr=addr_count++;
CurrentToken.label=label_count++;
OutPut();
ch=fgetc(SourceFin);
}
/*************** 注释处理 *********************/
void IsAnotation()
{
char ch1;
ch1=ch;
ch=fgetc(SourceFin);
if(ch=='*')
{
LineOfCurrent=LineOfPro+1; //处理行数加1
for(;;)
{
ch=fgetc(SourceFin);
if(ch==10) LineOfPro++; //换行
if(ch==EOF)
{
Error(3);break;
} //注释不正常结束
if(ch=='*')
{
ch1=ch;
ch=fgetc(SourceFin);
if(ch=='/')
{
ch=fgetc(SourceFin);break;}
}
}
}
else{ /*不是注释,当作除号处理*/
CurrentToken.name[0]='/';
CurrentToken.code=39;
CurrentToken.addr=-1;
CurrentToken.label=label_count++;
OutPut();
}
}
/****************** 其他情况的处理 *******************/
void IsOther()
{
char ch1;
int i;
for(i=0;i<30;i++) //清空
CurrentToken.name[i]='\0';
switch(ch)
{
case '(':
CurrentToken.name[0]='(';
CurrentToken.code=32;
CurrentToken.addr=-1;
CurrentToken.label=label_count++;
OutPut();
ch=fgetc(SourceFin);
break;
case ')':
CurrentToken.name[0]=')';
CurrentToken.code=33;
CurrentToken.addr=-1;
CurrentToken.label=label_count++;
OutPut();
ch=fgetc(SourceFin);
break;
case '*':
CurrentToken.name[0]='*';
CurrentToken.code=34;
CurrentToken.addr=-1;
CurrentToken.label=label_count++;
OutPut();
ch=fgetc(SourceFin);
break;
case '+':
CurrentToken.name[0]='+';
CurrentToken.code=35;
CurrentToken.addr=-1;
CurrentToken.label=label_count++;
OutPut();
ch=fgetc(SourceFin);
break;
case ',':
CurrentToken.name[0]=',';
CurrentToken.code=37;
CurrentToken.addr=-1;
CurrentToken.label=label_count++;
OutPut();
ch=fgetc(SourceFin);
break;
case '-':
CurrentToken.name[0]='-';
CurrentToken.code=36;
CurrentToken.addr=-1;
CurrentToken.label=label_count++;
OutPut();
ch=fgetc(SourceFin);
break;
case '.':
CurrentToken.name[0]='.';
CurrentToken.code=38;
CurrentToken.addr=-1;
CurrentToken.label=label_count++;
OutPut();
ch=fgetc(SourceFin);
break;
case ':':
ch1=ch;
ch=fgetc(SourceFin);
if(ch!='='){
CurrentToken.name[0]=':';
CurrentToken.code=40;
CurrentToken.addr=-1;
CurrentToken.label=label_count++;
OutPut();
}
else{
CurrentToken.name[0]=':';
CurrentToken.name[1]='=';
CurrentToken.code=41;
CurrentToken.addr=-1;
CurrentToken.label=label_count++;
OutPut();
ch=fgetc(SourceFin);}
break;
case ';' :
CurrentToken.name[0]=';';
CurrentToken.code=42;
CurrentToken.addr=-1;
CurrentToken.label=label_count++;
OutPut();
ch=fgetc(SourceFin);
break;
case '<':
ch1=fgetc(SourceFin);
if(ch1=='='){
CurrentToken.name[0]='<';
CurrentToken.name[1]='=';
CurrentToken.code=44;
CurrentToken.addr=-1;
CurrentToken.label=label_count++;
OutPut();
ch1=fgetc(SourceFin);
}
else{
if(ch1=='>'){
CurrentToken.name[0]='<';
CurrentToken.name[1]='>';
CurrentToken.code=45;
CurrentToken.addr=-1;
CurrentToken.label=label_count++;
OutPut();
ch1=fgetc(SourceFin);
}
else{
CurrentToken.name[0]='<';
CurrentToken.code=43;
CurrentToken.addr=-1;
CurrentToken.label=label_count++;
OutPut();
}
}
ch=ch1;
break;
case '=':
CurrentToken.name[0]='=';
CurrentToken.code=46;
CurrentToken.addr=-1;
CurrentToken.label=label_count++;
OutPut();
ch=fgetc(SourceFin);
break;
case'>':
ch1=fgetc(SourceFin);
if(ch1=='='){
CurrentToken.name[0]='>';
CurrentToken.name[1]='=';
CurrentToken.code=48;
CurrentToken.addr=-1;
CurrentToken.label=label_count++;
OutPut();
ch1=fgetc(SourceFin);
}
else{
CurrentToken.name[0]='>';
CurrentToken.code=47;
CurrentToken.addr=-1;
CurrentToken.label=label_count++;
OutPut();
}
ch=ch1;
break;
case 10:
LineOfPro++;
ch=fgetc(SourceFin);
break;
case 13:
LineOfPro++;
ch=fgetc(SourceFin);
break;
case' ':
ch=fgetc(SourceFin);
break;
case EOF:
Error(4);
break;
default:
Error(1);
ch=fgetc(SourceFin);
break;
}//end switch(ch)
}
/*************** 输出模块 *************************/
void OutPut()
{
int flag,i=0;
int k;
//如果是 27=标识符 28=整常数 29=实常数 30=字符常数,查填符号表SymbleList
if((CurrentToken.code==27)||
(CurrentToken.code==28)||
(CurrentToken.code==29)||
(CurrentToken.code==30))
{
CurrentSymble.number=CurrentToken.addr;
CurrentSymble.type=CurrentToken.code;
strcpy(CurrentSymble.name,CurrentToken.name);
flag=WordHave();//查表
if (flag==1) //原来不在表中,现插入到表的最后,同时写符号表文件
{
//插入到表的最后
SymbleList[var_count].number=CurrentSymble.number;
SymbleList[var_count].type=CurrentSymble.type;
strcpy(SymbleList[var_count].name,CurrentSymble.name);
//写符号表文件
fprintf(SymbleFout,"%10d%10s%10d\n",
CurrentSymble.number,
CurrentSymble.name,
CurrentSymble.type);
}
}
/*写token表文件*/
for(;;)
if(CurrentToken.name[i++]=='\0')
break; //找到name字符串结束位置
for(k=30-i;k>0;k--)
CurrentToken.name[i]='\0';
//CurrentToken.name[k]='\0';
fprintf(TokenFout,"%10d%10s%10d%10d\n",
CurrentToken.label,
CurrentToken.name,
CurrentToken.code,
CurrentToken.addr);
printf("%10d%10s%10d%10d\n",
CurrentToken.label,
CurrentToken.name,
CurrentToken.code,
CurrentToken.addr);
}
void Error(int a)
{
error_count++;
switch(a)
{
case 1:printf("error%2d非法字符于第%3d行.\n",error_count,LineOfPro+1);break;
case 2:printf("error%2d实常数出错于第%3d行.\n",error_count,LineOfPro+1);break;
case 3:printf("error%2d第%3d行的注释没有与之匹配的注释符'*/'. \n",
error_count,LineOfCurrent);break;
case 4:printf("error%2d非正常结束!\n",error_count);break;
default:break;
}
return;
}
/**********查填符号表************/
int WordHave()
{
int flag,i=0;
//查表
for(i=1;i<var_count+1;i++)
{
flag=strcmp(CurrentSymble.name,SymbleList[i].name);
if(flag==0){ //找到,设置当前符号的符号表入口地址,返回0
CurrentToken.addr=SymbleList[i].number;
CurrentSymble.number = SymbleList[i].number;
return 0;
}
}
//没找到,返回1
var_count++;
CurrentToken.addr=var_count;
CurrentSymble.number = var_count ;
return 1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -