前言
写了这篇使用文法规则实现四则运算博客, 顺手也写了本篇。
这里涉及到树, 对树结构感兴趣且没有什么基础的小伙伴可以查看这个:详细二叉树实现c++, 我当时写的挺详细的,就是当时初学,代码没有优化…
生成语法树
//
// Created by Andy Dennis on 2020/12/9.
// 文法规则:
/*exp -> term {addop term}
* addop -> + | -
* term -> factor {mulop factor}
* mulop -> * | /
* factor -> (exp) | n
* */
# include <iostream>
# include <cmath>
using namespace std;
// 全局变量token
char token;
// 待处理的字符串
string str;
// 字符串读取到的地方
int strIndex = 0;
// 存放数字
string num;
struct BinTreeNode {
string data; // 存储数据
BinTreeNode *leftChild, *rightChild;
BinTreeNode() : leftChild(nullptr), rightChild(nullptr) {
}
};
// 用到的函数, 先提前声明
void getToken();
void match(char expectToken, int errorId);
void Error(int errorId, char expectToken);
void PrintBinTree(BinTreeNode *BT);
BinTreeNode *exp();
BinTreeNode *term();
BinTreeNode *factor();
int main() {
string examples[3] = {
"3.2-5+8", "3+8/2-6", "(5*(9-2)+1)/9"};
for (int i = 0; i < 3; i++) {
str = examples[i];
strIndex = 0;
cout << "task "<< i + 1 << ": " << str << endl;
getToken();
BinTreeNode *root = exp();
PrintBinTree(root);
cout << endl;
}
// 测试一下getToken函数
// while (token != '$') {
// getToken();
// if (token == '0')
// cout << num << endl;
// else
// cout << token << endl;
// }
}
BinTreeNode *exp() {
char errorId = 0;
BinTreeNode *temp, *newTemp;
temp = term();
while (token == '+' || token == '-') {
newTemp = new BinTreeNode();
newTemp->data = token;
match(token, errorId);
newTemp->leftChild = temp;
newTemp->rightChild = term();
temp = newTemp;
}
return temp;
}
BinTreeNode *term() {
char errorId = 1;
BinTreeNode *temp, *newTemp;
temp = factor();
while (token == '*' || token == '/') {
newTemp = new BinTreeNode();
newTemp->data = token;
match(token, errorId);
newTemp->leftChild = temp;
newTemp->rightChild = factor();
temp = newTemp;
}
return temp;
}
BinTreeNode *factor() {
BinTreeNode *temp;
char errorId = 2;
if (token == '(') {
match('(', errorId);
temp = exp();
match(')', errorId);
} else if (token == '0') {
match('0', errorId);
temp = new BinTreeNode();
temp->data = num;
// temp->leftChild = nullptr;
// temp->rightChild = nullptr;
} else {
cout << "---> col " << strIndex << ",at the character " << str[strIndex - 1] << endl;
cout << "error at factor -> (exp) | n, expected token is ( or num, but not found!" << endl;
exit(EXIT_FAILURE); // 非正常退出
}
return temp;
}
void getToken() {
if (strIndex < str.length()) {
if (str[strIndex] >= '0' && str[strIndex] <= '9') {
string tempNumStr;
while (strIndex < str.length() && (str[strIndex] >= '0' && str[strIndex] <= '9' || str[strIndex] == '.')) {
tempNumStr += str[strIndex];
strIndex++;
}
num = tempNumStr;
token = '0'; // token == 0 代表这个token的内容是 num
} else {
// + - * / ()
token = str[strIndex];
strIndex++;
}
} else {
token = '$'; // 结束符
}
}
void Error(int errorId, char expectToken) {
string grammar[3] = {
"exp -> term {addop term}", "term -> factor {mulop factor}",
"factor -> (exp) | n"};
cout << "---> col " << strIndex << ",at the character " << str[strIndex - 1] << endl;
cout << "error at " << grammar[errorId] << ", expected token is "
<< expectToken << " but not found!" << endl;
exit(EXIT_FAILURE); // 表示当前操作系统下未能成功退出的终止代码
}
void match(char expectToken, int errorId) {
if (token == expectToken) {
getToken();
} else {
Error(errorId, expectToken); // Error函数
}
};
void PrintBinTree(BinTreeNode *BT) {
if (BT != nullptr) {
cout << BT->data;
if (BT->leftChild != nullptr || BT->rightChild != nullptr) {
cout << "(";
PrintBinTree(BT->leftChild); // 递归输出左子树
if (BT->rightChild != nullptr) {
cout << ",";
PrintBinTree(BT->rightChild); // 递归输出右子树
}
cout << ")";
}
}
}
生成汇编代码
//
// Created by Andy Dennis on 2020/12/9.
// 文法规则:
/*exp -> term {addop term}
* addop -> + | -
* term -> factor {mulop factor}
* mulop -> * | /
* factor -> (exp) | n
* */
# include <iostream>
# include <cmath>
using namespace std;
// 全局变量token
char token;
// 待处理的字符串
string str;
// 字符串读取到的地方
int strIndex = 0;
// 存放数字
string num;
// 存放生成的汇编代码结果
string assemblyCode;
// 用到的函数, 先提前声明
void getToken();
void match(char expectToken, int errorId);
void Error(int errorId, char expectToken);
void exp();
void term();
void factor();
void gen(const string& code);
int main() {
string examples = "3+8/2-6";
str = examples;
strIndex = 0;
getToken();
exp();
cout << "the generation assembly code:" << endl;
cout << assemblyCode << endl;
}
void exp() {
char errorId = 0;
term();
while (token == '+' || token == '-') {
if (token == '+') {
match(token, errorId);
term();
gen("Adi");
} else if (token == '-') {
match(token, errorId);
term();
gen("Sbi");
}
}
}
void term() {
char errorId = 1;
factor();
while (token == '*' || token == '/') {
if (token == '*') {
match(token, errorId);
factor();
gen("Mpi");
} else if (token == '/') {
match(token, errorId);
factor();
gen("Dvi");
}
}
}
void factor() {
char errorId = 2;
if (token == '(') {
match('(', errorId);
exp();
match(')', errorId);
} else if (token == '0') {
match('0', errorId);
gen("Ldc " + num);
} else {
cout << "---> col " << strIndex << ",at the character " << str[strIndex - 1] << endl;
cout << "error at factor -> (exp) | n, expected token is ( or num, but not found!" << endl;
exit(EXIT_FAILURE); // 非正常退出
}
}
void getToken() {
if (strIndex < str.length()) {
if (str[strIndex] >= '0' && str[strIndex] <= '9') {
string tempNumStr;
while (strIndex < str.length() && (str[strIndex] >= '0' && str[strIndex] <= '9' || str[strIndex] == '.')) {
tempNumStr += str[strIndex];
strIndex++;
}
num = tempNumStr;
token = '0'; // token == 0 代表这个token的内容是 num
} else {
// + - * / ()
token = str[strIndex];
strIndex++;
}
} else {
token = '$'; // 结束符
}
}
void Error(int errorId, char expectToken) {
string grammar[3] = {
"exp -> term {addop term}", "term -> factor {mulop factor}",
"factor -> (exp) | n"};
cout << "---> col " << strIndex << ",at the character " << str[strIndex - 1] << endl;
cout << "error at " << grammar[errorId] << ", expected token is "
<< expectToken << " but not found!" << endl;
exit(EXIT_FAILURE); // 表示当前操作系统下未能成功退出的终止代码
}
void match(char expectToken, int errorId) {
if (token == expectToken) {
getToken();
} else {
Error(errorId, expectToken); // Error函数
}
};
void gen(const string& code) {
assemblyCode += code + "\n";
}
结语
编译原理摸爬滚打中…