【问题标题】:Making YACC output an AST (token tree)让 YACC 输出一个 AST(token tree)
【发布时间】:2010-10-31 10:03:34
【问题描述】:

是否可以让 YACC(或者我是 MPPG)输出抽象语法树 (AST)。

我正在阅读的所有内容都表明让 YACC 执行此操作很简单,但我很难知道您如何知道在构建节点时何时将树中的节点向上移动。

【问题讨论】:

    标签: parsing syntax yacc gppg


    【解决方案1】:

    其他答案建议修改语法,这在使用 C++ 语法时是不可行的(数百条规则..)

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

    %{
    
    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 词法分析器中的 RETURN 之前创建的

    【讨论】:

      【解决方案2】:

      根据 Hao 的观点,从 the manual 开始,您想要执行以下操作:

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

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

      这段代码翻译为“当用加号解析表达式时,取左右后代$1/$3并将它们用作节点的参数。将输出保存到$$(返回值)表达。

      $$(来自手册):

      要返回一个值,动作正常 将伪变量“$$”设置为一些 价值。

      【讨论】:

        【解决方案3】:

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

        【讨论】:

        • 谢谢,我以前在 lexx & yacc 的书中看到过这个。但我有点把它写成死胡同。为了让它全部挂在一起,您需要修改在联合标记 %union { private State _state; 中定义的 LexType ... LexValue(State state, object child1, object child2) {...} } 这允许您将树节点存储为您的状态。然后,您可以使用 $$ 别名 $$ = new LexValue(State.SchemaImport, $3, $5); 为其分配数据注意:词法分析器也需要将其标记数据推送到此结构中。当你知道如何时很容易......
        猜你喜欢
        • 1970-01-01
        • 2011-08-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-10
        • 2011-07-17
        • 2011-05-24
        相关资源
        最近更新 更多