掌握预测分析程序的分析、设计与实现的基本技术与一般方法。
编写识别由下列文法所定义的表达式的预测分析程序。
E
−
>
E
+
T
∣
E
−
T
∣
T
E -> E+T | E-T | T
E−>E+T∣E−T∣T
T
−
>
T
∗
F
∣
T
/
F
∣
F
T ->T*F | T/F | F
T−>T∗F∣T/F∣F
F
−
>
(
E
)
∣
i
F ->(E) | i
F−>(E)∣i
输入:从键盘输入表达式,或每行含有一个表达式的文本文件。其中,表达式中含有任意的十进制数或十六进制数,并以#结束。
如:80-5H+(6+1)+4h/2#。
本次实验运用到了基础数据结构——栈,并且是用链表代替线性表,体现了数据结构与编译原理概念相结合的思想。经过前两次实验,这次编写代码显得驾轻就熟,遇到一些bug,能够根据程序流程图进行复查,并顺利解决。对于LL(1)文法的理解与掌握也深刻了很多。
C++
#include#include #include #include #include #define digit 1 // 1数字 #define op 2 // +-*/()# #define Hh 3 // 3Hh #define AF 4 // 4A-F #define letter 5 // 5其它字母 using namespace std; typedef struct node { char data; struct node* next; }; node* temp, * top; char cmpchar; string line; // 定义分析表结构 int table[5][8] = { {0, 0, 0, 0, 1, 0, 1, 0}, {1, 1, 0, 0, 0, 1, 0, 1}, {0, 0, 0, 0, 1, 0, 1, 0}, {1 ,1, 1, 1, 0, 1, 0, 1}, {0, 0, 0, 0, 1, 0, 1, 0} }; char q; // 指向输入符号串中当前的字符 char word[20]; // 存储当前识别的单词 int state; // 表示所处的状态 int i; // 单词的下标 char read(string line, int k); void push(char c); void pop(); int i2d(char cmpchar); // EATBF int j2d(char current); // +-*/()i# void dopush(int t); bool check_terminal(char ch); // 判断是否是终结符 int isDigitOrChar(char ch); string change_i(string words); // 将含有十进制或十六进制数的表达式转换为用i代替的表达式 int main() { ifstream fin("D:/Compile_exp/exp2-test.txt"); if (!fin.is_open()) { cout << "open file error." << endl; _getch(); return -1; } while (getline(fin, line)) { puts("--------------------------------------------"); string temp = line; line = change_i(line); if (line == "-1") { cout << temp << " is not a valid express." << endl; continue; } cout << "Output string is: " << line << endl; int i, j, t; push('#'); push('E'); // 初始化 int cur = 0; char current; while (cur < line.size()) { current = read(line, cur); cmpchar = top->data; pop(); printf("Top: %c --- Cur: %c", cmpchar, current); // 栈顶是终结符或#,但输入串中不是终结符或#时,判定为出错 if (check_terminal(cmpchar) && cmpchar != current) { cur--; // 便于判定为非法 break; } if (current == cmpchar) { if (current == '#') break; printf(" match success of %cnn", current); cur++; continue; } cout << endl; i = i2d(cmpchar); j = j2d(current); if (table[i][j] == 1) { t = 10 * i + j; dopush(t); } else { cur--; // 便于判定为非法 break; } } if (cur + 1 == line.size()) { cout << endl; cout << temp << endl; cout << "Your input is valid!" << endl; } else { cout << endl; cout << temp << endl; cout << "Sorry, your input is invalid!" << endl; } } return 0; } char read(string line, int k) { return line[k]; } // 压栈 void push(char c) { temp = (node*)malloc(sizeof node); temp->data = c; temp->next = top; top = temp; } // 弹栈 void pop() { cmpchar = top->data; if (top->next != NULL) top = top->next; } // 将i字符数字化 int i2d(char cmpchar) { int i = 0; switch (cmpchar) { case 'E': i = 0; break; case 'A': i = 1; break; case 'T': i = 2; break; case 'B': i = 3; break; case 'F': i = 4; } return i; } // 将j字符数字化 int j2d(char current) { int j = 0; switch (current) { case '+': j = 0; break; case '-': j = 1; break; case '*': j = 2; break; case '/': j = 3; break; case '(': j = 4; break; case ')': j = 5; break; case 'i': j = 6; break; case '#': j = 7; } return j; } void dopush(int t) { switch (t) { case 4: push('A'); push('T'); break; case 6: push('A'); push('T'); break; case 10: push('A'); push('T'); push('+'); break; case 11: push('A'); push('T'); push('-'); break; case 15: break; case 17: break; case 24: push('B'); push('F'); break; case 26: push('B'); push('F'); break; case 30: break; case 31: break; case 32: push('B'); push('F'); push('*'); break; case 33: push('B'); push('F'); push('/'); break; case 35: break; case 37: break; case 44: push(')'); push('E'); push('('); break; case 46: push('i'); break; } } int isDigitOrChar(char ch) { if (ch >= 48 && ch <= 57) // 数字 return digit; else if (ch == 72 || ch == 104) // H or h return Hh; else if ((ch >= 65 && ch <= 70) || (ch >= 97 && ch <= 102)) // 字母A,B,C,D,E,F return AF; else if ((ch >= 65 && ch <= 90) || (ch >= 97 && ch <= 122)) // 除A~F外的其它字母 return letter; else if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '(' || ch == ')' || ch == '#') return op; } // 将含有十进制或十六进制数的表达式转换为用i代替的表达式 string change_i(string words) { memset(word, 0, sizeof word); state = 0; i = 0; cout << "Input string is: " << words << endl; string result = ""; int cnt = 0; q = words[cnt++]; while (cnt <= words.size()) { // 先判断状态,再判断字符 switch (state) { case 0: // 0状态 switch (isDigitOrChar(q)) { case digit: // 数字 word[i++] = q; state = 2; // 转移到2状态 break; case Hh: // H or h case AF: // 字母A,B,C,D,E,F or a,b,c,d,e,f case letter: // 字母 word[i++] = q; state = 1; break; case op: // 操作符 result += q; state = 0; break; default: // 其它(非法字符 ) word[i++] = q; state = 5; } break; case 1: // 1状态 switch (isDigitOrChar(q)) { case Hh: // 当前状态遇到字母、数字往下读入 case AF: case digit: case letter: word[i++] = q; state = 1; break; case op: // 读入完毕,识别为标识符 word[i] = ' '; printf("%s is an identifier.n", word); //result += "i"; memset(word, 0, sizeof word); i = 0; state = 0; break; default: word[i++] = q; state = 5; } break; case 2: // 2状态 switch (isDigitOrChar(q)) { case digit: // 若为数字,不改变状态往下读入 word[i++] = q; state = 2; break; case Hh: // 若为Hh,转移至状态3 word[i++] = q; state = 3; break; case AF: // 若为AF,则有可能是16进制,转移至状态4 word[i++] = q; state = 4; break; case op: // 成功识别为整数 word[i] = ' '; printf("%s is an Integer.n", word); result += "i"; result += q; //cout << result << endl; memset(word, 0, sizeof word); i = 0; state = 0; break; default: word[i++] = q; state = 5; } break; case 3: // 3状态 switch (isDigitOrChar(q)) { case op: // 识别为16进制数 word[i] = ' '; printf("%s is a Hex digit.n", word); result += "i"; result += q; //cout << result << endl; memset(word, 0, sizeof word); i = 0; state = 0; break; default: word[i++] = q; state = 5; } break; case 4: // 4状态 switch (isDigitOrChar(q)) { case digit: // 若为数字或A~F,仍为状态4,往下读入 case AF: word[i++] = q; state = 4; break; case Hh: word[i++] = q; state = 3; break; case op: // 如果16进制没有以h或H结尾,转移至错误状态 state = 5; cnt--; break; default: word[i++] = q; state = 5; } break; case 5: // 出错状态 if (isDigitOrChar(q) == op) { // 若为空格,则识别为非标识符 word[i] = ' '; printf("%s is not an identifier.n", word); memset(word, 0, sizeof word); i = 0; state = 0; result = "-1"; return result; } else { // 出错序列还未读取完毕,往下读入 word[i++] = q; q = words[cnt++]; continue; } break; } q = words[cnt++]; // 指针下移(指向输入符号串中的下一个字符) } return result; } // 判断是否是终结符 bool check_terminal(char ch) { if (isDigitOrChar(ch) == op || ch == 'i') return true; else return false; }



