编译原理——词法分析

词法分析程序设计


题目

Description

设一语言的关键词、运算符、分界符的个数与单词如下:

struct { int number; string str[10]; }
keywords={3,"int","main","return"} ; //关键词

struct { int number; string str[10]; }
operators ={5,"+","*","=","+=","*="}; //运算符

struct { int number; string str[10]; }
boundaries ={6,"(",")","{","}",",",";"} ; //分界符

struct { int number; string str[100];}
identifieres={0}; //标识符

struct { int number; string str[100];}
Unsigned_integer={0}; //无符号整数

以上类号分别为1~5,序号从0开始;
标识符是字母开头的字母数字串;
常量为无符号整数;
用C++设计一程序实现词法分析。

Input
输入一程序,结束符用”#”

Output
输出单词数对:<类号,序号>。
输出标识符表,用空格分隔;
输出无符号整数表,用空格分隔

Sample Input

main()
{ int a=2,b=3;
  return 2*b+a;
}#

Sample Output

<1,1><3,0><3,1><3,2><1,0><4,0><2,2><5,0><3,4><4,1><2,2><5,1><3,5><1,2><5,0><2,1><4,1><2,0><4,0><3,5><3,3>
identifieres:a b
Unsigned_integer:2 3

解析

词法分析是编译的第一阶段,它的主要任务是扫描输入字符流,产生用于语法分析的词法记号序列。简单的来说,就是通过将字符流翻译成词法记号流。可以看作将一个英文句子划分成一个个单词。

上面的题目是一个简单的词法分析的程序设计题目,只需通过扫描输入的字符串,判断其中字符是否组成符合要求的词法记号,输出对应的类号和序号即可。


解决

#include <iostream> 
#include <string>
#include <vector>

using namespace std;

// 关键字keyword、operate、boundary的初始化
string keyword[3] = {"int", "main", "return"};
string operate[5] = {"+", "*", "=", "+=", "*="};
string boundary[6] = {"(", ")", "{", "}", ",", ";"};
// 用于存储标识符和无符号整数
vector<string> identifieres;
vector<string> integer;

// 函数isIn()主要用于判断字符串temp是否在标识符/无符号整数中,避免temp重复出现在标识符/无符号整数
int isIn(string temp, vector<string> in) {
    int s = in.size();
    for (int i = 0; i < s; i++) {
        if (temp == in[i]) {
            // 返回temp的index,便于输出其序号
            return i; 
        }
    }
    // 若temp未在in里面,返回-1作为一个判断
    return -1;
}

// 函数dealString()对输入的字符串进行处理,输出相应的<类号,序号>,并将标识符和无符号整数进行记录
void dealString(string temp) {
    int len = temp.length();
    // 循环遍历字符串
    for (int i = 0; i < len; i++) {
        // 由于分界符是单个字节组成,所以先判断temp[i]是否为分界符
        if (temp[i] == '(' || temp[i] == ')' || temp[i] == '{' || temp[i] == '}' || temp[i] == ',' || temp[i] == ';') {
            // 处理boundary,分界符的类号为3
            if (temp[i] == '(') cout << "<3,0>";
            if (temp[i] == ')') cout << "<3,1>";
            if (temp[i] == '{') cout << "<3,2>";
            if (temp[i] == '}') cout << "<3,3>";
            if (temp[i] == ',') cout << "<3,4>";
            if (temp[i] == ';') cout << "<3,5>";
        } else if (temp[i] == '+' || temp[i] == '*' || temp[i] == '=') {
            // 处理operator,运算符的类号为2
            if (temp[i + 1] != '=') {
                if (temp[i] == '+') cout << "<2,0>";
                if (temp[i] == '*') cout << "<2,1>";
                if (temp[i] == '=') cout << "<2,2>";
            } else {
                if (temp[i] == '+') cout << "<2,3>";
                if (temp[i] == '*') cout << "<2,4>";
            }
        } else if (temp[i] >= 'a' && temp[i] <= 'z') {
            // 区分关键字和标识符
            string sub = "";
            sub += temp[i];
            bool key = false;
            for(int k = i + 1; k < len; k++) {
                // 根据标识符的定义:字母+数字组成的字符串,构造子字符串,判断其为关键字还是标识符
                if (temp[k] >= 'a' && temp[k] <= 'z') {
                    sub += temp[k];
                } else if (temp[k] >= '0' && temp[k] <= '9') {
                    sub += temp[k];
                } else {
                    break;
                }
                // 关键字的判定,关键字的类号为1
                if (sub.length() == 3 && sub == "int") {
                    cout << "<1,0>";
                    key = true;
                    break;
                } else if (sub.length() == 4 && sub == "main") {
                    cout << "<1,1>";
                    key = true;
                    break;
                } else if (sub.length() == 6 && sub == "return") {
                    cout << "<1,2>";
                    key = true;
                    break;
                }
            }
            // 该子字符串为标识符,标识符的类号为4
            if (!key) {
                // 判断该标识符是否在之前出现过
                int index = isIn(sub, identifieres);
                if (index == -1) {
                    // 第一次出现,将该标识符添加到identifieres中
                    identifieres.push_back(sub);
                    cout << "<4," << identifieres.size() - 1 << ">";
                } else {
                    // 之前出现过,直接输出其序号
                    cout << "<4," << index << ">";
                }
            }
            // 直接跳过组成该标识符/关键字的字符
            i += sub.length() - 1;
        } else if (temp[i] >= '0' && temp[i] <= '9') {
            // 处理无符号整数,无符号整数的类号为5
            string sub = "";
            sub += temp[i];
            for(int k = i + 1; k < len; k++) {
                // 无符号整数只由数字组成
                if (temp[k] >= '0' && temp[k] <= '9') {
                    sub += temp[i];
                } else {
                    break;
                }
            }
            // 判断该无符号整数是否在之前出现过
            int index = isIn(sub, integer);
            if (index == -1) {
                // 第一次出现,将该无符号整数添加到integer中
                integer.push_back(sub);
                cout << "<5," << integer.size() - 1 << ">";
            } else {
                // 之前出现过,直接输出其序号
                cout << "<5," << index << ">";
            }
        } else if (temp[i] == ' ') {
            // 遇到空格不处理,但是用cin读入输入字符串的话会自动忽略空格
            continue;
        }
    }
}

int main() {
    string temp;
    int len;
    bool isEnd = false;
    while (!isEnd) {
        cin >> temp;
        size_t t = temp.find("#");
        // 若temp中有“#”,那么t不为空,而“#”是终结输入的标志
        if (t != string::npos) {
            temp = temp.substr(0, t);
            isEnd = true;
        }
        dealString(temp);
    }
    cout << endl;
    // 输出字符串中的标识符
    cout << "identifieres:";
    for (int i = 0; i < identifieres.size(); i++) {
        cout << identifieres[i] << " ";
    }
    // 输出字符串中的无符号整数
    cout << "\nUnsigned_integer:";
    for (int i = 0; i < integer.size(); i++) {
        cout << integer[i] << " ";
    }
    cout << endl;
    return 0;
}
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值