- 词法分析实验设计思想及算法
本实验采用的基本思想是根据C++语言的基本状态集,根据各个状态的转移条件构造各个判断逻辑,将程序运行的状态加以区别。源程序来源采用文件导入的方式,对输入源程序的文件进行逐行的词法分析。支持对标识符、关键字、整数、浮点数、分界符、运算符等识别。对于读取的每一行代码保存在字符数组buf [120]中,设置起点指示器start(数组下标索引)和搜索指示器end(数组下标索引),其中start指向当前正在识别单词的开始位置(指向新单词的首字符),而end用于先前搜索寻找单词的终点。识别每一个单词依赖于其相应的词法分析的状态转换图。对于关键字,不专设对应的转换图,把其存放在字符串数组中(保留字表)。当转化图识别出一个标识符时,就去查这张表,确定是否为关键字。具体实现思路见如下分析。
- 主程序设计基本思路
按照如下状态转移图的形式,对目标分析文件中的内容进行分析:
图1.1 状态转换图
按照上图所示,采用超前搜索的核心思路进行分析。每读取一行代码后后,默认进入
状态 0,超前搜索指针 end 向前搜索, 按照以下分析逻辑依次序进行:
- 如果识别到空格,start索引和end索引分别先前移动(即加1)。
- 如果连续识别的都是字母,end指向运算符或分界符时识别结束,获取索引start和end-1之间的字符串,此时应该对读取的字符串与关键字表进行对比,如果是关键字,则将其返回。否则,返回标识符。
- 如果start指向”_”或字母,end如果识别数字或字母,同时也向前移动,此间如果遇到非法字符(不包括字母、数字、运算符和分界符),则标志变量flag = 1,否则为0。标志变量为1表示为非法标识符,同时end继续前进直到识别分割符为止(运算符和分界符)。然后获取索引start和end-1之间的字符串,如果flag =1,则返回非法标识符,否则,返回此标识符。
注:在算法实现上可以把标识符的识别和关键字的识别放在一起。即可在设置一个标记变量isKey = 0,其识别状态见如下表格1.1:
表1.1
isKey | flag | 状态 |
1 | 0/1 | 关键字 |
0 | 0 | 标识符 |
0 | 1 | 非法标识符 |
4. 果start指向数字,end连续的识别字符,最后end指向分割符。其中如果end有识别非法字符,则isInt = 0,否则isInt =1 ;,见 如下表1.2
表1.2
isInt | 状态 |
0 | 非法整数 |
1 | 整数 |
5.如果start指向数字,end连续的识别数字,之后识别小数点,再连续识别数字,最后end指向分割符。再这期间如果识别非法字符,则报错。
6.对于运算符、分界符正常识别即可。
程序逻辑图如下:
图1.2
- 代码实现
#ifndef _READFILE_
#define _READFILE_
#include <iostream>
#include <Cstdio>
#include <vector>
#include <Cstring>
using namespace std;
class Table{
public:
string array[100];
int length;
Table(){
length = 0;
}
};
//定义关键字容器
Table key;
//定义界定符容器
Table delimiter;
//定义算术运算符容器
Table arithmeticOperator;
//定义逻辑运算符容器
Table logicalOperator;
//定义关系运算符容器
Table relationOperator;
void loadFile(){
int N =5;
string fileName[N] = {"key.txt","delimiter.txt","arithmeticOperator.txt","logicalOperator.txt","relationOperator.txt"};
Table* tableName[N] = {&key,&delimiter,&arithmeticOperator,&logicalOperator,&relationOperator};
//定义文件指针
FILE * fp;
//保存字符串的缓冲数组
char buf[30];
char temp[50];
for(int i=0;i < N;i++){
strcpy(temp,fileName[i].c_str());
if((fp = fopen(temp,"r"))!= NULL )
{
int count = 0;
while(!feof(fp)){
fscanf(fp,"%s",buf);
tableName[i]->array[count] = buf;
count++;
}
tableName[i]->length = count+1;
fclose(fp);
}
else{
cout<<"文件打开失败!"<<endl;
}
}
}
#endif // _READFILE_
#include <iostream>
#include <fstream>
#include <string>
#include <Cstdio>
#include <iomanip>
#include "readFile.h"
#define FILENAME "code.txt"
#define N 200
using namespace std;
//保存代码
string code[N];
//保存代码行数
int lineCount = 0;
//加载代码
void loadCode();
//判断字符是否为字母
bool isLetter(char var);
//判断字符是否为数字
bool isDigit(char var);
//判断一个字符是否为分割符
bool isBoundary(char var);
//检测一个字符是否为分界符
bool isDelimiter(char var);
//核心函数,对字符串进行循环处理
void wordAnalyse();
int main()
{
loadFile();
loadCode();
wordAnalyse();
return 0;
}
//加载代码
void loadCode(){
ifstream fin;
string tempStr;
fin.open(FILENAME,ifstream::in);
while(!fin.eof()){
getline(fin,tempStr);
lineCount +=1;
code[lineCount] = tempStr;
}
}
//判断字符是否为字母
bool isLetter(char var){
//强制转换
int ascii = (int) var;
bool bo = ((ascii>=97) && (ascii<=122)) || ((ascii>=65) && (ascii<=90));
if(bo){
return true;
}
else{
return false;
}
}
//判断字符是否为数字
bool isDigit(char var){
//强制转换
int ascii = (int) var;
bool bo = ((ascii>=48) && (ascii<=57));
if(bo){
return true;
}
else{
return false;
}
}
//判断一个字符是否为分割符
bool isBoundary(char var){
//不是字母、数字、下划线、小数点可认为是分割符
if((!isLetter(var)) &&(!isDigit(var))&& (var != '_') && (var!= '.') && (var!= '$') && (var!= '@')&& (var!= '#')&& (var!= '&')){
return true;
}
return false;
}
//检测一个字符是否为分界符
bool isDelimiter(char var){
//将单个字符转化为字符串
char buf[2] = {var,0};
string str(buf);
for(int i =0;i<delimiter.length;i++){
if(delimiter.array[i] == str){
return true;
}
}
return false;
}
//核心函数,对字符串进行循环处理
void wordAnalyse(){
cout<<setw(20)<<"单词"<<setw(20)<<"二元序列"<<setw(20)<<"类 型"<<setw(30)<<"位置(行,列)"<<endl;
string str;
char buf[150] ={0};
char temp[60];
//定义字符首尾索引
int start = 0;
int end = 0;
//分别对每行代码进行处理
for(int i=1;i<=lineCount;i++){
//将字符串转化成字符数组
strcpy(buf,code[i].c_str());
//定义字符首尾索引
start = 0;
end = 0;
//保存列数
int position =0;
while((int)buf[start] != 0){
//去掉开始空白符号
while((int)buf[start] == 32){
//地址加1
start++;
end++;
}
bool isKey = true;
bool flag = false;
//检测是否为关键字或标识符,首字符是字母或下划线
if(isLetter(buf[end]) || buf[end] == '_'){
//如果是下划线,那么一定不是关键字
if(buf[end] == '_'){
//标记不是关键字
isKey = false;
}
//否则可能是关键字、标识符,也可能是非法标识符
//字符指针向前移1位
end++;
//使end指向分割符
while(!isBoundary(buf[end])){
//如果end指向非法字符(不是字母和数字),则flag标记为1
if(!isLetter(buf[end]) && !isDigit(buf[end])){
flag = true;
}
end++;
}
str = code[i].substr(start,end-start);
position++;
//如果isKey = false,则一定不是关键字
if(!isKey){
//如果flag = false,则一定是标识符
if(!flag){
cout<<setw(20)<<str<<setw(20)<<(string)"("+"2"+","+str+")"<<setw(20)<<"标识符"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
}
//否则为非法标识符
else{
cout<<setw(20)<<str<<setw(20)<<"Error"<<setw(20)<<"Error"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
}
}
//否则可能是关键字、标识符、非法标识符
else{
//判断是否为关键字
for(int j=0;j<key.length;j++){
if(str.compare(key.array[j]) == 0){
cout<<setw(20)<<str<<setw(20)<<(string)"("+"1"+","+str+")"<<setw(20)<<"关键字"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
isKey = false;
break;
}
}
//flag == false,则为标识符
if(isKey == true && flag == false)
{
cout<<setw(20)<<str<<setw(20)<<(string)"("+"2"+","+str+")"<<setw(20)<<"标识符"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
}
//为非法标识符
else if(isKey == true && flag == true){
cout<<setw(20)<<str<<setw(20)<<"Error"<<setw(20)<<"Error"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
}
else{
//空语句
}
}
}
//检测是否为整数或浮点数
else if(isDigit(buf[end])){
//字符指针向前移1位
end++;
while(isDigit(buf[end])){
end++;
}
//如果下一个是分割字符,则识别完成(整数识别)
if(isBoundary(buf[end])){
str = code[i].substr(start,end-start);
position++;
cout<<setw(20)<<str<<setw(20)<<(string)"("+"7"+","+str+")"<<setw(20)<<"常数"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
}
//不是分割符
else{
//如果是小数点
if((int)buf[end] == '.'){
//字符指针向前移1位
end++;
while(isDigit(buf[end])){
end++;
}
//如果下一个是分割字符,则识别完成(浮点数识别)
if(isBoundary(buf[end])){
str = code[i].substr(start,end-start);
position++;
cout<<setw(20)<<str<<setw(20)<<(string)"("+"7"+","+str+")"<<setw(20)<<"常数"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
}
//不是分隔符,则继续识别
else{
while(!isBoundary(buf[end])){
end++;
}
str = code[i].substr(start,end-start);
position++;
cout<<setw(20)<<str<<setw(20)<<"Error"<<setw(20)<<"Error"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
}
}
//不是小数点
else{
while((isLetter(buf[end])) || (isDigit(buf[end]))|| (buf[end] == '_') ){
end++;
}
str = code[i].substr(start,end-start);
position++;
cout<<setw(20)<<str<<setw(20)<<"Error"<<setw(20)<<"Error"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
end++;
}
}
}
//检测是否为"("或")"或"{"或"}"或","或";"
else if(isDelimiter(buf[end])){
//字符指针向前移1位
position++;
cout<<setw(20)<<buf[end]<<setw(20)<<(string)"("+"6"+","+buf[end]+")"<<setw(20)<<"分界符"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
end++;
}
//检测是否为算术运算符+,-,*,%,/,++,--,+=,-=
else if(((int)buf[end] == 43) ||((int)buf[end] == 45) ||((int)buf[end] == 42) ||((int)buf[end] == 37)||((int)buf[end] == 47)){
position++;
if((int)buf[end] == 43){
//字符指针向前移1位
end++;
if((int)buf[end] == 43){
cout<<setw(20)<<"++"<<setw(20)<<(string)"("+"3"+","+"++"+")"<<setw(20)<<"算术运算符"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
//字符指针向前移1位
end++;
}
else if((int)buf[end] == 61){
cout<<setw(20)<<"+="<<setw(20)<<(string)"("+"3"+","+"+="+")"<<setw(20)<<"算术运算符"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
//字符指针向前移1位
end++;
}
else{
cout<<setw(20)<<"+"<<setw(20)<<(string)"("+"3"+","+"+"+")"<<setw(20)<<"算术运算符"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
}
}
else if((int)buf[end] == 45){
//字符指针向前移1位
end++;
if((int)buf[end] == 45){
cout<<setw(20)<<"--"<<setw(20)<<(string)"("+"3"+","+"--"+")"<<setw(20)<<"算术运算符"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
//字符指针向前移1位
end++;
}
else if((int)buf[end] == 61){
cout<<setw(20)<<"-="<<setw(20)<<(string)"("+"3"+","<<"-="<<")"<<setw(20)<<"算术运算符"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
//字符指针向前移1位
end++;
}
else{
cout<<setw(20)<<"-"<<setw(20)<<(string)"("+"3"+","+"-"+")"<<setw(20)<<"算术运算符"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
}
}
else{
cout<<setw(20)<<buf[end]<<setw(20)<<(string)"("+"3"+","+buf[end]+")"<<setw(20)<<"算术运算符"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
//字符指针向前移1位
end++;
}
}
//检测关系运算符<,<=,=,==,>,>=,!=,,,(先判断>,<,=,!)
else if(((int)buf[end] == 62) ||((int)buf[end] == 60) ||((int)buf[end] == 61) ||((int)buf[end] == 33)){
position++;
//判断首字符是否为">"
if((int)buf[end] == 62){
end++;
//判断是否为"="
if((int)buf[end] == 61){
cout<<setw(20)<<">="<<setw(20)<<(string)"("+"5"+","+">="+")"<<setw(20)<<"关系运算符"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
//向前移一位,使其指向"="的下一个字符
end++;
}
else{
cout<<setw(20)<<">"<<setw(20)<<(string)"("+"5"+","+">"+")"<<setw(20)<<"关系运算符"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
}
}
//判断首字符是否为"<"
else if((int)buf[end] == 60){
end++;
//判断是否为"="
if((int)buf[end] == 61){
cout<<setw(20)<<"<="<<setw(20)<<(string)"("+"5"+","+"<="+")"<<setw(20)<<"关系运算符"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
//向前移一位,使其指向"="的下一个字符
end++;
}
else{
cout<<setw(20)<<"<"<<setw(20)<<(string)"("+"5"+","+"<"+")"<<setw(20)<<"关系运算符"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
}
}
//判断首字符是否为"="
else if((int)buf[end] == 61){
end++;
//判断是否为"="
if((int)buf[end] == 61){
cout<<setw(20)<<"=="<<setw(20)<<(string)"("+"5"+","+"=="+")"<<setw(20)<<"关系运算符"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
//向前移一位,使其指向"="的下一个字符
end++;
}
else{
cout<<setw(20)<<"="<<setw(20)<<(string)"("+"5"+","+"="+")"<<setw(20)<<"关系运算符"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
}
}
//否则为字符"!"
else{
end++;
//判断是否为"="
if((int)buf[end] == 61){
cout<<setw(20)<<"!="<<setw(20)<<(string)"("+"5"+","+"!="+")"<<setw(20)<<"关系运算符"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
//向前移一位,使其指向"="的下一个字符
end++;
}
else{
cout<<setw(20)<<"!"<<setw(20)<<(string)"("+"4"+","+"!"+")"<<setw(20)<<"逻辑运算符"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
}
}
}
//检测逻辑运算符和位运算符,检测"&&","||","!","&","^","|","~"
else if(((int)buf[end] == 38) ||((int)buf[end] == 124)||((int)buf[end] == 94)||((int)buf[end] == 126)){
position++;
//判断是否为"&"
if((int)buf[end] == 38){
//end指向下一位
end++;
if((int)buf[end] == 38){
cout<<setw(20)<<"&&"<<setw(20)<<(string)"("+"4"+","+"&&"+")"<<setw(20)<<"逻辑运算符"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
//向前移一位,使其指向"="的下一个字符
end++;
}
else{
cout<<setw(20)<<"&"<<setw(20)<<(string)"("+"8"+","+"&"+")"<<setw(20)<<"位运算符"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
}
}
//判断是否为"|"
else if((int)buf[end] == 124){
//end指向下一位
end++;
if((int)buf[end] == 124){
cout<<setw(20)<<"||"<<setw(20)<<(string)"("+"4"+","+"||"+")"<<setw(20)<<"逻辑运算符"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
//向前移一位,使其指向"="的下一个字符
end++;
}
else{
cout<<setw(20)<<"|"<<setw(20)<<(string)"("+"8"+","+"|"+")"<<setw(20)<<"位运算符"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
}
}
//否则为"^"或"~"
else {
cout<<setw(20)<<buf[end]<<setw(20)<<(string)"("+"8"+","+buf[end]+")"<<setw(20)<<"位运算符"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
//向前移一位,使其指向"="的下一个字符
end++;
}
}
//否则报错
else{
position++;
cout<<setw(20)<<buf[end]<<setw(20)<<"Error"<<setw(20)<<"Error"<<setw(20)<<"("<<i<<","<<position<<")"<<endl;
//字符指针向前移1位
end++;
}
start = end;
}
}
}
注:arithmeticOperator.txt内容为:+ - * % / += -= (每个运算符占一行)
delimiter.txt内容为:; , ( ) { } (每个分割符占一行)
key.txtt内容为:asm do if return typedef auto double inline short typeid bool dynamic_cast int signed typename break else long sizeof union case enum mutable static unsigned catch explicit namespace
static_cast using char export new struct virtual class extern operator switch void const false private
template volatile const_cast float protected this wchar_t continue for public throw while default friend
register true delete goto reinterpret_cast try (每个关键词占一行)
logicalOperator.txt内容为:&& || ! & ^ | ~ (每个逻辑运算符号占一行)
relationOperator.txt内容为:< <= = == > >= !=(每个关系运算符号占一行)
code.txt的内容为:
if (i==1.a0ab)
{
n++;
}
else
{
n--;
}
%
int _va123r=7a;
double va$r = 56.0;
a = 7 &&8;
a +=2;
while (k | b ){
return true;
}
- 程序运行结果如下