【编译原理】编译原理实验: 词法分析程序

1. 实验要求

编制一个词法分析程序,设置5类或者3类单词,能识别字符。词法分析器的大小自定,语言模版可以参考PL/0,也可以自己定义。撰写实验报告。

2. 总体设计

参考教材中对PL/0语言的定义,我们将PL/0语言的单词分为保留字、运算符、标识符、界符和常数五大类,其中常数包括整型、浮点型、布尔型和字符串类型。
下面的表格展示了具体的定义规范。
请添加图片描述
程序通过该表的定义规范从输入中识别出各个单词的类型并输出。在碰到程序没有定义的单词时,则输出“非法字符(程序为定义)!”的报错提示。
在本程序中设计了两种输入形式,由用户自行选择。第一种是通过用户输入单个字符来判断该字符的单词类型,并以<单词自身值,单词的类型,单词编码>的形式输出。第二种是通过读入外部文件程序来识别该该程序中各个单词的类型,并且,程序依次输出各个单词的内部编码及单词单词自身的值,在遇到错误时显示报错提示,然后跳过该字符继续识别。

3. 实验条件

实验语言:C++
实验系统:Mac OS操作系统
实验环境:Xcode Version 12.4

4. 解决方案

通过定义相关判断函数来确定输入单词的单词类型,以下是定义的相关函数:
int isConstant(string s)
函数功能:判断单词是不是整数型常数,如果是,判断单词是什么类型的整数,整型还是浮点型。
返回值:如果单词是整型,返回1;如果单词是浮点型,返回2;如果单词整数型常数返回0。
int isBool(string s)
函数功能:判断单词是不是布尔型常数。
返回值:如果单词是布尔型,返回1;如果单词不是布尔型,返回0。
int isString(string s)
函数功能: 判断单词是不是字符型常数。
返回值: 如果单词是字符型,返回1;如果单词不是字符型,返回0。
int isIdentifier(string s)
函数功能: 判断单词是不是标识符。
返回值: 如果单词是标识符,返回1;如果单词不是标识符,返回0。
int isKeyword(string s)
函数功能: 判断单词是不是保留字。
返回值: 如果单词是保留字,返回1;如果单词不是保留字,返回0。
int isOperator(string s)
函数功能: 判断单词是不是运算符。
返回值: 如果单词是运算符,返回1;如果单词不是运算符,返回0。
int isDelimiters(string s)
函数功能: 判断单词是不是界符。
返回值: 如果单词是界符,返回1;如果单词不是界符,返回0。

5. 代码实现

