首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在Bison (或yacc )中,是否存在由语法定义的顺序?

在Bison (或yacc )中,是否存在由语法定义的顺序?
EN

Stack Overflow用户
提问于 2018-09-27 06:20:39
回答 1查看 657关注 0票数 1

我在一个Bisone文件中有以下语法:

代码语言:javascript
复制
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’,它接受了";“。我是否需要做一些事情来允许指定任何顺序?如果是,我希望有一个简单的解决方案。否则,我将需要做更多的工作。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-09-27 09:16:50

不可能告诉bison (或yacc)顺序无关紧要。规则是严格有序的。

所以你有两个选择:

  1. 列出所有可能的订单。如果这样做,请注意可选结果引起的多义性。实际上,您需要列出所有订单和子集。挂载exponentially.
  2. Just接受任何组件列表,作为列表。这将接受重复的组件,所以如果您关心的话,您需要在语义操作中捕获它。

第二种选择几乎总是你想要的。实现通常很简单,因为您希望将组件存储在某个位置;只要该位置有一个唯一的值(例如NULL),这意味着“尚未设置”,那么您只需在设置该值之前测试该值。例如,而不是问题中的那个):

代码语言:javascript
复制
%{
   #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产品分成类似以下内容:

代码语言:javascript
复制
item-def: "ITEM" NAME   { /* ... */ }
        | item-def item-option
item-option: type | storage | prefix | tag

但是在操作中,您需要获取item对象,它不是option production的一部分。您可以使用Bison特性来实现这一点,该特性允许您查看解析器堆栈:

代码语言:javascript
复制
prefix: "PREFIX" STRING { if (check_dup($<item>0->prefix, "prefix")
                            $<item>0->prefix = $2; }

在本文中,$0指的是在prefix之前出现的任何东西,也就是在item-option之前出现的任何东西,也就是item-def。参见Bison手册中this section的结尾,其中将这种做法描述为“有风险的”,事实的确如此。它还要求您显式地指定标记,因为bison不执行验证$0使用所需的语法分析,这将标识其类型。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52526784

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档