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

Bison 野牛-将值传递给下一个产品,bison,abstract-syntax-tree,Bison,Abstract Syntax Tree,我有一个上面给出的bison语法,我正试图使用这个语法为我的编程语言创建一个AST。此语法用于分析字段声明,例如: field_dec: type id_list ; id_list: ID punct id_list | ID SQUARE_OPEN INTEGER SQUARE

我有一个上面给出的bison语法,我正试图使用这个语法为我的编程语言创建一个AST。此语法用于分析字段声明,例如:

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
;
我想问的是,当“type”non-terminal的值到达产品
id\u列表时,如何将其传递给bison解析器

我的意思是,当我在解析阶段处于
id\u list
production时,我希望获得每个标识符的类型,因为我需要将其存储在identifier节点中。我知道我们可以将
$
值传递给上层产品,但是如何将一些值传递给解析阶段中产品之后的产品

在发布问题后,我发现我们可以将
$n
与n<0一起使用,但我在网上找不到任何好的资源来阅读它,并且我尝试用n<0测试
$n
,但它只给了我以下错误:

int a;

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

int a[10];


与其使用右递归来定义
id\u list
(这实际上从来都不是您想要的),不如使用左递归规则来实现所需的效果

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

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

bison.y:124.43-45: error: $-1 of ‘callout_arg’ has no declared type
 callout_arg: expr {printf("testing %s\n", $-1);}
                                           ^^^
为简单起见,我假设所有语义值都只是字符串,但实际上您可能需要表示“类型”和“标识符”的特定类型。此外,避免所有可能的声明符语法的过度重复也会更干净,因为可能有两种以上的可能性。这也可以通过使用自定义语义类型来实现

这里有一个稍微复杂一点的版本:

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 ';'
%{
#包括
枚举类型{布尔,整数};
结构声明器{
常量字符*id;
布尔矩阵;
整数维;
}
%}
%联合{
枚举类型;
结构声明器decl;
常量字符*id;
长数;
}
%{
/*通过引用传递语义值以避免复制,
因为结构声明器有点大。
*/
void从decl分配类型(常量字符**类型,
结构声明器*dec){
if(dec->is\u数组)
分配数组类型(*类型,dec->id,dec->维度);
其他的
分配类型(*类型,十二月->id);
}
%}
%令牌T_ID
%令牌T_整数
%令牌T_INT“INT”
T_布尔“布尔”
%类型decl\u列表
%类型声明符
%%
类型:“boolean”{$$=boolean;}
|“int”{$$=INTEGER;}
字段_dec:decl_list';'
decl_列表:类型声明符{assign_type(&$1,&$2);}
|decl_列表','声明符{assign_type(&$1,&$3);}
声明符:ID{$$.ID=$1;
$$.is_array=false;
}
|ID'['整数']'{$$。ID=$1;
$$.is_array=true;
$$。维度=$3;
}
如问题所示,可以使用堆栈“向上引用”来代替声明器结构的使用。在我看来,这些参考文献有点脆弱,因为它们依赖于关于生产可能发生的环境的全局知识,而bison并不验证其使用。缺少验证的一个结果是,在使用此类引用时必须指定语义类型标记,这一事实在bison手册中是隐式的,这就是为什么您从bison收到错误消息的原因

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

%{
#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;
                                    }
%类型和表达式固定器
%%
总数:
expr保持器“+”expr{…}
|expr保持器'-'expr{…}
;
定金:
/*空*/{previous_expr=$0;}
;

您可以使用
$0
$-N
引用值堆栈上以前的值,不过您需要注意始终正确输入类型。在您的情况下,您可能需要以下内容:

 %type <number> sum expr retainer
 %%

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

 retainer:
   /* empty */    { previous_expr = $<number>0; }
 ;
%类型
... 产品的其他类型声明
%%
字段_dec:type id_list';';
id_list:id_decl{$$=make_list($1);}
|id_list',{$$=$0;}id_decl{$$=append_list($1,$3);}
;
id_decl:id{$$=declare_id($1,$0;}
|ID“['整数']”
{$$=declare_id($1,get_数组_type($0,$3));}
;
类型:INT{$$=&INT_-type;}{$$=&bool_-type;}
字段定义列表:/*空*/|字段定义列表字段定义;
如果您使用,它有语法上的糖分使这更容易(和更安全的类型):

%类型
%类型id_decl()
%类型id_列表()
…其他产品的其他类型声明
%%
字段_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));}
;
类型:INT{$$=&INT_-type;}{$$=&bool_-type;}
字段定义列表:/*空*/|字段定义列表字段定义;

你的语法看起来不正确。
id\u列表
没有终止分支:每个
id\u列表
后面都必须跟着另一个
id\u列表
,即它是无限的。@melpomene是的,谢谢你,我完全错过了它。
 %type <number> sum expr retainer
 %%

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

 retainer:
   /* empty */    { previous_expr = $<number>0; }
 ;
%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 ;
%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 ;