内容有更新哦~~~
能识别小数,科学记数法表示的数,负数亦可。
不多解释,代码先上:
#include <cstdio>
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <fstream>
#include <map>
#include <cstdlib>
#include <cmath>
using namespace std;
const int maxn = 1002;
const int n_key = 40;
const int n_oper = 21;
char c;
string key_word[n_key] = {"auto", "enum", "restrict", "unsigned", "break",
"extern", "return", "void", "case", "float",
"short", "volatile", "char", "for", "signed",
"while", "const", "goto", "sizeof", "_Bool",
"continue", "if", "static", "_Complex", "default",
"inline", "struct", "_Imaginary", "do", "int",
"switch", "double", "long", "typedef", "else",
"register", "union", "main", "scanf", "printf"
};
string oper[] = {"+", "-", "*", "/", "^",
"<", ">", "++", "--", "==",
"*=", "/=", ">=", "<=", "<<",
">>", ">>=", "<<=", "%", "&",
"^"
};
char bound[] = {',', ';', '(', ')', '[', ']', '{', '}'};
struct Word{ //词结构体
int id;
string value;
};
struct Num{
int id;
int vi;
double vd;
};
Num n[maxn]; //数字
Word w[maxn]; //词
map<string, int> m; //标识符
int f = 0, ff = 0;
bool is_oper(string s){
for(int i=0; i<n_oper; i++) if(s == oper[i]) return true;
return false;
}
bool is_bound(char c){
for(int i=0; i<sizeof(bound); i++) if(c == bound[i]) return true;
return false;
}
bool is_key(string s){
for(int i=0; i<n_key; i++) if(s == key_word[i]) return true;
return false;
}
int stoi(string s){ //get int
int ans = 0;
for(int i=0; i<s.size(); i++) ans = ans * 10 + s[i] - '0';
return ans;
}
double stof(string s){ //get double
long long ans = 0;
int fd = -1, fe = -1;
for(int i=0; i<s.size(); i++){
if(s[i] == '.'){
fd = i;
continue;
}
if(s[i] == 'e'){
fe = i;
continue;
}
ans = ans * 10 + s[i] - '0';
}
if(fd != -1 && fe == -1) return double(ans)/(pow(10, s.size() - fd - 1));
else if(fd == -1 && fe != -1){
long long temp = ans % (long long)pow(10, s.size() - fe - 1); //得到e后的数字
ans /= pow(10, s.size() - fe - 1); //得到e前的数字
return double(ans*pow(10, temp));
}
else{
long long temp = ans % (long long)pow(10, s.size() - fe - 1); //得到e后的数字
ans /= pow(10, s.size() - fe - 1); //得到e前的数字
long long tt = (s.size() - fd - 1) - (s.size() - fe - 1) - 1; //得到.后的数字
return (double)ans/pow(10, tt) * (pow(10, temp));
}
}
void getword(char filename[]){
freopen(filename, "r", stdin); //重定向
string str = "";
int flag, is_end;
is_end = scanf("%c", &c);
while(is_end != EOF){
flag = 0;
if(isspace(c)){
str = "";
while(isspace(c) && is_end != EOF){ //滤空格
is_end = scanf("%c", &c);
}
}
if(isalpha(c)){ //以字母开头
str = "";
while(isalnum(c) || c == '_'){
str += c;
is_end = scanf("%c", &c);
}
w[++f].value = str;
if(is_key(str)) w[f].id = 1; //保留字
else{
w[f].id = 2; //标识符
m[str] ++;
}
flag = 1;
}
if(isdigit(c)){ //数字
int fd = 0, fe = 0, fflag = 0, is_neg = 0;
if(str == "-") is_neg = 1;
str = "";
while(isdigit(c) || c == '.' || c == 'e'){
if(c == '.') fd ++;
if(c == 'e') fe ++;
if(c == '.' && fe) fflag = 1;
str += c;
is_end = scanf("%c", &c);
}
if(str[str.size()-1] == '.' || str[str.size()-1] == 'e') fflag = 1;
if(fflag){
cout<<"错误-->不合法数字:"<<(is_neg ? "-" + str : str)<<endl; //忽略不合法输入
}
else{
if(!fd && !fe){
n[++ff].vi = (is_neg ? -stoi(str) : stoi(str));
n[ff].id = 1;
}
else{
n[++ff].vd = (is_neg ? -stof(str) : stof(str));
n[ff].id = 2;
}
w[++f].id = 3; w[f].value = (is_neg ? "-" + str : str);
}
flag = 1;
}
if(is_bound(c)){ //界符
str = "";
str += c;
w[++f].value = str;
w[f].id = 4;
is_end = scanf("%c", &c);
flag = 1;
}
string ss = "";
ss += c;
if(is_oper(ss)){
bool is_lastdigt = isdigit(str[str.size()-1]);
str = "";
while(is_oper(ss)){
str += c;
is_end = scanf("%c", &c);
ss += c;
}
if(str == "-" && !is_lastdigt && isdigit(c)) continue;
if(is_oper(str)){
w[++f].value = str;
w[f].id = 5;
}
flag = 1;
}
if(!flag && is_end != EOF){
str = "";
str += c;
w[++f].value = str;
w[f].id = 6;
is_end = scanf("%c", &c);
}
}
freopen("CON", "r", stdin); //关闭重定向,恢复标准
}
void to_file1(){ //主表
char filename[20];
puts("请输入词法分析主表要保存到的地址:");
scanf("%s", filename);
fstream out;
out.open(filename, ios::out);
out<<"1.保留字 2.标识符 3.数字 4.界符 5.操作符 6.其他"<<endl<<endl;
for(int i=1; i<=f; i++) out<<w[i].id<<" "<<w[i].value<<endl;
out.close();
}
void to_file2(){ //标识符表
ofstream out;
char filename[20];
puts("请输入词法分析标识符表要保存到的地址:");
scanf("%s", filename);
out.open(filename, ios::out);
map<string, int>::iterator it;
for(it=m.begin(); it!=m.end(); it++) out<<it->first<<endl;
out.close();
}
void to_file3(){ //数字表
ofstream out;
char filename[20];
puts("请输入词法分析数字表要保存到的地址:");
scanf("%s", filename);
out.open(filename, ios::out);
out<<"1.int 2.double"<<endl<<endl;
for(int i=1; i<=ff; i++) out<<n[i].id<<" "<<(n[i].id == 1 ? n[i].vi : n[i].vd)<<endl;
out.close();
}
int main(){
char filename[20];
puts("请输入您要打开的文件地址:");
scanf("%s", filename);
getword(filename);
to_file1();
to_file2();
to_file3();
return 0;
}
编译原理之词法分析实验终于写完了,收工啦~~~
PS:本人还是比较满意的o(^▽^)o