词法分析程序

 

一、实验目的

学习和掌握利用有限自动机编写词法分析程序。

实验要求如下:

二、程序功能描述

简要描述:该程序根据C语言的文法,实现了C语言词法分析。

详细来说,其功能主要表现在:

①该程序可以从头到尾扫描整个文本

②该程序可以分析每个token是什么,如int为保留字,>=是双字符分节符

③该程序可以实现报错

三、主要数据结构描述

1、keyArray[]

key是一个数组,存放保留字。 提供给扫描器,以识别每个token是否为保留字。

2、ch

ch是一个字符变量,保存的是从源程序中读取的单个字符。

3、result

result是一个字符串变量,保存的是从源程序中连续读取的字符串。

4、resultArray[]

resultArray是一个字符串数组,用于存放每个获取的单词的值。

5、resultNum

resultNum是一个整型变量,用于记录获取单词的个数。

四、程序结构描述

1、设计方法——构造有限自动机

 

 

 

 

为方便表示,加上了

<运算符> → <单字符分界符>|<双字符分界符>

其余略。

2、函数定义及函数之间的调用关系

(1)bool isKey(string s)

函数名称:isKey

参数解释:字符串变量s

返回值:bool值

功能:判断一个字符串是否为保留字,若是,返回True,否则返回False。

(2)bool isOperator(char ch)

函数名称:isOperator

参数解释:字符变量ch

返回值:bool值

功能:判断一个字符是否为运算符,若是,返回True,否则返回False。

(3)bool isSeparator(char ch)

函数名称:isSeparator

参数解释:字符变量ch

返回值:bool值

功能:判断一个字符是否为分隔符,若是,返回True,否则返回False。

(4)int main( )

函数名称:main

参数解释:无

返回值:int

功能:主函数,实现文本读取,扫描分析,结果文件输出功能。

调用关系:扫描每一个字符时利用自定义的isOperator(ch)

和isSeparator(ch) 以及string库中的isalpha(ch) 和 isdigit(ch)来判断该字符为何类型,有以下几种情况:

1、若读入首字符为字母

①:继续读入字母、数字,组成标识符或关键字

②:读取过程中读到操作符或分隔符,则保存该标识符或关键字。

③:读取过程中遇到违规字符,则一并读取后续字母和数字,直到遇到操作符或分隔符,并报错。

2、若读入首字符为数字

①:继续读入数字,组成无符号整数

②:遇到操作符或分隔符正常终止,并保存该常数

③:若读入其他错误字符,一并读取后续字母和数字,直到遇到操作符或分隔符,并报错。

3、若读入首字符为运算符

①:判断是否为双字符边界

②:下一个字符若为字母、数字、分隔符,正常保存运算符。

③:若非上述字符,则将错误输入符一并读取并报错。

4、若读入首字符为分隔符

①:保存该分隔符

5、若读入首字符为非法字符——报错

五、程序测试

测试用例1:

测试结果截图1:

测试用例2:

测试结果截图2:

六、实验总结

词法分析是编译器进行文法分析的第一步,完成词法分析任务的程序称为词法分析程序或词法分析器或扫描器。从左至右地对源程序进行扫描,按照语言的词法规则识别各类单词,并产生相应单词的属性字。

经过本次实验,我学会了如何用有限自动机理论编写词法分析程序,对编译器如何分析文法有了更深一步的理解。

 

七、源代码

#include <iostream>
#include <fstream>
#include <cassert>
#include <string>
#define LENGTH 32
using namespace std;

//判断当前字符串是否为关键字
bool isKey(string s){
    //关键字数组
    string keyArray[] = {"int","char","string","void","bool","float","double","float","true","false","return",
                        "if","else","while","for","default","do","public","static","switch","case","include"};
    //与当前字符串一一对比
    for(unsigned int i=0;i<sizeof(keyArray);i++){
        if(s==keyArray[i]){
            return true;
        }
        if("include"==keyArray[i]){
        	break;
		}
    }
    return false;
}

