如何在yacc中使用递归来打印AST?

How to use recursion in yacc to print AST?

我正在为特定语言构建一个编译器,我制作了一个 lex 扫描器和 yacc Parsar 以及一个包含某些语言的文本文件,目标是构建一个合适的 AST 并打印它,

我已经用我需要的所有规则制作了完整的 yacc 和 lex 文件, 我 运行 他们使用代码:

yacc -d test.y
lex test.l
cc -o test y.tab.c -ll -Ly
./test < file.t

这些文件能够从文本文件生成解析器而没有任何语法问题,因此可以使用 lex 和 yacc 进行扫描和解析。

我已经准备好构造AST的函数, 为了正确打印它,我做了一个递归函数,它按顺序扫描以打印所有树。

*我删除了大部分不相关的代码

部分yacc代码:

%{
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    typedef struct node {
        char* token;
        struct node *left;
        struct node *middle; 
        struct node *right;
    }node;



    node *mknode(char *token,node *left,node *middle,node *right);

    void printTree(node *tree);

    void yyerror(const char *s);

    int yylex();

    #define printTree

    #define YYSTYPE struct node*
    extern char *yytext;

%}
%start start
%token MULTI DIVISION BOOL CHAR INT REAL STRING INTPTR CHARPTR REALPTR IF ELSE WHILE FOR VAR FUNC PROC RETURN ASSIGN AND EQUAL GREATER GREATEREQUAL LESS LESSEQUAL MINUS NOT NOTEQUAL OR PLUS ADDRESS DEREFERENCE ABSUOLUT NULLL SEMICOLON COLUMS COMMA NEGATIVE_NUM LEFTBRACE RIGHTBRACE LEFTBRACKET RIGHTBRACKET COOMMENT PRESENT MAIN BOOLTRUE LEFTPAREN RIGHTPAREN BOOLFALSE INTEGER_CONST CHAR_CONST REAL_CONST ID STRING_CONST HEX_CONST 
%right ASSIGN ELSE DIVISION
%left LEFTBRACE RIGHTBRACE LEFTPAREN RIGHTPAREN
%left EQUAL GREATER GREATEREQUAL LESSEQUAL LESS NOTEQUAL
%left PLUS MINUS AND OR 
%left MULTI 

%%
    start: Main                {printTree();};

    Main: proc Main            {$$=mknode("CODE",,,NULL);}  
         |empty                {$$=mknode("CODE",,NULL,NULL);};


    id: ID                                               {$$=mknode(yytext,NULL,NULL,NULL);};


    leftParen: LEFTPAREN                                       {$$=mknode("(",NULL,NULL,NULL);};

    rightParen: RIGHTPAREN                                     {$$=mknode(")",NULL,NULL,NULL);};

    empty:                                               {$$=mknode("",NULL,NULL,NULL);};

    proc: PROC id leftParen paramsList rightParen Problock {$$=mknode("PROC",mknode(->token,,,),NULL,);}
         |FUNC id leftParen paramsList rightParen returnInsideFuncDeclaration Problock {$$=mknode("FUNC",mknode(->token,,,),,);};


    paramsList: startparamsList SEMICOLON paramsList     {$$=mknode("start_params",,mknode(";",NULL,NULL,NULL),);}
                |startparamsList                         {$$=mknode("start_params",,NULL,NULL);}
                |empty                                   {$$=mknode("start_params",,NULL,NULL);}; 

    startparamsList: id next_param_in_proc               {$$=mknode("start_params",,,NULL);};

    next_param_in_proc: COMMA id next_param_in_proc      {$$=mknode(",",,,NULL);}
                        |COLUMS varType                  {$$=mknode(":",,NULL,NULL);};



    Problock: leftBrace Procbody rightBrace              {$$=mknode("PROC",,,);};

    Procbody: BlockBody                                  {$$=mknode("BODY",,NULL,NULL);}
              |BlockBody return                          {$$=mknode("BODY",,,NULL);} ; 


    HelpToStatement: ProcStatement HelpToStatement       {$$=mknode("help to statment",,,NULL);}
                     |empty                              {$$=mknode("help to statment",,NULL,NULL);};

    HelpToTheProcedure: proc HelpToTheProcedure          {$$=mknode("help proc",,,NULL);}
                        |empty                           {$$=mknode("help proc",,NULL,NULL);};

    HelpDeclare: Declaration HelpDeclare                 {$$=mknode("declartion",,,NULL);}
                 |empty                                  {$$=mknode("declartion",,NULL,NULL);};

    BlockBody: HelpToTheProcedure HelpDeclare HelpToStatement   {$$=mknode("Body",,,);};   


    ProcStatement:   exp SEMICOLON 
                     |structOfCond
                     |block;

%%
#include "lex.yy.c"

int main()
{
    return yyparse();
}

node *mknode(char *token, node *left, node *middle, node *right)
{
    node *newnode = (node*)malloc(sizeof(node));
    char *newstr = (char*)malloc(sizeof(token)+1);
    strcpy(newstr,token);
    newnode->left = left;
    newnode->middle = middle;
    newnode->right = right;
    newnode->token = newstr;
    return newnode;
}
void printtree(node *tree)
{
    printf("%s\n",tree->token);
    if(tree->left)
        printtree(tree->left);
    if(tree->middle)
        printtree(tree->middle);
    if(tree->right)
        printtree(tree->right);
}

void yyerror(const char *str)
{
    printf("%s - %s in line:%d \n",str,yytext,counter);
}

所以我设法从该语言构建 AST,但没有打印它,出于某种原因,函数 'printTree' 什么都不做,

如果我尝试像这样打印:printf("%s", ->token)printf("%s", ->left->token),那么一切都很好,每个标记都在其正确的位置,那么为什么我不能使用递归函数打印它们?

您使用 #define printTreeprintTree 定义为无。所以 printTree(); 被宏扩展为 ();,这是一个空操作。另一方面,您的函数 printtree(没有大写字母)永远不会被调用。

所以您应该删除 #define,转发声明 printtree 函数,然后在您的操作中调用它。