Re[11]: Разбор деклараторов
От: Roman Odaisky Украина  
Дата: 15.10.07 20:32
Оценка: 64 (9)
Здравствуйте, _hum_, Вы писали:

__>Я хотел выяснить у Вас, какими по возможности формальными правилами Вы пользуетесь.


Есть простое правило для распознавания выражений вроде char (&f(X (&)[N])[N] (кстати, это важный реальный пример). Обычно называется «направо — налево» или еще как-то так. Следует начать с идентификатора, затем двигаться направо до ближайшей закрывающей скобки, затем налево до скобки открывающей, стирая всё на своем пути. Натыкаясь на «*», «&», «[]», «()», записывать их значения.

Например, выясним тип f в следующей записи:
char ( & f () ) [N];
         ↑           f -- это
           ↑         функция
            ↑        без аргументов,
              ←
       ↑             возвращающая ссылку на
      →
                ↑    массив
                 ↑   из N элементов типа
                   ←
↑                    char.

И еще пример:
typedef int ( & ( C :: * ( * const * X ) ( void () ) throw() ) ( char, int () ) const ) [];
                                     ↑                                                      тип X -- это
                                       ←
                                   ↑                                                        указатель на
                             ↑                                                              неизменяемое значение типа
                           ↑                                                                указатель на
                         →
                                         ↑                                                  функцию, принимающую
                                           ↑                                                void(),
                                                     ↑                                      не бросающую исключений,
                                                             ←                              и возвращающую
                       ↑                                                                    указатель на
                    ↑                                                                       член
                  ↑                                                                         класса C типа
                →
                                                               ↑                            функция, принимающая
                                                                 ↑                          char и
                                                                       ↑                    int(),
                                                                                ↑           не изменяющая состояние объекта класса
                                                                                      ←     и возвращающая
              ↑                                                                             ссылку на
            →
                                                                                        ↑   массив
                                                                                          ←
        ↑                                                                                   целочисленных значений.

Это правило, впрочем, имеет тот недостаток, что требуется начинать с идентификатора. Иногда его нет. Например:
void foo(double*((*(&)[42]))[]);
boost::function<int*(&(int(*)[]))[]> bar;

Тогда принцип тот же, только снаружи: начинаем слева, увидев скобки, запоминаем их расположение, но пропускаем всё, что в них, обрабатываем то, что справа за скобками, затем то же самое для содержимого скобок. Полученное читаем с конца.

Идея в том, что квалификаторы, расположенные справа, имеют больший «приоритет», чем те, что слева:
int * нечто [];

Здесь нечто — массив указателей, а не наоборот. Применяя к этому нечему то же рассуждение рекурсивно, получаем полное описание всего выражения.

Таким образом, перевод с C++ на естественный язык есть просто обход AST в обратном центральном порядке (корень — правое — левое):
typedef
    int
    (
        &
        (
            C ::
            *
            (
                *
                const
                *
                X
            )
            (
                void ()
            )
            throw()
        )
        (
            char,
            int ()
        )
        const
    )
    []
;

(читать вот так: ↑/|/|/|)

Еще следует заметить, что конструкции «[]()» и «()[]» невозможны, потому что функции не возвращают массивы (хотя могут указатели на них), а массивы не содержат функции (хотя могут указатели на них).

Формально грамматика деклараторов описана в Стандарте в приложении A.7.
До последнего не верил в пирамиду Лебедева.
Re[12]: вдогонку
От: Roman Odaisky Украина  
Дата: 15.10.07 20:41
Оценка:
Прошу прощения, мое предыдущее сообщение было попыткой объяснить связь между деклараторами и типами C++, а не C. Сути это не меняет, разница лишь та, что в C одних деклараторов нет (например, X &), а другие есть (например, X[*], X* restrict), и ссылался я на стандарт ISO 14882:2003, а в стандарте 9899:1999 грамматика деклараторов расположена в приложении A2.2.

Собственно, на C, в отсутствие метапрограммирования, эдаких монстров пишут реже. И еще там очень любят void *, что заметно упрощает написание программ и заметно усложняет отладку программ ;-)
До последнего не верил в пирамиду Лебедева.
Re[8]: есть ли логика в системе типов С
От: gear nuke  
Дата: 18.10.07 04:26
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Обычно в теле объекта — не тыщща указателей на отдельные функции, а указатель на таблицу этих указателей.


В контексте "восприятия семантики языка" — это не для экономии памяти, а что бы различные экземпляры класса не могли иметь разных функций-членов (если же такое поведение требуется, то и решение вполне логичное — используется явный указатель).
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Re[9]: есть ли логика в системе типов С
От: Кодт Россия  
Дата: 18.10.07 08:14
Оценка:
Здравствуйте, gear nuke, Вы писали:

К>>Обычно в теле объекта — не тыщща указателей на отдельные функции, а указатель на таблицу этих указателей.


GN>В контексте "восприятия семантики языка" — это не для экономии памяти, а что бы различные экземпляры класса не могли иметь разных функций-членов (если же такое поведение требуется, то и решение вполне логичное — используется явный указатель).


Ну, завести дубликат vtbl и пропатчить его по вкусу — тоже несложно... поскольку от vtbl не требуется идентичности (хотя, возможно, отдельные реализации RTTI на это и закладываются).
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.