編譯原理實驗之詞法分析
阿新 • • 發佈:2019-01-28
內容有更新哦~~~
能識別小數,科學記數法表示的數,負數亦可。
不多解釋,程式碼先上:
#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