Compiler construction 野牛规则定义

Compiler construction 野牛规则定义,compiler-construction,bison,compiler-optimization,asn.1,Compiler Construction,Bison,Compiler Optimization,Asn.1,我在用Bison编写的ASN.1编译器中遇到了一个问题 A OCTET STRING (CONTAINING B) 编译器忽略包含B的数据,并将数据引用为八位字节字符串 而不是把它称为B。 以下是当前规则: OctetStringType : OCTET STRING Constraint { $$ = new OctetString($3); } | OCTET STRING '{' NamedOctetList '}'

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

A   OCTET STRING (CONTAINING B)
编译器忽略包含B的数据,并将数据引用为八位字节字符串 而不是把它称为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?

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

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

OCTET STRING '('ContentsConstraint')' {printf("$$: %s\n",$$);}
毫无意义;您尚未为
$$
指定值,因此必须将其视为未定义的值

实际上,bison/yacc解析器有效地执行了赋值
$$=$1在执行操作之前(这很有用,因为这意味着当您只想在操作中执行操作时,不必编写代码)。因此,在本例中,您正在打印产品中第一个符号的语义值(这就是
$1
的意思),即终端
八位字节。然而,令牌
八位字节
不太可能具有语义值;在大多数解析器中,从未使用关键字终端的语义值,因此分配它没有意义

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

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

ContentsConstraint :   CONTAINING Type  {  }

否则,
ContentsConstraint
的值将是默认操作的结果,即
$1
,在本例中,它没有语义值,如上所述

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

实际上,
OCTET字符串(包含B)
是一个
OCTET字符串
,而不是
B
类型。只有在八位字节sting中传输的字节是
B
的一些编码。
ContentsConstraint :   CONTAINING Type  { $$ = $2; }