代码之家  ›  专栏  ›  技术社区  ›  Sprotty

使yacc输出为ast(令牌树)

  •  12
  • Sprotty  · 技术社区  · 16 年前

    是否可以使yacc(或者我的示例mppg)输出抽象语法树(ast)。

    我读到的所有资料都表明,让yacc这么做很简单,但我很难知道,当你在树上构建一个节点时,你是如何知道何时向上移动的。

    3 回复  |  直到 7 年前
        1
  •  5
  •   hao    16 年前

    你看过吗 the manual (搜索“解析树”以查找位置)?它建议将节点创建放在一个操作中,您的左、右后代分别为$1和$3,或者它们可能是什么。在这种情况下,yacc将代表您向树上移动,而不是手动操作。

        2
  •  6
  •   geowa4    14 年前

    从郝的观点出发 the manual ,您要执行以下操作:

    假设您的抽象语法树具有函数 node 它在树中创建一个对象:

    expr : expr '+' expr
      {  
         $$ = node( '+', $1, $3 );  
      }
    

    此代码转换为“当用加号分析表达式时,取左、右后代” $1 / $3 并将它们用作节点的参数。将输出保存到 $$ 表达式的(返回值)。

    $(来自手册):

    要返回值,操作通常 将伪变量“`$$”设置为 价值。

        3
  •  1
  •   reuns    7 年前

    其他的答案提出修改语法,这是不可行的,当玩C++语法(几百条规则)。

    幸运的是,我们可以通过重新定义调试宏来自动完成。 在这段代码中,我们正在重新定义 YY_SYMBOL_PRINT 活跃的 YYDEBUG :

    %{
    
    typedef struct tree_t {
        struct tree_t **links;
        int nb_links;
        char* type; // the grammar rule
    };
    
    #define YYDEBUG 1
    //int yydebug = 1;
    
    tree_t *_C_treeRoot;
    %}
    %union tree_t
    
    %start program
    
    %token IDENTIFIER
    %token CONSTANT
    
    %left '+' '-'
    %left '*' '/'
    %right '^'
    
    %%
    progam: exprs { _C_treeRoot = &$1.t; }
        |
        | hack
        ;
    
    exprs:
        expr ';'
        | exprs expr ';'
        ;
    
    
    number:
        IDENTIFIER
        | '-' IDENTIFIER
        | CONSTANT
        | '-' CONSTANT
        ;
    
    expr:
        number
        | '(' expr ')'
        | expr '+' expr
        | expr '-' expr
        | expr '*' expr
        | expr '/' expr
        | expr '^' expr
        ;
    
    hack:
        {
        // called at each reduction in YYDEBUG mode
        #undef YY_SYMBOL_PRINT
        #define YY_SYMBOL_PRINT(A,B,C,D) \
            do { \
                int n = yyr2[yyn]; \
                int i; \
                yyval.t.nb_links = n; \
                yyval.t.links = malloc(sizeof *yyval.t.links * yyval.t.nb_links);\
                yyval.t.str = NULL; \
                yyval.t.type = yytname[yyr1[yyn]]; \
                for (i = 0; i < n; i++) { \
                  yyval.t.links[i] = malloc(sizeof (YYSTYPE)); \
                  memcpy(yyval.t.links[i], &yyvsp[(i + 1) - n], sizeof(YYSTYPE)); \
                } \
            } while (0)
    
        }
        ;
    %%
    
    #include "lexer.c"
    
    
    int yyerror(char *s) {
        printf("ERROR : %s [ligne %d]\n",s, num_ligne);
        return 0;
    }
    
    
    int doParse(char *buffer)
    {
        mon_yybuffer = buffer;
        tmp_buffer_ptr = buffer;
        tree_t *_C_treeRoot = NULL;
        num_ligne = 1;
        mon_yyptr = 0;
    
        int ret = !yyparse();
    
        /////////****
                 here access and print the tree from    _C_treeRoot 
        ***///////////
    }
    
    
    char *tokenStrings[300] = {NULL};
    char *charTokenStrings[512];
    
    void initYaccTokenStrings()
    {
        int k;
        for (k = 0; k < 256; k++)
        {
            charTokenStrings[2*k] = (char)k;
            charTokenStrings[2*k+1] = 0;
            tokenStrings[k] = &charTokenStrings[2*k];
        }
        tokenStrings[CONSTANT] = "CONSTANT";
        tokenStrings[IDENTIFIER] = "IDENTIFIER";
    
    
        extern char space_string[256];
    
        for (k = 0; k < 256; k++)
        {
            space_string[k] = ' ';
        }
    }
    

    在flex lexer中的返回之前创建叶