求语法树的初级问题

skyspeed 2003-10-10 11:22:38
一个表达式: a+b*(c-d)-e/f
用什么步骤作出它的语法树?
已知答案是:
'-'
/ \
'+' '/'
/ \ / \
'a' '*' 'e' 'f'
/ \
'b' '-'
/ \
'c' 'd'
时间长了,忘了怎么做的了,应该很简单吧? 还有哪有讲这个问题的?
...全文
442 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!!!
【资源介绍】 1、该资源包括项目的全部源码,下载可以直接使用! 2、本项目适合作为计算机、数学、电子信息等专业的课程设计、期末大作业和毕设项目,也可以作为小白实战演练和初期项目立项演示的重要参考借鉴资料。 3、本资源作为“学习资料”如果需要实现其他功能,需要能看懂代码,并且热爱钻研和多多调试实践。 中英文手写印刷公式、支持初级符号推导(数据结构基于 LaTeX 抽象语法树).zip 中英文手写印刷公式、支持初级符号推导(数据结构基于 LaTeX 抽象语法树).zip 中英文手写印刷公式、支持初级符号推导(数据结构基于 LaTeX 抽象语法树).zip 中英文手写印刷公式、支持初级符号推导(数据结构基于 LaTeX 抽象语法树).zip 中英文手写印刷公式、支持初级符号推导(数据结构基于 LaTeX 抽象语法树).zip 中英文手写印刷公式、支持初级符号推导(数据结构基于 LaTeX 抽象语法树).zip 中英文手写印刷公式、支持初级符号推导(数据结构基于 LaTeX 抽象语法树).zip 中英文手写印刷公式、支持初级符号推导(数据结构基于 LaTeX 抽象语法树).zip 中英文手写印刷公式、支持初级符号推导(数据结构基于 LaTeX 抽象语法树).zip 中英文手写印刷公式、支持初级符号推导(数据结构基于 LaTeX 抽象语法树).zip 中英文手写印刷公式、支持初级符号推导(数据结构基于 LaTeX 抽象语法树).zip 中英文手写印刷公式、支持初级符号推导(数据结构基于 LaTeX 抽象语法树).zip 中英文手写印刷公式、支持初级符号推导(数据结构基于 LaTeX 抽象语法树).zip 中英文手写印刷公式、支持初级符号推导(数据结构基于 LaTeX 抽象语法树).zip 中英文手写印刷公式、支持初级符号推导(数据结构基于 LaTeX 抽象语法树).zip 中英文手写印刷公式、支持初级符号推导(数据结构基于 LaTeX 抽象语法树).zip 中英文手写印刷公式、支持初级符号推导(数据结构基于 LaTeX 抽象语法树).zip

33,028

社区成员

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

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