野牛规则定义

Bison rules definition

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

A   OCTET STRING (CONTAINING B)

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

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

我尝试创建一个新规则:

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

当我尝试打印结果时:

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

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

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

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

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

完全没有意义;您尚未为 $$ 赋值,因此它必须被视为未定义的值。

在实践中,bison/yacc 解析器在执行操作之前有效地执行了赋值 $$ = ;(这很有用,因为这意味着您不必在执行时编写它所有你想在行动中做的事情)。所以在这种情况下,您正在打印产生式中第一个符号的语义值(</code> 的意思),即终端 <code>OCTET。但是,令牌 OCTET 不太可能具有 语义值;在大多数解析器中,关键字终端的语义值从不使用,因此分配它没有意义。

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

我假设您想打印 ContentsConstraint non-terminal 的语义值。假设您对定义 non-terminal 的产生式的语义操作都正确地为其分配了一个值,您可以将其作为 </code> 访问,因为 <code>ContentsConstraint 是规则中的第四个标记。这意味着你至少需要修改你的规则

ContentsConstraint :   CONTAINING Type  {  }

ContentsConstraint :   CONTAINING Type  { $$ = ; }

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

我建议阅读 bison manual,至少阅读前几页 "Semantic Actions" 参考示例,这可能会使概念更清晰。 (阅读整个手册应该不会花费太多时间,而且会更有用,但我知道现在阅读手册被认为是passé。)