//判断当前字符是否是运算符
bool isOperator(char ch){
    if('+'==ch || '-'==ch || '*'==ch || '/'==ch || '='==ch || '<'==ch || '>'==ch || '!'==ch|| '&'==ch|| '|'==ch)
        return true;
    else
        return false;
}

//判断当前字符是否是分隔符
bool isSeparator(char ch){
    if(','==ch || ';'==ch || '{'==ch || '}'==ch || '('==ch || ')'==ch|| ':'==ch)
        return true;
    else
        return false;
}


int main( )
{
    //定义字符变量,保存从源程序中读取的单个字符
    char ch;
    //定义字符串,保存从源程序中连续读取的字符串
    string result;
    //存放每个获取的单词的值
    string resultArray[999];
    //记录获取单词的个数
    int resultNum=0;

    //代码存放的文件名
    string file = "D:\\project\\cl\\src\\ccl\\bianyi\\input.txt";
    cout << file.data() << endl;

    ifstream infile;
    //将文件流对象与文件连接起来
    infile.open(file.data());
    //若失败,则输出错误消息,并终止程序运行
    assert(infile.is_open());

    //txt文本中读取空格符与换行符
    //infile >> noskipws;
    //读取文本中的一个字符
    infile>>ch;

    while (!infile.eof())
    {
        //ch是英文字母
        if(isalpha(ch)){
            result.append(1,ch);
            infile>>ch;
            //判断是否为关键字
            if(isKey(result)){
                resultArray[resultNum++]="(关键字,\""+result+"\")";
                result="";
            }
            //读入首字符为字母,继续读入字母、数字,组成标识符或者关键字
            while(isalpha(ch) || isdigit(ch)){
                result.append(1,ch);
                infile>>ch;
                if(isKey(result)){
	                resultArray[resultNum++]="(关键字,\""+result+"\")";
	                result="";						
                }
                if(result.length()==LENGTH){
                	break;
				}
            }
            //读入操作符或者分割符,正确保存标识符或者关键字
            if(isSeparator(ch) || isOperator(ch)){
                if(isKey(result)){
                    resultArray[resultNum++]="(关键字,\""+result+"\")";
                    result="";
                    continue;
                }
                else{
                    resultArray[resultNum++]="(标识符,\""+result+"\")";
                    result="";
                    continue;
                }

            }
            //读入不是字母、数字、运算符、标识符,继续读入直到遇到运算符或者分隔符
            else{
                result.append(1,ch);
                infile>>ch;
                while(!isSeparator(ch) && !isOperator(ch)){
                    result.append(1,ch);
                    infile>>ch;
                }
                resultArray[resultNum++]="(Error,标识符中有违规符号,\""+result+"\")";
                result="";
                continue;
            }
        }
        //读入数字
        else if(isdigit(ch)){
            result.append(1,ch);
            infile>>ch;
            //继续读入数字,组成常数
            while(isdigit(ch)){
                result.append(1,ch);
                infile>>ch;
            }
            //遇到操作符或者运算符,正常终止
            if(isOperator(ch) || isSeparator(ch)){
                resultArray[resultNum++]="(无符号整数,\""+result+"\")";
                result="";
                continue;
            }
            //也可以读小数
			else if('.'==ch){
            	result.append(1,ch);
            	infile>>ch;	
            	int num=0;
				while(isdigit(ch)){
					num++;
					result.append(1,ch);
            		infile>>ch;
				}
				if(num==0){
					resultArray[resultNum++]="(Error,小数点后没有数字,\""+result+"\")";
	                result="";
	                continue;
				}
	            if(isOperator(ch) || isSeparator(ch)){
	                resultArray[resultNum++]="(浮点数,\""+result+"\")";
	                result="";
	                continue;
	            }
				else{
	                result.append(1,ch);
	                infile>>ch;
	                while(!isSeparator(ch) && !isOperator(ch)&& !infile.eof()) {
	                    result.append(1,ch);
	                    infile>>ch;
	                }
	                resultArray[resultNum++]="(Error,浮点数后有未知符号,\""+result+"\")";
	                result="";
	                continue;
	            }			
			} 
            //读入其他错误字符
            else{
                result.append(1,ch);
                infile>>ch;
                while(!isSeparator(ch) && !isOperator(ch)&& !infile.eof()) {
                    result.append(1,ch);
                    infile>>ch;
                }
                resultArray[resultNum++]="(Error,整数后有错误符号,\""+result+"\")";
                result="";
                continue;
            }
        }
        //遇到运算符
        else if(isOperator(ch)){
            result.append(1,ch);
            infile>>ch;
            //判断是否存在<=、>=、!=、==、+=、-=、*=
            if("<"==result || ">"==result || "!"==result|| "="==result ||"+"==result ||"-"==result ||"*"==result){
                if('='==ch){
                    result.append(1,ch);
                    infile>>ch;
                }
            }
            if("+"==result){
            	if('+'==ch){
            		result.append(1,ch);
                    infile>>ch;
				}
			}
            if("-"==result){
            	if('-'==ch){
            		result.append(1,ch);
                    infile>>ch;
				}
			}
			if(">"==result){
            	if('>'==ch){
            		result.append(1,ch);
                    infile>>ch;
				}
			}
			if("<"==result){
            	if('<'==ch||'>'==ch){
            		result.append(1,ch);
                    infile>>ch;
				}
			}
			if("&"==result){
            	if('&'==ch){
            		result.append(1,ch);
                    infile>>ch;
				}
				else{
					resultArray[resultNum++]="(Error:逻辑与运算符号错误:\""+result+"\")";
                	result="";
				}
			}
			if("|"==result){
            	if('|'==ch){
            		result.append(1,ch);
                    infile>>ch;
				}
				else{
					resultArray[resultNum++]="(Error:逻辑或运算符号错误:\""+result+"\")";
                	result="";
				}
			}
            if("/"==result){
            	if('*'==ch){
            		result.append(1,ch);
                    infile>>ch;
            		while(1){
            			//这里一定要把文件指针往后移动两位,不然的话/*/形式的也会被无认为是注释(虽然应该不会有人这么写) 
            			result.append(1,ch);
                    	infile>>ch;
                    	char ch2 = result.at(result.length()-1);
                    	if('*'==ch2 && '/'==ch){
                    		result.append(1,ch);
                    		infile>>ch;
                    		resultArray[resultNum++]="(可以跨行的注释内容:\""+result+"\")";
                			result="";
                    		break;
						}
					}
					continue;
				}
				else if('='==ch){
					result.append(1,ch);
                    infile>>ch;
				}
			}
            //下一个读入符为字母、数字、分隔符,即正确
            if(isalpha(ch) || isdigit(ch) || isSeparator(ch)){
                resultArray[resultNum++]="(运算符,\""+result+"\")";
                result="";
                continue;
            }
            else{
                //将错误输入符一起读入,直到正确
                while(!isSeparator(ch) && !isalpha(ch) && !isdigit(ch) && !infile.eof()){
                    result.append(1,ch);
                    infile>>ch;
                }
                resultArray[resultNum++]="(Error,\""+result+"\")";
                result="";
                continue;
            }
        }
        //读取到分隔符
        else if(isSeparator(ch)){
            result.append(1,ch);
            resultArray[resultNum++]="(分隔符,\""+result+"\")";
            result="";
            infile>>ch;
        }
        //读取到未定义输入
        else{
            //出错处理
            result.append(1,ch);
            resultArray[resultNum++]="(Error,遇到了未定义输入(非字母数字,运算符,分隔符),且不在注释中,\"" + result + "\")";
            result="";
            infile>>ch;

        }
    }
    //关闭文件输入流
    infile.close();

    //以 (单词类编码,值) 输出结果
    for(int i=0;i<resultNum;i++){
        cout<<resultArray[i]<<endl;
    }

    ofstream ofs;						//定义流对象
    ofs.open("text.txt",ios::out);		//以写的方式打开文件
    for(int i=0;i<resultNum;i++){
        ofs<<resultArray[i]<<endl;
    }
    ofs.close();

	
   	return 0;
}

 

posted @ 2022-10-24 17:36  cyberbase  阅读(1143)  评论(0编辑  收藏  举报