词法分析程序设计实现代码


这几天按照要求写了个词法分析程序,期间遇到了许多bug,但都一一解决了。其他就不多说,程序不是很完美,但是功能基本完成。我没把一些多余的代码删除优化,我希望我的代码记录我的原始思路。希望大家谅解!!因为我还是菜鸟!如果大家有好的优化方向可在下面评论区留言。

先看下程序要求与说明:

要求

1.能对任何S语言源程序进行分析

在运行词法分析程序时,应该用问答形式输入要被分析的S源语言程序的文件名,然后对该程序完成词法分析任务。

2.能检查并处理某些词法分析错误

词法分析程序能给出的错误信息包括:总的出错个数,每个错误所在的行号,错误的编号及错误信息。

要求处理以下两种错误(编号分别为1,2):

1:非法字符:单词表中不存在的字符处理为非法字符,处理方式是删除该字符,给出错误信息,“某某字符非法”。

2:源程序文件结束而注释未结束。注释格式为:/* …… */

保留字和特殊符号表

单词代码 1 2 3 4 5 6 7 8 9
单词 int char float void const for if else then
单词助记符 int char float void const for if else then
内码值
单词代码 10 11 12 13 14 15 16 17 18
单词 while switch break begin end { } 标识符 整数
单词助记符 while switch break begin end { } id num
内码值 在符号表中的位置 在常数表中的位置
单词代码 19 20 21 22 23 24 25 26 27
单词 + * / % ( ) [ ]
单词助记符 + * / % ( ) [ ]
内码值
单词代码 28 30 35 36
单词 < > <= >= == != % ;
单词助记符 rlop % ;
内码值 < > <= >= == !=
单词代码 37 38 39 40 41 42 43 44 45
单词 /= += -= *= %= || && ! =
单词助记符 /= += -= *= %= or and not =
内码值

单词的构词规则:

字母=[A-Za-z]

数字=[0-9]

标识符=字母(字母|数字)*

数字=数字(数字)*

语言表达式和语句说明

1.算术表达式:+、-、*、/、%

2.关系运算符:>、>=、<、<=、==、!=

3.赋值运算符:=,+=、-=、*=、/=、%=

4.变量说明:类型标识符   变量名表;

5.类型标识符:int   char    float

6.If语句:if  表达式then  语句  [else  语句]

7.For语句:for(表达式1;表达式2;表达式3) 语句

8.While语句:while 表达式  do   语句

9.S语言程序:由函数构成,函数不能嵌套定义。

函数说明

1.Initscanner函数:程序初始化:输入并打开源程序文件和目标程序文件,初始化保留字表

2.Scanner函数:识别源文件所有单词与字符。(处理除号/和注释)

3.Lexscan函数:根据读入的单词的第一个字符确定调用不同的单词识别函数

4.Isalpha函数:识别保留字和标识符

5.Isnumber函数:识别整数

6.Isother函数识别其他特殊字符

7.Output函数:输出单词的二元式到目标文件,输出格式(单词助记符,单词内码值),如(int,-)(rlop,>)……

8.errormark函数:输出错误信息到屏幕

——————————————————

程序代码

源文件与目标文件: test.txt   result.txt

#include<stdio.h>
#include <stdlib.h>
#include<cstdlib>
#include<iostream>
#include<string.h>
#include<string>
using namespace std;

#define F_PATH "E:\\大三下\\编译原理\\词法分析程序\\test.txt"
#define F_PATH1 "E:\\大三下\\编译原理\\词法分析程序\\result.txt"
int ch,errorline,errorkey;//ch用来存取源文件单个字符,errorline标记出错行号 ,errorkey标记 errortable与 errorlinetable的下标
string word[1000];//将单词与符号一一顺序存储到相应字符串指针中
string numtable[1000],marktable[1000];//定义常数表和符标识符表
int wordkey,numtablekey,marktablekey; //标记word\numtable\marktable字符串数组下表
char errortable[1000];//错误字符表
int errorlinetable[1000];//存储错误行数表
int mark=0; //标记/* 。。。*/ 是否成对

