2015-10-11 1 views
0
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 для моего языка программирования, используя эту грамматику. Эта грамматика для разбора объявления полей, таких как:bison - pass value to next production

int a; 

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

int a[10]; 

Я хотел спросить, как я могу передать значение «типа» не-терминал для анализатора Bison, когда он достигает производства id_list.

Я хочу сказать, что когда я нахожусь в id_list производстве на этапе синтаксического анализа, я хочу иметь тип каждого идентификатора, поскольку мне нужно его сохранить в узле идентификатора. Я знаю, что мы можем передать значение $$ в верхние постановки, но как передать некоторое значение продуктам, которые появляются после производства на этапе синтаксического анализа.

После размещения вопрос я узнал, что мы можем использовать $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

Ваша грамматика не выглядит правильно , 'id_list' не имеет завершающей ветви: перед каждым' id_list' должен следовать другой 'id_list', т. е. он бесконечен. – melpomene

+0

@melpomene да спасибо за это, я пропустил это полностью. – tom

ответ

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; 
            } 

можно было бы заменить использование структуры описателя с использованием стека «вверх-ссылки», как указано в этом вопросе. Эти ссылки, на мой взгляд, немного хрупкие, поскольку они зависят от глобальных знаний о контексте, в котором может произойти производство, а бизон не проверяет использование. Одним из следствий отсутствия проверки является то, что вы должны указать тег семантического типа при использовании такой ссылки, факт, который остается неявным в руководстве bison, поэтому вы получаете сообщение об ошибке от бизона.

Убедитесь, что стек правильно настроен для семантического действия, является сложным и обычно требует использования маркерных производств (или действий среднего уровня).Следующий пример заимствован из бизона руководства, с добавлением необходимого явного типа синтаксиса:

%type <number> sum expr retainer 
%% 

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

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