【问题标题】:Bison rules definitionBison 规则定义
【发布时间】:2017-01-23 13:48:46
【问题描述】:

我在用 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?

【问题讨论】:

  • 实际上,OCTET STRING (CONTAINING B) 是一个OCTET STRING,而不是一个类型B。只有八位字节字符串中传输的字节是B 的某种编码。

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


【解决方案1】:

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

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

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

完全没有意义;你还没有给$$赋值,所以它必须被认为是一个未定义的值。

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

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

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

ContentsConstraint :   CONTAINING Type  {  }

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多