FILE *fp=NULL;//需要注意
FILE *fp_result=NULL;//需要注意

char other[][10]={"{","}","+","-","*","%","(",")","[","]","<",">","<=","=>","==","!=",";","+=","-=","*=","%=","||","&&","!","="};//定义其他字符

struct BinaryGroup{//定义二元组结构体
char before;
string beftest;
char comma;
string afttest;
char after;
}BG[1000];
void Initscanner()//初始化结构体数组以及相关所需初始化文件
{
wordkey=numtablekey=marktablekey=errorline=errorkey=0;
for(int i=0;i<1000;i++)
{
word[i]="\0";
BG[i].before='(';
BG[i].beftest="\0";
BG[i].comma=',';
BG[i].beftest="\0";
BG[i].after=')';
}
fp=fopen(F_PATH,"r"); //打开源文件
if(NULL==fp)
{
printf("open origin file fail!!!");
}
fp_result=fopen(F_PATH1,"w"); //打开目标文件
if(NULL==fp_result)
{
printf("open aims file fail!!!");
}
// while(scanf("%c",&c)!=EOF) fprintf(fp,"%c",c); //从控制台中读入并在文本输出

}
void lind(char *old,char str)//将字符转化为字符串类型,字符追加到字符串末尾
{
int iLen = strlen(old);
old[iLen] = str;
old[iLen+1] = '\0';
}
void Scanner()//把源文件所需的单词或字符转为单独存储的字符串数组word里
{
while((ch=fgetc(fp))!=EOF)
{
if(ch=='\n') errorline++;
if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z'))//保留字和标识符
{
char loadmark[]={""};
// mark=1;
lind(loadmark,ch);
while((ch=fgetc(fp))!=EOF)
{
if((ch>='0'&&ch<='9')||(ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z'))
{
lind(loadmark,ch);
}
else
{
word[wordkey]=loadmark;
wordkey++;
fseek(fp,-1,1);
break;
}
}
}
else if(ch=='/')//去注释(// 和/**/*/) 和识别 符号表中‘/’和‘/=’
{
ch=fgetc(fp);
if(ch=='/')
{
while((ch=fgetc(fp))!='\n');
errorline++;
}
else if(ch=='*')
{
mark=1;
while((ch=fgetc(fp))!=EOF)
{
if(ch=='\n') errorline++;
if(ch=='*')
{
ch=fgetc(fp);
if(ch=='\n') errorline++;
if(ch=='/')
{
mark=0;
break;
}
fseek(fp,-1,1);
}

}
}
else if(ch=='=')
{

word[wordkey]="/=";
wordkey++;
}
else
{
word[wordkey]="/";
wordkey++;
fseek(fp,-1,1);
}
}
else if(ch>='0'&&ch<='9')//数字
{
char loadnum[]={""};
lind(loadnum,ch);
while((ch=fgetc(fp))!=EOF)
{
if(ch>='0'&&ch<='9')
{
lind(loadnum,ch);
}
else
{
word[wordkey]=loadnum;
wordkey++;
fseek(fp,-1,1);
break;
}
}
}
else //其他字符
{
char loadother[]={""};//用来存储字符的字符串
if(ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='%'||ch=='|'||ch=='&'||ch=='!'||ch=='<'||ch=='>'||ch=='{'||ch=='['||ch=='('||ch=='=')
{
lind(loadother,ch);
ch=fgetc(fp);
if(ch=='\n') errorline++;
if(ch=='='||ch=='|'||ch=='&')
{
lind(loadother,ch);
}
else fseek(fp,-1,1);
word[wordkey]=loadother;wordkey++;

}
else if(ch==']'||ch=='}'||ch==';'||ch==')')
{
lind(loadother,ch);
word[wordkey]=loadother;
wordkey++;
}
else //去空格和不需要识别字符
{
if(ch==' '||ch=='\t')
{

}
else
{
errortable[errorkey]=ch;
errorlinetable[errorkey]=errorline+1;
errorkey++;
}
}
}
//Lexscan();
//fputc(ch,stdout); //这里是输出到屏幕
}
fclose(fp);
fp=NULL; //需要指向空,否则会指向原打开文件地址
}
void Output(int as)//输出单词的二元式到目标文件,输出格式(单词助记符,单词内码值)
{
cout<<BG[as].before<<BG[as].beftest<<BG[as].comma<<BG[as].afttest<<BG[as].after<<"---"<<as<<endl;//打印到界面
fprintf(fp_result,"%c",BG[as].before);//fprintf()不支持字符串类型写入
fputs(BG[as].beftest.data(),fp_result); //fput(char*,FILE *)所以需要将string类型转化为char*
fprintf(fp_result,"%c",BG[as].comma);
fputs(BG[as].afttest.data(),fp_result);
fprintf(fp_result,"%c",BG[as].after);
}
void errormark()//报错函数
{
for(int i=0;i<errorkey;i++)
{
printf("出错字符:%c 出错行号:%d\n",errortable[i],errorlinetable[i]);
}
printf("总出错字符个数:%d \n",errorkey);
if(mark!=0) printf("源程序文件结束而注释未结束");
}
void Isalpha(string word,int as)// 标示符或者变量名二元制生成
{
if(word=="int"||word=="char"||word=="float"||word=="void"||word=="const"||word=="for"||word=="if"||word=="else"||word=="then"||word=="while"||word=="switch"||word=="break"||word=="begin"||word=="end")
{
BG[as].beftest=word;
BG[as].afttest="-";
}
else
{
BG[as].beftest="id";
char str[10];
int i;
for(i=0;i<marktablekey;i++)
{
if(marktable[i]==word)
{
itoa(i,str,10);
BG[as].afttest=str;
break;
}
}
if(i==marktablekey)
{
marktable[marktablekey]=word;
itoa(i,str,10);
BG[as].afttest=str;
marktablekey++;
}
}
}
void Isnumber(string word,int as)//数字二元组生成
{
char str[10];
int i;
for(i=0;i<numtablekey;i++)
{
if(numtable[i]==word)
{
itoa(i,str,10);
BG[as].beftest="num";
BG[as].afttest=str;
break;
}
}
if(i==numtablekey)
{
numtable[numtablekey]=word;
itoa(i, str, 10);
BG[as].beftest="num";
BG[as].afttest=str;
numtablekey++;
}
}
void Isother(string word,int as)//其他符号二元组生成
{
if(word=="||")
{
BG[as].beftest="or";
BG[as].afttest="-";
}
else if(word=="&&")
{
BG[as].beftest="and";
BG[as].afttest="-";
}
else if(word=="!")
{
BG[as].beftest="not";
BG[as].afttest="-";
}
else if(word=="<"||word==">"||word==">="||word=="<="||word=="=="||word=="!=")
{
BG[as].beftest="rlop";
BG[as].afttest=word;
}
else
{
BG[as].beftest=word;
BG[as].afttest="-";
}
}
void Lexscan()//判断word数组中的字符串是什么类型,并调用相关的函数处理与写入目标文件result.text
{
int as;
for(as=0;as<wordkey;as++)
{
if((word[as][0]>='a'&&word[as][0]<='z')||(word[as][0]>='A'&&word[as][0]<='Z')) //标示符或者变量名
{
Isalpha(word[as],as);
}
else if(word[as][0]>='0'&&word[as][0]<='9') //数字
{
Isnumber(word[as],as);
}
else
Isother(word[as],as);//其他符号
Output(as);
}
fclose(fp_result);//关闭目标文件

}
int main()
{
Initscanner();
Scanner();
Lexscan();
errormark();
return 0;
}

 

其他文章:流缓冲socket编程基础知识如何编写Makefile区块链的价值


更多资讯可收藏→→北华航天工业学院——小博主花生

发表评论

电子邮件地址不会被公开。 必填项已用*标注