Так что в настоящее время я делаю компилятор 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; }