Делая конструктор AST для компилятора, не могу понять segfault - PullRequest
0 голосов
/ 20 июня 2019

Так что в настоящее время я делаю компилятор c-- для школьного проекта (который должен выйти сегодня), и у меня есть ошибка, которую я не могу понять. Существует большое количество кода, который не хочет заваливать этот вопрос всем этим.

Я запустил GDB, и он указал на пару функций одного файла, но я не мог сказать, в чем проблема, вероятно, потому что у меня нет такого большого опыта работы с C. Функции вызываются из другого файла .

Ниже приведены используемые функции / структуры файла, GDB указал на строки, которые я прокомментировал. Я могу сказать, что он не может получить доступ к родительскому узлу, но я не могу понять причину этого.

Я смотрю этот пост, если вы считаете, что какой-то код или информация отсутствует, укажите, и я немедленно отредактирую сообщение.

PS: AST - это узел. Весь этот код C.

#define CHILDREN_LIMIT 20
struct node {
    NodeKind kind;
    int data;
    int count;
    AST* parent;
    AST* child[CHILDREN_LIMIT];
};

AST* new_node(NodeKind kind, int data) {
    AST* node = malloc(sizeof * node);
    node->kind = kind;
    node->data = data;
    node->count = 0;
    node->parent = NULL;
    for (int i = 0; i < CHILDREN_LIMIT; i++) {
        node->child[i] = NULL;
    }
    return node;
}

void add_child(AST *parent, AST *child) {
    if (parent->count == CHILDREN_LIMIT) {
        fprintf(stderr, "Cannot add another child!\n");
        exit(1);
    }
    parent->child[parent->count] = child;
    parent->count++;
    child->parent = parent; // GDB POINTS HERE
}

AST* get_child(AST *parent, int idx) {
    return parent->child[idx];
}

// Adds s2 as child of s1 parent
void add_sibling(AST *s1, AST *s2) {
  if (s1->parent->count == CHILDREN_LIMIT) { // GDB POINTS HERE
      fprintf(stderr, "Cannot add another child!\n");
      exit(1);
  }
  s1->parent->child[s1->parent->count] = s2;
  s1->parent->count++;
  s2->parent = s1->parent;
}

AST* new_subtree(NodeKind kind, int child_count, ...) {
    if (child_count > CHILDREN_LIMIT) {
        fprintf(stderr, "Too many children as arguments!\n");
        exit(1);
    }

    AST* node = new_node(kind, 0);
    va_list ap;
    va_start(ap, child_count);
    for (int i = 0; i < child_count; i++) {
        add_child(node, va_arg(ap, AST*));
    }
    va_end(ap);
    return node;
}

---------- РЕДАКТИРОВАТЬ ------------------

На моем парсере (бизоне) это правила вызова и его производные:

write-call: WRITE LPAREN STRING RPAREN { new_subtree(WRITE_NODE,1,$3); }; // THIS ONE

var-decl-list: var-decl-list var-decl { add_sibling($1,$2); $$ = $1; } // AND THIS ONE
| var-decl { $$ = new_node(VAR_LIST_NODE, 0); add_child($$,$1); };

var-decl: INT ID SEMI { var_size = 0; $$ = new_var(); }
| INT ID LBRACK NUM { var_size = atoi(yytext); $$ = new_var(); } RBRACK SEMI;

AST* new_var() {
    int index = lookup_var(vt, current_id, scope);
    if (index != -1) {
        printf("SEMANTIC ERROR (%d): variable '%s' already declared at line %d.\n",
                yylineno, current_id, get_var_line(vt, index));
        exit(1);
    }
    index = add_var(vt, current_id, yylineno, scope, var_size);
    AST *vd = new_node(VAR_DECL_NODE,index);
    if(var_size > 0) {
      add_child(vd,new_node(NUM_NODE,var_size));
    }
    return vd;
}

На моем сканере (flex) у меня также есть:

{number} { yylval = new_node(NUM_NODE, atoi(yytext)); return NUM; }
{string} { int index = add_literal(lt, yytext); yylval = new_node(STR_NODE, index); return STRING; }
...