首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

bison操作符结合性有bug解决方法

2012-03-05 
bison操作符结合性有bug好像bison的操作符结合性不起作用啊,我按照bison的手册上抄过来的,程序如下(在exp

bison操作符结合性有bug
好像bison的操作符结合性不起作用啊,
我按照bison的手册上抄过来的,程序如下(在exp规则中加了一些printf的debug信息):
          /*   Reverse   polish   notation   calculator.     */
         
          %{
              #define   YYSTYPE   double
              #include   <math.h>
              #include   <ctype.h>
              #include   <stdio.h>
              int   yylex   (void);
              void   yyerror   (char   const   *);
          %}
         
          %token   NUM
         
          /*   Bison   declarations.     */
          %token   NUM
          %left   '- '   '+ '
          %left   '* '   '/ '
          %left   NEG           /*   negation--unary   minus   */
          %right   '^ '         /*   exponentiation   */
         
          %%   /*   The   grammar   follows.     */
          input:         /*   empty   */
                          |   input   line
          ;
         
          line:           '\n '
                          |   exp   '\n '     {   printf   ( "\t%.10g\n ",   $1);   }
          ;
         
          exp:             NUM                                 {   $$   =   $1;printf( "debug   1\n ");                   }
                          |   exp   '+ '   exp                 {   $$   =   $1   +   $3;printf( "debug   2\n ");         }
                          |   exp   '- '   exp                 {   $$   =   $1   -   $3;printf( "debug   3\n ");         }
                          |   exp   '* '   exp                 {   $$   =   $1   *   $3;printf( "debug   4\n ");         }


                          |   exp   '/ '   exp                 {   $$   =   $1   /   $3;printf( "debug   5\n ");         }
                          |   '- '   exp     %prec   NEG   {   $$   =   -$2;printf( "debug   6\n ");                 }
                          |   exp   '^ '   exp                 {   $$   =   pow   ($1,   $3);printf( "debug   7\n ");   }
                          |   '( '   exp   ') '                 {   $$   =   $2;printf( "debug   8\n ");                   }
          ;
          %%

          /*   The   lexical   analyzer   returns   a   double   floating   point
                number   on   the   stack   and   the   token   NUM,   or   the   numeric   code
                of   the   character   read   if   not   a   number.     It   skips   all   blanks
                and   tabs,   and   returns   0   for   end-of-input.     */
         
          int
          yylex   (void)
          {
              int   c;
         
              /*   Skip   white   space.     */
              while   ((c   =   getchar   ())   ==   '   '   ||   c   ==   '\t ')
                  ;
              /*   Process   numbers.     */
              if   (c   ==   '. '   ||   isdigit   (c))
                  {
                      ungetc   (c,   stdin);
                      scanf   ( "%lf ",   &yylval);
                      return   NUM;
                  }
              /*   Return   end-of-input.     */
              if   (c   ==   EOF)
                  return   0;
              /*   Return   a   single   char.     */


              return   c;
          }

          int
          main   (void)
          {
              return   yyparse   ();
          }

          /*   Called   by   yyparse   on   error.     */
          void
          yyerror   (char   const   *s)
          {
              fprintf   (stderr,   "%s\n ",   s);
          }
运行之后输入(1+2)^(4-3)
然后这是结果:
(1+2)^(4-3)
debug   1
debug   1
debug   2
debug   8
debug   1
debug   1
debug   3
debug   8
debug   7
                3
为什么不是预想的:
(1+2)^(4-3)
debug   1
debug   1
debug   3
debug   8
debug   1
debug   1
debug   2
debug   8
debug   7
                3

(1+2)^(4-3)
debug   1
debug   1
debug   1
debug   1
debug   3
debug   8
debug   2
debug   8
debug   7
                3
?把right改成left之后执行结果也是一样,那么操作符结合性还有什么意义?
Solaris和Windows下的bison都试过了,结果都是一样。
不知如何才能使结果是预想的这样?

[解决办法]
那是什么东东?
[解决办法]
你试试看 1^2^3 在想想是咋回事 ....
[解决办法]
你再在有疑问的几个地方下个断点看看 yyvs 里的内容吧 ...
[解决办法]
这个顺序有关系么 ...
如果你的程序有代码生成的过程, 可以在这个时候做这件事情 ...

[解决办法]
c/cpp 里表达式求值本来就大部分是从右到左, 偶觉得这暴不自然, 竟然有人会稀饭这种顺序, 狂晕 ...
不需要对语句进行预分析, yacc 直接可以生成你需要的东东.. 一会有空的时候写个 ..
[解决办法]
yacc..
不太明白..
[解决办法]
什么跟什么哦, 左结合只是表示 a+b+c+d == ((a+b)+c)+d ,右结合只是表示 a^b^c^d == a^(b^(c^d))), abcd 的计算顺序本来就没有保证, 你想怎么算就怎么算 ...
[解决办法]
bison中的left和right只是用来解决生成语法树的二义性,而左右部分哪个先运算出来是由语法树的遍历方式决定的吧。
[解决办法]
偶可木有说过要预处理才能生成结果, 代码生成的时候你想先给右边的表达式求值就先求右边, 想先求左边就先左边, 跟其他东东有啥关系 ...
[解决办法]
bison生成语法树的顺序是没法改变的。bison用的是LALR分析法。(1+2)^(4-3)中1+2会被先规约,也就是:(1+2)^(4-3)中
1.规约exp -> exp + exp 即 (exp)^(4-3)
2.规约exp -> ( exp ) 即 exp ^ ( 4-3 ),这时^是右结合的,所以会先规约右侧
3.规约exp -> exp - exp 即 exp ^ ( exp ), 现作这个规约是因为在遇到 ') '前,遇到了 '+ '。
4.规约exp -> ( exp )即 exp ^ exp
5.规约exp -> exp ^ exp 即 exp, 规约完成。
所以执行顺序是无法改变的。但是,如果不是解释执行,而是编译执行,就像C++这样的。bison是可以自定义语意记录的。所以实现起来还是比较简单的。
例如,基本块使用链表保存的。
...
%{
typedef struct block{
struct block *next;


...//存放生成代码的中间结果。
}block_t;
%}

