编译原理-词法分析
编译原理 实验一作业
分类
-
关键字
- 特殊的标识符,在标识符中进行判断即可
- 用一个数组存放所有定义的关键字
-
标识符
- <字母>|<下划线>{<字母>|<数字>|<下划线>}
- 不是关键字
-
常数
-
数字常量
1. 整数 111 001(可以0开头 等价于 1) 2. 小数(有且只有一个小数点) 111.1 011.100(小数点后允许有多余的0)
-
字符常量
‘c’ 单引号括一个字符(字符不能为空) -
字符串常量
“string” 双引号括起来的字符串(可以为空串)
-
-
运算符 在界限符后判断
1. 单一符号(无扩展)的运算符 ? : 2. <符号>[=]的运算符 = == ! != ^ ^= * *= / /= % %= 3. <符号>[符号][=]的运算符 & && &= | || |= + ++ += - -- -= 4. <符号>[符号][=] 或 <符号>[=]的运算符 < << <<= <= > >> >>= >=
-
界限符
- 在常量判断后调用 可以将之前条件只完成一半的算入 界限符
1. 对称符号 [ ] ( ) { } ' ' " " 2. 单一符号 ~ ` @ # $ \ 3. 注释 /* */ (/**/内整片区域) // (//后面的整行内容)
通用函数、全局变量与结构体
结构体
- 用于记录存储词法分析的结果的二元式结构体
- ( 类型号 , 词串 )
- 两种构造函数
- toString()方法便于输出
/*二元式结构体*/
typedef struct node{
int type = 0;
string s = "";
node(int t,string str){ type = t,s = str; }
node(int t,char c){ type = t,s += c; }
string toString(){return "( " + to_string(type) + " , " + s + " )";}
};
全局变量
/*全局变量*/
//存储输出内容的二元式
vector<node>ans;
//输入文本
string text;
int typeCnt[10];//各种类型的数量
//关键字集合
set<string>keys;
//界限符集合
set<char>boundarySymbols;
通用函数
/*工具函数*/
//去字符串两边的空白
void trim(string & s){
int end = s.length() - 1;
int begin = 0;
while(begin < end && isblank(s[begin])){ begin++; }
while(end > begin && isblank(s[end])){ end--; }
s = s.substr(begin,end - begin + 1);
}
//判断当前下标是否还有字符
bool exist(int pos){
return pos < text.length();
}
主函数
int main(){
init();//初始化函数
while(true){
reset();//重置信息函数
scan();//读入文本函数
analysis();//词法分析函数
print();//结果输出函数
}
return 0;
}
需要导入的头文件
#include <iostream>
#include <string>
#include <set>
#include <vector>
#include <fstream>
using namespace std;
初始化函数 init()
-
init()
/*初始化函数*/ void init(){ cout << "[词法分析器]\n" "0. 非法字符\n" "1. 关键字\n" "2. 标识符\n" "3. 常量[整数、小数、字符常量、字符串常量]\n" "4. 运算符\n" "5. 界限符[常见非运算符、括号、引号、注释]\n\n"; /*关键字初始化*/ initKeys(); /*界限符初始化*/ initBoundarySymbols(); }
-
initKeys()
/*关键字*/ //关键字集合 set<string>keys; //初始化函数 void initKeys(){ string keysString[] = { "char", "int", "bool", "short", "long", "float", "double", "string", "void", "return", "sign", "goto", "while", "for", "if", "else", "switch", "case", "main", "include", "using", "namespace" "printf", "scanf", "cos", "sqrt", "sin", "typedef", "struct", "class" }; for(string s : keysString){ keys.insert(s); } }
-
initBoundarySymbols()
//界限符集合初始化函数 void initBoundarySymbols(){ char chars[] = { ',', ';', '[', ']', '{', '}', '(', ')', '#', '$', '~', '`', '@', '\\', //如果是没有闭合的双引号或单引号则算入界限符 (因此 字符常量和字符串常量要在界限符之前进行判断) '\"', '\'', //如果是非小数的小数点则算入界限符 (因此 小数常量要在界限符之前进行判断) '.' }; for(char c : chars){ boundarySymbols.insert(c); } }
重置信息函数 reset()
/*重置信息*/
void reset(){
//清空结果集
ans.clear();
//将文本设置为空串
text = "";
//将类型计数器清0
for(auto cnt : typeCnt)cnt = 0;
}
文本读入函数 scan()
/*数据输入
两种输入方式
0:读取一行输入
非0:根据文件地址读取文本
*/
void scan(){
cout << "请选择文本输入方式[0:读入一行]、[1:根据文件地址读取文件](输入任何非0字符则视为1)" << endl;
string s;
cin >> s;
getchar();//读取回车符
if(s == "0"){
cout << "请输入一行需要进行语法分析的数据:" << endl;
getline(cin,text);
} else{
string path;
printf("\n请输入需要进行词法分析的文件地址(英文地址):\n");
getline(cin,path);
ifstream f(path);
if(!f.is_open()){
cerr << "打开文件失败!:" << path << endl;
} else{
string s;
while(getline(f,s)){
text += s;
text += '\n';