Как вернуть более одного токена на синтаксический анализатор Bison? - PullRequest
2 голосов
/ 28 октября 2011

Моя грамматика что-то вроде этого

decl:

   attributes;  {/*create an object here with the attributes $$?*/ }


attributes:



  |

  att1 attributes {$$ = $1;}

  |

  att2 attributes {$$ = $1;}

  |

  attn attributes {$$ = $1;};

Я хочу получить все атрибуты, введенные пользователем, некоторые из них являются необязательными, и порядок не имеет значения, типы отличаются

Ответы [ 2 ]

1 голос
/ 02 декабря 2011
struct objectStruct{
  char* name;
  int value;
  objectStruct next;
  //...
}

теперь грамматика

decl:
  attributes {
    objectStruct* myObject = $1;
    while(myObject!=NULL){
       if(myObject->name!=NULL){
          //do something with name
          myObject=myObject->next;
       }
       else if(myObject->value!=NULL){
          //do something with value
          myObject=myObject->next;
       }
       //...
     }
  };

attributes:
 {$$=NULL;} 
|
 NAME attributes {
   objectStruct* myObject = new objectStruct();
   myObject->name = $1;
   myObject->value = NULL;
   myObject->next = $2;
   $$=myObject;
}
|
 VALUE attributes {
   objectStruct* myObject = new objectStruct();
   myObject->value = $1;
   myObject->name= NULL;
   myObject->next = $2;
   $$=myObject;
}
//...
;
1 голос
/ 28 октября 2011

Вам необходимо вернуть структуру в вашей переменной $$; назначить своим членам, как вам нужно. Вот пример из некоторого кода, который мне пригодится:

struct value_list {
    char *value;
    struct value_list *next;
};

# ...

valuelist:  TOK_VALUE
    {
        struct value_list *new = calloc(1, sizeof(struct value_list));
        if (!new)
            yyerror(_("Memory allocation error."));
        PDEBUG("Matched: value (%s)\n", $1);

        new->value = $1;
        new->next = NULL;
        $$ = new;
    }

valuelist:  valuelist TOK_VALUE
    {
        struct value_list *new = calloc(1, sizeof(struct value_list));
        if (!new)
            yyerror(_("Memory allocation error."));
        PDEBUG("Matched: value (%s)\n", $1);

        new->value = $2;
        new->next = $1;
        $$ = new;
    }

Еще один пример из того же парсера, который прилагает больше усилий для настройки struct на основе записи, чем приведенные выше более простые правила; недостаток в том, что это становится довольно сложным, но недостаток в том, что это лучшая демонстрация атрибутов одного объекта:

/* from a header file */
struct codomain {
    char *namespace;
    char *name;             /* codomain name */
    char *attachment;
    struct alt_name *altnames;
    void *xmatch;
    size_t xmatch_size;
    int xmatch_len;
    /* ... and it goes on like this ... */
}

# from the grammar:

profile_base: TOK_ID opt_id flags TOK_OPEN rules TOK_CLOSE
    {
        struct codomain *cod = $5;

        if (!cod) {
            yyerror(_("Memory allocation error."));
        }

        cod->name = $1;
        cod->attachment = $2;
        if ($2 && $2[0] != '/')
            /* we don't support variables as part of the profile
             * name or attachment atm
             */
            yyerror(_("Profile attachment must begin with a '/'."));
        cod->flags = $3;
        if (force_complain)
            cod->flags.complain = 1;

        post_process_nt_entries(cod);
        PDEBUG("%s: flags='%s%s'\n",
               $3,
               cod->flags.complain ? "complain, " : "",
               cod->flags.audit ? "audit" : "");

        $$ = cod;

    };
...