紧跟上一篇计算器的文章,笔者这次基于完全相同的思想再做一个表达式语法树生成吧
语法树是按照preorder的顺序遍历捏~
先上结果!!!
对了,记得最后一个测试案例要多一个换行符蛤~因为在判断表达式是否正确的时候用到了最终的换行符作为判断依据的
#define _CRT_SECURE_NO_WARNINGS
/*Simple integer/float arithmetic calculator
according to the EBNF:
<exp> -> <modexp> { <addop> <modexp> }
<addop> -> + | -
<modexp> -> <mulexp> { <modop> <mulexp> }
<modop> -> %
<mulexp> -> <brkexp> { <mulop> <brkexp> }
<mulop> -> * | /
<brkexp> -> ( <exp> ) | Number
*/
#include <stdlib.h>
#include <stdio.h>
struct Tree {
char *val;
struct Tree* left;
struct Tree* right;
};
typedef struct Tree* syntaxTree;
FILE* in;
char token; /* global token variable */
int right = 1; /* 0 for false, 1 for right */
/* function prototypes for recursive calls */
syntaxTree exp(void);
syntaxTree modexp(void);
syntaxTree mulexp(void);
syntaxTree brkexp(void);
void error(void) {
fprintf(stderr, "Error\n");
}
void match(char expectedToken) {
if (token == expectedToken)
while ((token = getc(in)) == ' ') {}
else {
right = 0;
}
}
syntaxTree makeOpNode(char ch) {
syntaxTree tmp = (syntaxTree)malloc(sizeof(struct Tree));
switch (ch) {
case '+':
tmp->val = "Add";
break;
case '-':
tmp->val = "Sub";
break;
case '*':
tmp->val = "Mul";
break;
case '/':
tmp->val = "Div";
break;
case '%':
tmp->val = "Mold";
break;
}
return tmp;
}
/* print the syntaxtree in preorder */
void Print(syntaxTree root, int h) {
for (int i = 0; i < h; i++)
printf(" ");
printf("%s :\n", root->val);
if (root->val == "Const")
return;
Print(root->left, h + 1);
Print(root->right, h + 1);
}
main()
{
in = fopen("test.txt", "r");
syntaxTree root;
while ((token = getc(in)) != EOF) { /* end with '#' */
root = exp();
if (token == '\n' && right) /* right is to prevent errors in the middle */
Print(root, 0);
else {
error();
right = 1;
if (token == '\n')
continue;
else {
while ((token = getc(in)) != '\n') {} /* traverse to the end */
}
}
}
return 0;
}
syntaxTree exp(void) {
syntaxTree newtmp;
syntaxTree tmp = modexp();
while (token == '+' || token == '-') {
switch (token) {
case '+':
match('+');
newtmp = makeOpNode('+');
newtmp->left = tmp;
newtmp->right = modexp();
tmp = newtmp;
break;
case '-':
match('-');
newtmp = makeOpNode('-');
newtmp->left = tmp;
newtmp->right = modexp();
tmp = newtmp;
break;
}
}
return tmp;
}
syntaxTree modexp(void) {
syntaxTree newtmp;
syntaxTree tmp = mulexp();
while (token == '%') {
match('%');
newtmp = makeOpNode('%');
newtmp->left = tmp;
newtmp->right = mulexp();
tmp = newtmp;
}
return tmp;
}
syntaxTree mulexp(void) {
syntaxTree newtmp;
syntaxTree tmp = brkexp();
while (token == '*' || token == '/') {
switch (token) {
case '*':
match('*');
newtmp = makeOpNode('*');
newtmp->left = tmp;
newtmp->right = brkexp();
tmp = newtmp;
break;
case '/':
match('/');
newtmp = makeOpNode('/');
newtmp->left = tmp;
newtmp->right = brkexp();
tmp = newtmp;
break;
}
}
return tmp;
}
syntaxTree brkexp(void) {
syntaxTree tmp = (syntaxTree)malloc(sizeof(struct Tree));
float TMP; /* used as a buffer */
if (token == '(') {
match('(');
tmp = exp();
match(')');
}
else if (isdigit(token)) {
ungetc(token, in);
fscanf(in, "%f", &TMP);
tmp->val = "Const";
while ((token = getc(in)) == ' ') {}
}
else {
right = 0;
}
return tmp;
}