野牛规则的定义

时间:2017-01-23 13:48:46

标签: compiler-construction bison compiler-optimization asn.1

我在Bison编写的ASN.1编译器中遇到了问题。

A   OCTET STRING (CONTAINING B)

编译器忽略CONTAINING B并将数据引用为OCTET STRING 而不是将其称为B. 以下是当前规则:

 OctetStringType :
    OCTET STRING Constraint                      { $$ = new     OctetString($3); } |
    OCTET STRING '{' NamedOctetList '}' Constraint { $$ = new OctetString($6); }
    ;

我尝试创建一条新规则:

OctetStringType :
    OCTET STRING '('ContentsConstraint')' {}|
    OCTET STRING Constraint                      { $$ = new OctetString($3); } |
    OCTET STRING '{' NamedOctetList '}' Constraint { $$ = new OctetString($6); }
    ;
ContentsConstraint :
   CONTAINING Type  {  }
   ;

当我尝试打印结果时:

  OCTET STRING '('ContentsConstraint')' {printf("$$: %s\n",$$);}

我得到A. 如何访问B?我是否必须修改这些规则才能访问B?

1 个答案:

答案 0 :(得分:1)

(我假设您正在修改现有的ASN.1语法,而不是您自己编写的语法。)

$$是由语义动作计算的语义值。所以

OCTET STRING '('ContentsConstraint')' {printf("$$: %s\n",$$);}

毫无意义;您尚未为$$分配值,因此必须将其视为未定义的值。

实际上,bison / yacc解析器在执行操作之前已经有效地执行了赋值$$ = $1;(这很有用,因为这意味着当你想要的时候你不需要写它在行动中做)。因此,在这种情况下,您将打印生产中第一个符号的语义值(这是$1的含义),即终端OCTET。但是,令牌OCTET 不太可能具有语义值;在大多数解析器中,从不使用关键字终端的语义值,因此分配它没有意义。

大多数bison / yacc衍生物都会遇到麻烦,以确保将每个语义值初始化为某些以防止编译器警告(旧版本没有这样做),但是从未指定过,应将其视为未初始化。简而言之,您的代码显示未定义的行为,并且可以打印任何内容。

我想你想要打印ContentsConstraint非终端的语义值。假设您定义非终端的产品的语义操作都正确地为其分配了值,您可以将其作为$4访问,因为ContentsConstraint是规则中的第四个标记。这意味着您至少需要修改规则

ContentsConstraint :   CONTAINING Type  {  }

ContentsConstraint :   CONTAINING Type  { $$ = $2; }

因为否则ContentsConstraint的值将是默认操作的结果,即$1,在这种情况下没有语义值,如上所述。

我建议阅读bison manual,至少在前几页“Semantic Actions”中参考可能使概念更清晰的示例。 (阅读整本手册不应该消耗太多时间,而且会更有用,但我知道阅读手册最近被视为passé。)