求语法树的初级问题

skyspeed 2003-10-10 11:22:38
一个表达式: a+b*(c-d)-e/f
用什么步骤作出它的语法树?
已知答案是:
'-'
/ \
'+' '/'
/ \ / \
'a' '*' 'e' 'f'
/ \
'b' '-'
/ \
'c' 'd'
时间长了,忘了怎么做的了,应该很简单吧? 还有哪有讲这个问题的?
...全文
372 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
短歌如风 2003-10-13
  • 打赏
  • 举报
回复
无论是语法树还是波兰式都非常适应表示二元操作符,通常我会为所有的一元操作符加一个“空操作数”转换为二元操作符。然后就不用特殊处理了。

此外,a--y中的两个减号不应该看成同一个操作符,一个是二元减,优先级较低;另一个是一元减,优先级比乘号还高。

这样生成的语法树就是
-(2)
a -(1)
nil y
处理到第二个操作数时却取出一个“减号”,从而判定是一遇到了单目操作符“-”,这时空操作数入栈,当前符为单目减。事实上处理的序列是(a) <subtract> (nil) <negative> (y),圆括号中的是操作数。
事实上,我上面的算法只是提到从表达式到语法树的一般过程,而从字符串到表达式的词法分析的过程,根据表达式所用语言的定义不同其细节也不同,可能简单也可能复杂。比如Fortran表达式:a/b**c如果你每次读一个字符就会在遇到第一个*号时计算a/b,但明显是错了。更复杂的是C,比如a---b,要分析为(a--)-b而不是a-(--b);此外还有三目操作符,要分解为两个双目操作符……
heartup 2003-10-12
  • 打赏
  • 举报
回复
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>

char ch;

typedef enum { real, add, sub, mul, di, po } NodeType;

typedef struct TNode {
NodeType tag;
union {
struct {
struct TNode* left, *right;
}child;
float value;
} tnt;
} TNode, *Tree;

Tree E();
Tree T();
Tree F();
Tree C();
Tree R();
int D();

Tree mkleaf(float val) {
Tree p = (Tree)malloc(sizeof(TNode));
p->tag = real;
p->tnt.value = val;
return p;
}

Tree mknode(NodeType tag, Tree left, Tree right) {
Tree p = (Tree)malloc(sizeof(TNode));
p->tag = tag;
p->tnt.child.left = left;
p->tnt.child.right = right;
return p;
}

void print(int dent, Tree t) {
int i = dent;
if(t) {
if(t->tag != real) print(dent+1, t->tnt.child.right);
while(i--) printf(" ");
switch(t->tag) {
case real: printf("%f\n", t->tnt.value); break;
case add : printf("%c\n", '+'); break;
case sub : printf("%c\n", '-'); break;
case mul : printf("%c\n", '*'); break;
case di : printf("%c\n", '/'); break;
case po : printf("%c\n", '^'); break;
}
if(t->tag != real) print(dent+1, t->tnt.child.left);
}
}

void error() {
printf("error!\n");
exit(0);
}

void match(char c) {
if(ch==c) {
ch = getchar();
while(ch==' ' || ch=='\t') ch = getchar();
}
else error();
}

int D() {
int val;
if(isdigit(ch)) {
val = (int)(ch-'0');
match(ch);
}
else {
val = 0;
error();
}
return val;
}

Tree R() {
float val = 1, f, tmpval = 1;
if(ch=='.') {
match('.');
f = 0.1;
val = f*D();
while(isdigit(ch)) {
f /= 10;
val += f*D();
}
}
else {
if(ch=='+') {
val = 1;
match('+');
}
else if(ch=='-') {
val = -1;
match('-');
}
val *= D();
while(isdigit(ch))
val = val*10+D();
if(ch=='.') {
match('.');
f = 0.1;
tmpval = f*D();
while(isdigit(ch)) {
f /= 10;
tmpval += f*D();
}
val += tmpval;
}
else if(ch=='e' || ch=='E') {
if(ch=='e') match('e');
else match('E');
if(ch=='+') {
tmpval = 1;
match('+');
}
else if(ch=='-') {
tmpval = -1;
match('-');
}
tmpval *= D();
while(isdigit(ch))
tmpval = tmpval*10+D();
val = pow(val, tmpval);
}
}
return mkleaf(val);
}

