<>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位时,系统自动判断并输出;如若标识符超过五位,系统只输出前五位作为标识符。
用户根据提示输入单词,在输入保留字时,系统自动判断并输出。
用户根据提示输入单词,在输入运算符时,系统自动判断并输出。