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);}
^^^
答案 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 ;