野牛 - 将值传递给下一个生产

时间:2015-10-11 12:13:15

标签: bison abstract-syntax-tree

field_dec: type id_list        ;                                               

id_list: ID punct id_list                                             
         | ID SQUARE_OPEN INTEGER SQUARE_CLOSED punct id_list
         | ID punct
         | ID SQUARE_OPEN INTEGER SQUARE_CLOSED punct
 ;

type: INT | BOOLEAN
;

punct: COMMA | SEMICOLON
;

我有一个如上所述的野牛语法,我正在尝试使用这种语法为我的编程语言创建一个AST。该语法用于解析字段声明,例如:

int a;

int a, b, c[10], d;

int a[10];

我想问一下,当它到达生产id_list时,如何将“type”非终端的值传递给bison解析器。

我的意思是说,当我在解析阶段id_list生产时,我想拥有每个标识符的类型,因为我需要将它存储在标识符节点中。我知道我们可以将$$值传递给上层制作,但是如何将一些值传递给解析阶段制作后的制作。

在发布问题后,我发现我们可以使用$n n< 0但我在网上找不到任何好的资源来阅读它,我也尝试用{<}来测试$n 0但它只是给我以下错误:

bison.y:125.45-46: error: $0 of ‘callout_arg’ has no declared type         
             | STRING {printf("testing %s\n", $0);};       
                                              ^^

bison.y:124.43-45: error: $-1 of ‘callout_arg’ has no declared type
 callout_arg: expr {printf("testing %s\n", $-1);}
                                           ^^^

2 个答案:

答案 0 :(得分:0)

使用右递归来定义id_list,而不是你想要的,你可以使用左递归规则来实现所需的效果。

在下面的语法中,与声明符关联的类型始终可用作声明符本身的语义值。我还纠正了标点符号的处理:只有逗号分隔标识符,而只有半冒号终止声明。

为了使类型始终可用,有必要对语法进行“非规范化”,这会导致一定程度的重复。请参阅下面的稍微重构版本。

decl_list: type ID                  { assign_type($1, $2); }
         | type ID '[' INTEGER ']'  { assign_array_type($1, $2, $4); }
         | decl_list ',' ID         { assign_type($1, $3); }
         | decl_list ',' ID '[' INTEGER ']'
                                    { assign_array_type($1, $3, $5};

field_dec: decl_list ';'

为简单起见,我假设所有语义值都只是字符串,但在实践中,您可能需要表示“类型”和“标识符”的特定类型。此外,避免所有可能的声明符语法的过多重复会更加清晰,因为可能有两种以上的可能性。这也可以使用自定义语义类型来实现。

这是一个稍微复杂的版本:

%{
#include <stdbool.h>

enum Type {BOOLEAN, INTEGER};
struct Declarator {
    const char* id;
    bool        is_array;
    int         dimension;
}
%}

%union {
    enum Type         type;
    struct Declarator decl;
    const char*       id;
    long              number;
}

%{
   /* Pass semantic values by reference to avoid copying,
      since the struct Declarator is a bit big.
    */
   void assign_type_from_decl(const char** typ,
                              struct Declarator* dec) {
     if (dec->is_array)
       assign_array_type(*typ, dec->id, dec->dimension);
     else
       assign_type(*typ, dec->id);
   }
%}

%token <id>     T_ID
%token <number> T_INTEGER
%token          T_INT     "int"
                T_BOOLEAN "boolean"
%type <type> decl_list
%type <decl> declarator

%%

type     : "boolean"                { $$ = BOOLEAN; }
         | "int"                    { $$ = INTEGER; }
field_dec: decl_list ';'
decl_list: type declarator          { assign_type(&$1, &$2); }
         | decl_list ',' declarator { assign_type(&$1, &$3); }
declarator: ID                      { $$.id = $1;
                                      $$.is_array = false;
                                    }
         | ID '[' INTEGER ']'       { $$.id = $1;
                                      $$.is_array = true;
                                      $$.dimension = $3;
                                    }

如问题所示,可以使用堆栈“up-reference”替换Declarator结构的使用。在我看来,这些参考文献有点脆弱,因为它们依赖于有关生产可能发生的背景的全球知识,而野牛不会验证其用途。缺少验证的一个结果是,当您使用此类引用时,必须指定语义类型标记,这一事实在bison手册中隐含,这就是您收到错误消息的原因来自野牛。

确保为语义操作正确配置堆栈非常棘手,并且通常需要使用标记生成(或中间规则操作)。以下示例改编自bison手册,并添加了必要的显式类型语法:

 %type <number> sum expr retainer
 %%

 sum:
   expr retainer '+' expr  { ... }
 | expr retainer '-' expr  { ... }
 ;

 retainer:
   /* empty */    { previous_expr = $<number>0; }
 ;

答案 1 :(得分:0)

您可以使用$<type>0$<type>-N引用值堆栈上的先前值,但您需要小心始终确保类型正确。在您的情况下,您可能需要以下内容:

%type<type> type
    ... other type declarations for productions

%%

field_dec: type id_list ';' ;

id_list: id_decl { $$ = make_list($1); }
       | id_list ',' { $<type>$ = $<type>0; } id_decl { $$ = append_list($1, $3); }
       ;

id_decl: ID { $$ = declare_id($1, $<type>0; }
       | ID '[' INTEGER ']'
         { $$ = declare_id($1, get_array_type($<type>0, $3)); }
       ;

type: INT { $$ = &int_type; } | BOOLEAN { $$ = &bool_type; }

field_dec_list : /* empty */ | field_dec_list field_dec ;

如果你使用btyacc,它会有语法糖,使这更容易(更安全):

%type<type>  type
%type<???>   id_decl(<type>)
%type<list>  id_list(<type>)    
    ... other type declarations for other productions

%%

field_dec: type id_list($1) ';' ;

id_list($t): id_decl($t) { $$ = make_list($1); }
           | id_list($t) ',' id_decl($t) { $$ = append_list($1, $3); }
       ;

id_decl($t): ID { $$ = declare_id($1, $t); }
           | ID '[' INTEGER ']' { $$ = declare_id($1, get_array_type($t, $3)); }
           ;

type: INT { $$ = &int_type; } | BOOLEAN { $$ = &bool_type; }

field_dec_list : /* empty */ | field_dec_list field_dec ;