В Bison (или, если на то пошло, yacc) есть ли порядок, определяемый грамматикой? - PullRequest
0 голосов
/ 27 сентября 2018

У меня есть следующая грамматика в файле Bisone:

item
    : "ITEM" t_name t_type v_storage t_prefix t_tag ';'
    ;
t_name
    : [$_A-Za-z][$_A-Z0-9a-z]*
    ;
t_type
    : "BYTE"
    | "WORD"
    | "LONG"
    | "QUAD"
    ;
v_storage
    : %empty
    | "TYPEDEF"
    ;
t_prefix
    : %empty
    | "PREFIX" t_name
    ;
t_tag
    : %empty
    | "TAG" t_name
    ;

Когда я пытаюсь разобрать следующую строку ITEM foobar BYTE PREFIX str_ TAG S TYPEDEF; Я получаю неожиданный «TYPEDEF», и он принимает «;».что-то, что мне нужно сделать, чтобы разрешить указание любого заказа? Если это так, я надеюсь, что есть простое решение. В противном случае мне нужно будет сделать немного больше работы.

1 Ответ

0 голосов
/ 27 сентября 2018

Невозможно сказать бизону (или yacc), что порядок не имеет значения.Правила строго заказаны.

Таким образом, у вас есть два варианта:

  1. Список всех возможных заказов.Если вы сделаете это, остерегайтесь неясностей, вызванных дополнительными постановками.Вам действительно нужно перечислить все заказы и подмножества.Это растет экспоненциально.

  2. Просто примите любой список компонентов, как список.Это будет принимать повторяющиеся компоненты, поэтому вам нужно поймать это в семантическом действии, если вам небезразлично.

Второй вариант почти всегда тот, который вам нужен.Реализация обычно тривиальна, потому что вы захотите где-то хранить компоненты;пока это где-то имеет уникальное значение (например, NULL), что означает «еще не установлено», вам нужно только проверить это значение перед его установкой.Например, а не тот, что в вопросе):

%{
   #include <stdbool>
   enum Type { 
     TYPE_DEFAULT = 0, TYPE_BYTE, TYPE_WORD, TYPE_LONG, TYPE_QUAD
   };
   typedef struct Item Item;
   struct Item {
     const char *name;
     enum Type   type;
     int         storage; /* 0: unset, 1: TYPEDEF */
     const char *prefix;
     const char *tag;
  };
  // ...
  // Relies on the fact that NULL and 0 are converted to boolean 
  // false. Returns true if it's ok to do the set (i.e. thing
  // wasn't set).
  bool check_dup(bool already_set, const char* thing) {
    if (already_set) 
      fprintf(stderr, "Duplicate %s ignored at line %d\n", thing, yylineno);
    return !already_set;
  }
%}

%union {
   const char *str;
   Item  *item;
   // ...
}

%type <item> item item-def
%token <str> NAME STRING

%%
/* Many of the actions below depend on $$ having been set to $1.
 * If you use a template which doesn't provide that guarantee, you
 * will have to add $$ = $1; to some actions.
 */
item: item-def { /* Do whatever is necessary to finalise $1 */ }
item-def
    : "ITEM" NAME
               { $$ = calloc(1, sizeof *$$); $$->name = $2; }
    | item-def "BYTE"
               { if (check_dup($$->type, "type") $$->type = TYPE_BYTE; }
    | item-def "WORD"
               { if (check_dup($$->type, "type") $$->type = TYPE_WORD; }
    | item-def "LONG"
               { if (check_dup($$->type, "type") $$->type = TYPE_LONG; }
    | item-def "QUAD"
               { if (check_dup($$->type, "type") $$->type = TYPE_QUAD; }
    | item-def "TYPEDEF"
               { if (check_dup($$->storage, "storage") $$->storage = 1; }
    | item-def "PREFIX" STRING
               { if (check_dup($$->prefix, "prefix") $$->prefix = $3; }
    | item-def "TAG" STRING
               { if (check_dup($$->tag, "tag") $$->tag = $3; }

Вы можете разделить все эти item-def произведения на что-то вроде:

item-def: "ITEM" NAME   { /* ... */ }
        | item-def item-option
item-option: type | storage | prefix | tag

Но тогда в действиях вам нужнополучить объект предмета, который не является частью производства опциона.Вы можете сделать это с помощью функции Bison, которая позволяет вам заглядывать в стек анализатора:

prefix: "PREFIX" STRING { if (check_dup($<item>0->prefix, "prefix")
                            $<item>0->prefix = $2; }

В этом контексте $0 будет ссылаться на то, что было до prefix, то есть на то, что было до item-option, который является item-def.См. Конец этого раздела в руководстве Bison, где он описывает эту практику как "рискованную".Это также требует от вас явного указания тега, поскольку bison не выполняет грамматический анализ, необходимый для проверки правильности использования $0, который определил бы его тип.

...