我在用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?
发布于 2017-01-23 16:43:37
(我假设您正在修改现有的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 )的结果,在本例中,该操作没有语义值,如上面所示。
我建议阅读野牛手册,至少前几页提到“语义操作”,并参考可能使概念更加清晰的示例。(阅读整本手册不应该花费太多时间,而且会更有用,但我知道,如今阅读手册被认为是过时的。)
https://stackoverflow.com/questions/41807914
复制相似问题