Вместо того чтобы использовать правую рекурсию для определения 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; }
;
Ваша грамматика не выглядит правильно , 'id_list' не имеет завершающей ветви: перед каждым' id_list' должен следовать другой 'id_list', т. е. он бесконечен. – melpomene
@melpomene да спасибо за это, я пропустил это полностью. – tom