词法分析程序设计
题目
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;
}