Определить структурное поле с циклической ссылкой - PullRequest
1 голос
/ 19 февраля 2020

У меня есть следующий код, где поле структуры зависит от поля структуры, которое еще не объявлено, поскольку эта структура, в свою очередь, может зависеть от структуры, которую я пытаюсь объявить.

Как я могу проектировать это так что компилирует? Или я упускаю очевидный способ избавиться от структуры объединения для хранения нескольких определений структуры?

typedef struct expression {
    expression_type type;
    union {
        bool_expression bool;
        identifier_expression ident;
        integer_expression _int;
        prefix_expression prefix;
        infix_expression infix;

        // TODO: Fix this
        if_expression _if;
    };
} expression;

typedef struct statement {
    token token;
    identifier name;
    expression * value;
} statement;

typedef struct block_statement {
    token token;
    statement *statements;
} block_statement;

typedef struct if_expression {
    token token;
    expression condition;
    block_statement *consequence;
    block_statement *alternative;
} if_expression;

Ответы [ 3 ]

2 голосов
/ 19 февраля 2020

В этом случае вы не можете.

if_expression содержит expression, который, в свою очередь, содержит if_expression. Если вы решите эту проблему с помощью указателей, вы можете изменить порядок своих определений и использовать struct expression*, чтобы создать указатель на структуру, которая еще не была определена.

1 голос
/ 19 февраля 2020

Вам лучше удалить typedefs, по крайней мере, на начальном этапе, чтобы вы могли лучше понять свои типы.

Вы должны изменить свои структуры, чтобы указывать (а не включать) другие структуры, например:

struct if_expression {
    /* struct? */ token *token;
    struct expression *condition;
    struct block_statement *consequence;
    struct block_statement *alternative;
}

Конечно, это приведет к разумному использованию вызовов malloc() и free(). В некоторых случаях вы можете позже вернуться к включению (как token выше, так как не ожидается, что оно указывает на другие ваши структуры, а копирование токенов вокруг - возможно, - дешевая операция).

Для цикличность ссылок, которые вы можете пересылать объявления в C, то есть вы говорите компилятору: «эй, есть структура с именем expression, внутреннюю структуру которой вы еще не знаете, но потерпите меня, вы скоро будете»:

struct expression;

Если позже вы решите использовать typedef - чтобы ваш код стал более упорядоченным - имейте в виду, что структуры могут иметь имя, а typedefs определяют имена, а эти имена не разделить одно и то же пространство имен. В примерах:

typedef struct {
    /* ...internal structure omited... */
} type_a;

typedef struct type_b {
    /* ...internal structure omited... */
} type_b;

typedef struct struct_c {
    /* ...internal structure omited... */
} type_c;

Здесь type_a - это тип, определение которого является анонимной структурой. И type_b - это тип, определение которого struct type_b, то есть именованная (type_b) структура. И type_c - это тип, определение которого struct struct_c, то есть именованная (struct_c) структура.

Теперь соберите все вместе, вы можете:

/* forward all your structs */
struct expression;
struct if_expression;
struct block_statement;

/* typedef them all */
typedef struct expression expression;
typedef struct if_expression if_expression;

/* actually define them */
struct expression {
    /* ... */
}

В качестве сноски вы можете многое узнать о C языке, понимая разницу между декларацией и определением.

1 голос
/ 19 февраля 2020

Если вы измените expression condition; на expression *condition; в if_expression, а затем вперёд объявите expression - typedef struct expression expression; вверху и затем поместите struct expression { … }; внизу, код должен быть в порядке.

/* Placeholder typedefs for undefined typedef names */
typedef int token;
typedef int identifier;
typedef int bool_expression;
typedef int identifier_expression;
typedef int integer_expression;
typedef int prefix_expression;
typedef int infix_expression;
typedef int expression_type;

/* The fixed code starts here */

typedef struct expression expression;

typedef struct statement
{
    token token;
    identifier name;
    expression * value;
} statement;

typedef struct block_statement
{
    token token;
    statement *statements;
} block_statement;

typedef struct if_expression
{
    token token;
    expression *condition;
    block_statement *consequence;
    block_statement *alternative;
} if_expression;

struct expression
{
    expression_type type;
    union
    {
        bool_expression bool;
        identifier_expression ident;
        integer_expression _int;
        prefix_expression prefix;
        infix_expression infix;
        if_expression _if;
    };
};

expression expr = { 0 };

Компилируется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...