编制一个词法分析程序,设置5类或者3类单词,能识别字符。词法分析器的大小自定,语言模版可以参考PL/0,也可以自己定义。撰写实验报告。
参考教材中对PL/0语言的定义,我们将PL/0语言的单词分为保留字、运算符、标识符、界符和常数五大类,其中常数包括整型、浮点型、布尔型和字符串类型。
下面的表格展示了具体的定义规范。
程序通过该表的定义规范从输入中识别出各个单词的类型并输出。在碰到程序没有定义的单词时,则输出“非法字符(程序为定义)!”的报错提示。
在本程序中设计了两种输入形式,由用户自行选择。第一种是通过用户输入单个字符来判断该字符的单词类型,并以<单词自身值,单词的类型,单词编码>的形式输出。第二种是通过读入外部文件程序来识别该该程序中各个单词的类型,并且,程序依次输出各个单词的内部编码及单词单词自身的值,在遇到错误时显示报错提示,然后跳过该字符继续识别。
实验语言:C++
实验系统:Mac OS操作系统
实验环境:Xcode Version 12.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。
//
// 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<
for(int i=0; i<ARRAY_SIZE(keywords); i++){
if(s == keywords[i]){
//cout<
//cout<
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"<
return 1; //是界符
}
}
return 0;
}
//判断单词是不是整数,如果是,是什么类型的整数,int或者float
int isConstant(string s){
int isInt = 1;
int isFloat = 1;
int countDot = 0;
int indexDot = 0;
//cout<<"长度:"<
for(int i=0; i<s.length(); i++){
//cout<
if(!isdigit(s[i])){
isInt = -1;
//cout<<"进"<
}
}
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<<"首字母规范"<
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<
continue; //判断之后字符是否为“下划线”或“字母”或“数字”
}else{
return 0;
}
}
return 1;
}else {
//首字母不符合规范,不是identifier
return 0;
}
}
void inputVol(string s){
//cout<<"请输入你想要判断的单词"<
string str = s;
//cin>>str;
if(isDelimiters(str) == 1){ //如果是界符
//cout<<"1"<
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<<"进来了"<
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:"<
//cout<<"s"<
//cout<
if(!isDelimiters(s) && !isOperator(s) && ch > 32 && ch != ' '){
//如果读入的字符不是那些用于分界的符号
//cout<<"ch"<
str += ch;
//cout<
}else{
//bool flag = false;
//如果读入的字符是那种分界的符号
if(ch == ' ' || ch == '\n'){
//如果是空格或者是换行,不用输出
//先输出str中的元素,再重置
//cout<<"1"<
//cout<<"str:"<
if(str != ""){
//cout<<"1"<
//cout<
if(ch == '\n') inputVol(str.substr(0,str.length()-1));
if(ch == ' ') inputVol(str);
}
//str = "";
}else{
//如果读入的不是那种分界符,是界符、操作符这类需要输出的
//先输出str中的元素,再输出这类符号,不要忘了重置
//cout<<"1:"<
if(isDelimiters(s) || isOperator(s)){
if(str != ""){
inputVol(str);
}
inputVol(s);
}
//cout<<"*:"<
}
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<<"请输入你想要判断的单词"<
int input;
cin>>input;
if(input == 1){
string str;
cout<<"请输入你想要判断的单词"<<endl;
cin>>str;
inputVol(str);
}else if(input == 2){
inputPro();
}
}
return 0;
}
在运行程序后,程序预先定义单词类型原则,并在控制台提供两种功能供用户进行选择,用户可以选择判断单词类型功能或是导入文件判断单词类型功能。
用户根据提示输入单词,在输入数字时,系统自动判断整型与浮点数并输出。
用户根据提示输入单词,在输入布尔型或字符串类型时,系统自动判断并输出。
布尔型存疑
用户根据提示输入单词,在输入标识符变量不超过5位时,系统自动判断并输出;如若标识符超过五位,系统只输出前五位作为标识符。
用户根据提示输入单词,在输入保留字时,系统自动判断并输出。
用户根据提示输入单词,在输入运算符时,系统自动判断并输出。