//
//  main.cpp
//  词法分析
//
//  Created by python on 2021/5/8.
//
#include <string>
#include <iostream>
#include <cctype>
#include <string>
#include <fstream>
#include <sstream>
#include <math.h>
using namespace std;
#define ARRAY_SIZE(a)(sizeof(a)/sizeof(a[0]))
const string keywords[] = {"const", "var", "procedure", "begin", "end", "odd", "if", "then", "call", "while", "do", "read", "write","void","main","short","long","int","double","float","while","if","else","for","break","return","endl"};
const string operators[] = {"+", "-", "*", "/", "=", "#", "<", ">", ":",":=", "<=", ">="};
string delimiters[] = {")", "(", ",", ";", "."};
string bools[] = {"true", "false"};
int isKeyword(string s){
    //cout<<ARRAY_SIZE(keywords)<<endl;
    for(int i=0; i<ARRAY_SIZE(keywords); i++){
        if(s == keywords[i]){
            //cout<<keywords[i]<<endl;
            //cout<<s<<endl;
            return 1; //是保留字
        }
    }
    return 0;
}
int isOperator(string s){
    for(int i=0; i<ARRAY_SIZE(operators); i++){
        if(s.compare(operators[i]) == 0){
            return 1; //是操作符
        }
    }
    return 0;
}
int isDelimiters(string s){
    for(int i=0; i<ARRAY_SIZE(delimiters); i++){
        if(s == delimiters[i]){
            //cout<<"1"<<endl;
            return 1; //是界符
        }
    }
    return 0;
}
//判断单词是不是整数,如果是,是什么类型的整数,int或者float
int isConstant(string s){
   
    int isInt = 1;
    int isFloat = 1;
    int countDot = 0;
    int indexDot = 0;
    //cout<<"长度:"<<s.length()<<endl;
    for(int i=0; i<s.length(); i++){
        //cout<<isdigit(s[i])<<endl;
        if(!isdigit(s[i])){
            isInt = -1;
            //cout<<"进"<<endl;
        }
    }
    if(isInt == 1){ //是整数
        return 1;
    }else{
        //判断该是浮点数还是都不是
        for(int i=0; i<s.size();i++){
            if(s[i] == '.'){
                countDot++;
                indexDot = i;
            }
        }
        if(countDot != 1){
            return 0;
        }
        else{
            for(int i=0; i<indexDot;i++){
                if(!isdigit(s[i])){
                    isFloat = -1;
                }
            }
            for(int i=indexDot+1; i<s.size();i++){
                if(!isdigit(s[i])){
                    isFloat = -1;
                }
            }
            if(isFloat == 1){
                return 2;
            }else{
                return 0;
            }
        }
    }
}
int isBool(string s){
    for(int i=0; i<ARRAY_SIZE(bools); i++){
        if(s.compare(bools[i]) == 0){
            return 1; //是布尔型
        }
    }
    return 0;
}
//判断该常数是不是字符串类型
int isString(string s){
    if(s[0] == '"' && s[s.size()] == '"'){
        return 1;
    }else{
        return 0;
    }
}
int isIdentifier(string s){
    int i;
    if(s[0]=='_'||(s[0]>='a'&&s[0]<='z')||(s[0]>='A'&&s[0]<='Z')){  //判断首个字符应是否“下划线”或者“字母”
        //cout<<"首字母规范"<<endl;
        for(i=1;i<s.size();i++){
            if(s[i]=='_'||(s[i]>='a'&&s[i]<='z')||(s[i]>='A'&&s[i]<='Z')||(s[i]>='0'&&s[i]<='9')){
                //cout<<s[i]<<":ok"<<endl;
                continue; //判断之后字符是否为“下划线”或“字母”或“数字”
            }else{
                return 0;
                }
            }
        
        return 1;
    }else {
        //首字母不符合规范,不是identifier
        return 0;
    }
}
void inputVol(string s){
    //cout<<"请输入你想要判断的单词"<<endl;
    string str = s;
    //cin>>str;
    if(isDelimiters(str) == 1){ //如果是界符
        //cout<<"1"<<endl;
        cout<<"<"<<str<<" 5 "<<"界符>"<<endl;
    }else if(isKeyword(str) == 1){ //如果是保留字
        cout<<"<"<<str<<" 3 "<<"保留字>"<<endl;
    }else if(isOperator(str)){ //如果是运算符
        cout<<"<"<<str<<" 4 "<<"运算符>"<<endl;
    }else if(isBool(str)){ //如果是常数中的布尔型
        cout<<"<"<<str<<" 1 "<<"布尔型>"<<endl;
    }else if(isString(str)){ //如果是常数中的字符串
        cout<<"<"<<str<<" 1 "<<"字符串>"<<endl;
    }else if(isConstant(str) == 2){ //如果是常数中的浮点数
        cout<<"<"<<str<<" 1 "<<"浮点数>"<<endl;
    }else if(isConstant(str) == 2){ //如果是常数中的整数
        cout<<"<"<<str<<" 1 "<<"整数>"<<endl;
    }else if(isIdentifier(str)){
        //cout<<"进来了"<<endl;
        if(str.size() >= 5){
            str = str.substr(0,5);
        }
        cout<<"<"<<str<<" 2 "<<"标识符>"<<endl;
    }else{
        cout<<"非法字符(程序未定义)!"<<endl;
    }
}
void inputPro(){
    cout<<"程序词法分析结果:"<<endl;
    ifstream in("input.txt");
    string str = "";
    char ch;
    ch = in.get();
    str += ch;
    
    while(!in.eof()){
        //一个一个读入
        in.get(ch);
        string s = "";
        //string str = "";
        s += ch;
        //cout<<"ch:"<<ch+'A'<<endl;
        //cout<<"s"<<s;
        //cout<<!isDelimiters(s)<<!isOperator(s)<<(ch != ' ')<<(ch != '\n')<<(ch != '\t')<<endl;
        if(!isDelimiters(s) && !isOperator(s) && ch > 32 && ch != ' '){
            //如果读入的字符不是那些用于分界的符号
            //cout<<"ch"<<ch<<"进入"<<endl;
            str += ch;
            //cout<<str<<endl;;
        }else{
            //bool flag = false;
            //如果读入的字符是那种分界的符号
            if(ch == ' ' || ch == '\n'){
                //如果是空格或者是换行,不用输出
                //先输出str中的元素,再重置
                //cout<<"1"<<endl;
                //cout<<"str:"<<str<<endl;
                if(str != ""){
                    //cout<<"1"<<endl;
                    //cout<<str<<endl;
                    if(ch == '\n') inputVol(str.substr(0,str.length()-1));
                    if(ch == ' ') inputVol(str);
                }
                //str = "";
            }else{
                //如果读入的不是那种分界符,是界符、操作符这类需要输出的
                //先输出str中的元素,再输出这类符号,不要忘了重置
                //cout<<"1:"<<str<<endl;
                if(isDelimiters(s) || isOperator(s)){
                    if(str != ""){
                        inputVol(str);
                    }
                    inputVol(s);
                }
                //cout<<"*:"<<isIdentifier(str)<<endl;
            }
            
            str = "";

        }
    }
    
}


void display(){
    cout<<"定义规范:"<<endl;
    cout<<"常数 >> 1"<<endl;
    cout<<"标识符 >> 2"<<endl;
    cout<<"保留字 >> 3"<<endl;
    cout<<"运算符 >> 4"<<endl;
    cout<<"界符 >> 5"<<endl;
    cout<<"请输入你的选择: 1.判断单词类型 2.导入文件判断"<<endl;
}

int main(int argc, const char * argv[]) {
    while(1){
        cout<<"本程序的定义原则:"<<endl;
        display();
        //cout<<"请输入你想要判断的单词"<<endl;
        int input;
        cin>>input;
        if(input == 1){
            string str;
            cout<<"请输入你想要判断的单词"<<endl;
            cin>>str;
            inputVol(str);
            }else if(input == 2){
            inputPro();
            }
        }
        
    return 0;
}
    

6. 实验结果

在运行程序后,程序预先定义单词类型原则,并在控制台提供两种功能供用户进行选择,用户可以选择判断单词类型功能或是导入文件判断单词类型功能。
在这里插入图片描述

6.1 判断单词类型

用户根据提示输入单词,在输入数字时,系统自动判断整型与浮点数并输出。
在这里插入图片描述
用户根据提示输入单词,在输入布尔型或字符串类型时,系统自动判断并输出。
布尔型存疑
用户根据提示输入单词,在输入标识符变量不超过5位时,系统自动判断并输出;如若标识符超过五位,系统只输出前五位作为标识符。
在这里插入图片描述
在这里插入图片描述
用户根据提示输入单词,在输入保留字时,系统自动判断并输出。
用户根据提示输入单词,在输入运算符时,系统自动判断并输出。
在这里插入图片描述

  • 1
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值