我想使用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(具有值的那个)。或类似的东西......?
答案 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>
因此,您无法同时在intValue
和char*
中的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;
}
}