题目描述
掌握预测分析程序的分析、设计与实现的基本技术与一般方法。
编写识别由下列文法所定义的表达式的预测分析程序。
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 <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <conio.h>
#define digit 1
#define op 2
#define Hh 3
#define AF 4
#define letter 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);
int j2d(char current);
void dopush(int t);
bool check_terminal(char ch);
int isDigitOrChar(char ch);
string change_i(string words);
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 %c\n\n", 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;
}
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;
}
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)
return Hh;
else if ((ch >= 65 && ch <= 70) || (ch >= 97 && ch <= 102))
return AF;
else if ((ch >= 65 && ch <= 90) || (ch >= 97 && ch <= 122))
return letter;
else if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '(' || ch == ')' || ch == '#')
return op;
}
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:
switch (isDigitOrChar(q)) {
case digit:
word[i++] = q;
state = 2;
break;
case Hh:
case AF:
case letter:
word[i++] = q;
state = 1;
break;
case op:
result += q;
state = 0;
break;
default:
word[i++] = q;
state = 5;
}
break;
case 1:
switch (isDigitOrChar(q)) {
case Hh:
case AF:
case digit:
case letter:
word[i++] = q;
state = 1;
break;
case op:
word[i] = '\0';
printf("%s is an identifier.\n", word);
memset(word, 0, sizeof word);
i = 0;
state = 0;
break;
default:
word[i++] = q;
state = 5;
}
break;
case 2:
switch (isDigitOrChar(q)) {
case digit:
word[i++] = q;
state = 2;
break;
case Hh:
word[i++] = q;
state = 3;
break;
case AF:
word[i++] = q;
state = 4;
break;
case op:
word[i] = '\0';
printf("%s is an Integer.\n", word);
result += "i";
result += q;
memset(word, 0, sizeof word);
i = 0;
state = 0;
break;
default:
word[i++] = q;
state = 5;
}
break;
case 3:
switch (isDigitOrChar(q)) {
case op:
word[i] = '\0';
printf("%s is a Hex digit.\n", word);
result += "i";
result += q;
memset(word, 0, sizeof word);
i = 0;
state = 0;
break;
default:
word[i++] = q;
state = 5;
}
break;
case 4:
switch (isDigitOrChar(q)) {
case digit:
case AF:
word[i++] = q;
state = 4;
break;
case Hh:
word[i++] = q;
state = 3;
break;
case op:
state = 5;
cnt--;
break;
default:
word[i++] = q;
state = 5;
}
break;
case 5:
if (isDigitOrChar(q) == op) {
word[i] = '\0';
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;
}
|