打印抽象语法树,无限递归问题

时间:2015-05-02 22:50:01

标签: c recursion stack abstract-syntax-tree

对于我的C编程类中的最终项目,我们正在实现一个反向抛光表示法计算器,它可以评估表达式的正确性,返回相应的中缀表达式,或打印出模拟汇编代码。为此,我们要实现堆栈和抽象语法树。

struct snode /*stack data structure */
{
  int datum;
  struct snode* bottom;
};

struct tnode /*tree data structure */
{
  int datum;
  struct tnode* left;
  struct tnode* right;
};

目前,我设计的程序是从stdin读取并将元素放到堆栈中,然后使用该堆栈创建一个抽象语法树,以后可以用它来评估表达式。现在,我还没有进行任何检查,我只是想先建立一个AST。

以下是我主要功能的大部分内容。目前,没有检查确保给定的等式是正确的。

int i = 1;


struct snode *stack;
stack = push(stack, -999); /* Here I set what will be the "empty" value of my stack. There's better ways to do it, but this is how I did it for a previous lab and it tended to cause less issues for me when I check if my stack is empty at the end */

struct tnode *AST;
AST = (struct tnode*)malloc(sizeof(struct tnode));
AST->datum = -7062; /*same thing as with stack, this is just a place holder that will be over written. */
AST->right = NULL;
AST -> left = NULL;

struct tnode* tmp;
tmp = (struct tnode*)malloc(sizeof(struct tnode));
tmp -> datum = -7062;
tmp -> right = NULL;
tmp -> left = NULL;

/*Operators are given as letters instead of +,-, etc. */
char *addition = "A"
char *subtraction = "S";
char *multiplication = "X";
char *division = "D"
char *mod = "M";

while(argv[i] !=NULL){
    if(isdigit(unsignedchar)argv[i][0])){
      stack = push(stack, atol(argv[i]));
   }else{ /* In the final code, a strcmp will check to see if argv[i] is one of the above A,S,X,D, or M arguments. For right now, it just fires if it's not a digit for my testing. */
       if(AST->datum == -7062){ /*if this is the first time we're running it*/
         AST->datum = atol(argv[i]);
         AST->right = create_node(stack->datum);
         stack = pop(stack);
         AST -> left = create_node(stack->datum);
         stack = pop(stack); /* I pop the top off the stack twice to get the 2 integers it stores. I know it will for the current testing, checks will be in place later */
       }else{ /* if AST already has elements in it. */
         tmp = AST;
         tmp -> left = tmp-> right = NULL;
         AST->datum = atol(argv[i]);
         AST->right = create_node(stack->datum);
         stack = pop(stack);
         AST->left = tmp; /*This puts the new operator as the root of the tree, the old tree as the left child of that root, and the right child as the integer stored on stack.*/
         }
     }
  i++;
  }

print_table(AST); /*Should print the AST */
}

create_node分配空间并存储给它的内容。

struct tnode*
create_node(int x){
  struct tnode* tmp;
  tmp = (struct tnode*)malloc(sizeof(struct tnode))
  tmp->datum = x;
  tmp->right = NULL;
  tmp->left = NULL;
  return tmp;
}

print_table以递归方式打印抽象语法树。

void
print_table(struct tnode *AST){
    if(AST !=NULL){
        print_table(AST->left);
        printf("%d ", AST->datum);
        print_table(AST->right);
      }
  }

目前,如果给出以下内容:/ rpcalc 5 4 A. 然后程序将返回5 0 4.我理解为什么A返回0,所以这部分按预期工作。 但是,当我尝试给程序/ rpcalc 5 4 A 3 X,即(5 + 4)* 3时,它会冻结片刻,然后返回分段错误。

使用几个printf语句,我已将问题分解为print_table函数中的递归。由于某种原因,AST-> left似乎没有到达NULL指针来终止程序,导致它无限运行直到程序崩溃。我不确定导致这种情况的原因,不幸的是,在我解决这个问题之前,我无法继续进行任何项目......

2 个答案:

答案 0 :(得分:3)

让我们从中间开始:

       }else{ /* if AST already has elements in it. */
         tmp = AST;
         tmp -> left = tmp-> right = NULL;
         AST->datum = atol(argv[i]);
         AST->right = create_node(stack->datum);
         stack = pop(stack);
         AST->left = tmp; /*This puts the new operator as the root of the tree, the old tree as the left child of that root, and the right child as the integer stored on stack.*/
         }
     }
  i++;
  }

这很糟糕。您将tmp = AST,然后tmp->lefttmp->right设置为NULL,但AST->leftAST->right设置为NULL,因为他们指的是同一件事!稍后,您设置了AST->left = tmp,这会创建一个循环,因为ASTtmp再次指向相同的内容,因此它等同于AST->left = AST。递归到AST->left因此无限下降,AKA 堆栈溢出

答案 1 :(得分:1)

虽然你的代码无限递归的原因已经由EOF的答案给出了,看看我无法抗拒的代码,至少对我而言,似乎你也应该重新考虑你的算法

很可能不是要保留在堆栈上的数字(int),而是AST片段。想象一下像1 2 + 3 4 + *这样的表达式,甚至更深层次的嵌套表达式。将struct snode更改为:

struct snode /*stack data structure */
{
    struct tnode* datum; /* we want to store AST nodes here !! */
    struct snode* bottom;
};

您的代码可能类似于:

int main(int argc, char* argv[]) {
    int i = 1;

    struct snode *stack = NULL;
    struct tnode *AST = NULL;

    while(argv[i] !=NULL){

        /* isdigit takes argument of type char! don't typecast here */
        if(isdigit(argv[i][0])){ 
            stack = push(stack, create_node(atol(argv[i])));
        } 
        else {
            /* original code using atol(argv[i]), always returning 0 here */
            AST = create_node(0); 
            AST->left = stack->datum;
            stack = pop(stack);
            AST->right = stack->datum;
            stack = pop (stack);
            stack = push(stack, AST);
        }
        i++;
    }

    if (stack != NULL) {
        AST = stack->datum;
        print_table(AST); /*Should print the AST */
    }

    return 0;
}

输入5 4 A 3 X会按预期生成3 0 4 0 5,因此您仍有足够的时间来处理。

祝你好运。

可以肯定的是,我们在这里谈论的是相同的事实。对于push()pop(),未在代码片段中给出,我使用了以下代码。

struct snode* push(struct snode* stack, struct tnode* datum) {
    struct snode *S = (struct snode*)malloc(sizeof(struct snode));
    S->datum = datum;
    S->bottom = stack;
    return S;
}

struct snode* pop(struct snode* stack) {
    struct snode *S;
    if (stack == NULL)
        return NULL;
    S = stack->bottom;
    free(stack);
    return S;
}