%union{
block_t *pblock;/*语意记录*/
};
...
type <pblock> exp
%%
...
exp:
...
| exp '+ ' exp {//左结合
$$ = $1;$1-> next=$3;...
}
| exp '^ ' exp{//右结合
$$ = $3;$3-> next=$1;...
}
...
[解决办法]
解释执行的话,可以利用延迟计算来完成,例如可以这样:
%{
...
typedef struct node{
charop;//存放运算符
struct node *left; //左子树
struct node *right; //右子树
double value; //叶子节点
}node_t;
double calculate( node_t *node );//实际运算的函数
...
%}

%union{
node_t *pnode;
doublevalue;
};
type <pnode> exp
type <value> NUM
...
%%
input:| input line;
line: '\n '
| exp '\n ' { printf( "\t%.10g\n ", calculate($1)); };

exp: NUM {
$$ = (node_t*)malloc(node_t);$$-> op= '\0 ';$$-> value = $1;
}
| exp '+ ' exp { $$ = (node_t*)malloc(node_t);$$-> op = '+ ';$$-> left=$1;$$-> right=$3; }
| exp '^ ' exp { $$ = (node_t*)malloc(node_t);$$-> op = '^ ';$$-> left=$1;$$-> right=$3; }
...
%%
double calculate( node_t *node )
{
double ret= 0.0;
if(node == NULL)return ret;
switch( node-> op )
{
case '\0 ':ret=node-> value;break;
case '+ ':ret=calculate(node-> left)+calculate(node-> right);break;
case '^ ':{
double tmpr = calculate(node-> right);//这里实现了先算右侧。
double tmpl = calculate(node-> left);
ret= pow(tmpl,tmpr);
}break;
...
}
free( node );
return ret;
}
...
还有,lz的产生式好像加减法和乘除法优先级相同。

热点排行