Tree C() {
Tree p;
if(ch=='(') {
match('(');
p = E();
match(')');
}
else p = R();
return p;
}

Tree F() {
Tree p, q;
p = C();
if(ch=='^') {
match('^');
q = F();
p = mknode(po, p, q);
}
return p;
}

Tree T() {
Tree p;
p = F();
while(ch=='*' || ch=='/') {
if(ch=='*') {
match('*');
p = mknode(mul, p, F());
}
else {
match('/');
p = mknode(di, p, F());
}
}
return p;
}

Tree E() {
Tree p;
p = T();
while(ch=='+' || ch=='-') {
if(ch=='+') {
match('+');
p = mknode(add, p, T());
}
else {
match('-');
p = mknode(sub, p, T());
}
}
return p;
}

void main() {
Tree t;
ch = getchar();
while(ch==' ' || ch=='\t') ch = getchar();
t = E();
print(0, t);
}
mmmcd 2003-10-12
  • 打赏
  • 举报
回复
递归下降分析
skywind 2003-10-11
  • 打赏
  • 举报
回复
哦,请问下按上面的方法: x--y答案是什么?应该提供一元运算符的判断,但是
栈不好弄,还是地归好弄些:比如x--y就是 x-(-y)
-
x (-)
y
短歌如风 2003-10-10
  • 打赏
  • 举报
回复
有点错误:出栈并运算的条件不是当前级别低,而是当前级别不高(级别相等时就进行)。
括号的处理有多种方法,一种是把前括号放到符栈中,遇到后括号号就运算到弹出一个前括号;
另一种方法是为符设一个主级别,初始为0;遇到一个前括号就把当前主级别加1,遇到一个后括号就把当前主线别减1,从表达式中得到的操作符使用当前主级别。比较时先比较主级别,主级另高则优先级高,相等时再比较操作符级别。

操作前先把第一个数放到数栈中;当表达式处理完后重复计算直到符栈空。

下面用第二种括号处理方法描述一下栈的情况,其中用a(b)(c)表示根为a左子为b右子为c的树,用*x表示主级别为x的操作符*

a+b*(c-d)-e/f

当前数 当前符  数栈            符栈 运算
 b  +0   a                n
 c *0 a,b +0 n
d -1   a,b,c +0, *0 n
e -0 a,b,c,d +0, *0, -1   y
e -0 a,b,-(c)(d) +0, *0 y
e -0 a,*(b)(-(c)(d)) +0 y
e -0 +(a)(*(b)(-(c)(d))) n
f /0 +(a)(*(b)(-(c)(d))), e -0 n
+(a)(*(b)(-(c)(d))), e,f -0, /0 y
+(a)(*(b)(-(c)(d))), /(e)(f) -0 y
-(+(a)(*(b)(-(c)(d))))(/(e)(f))

最后在数栈中就是你要的语法树,图形表示就是:
        -
+ /
a * e f
b -
c d
cafeeee 2003-10-10
  • 打赏
  • 举报
回复
先做出表达式的逆波兰式,再构造语法树。
短歌如风 2003-10-10
  • 打赏
  • 举报
回复
用两个栈,一个放操作数,一个放操作符。当当前操作符比栈顶操作级别低时两操作数出栈,操作符出栈,进行运算,结果入数栈。
由于是要生成语法树,运算过程就是生成树,以操作符为根,两操作数分别为左右子树。
skyspeed 2003-10-10
  • 打赏
  • 举报
回复
up!!!!!!
skyspeed 2003-10-10
  • 打赏
  • 举报
回复
UP!!!

33,007

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