Bison中的计算器,以及double或int值

时间:2015-03-03 00:27:48

标签: compiler-construction calculator bison yacc

我想使用flex / bison创建一个计算器。我创建了以下%union

%union{
     int intValue;
     double realValue;
     char * numType;
}

因此,当我想缩减为term: primary之类的规则时,如果它是“INT”或“REAL”,我会检查numType,我会这样做:

$<realValue>$=$<realValue>1; $<numType>$=$<numType>1;

(与intValue相同)。现在的问题是,当我有这样的规则时:

term:
  expr '+' expr |
  expr '*' expr |                          
  ...

如果条款是真实的或整数,我必须检查太多次,以便将它们放入$ realValue $或$ intValue $。问题是:bison / yacc是否有可能减少所有这些检查?

例如

%type <intValue,realValue>

您可以在哪里指定类型二值,然后例如,如果您有这样的规则:

a: primary ;

从现在开始,当a用于缩减到另一个规则并且访问a时,将访问realValue或intValue(具有值的那个)。或类似的东西......?

2 个答案:

答案 0 :(得分:1)

这实际上是一个C问题 - 没有C没有这样的动态类型,因此只要您使用bison生成C语法分析器,就不能这样做。如果你使用C ++,你可以做一些有限的动态类型,但你不能在%union中放入许多C ++类型,这可能会导致其他困难。

另外,请注意%union是一个联合 - 您一次只能使用一个值。所以当你执行$<realValue>$=$<realValue>1; $<numType>$=$<numType>1;时,第二个任务会覆盖(并破坏)第一个任务。如果要使用规则存储多个值,则需要在结合中放置一个结构:

%union {
    enum type_t { INT, DOUBLE } type;
    struct {
        type_t type;
        int value;
    } intval;
    struct {
        type_t type;
        double value;
    } floatval;
}

但是正如您所注意的那样,检查整个地方的类型标签很难。

答案 1 :(得分:1)

所有bison / yacc都会生成一个C程序。它们不会改变C的语义。联合仍然是联合,因此它们只能容纳一个的替代成员,而且没有固有的方法来判断哪种类型被包含。< / p>

因此,您无法同时在intValuechar*中的numType中保持整数。它是一个或另一个,从来都不是。

Bison并没有强迫您使用union类型作为语义类型。您可以使用自己的tagged union数据结构。但野牛的<type>机制不会帮助你;你需要自己做所有的工作。 (虽然它并不比你尝试的工作多得多;你最终会写下这样的东西:

expr: expr '+' expr { if ($1.type == INT && $3.type == INT) {
                        $$.type = INT;
                        $$.intValue = $1.intValue + $3.intvalue;
                      } else {
                        double v1 = $1.type == INT ? (double)$1.intValue
                                                   : $1.realValue;
                        double v2 = $3.type == INT ? (double)$3.intValue
                                                   : $3.realValue;
                        $$.type = REAL;
                        $$.realValue = v1 + v2;
                      }
                    }