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.10.07 11:23
Оценка: 1 (1)
Здравствуйте, _hum_, Вы писали:

__>Так являются функции отдельным типом или это какие-то специальные объекты со своими правилами ??


Функции — это специальные объекты (точнее, они не являются объектами). Да, для них действуют свои правила.
Как, кстати, и массивы.

В синтаксисе и в системах типов С/С++ есть хитрости.
Так, функция может быть приведена к указателю на функцию, а массив — к указателю на элемент.
Поэтому
int g(int); // объявление функции
int(*pf)(int); // объявление переменной "указатель на функцию"

pf = g; // int(int) --> int(*)(int)
pf = &g; // int(*)(int)
pf = &f; // ошибка: int(**)(int) --> int(*)(int)
pf = *f; // результат разыменования - int(int)

pf(123);
(*pf)(123);

Почему так сделано — а бог знает. Исторически сложилось.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[11]: есть ли логика в системе типов С
От: Кодт Россия  
Дата: 15.10.07 14:44
Оценка: 1 (1)
Здравствуйте, _hum_, Вы писали:

__>Ситуация такова — нужно другого человека вкратце ознакомить, что за штука язык С/C++ и с чем его едят.


Во, это другое дело! Сразу ясен контекст.

__>Понятно, что "вкратце" требует, чтоб рассказ шел системно, с общих позиций. Вот тут-то при попытке составить это системное видение и возникают проблемы.

__>Первая из них — определение типов и переменных данных типов, что собственно и явлилось темой эхи.

__>Как я понял из наших разговоров, заковырки здесь появляются из-за того, что в каждом языке есть понятие первоклассных и нет объектов, и наличие вторых мешает строить общие правила. Вроде, понятно...


Тут нужно всё-таки твёрдо уяснить. Есть синтаксис и есть семантика.
Синтаксис никаким образом не определяет, являются те или иные сущности первоклассными объектами или нет.
Семантика, конечно, частично зависит от синтаксиса: скажем, если не предусмотрено такой языковой конструкции, как ссылка на ссылку — то, хоть тресни, её не получишь. Ну, неявно или симуляцию — это пожалуйста...

__>Второй вопрос, который возникает — это как, с учетом наличия непервоклассных объектов, объяснить правила, по которым могут выводиться типы.


Непервоклассные объекты невозможно создавать в рантайме, но они могут создаваться во время компиляции.
Так, например, ты не можешь создать массив произвольного размера, чтобы тип его был именно "массив". new T[N] — имеет тип T*.
А функцию — вообще не можешь создать (впрочем, с использованием хаков — генерируя машинный код — пожалуйста).

Но во время компиляции-то они создаются! И типы имеют!
Вот и всё объяснение.

Дальше нужно курить синтаксис.

__>В Стандарте к языку есть нечто подобное, но слишком все-таки расплывчатое с кучей комметов и примеров... Я хотел выяснить у Вас, какими по возможности формальными правилами Вы пользуетесь.


Опытом

Есть правила разбора выражений типа. Правила конструирования — это обратные функции.
Примерно вот так сишные выражения типа превращаются в чисто префиксные.
type expr        ---> type expr
type (expr)      ---> type expr
type expr [dim]  ---> array(type,dim) expr
type expr (args) ---> function(type,args) expr
type const expr  ---> const(type) expr
const type expr  ---> const(type) expr
type *expr       ---> pointer(type) expr

Например,
int x [10][20][30] =
array(int,30) x [10][20] =
array(array(int,30),20) x [10] =
array(array(array(int,30),20),10) x

т.е. массив из 10 элементов, каждый из которых — массив из 20 элементов, каждый из которых, наконец — массив из 10 int'ов.

Ну и наоборот:
array(pointer(function(pointer(int),char)),10) tbl - таблица из 10 указателей на функции вида int* <- char
= pointer(function(pointer(int),char)) tbl[10]
= function(pointer(int),char) *tbl[10]
= pointer(int)(*tbl[10])(char)
= int*(*tbl[10])(char)


Вот примерно так.

Скобки возникают в тех случаях, когда нужно разрулить кажущуюся неоднозначность (для компилятора-то её нет, а программист мозг сломает).
Постфиксные операторы — [], () — приоритетнее префиксных — *, const.
Поэтому
int** x[10] =
array(int**,10) x =
array(pointer(pointer(int)),10) x

int* (*x) [10] =
array(int*,10) *x =
pointer(array(pointer(int),10)) x

int (**x) [10] =
array(int,10) **x =
pointer(pointer(array(int,10))) x
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[4]: есть ли логика в системе типов С
От: _hum_ Беларусь  
Дата: 12.10.07 12:21
Оценка: :)
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, _hum_, Вы писали:


__>>Тогда, получается, что переменной типа "функция" в С нет (есть тип, но переменной этого типа нет — только константы)


К>Именно. В С/С++ функции — не "первоклассные объекты".


О, это уже больше похоже на правду, где бы поподробнее про эту классификацию узнать?

__>>А тогда запись int f(int); должна означать не определение, а какое-то действие иного характера, типа декларирование для компилятора.

__>>Но ведь в struct{ int f(int); } X; эта же запись означает определение (под указатель на функцию отводится место в памяти, насколько я понимаю).

К>Неправильно понимаешь. Здесь ты объявил функцию-член у анонимной структуры. (Интересно, как ты её будешь определять )


Почему ж неправильно, и, кстати, я объявлял не анонимную структуру, а переменную X заданного типа. Можно, по-другому, например,

struct T{
int i;
int g(int);
};

T X;
X.i = 0;

будет работать и без объявления тела функции g, поскольку память под int g(int) отводить известно сколько.

К>Объявление переменной типа "указатель на функцию" — это всегда result(*f)(args).
есть ли логика в системе типов С
От: _hum_ Беларусь  
Дата: 12.10.07 11:04
Оценка:
вопрос:
в С заявляется, что производными типами являются структуры, массивы и функции
то есть, получается, функции являются значениями
тогда опять же, получается, что запись
int f(int);
должна означать создание переменной типа функции, с одним целым параметром и целым возвращаемым значением
тогда, почему недопускается следующая запись:
int g(int i){return i;}

f = g;// ошибка

и второй вопрос, почему, если объявляется указатель на функцию, то есть

int (*f)(int);

то валидна запись

f = g;

и при этом она оказывается равносильной

f = &g;

Так являются функции отдельным типом или это какие-то специальные объекты со своими правилами ??
Re: есть ли логика в системе типов С
От: Мухоморец Украина  
Дата: 12.10.07 11:21
Оценка:
Здравствуйте, _hum_, Вы писали:

__>int f(int);


__>int g(int i){return i;}


__>f = g;// ошибка


рассматривай как const тогда

__>и второй вопрос, почему, если объявляется указатель на функцию, то есть


__>int (*f)(int);


__>то валидна запись


__>f = g;


могу ошибаться, но это в стиле С
__>f = &g;
a это в стиле С++
в современных С++ компиляторах оставлено для поддержки С

а ля
int m[10];
m == &m;
Re[2]: есть ли логика в системе типов С
От: _hum_ Беларусь  
Дата: 12.10.07 11:46
Оценка:
Здравствуйте, Мухоморец, Вы писали:

М>Здравствуйте, _hum_, Вы писали:


__>>int f(int);


__>>int g(int i){return i;}


__>>f = g;// ошибка


М>рассматривай как const тогда


Тогда, получается, что переменной типа "функция" в С нет (есть тип, но переменной этого типа нет — только константы)
А тогда запись int f(int); должна означать не определение, а какое-то действие иного характера, типа декларирование для компилятора. Но ведь в struct{ int f(int); } X; эта же запись означает определение (под указатель на функцию отводится место в памяти, насколько я понимаю). Получается одна и та же запись в разных местах означает различное..

__>>и второй вопрос, почему, если объявляется указатель на функцию, то есть


__>>int (*f)(int);


__>>то валидна запись


__>>f = g;


М>могу ошибаться, но это в стиле С

__>>f = &g;
М>a это в стиле С++
М>в современных С++ компиляторах оставлено для поддержки С

М>а ля

М>int m[10];
М> m == &m;

А вот это хорошо, если так оно есть на самом деле
Re[3]: есть ли логика в системе типов С
От: Мухоморец Украина  
Дата: 12.10.07 12:00
Оценка:
Здравствуйте, _hum_, Вы писали:



__>Тогда, получается, что переменной типа "функция" в С нет (есть тип, но переменной этого типа нет — только константы)


ну ты же можешь обьявить указатели на функцию
значит тип(ы) есть

мы же можем сказать какой тип у указателя на функцию

__>А тогда запись int f(int); должна означать не определение, а какое-то действие иного характера, типа декларирование для компилятора. Но ведь в struct{ int f(int); } X; эта же запись означает определение (под указатель на функцию отводится место в памяти, насколько я понимаю). Получается одна и та же запись в разных местах означает различное..


что глобал функция, что метод в памяти находятся единожды
толко при вызове метода ему передаётся this объекта )), чтоб знал с чьими мемберами она работает

то что в структуре описано 100 методов не виртуальных
так это на размер объектов никак не влияет

так что никаких отличий практически)))
Re[3]: есть ли логика в системе типов С
От: Кодт Россия  
Дата: 12.10.07 12:04
Оценка:
Здравствуйте, _hum_, Вы писали:

__>Тогда, получается, что переменной типа "функция" в С нет (есть тип, но переменной этого типа нет — только константы)


Именно. В С/С++ функции — не "первоклассные объекты".

__>А тогда запись int f(int); должна означать не определение, а какое-то действие иного характера, типа декларирование для компилятора.

__>Но ведь в struct{ int f(int); } X; эта же запись означает определение (под указатель на функцию отводится место в памяти, насколько я понимаю).

Неправильно понимаешь. Здесь ты объявил функцию-член у анонимной структуры. (Интересно, как ты её будешь определять )
Объявление переменной типа "указатель на функцию" — это всегда result(*f)(args).
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[5]: есть ли логика в системе типов С
От: Кодт Россия  
Дата: 12.10.07 13:13
Оценка:
Здравствуйте, _hum_, Вы писали:

__>О, это уже больше похоже на правду, где бы поподробнее про эту классификацию узнать?


Ну, погугли на слово first class objects...

Да, кстати. Ты на каком языке раньше писал? Смолток, Яваскрипт, Питон?

К>>Неправильно понимаешь. Здесь ты объявил функцию-член у анонимной структуры. (Интересно, как ты её будешь определять )

__>Почему ж неправильно, и, кстати, я объявлял не анонимную структуру, а переменную X заданного типа.
Вот это и показывает, что ты понимаешь неправильно.
Ты объявил тип "анонимная структура" и тут же объявил переменную этого типа.

__> Можно, по-другому, например,

__>struct T{
__>        int i;
__>        int g(int);
__>    };

__>    T X;
__>    X.i = 0;

__>будет работать и без объявления тела функции g, поскольку память под int g(int) отводить известно сколько.
Именно. И знаешь, сколько памяти отведено под int g(int)? РОВНО НОЛЬ!!!

Имена (ну, или объявления) функций — это, считай, литералы, ссылающиеся (!) (не указывающие, а именно ссылающиеся) на куски кода.
Сколько памяти отведено под число 123? А под число 123+456? А если это число упомянуто в программе несколько раз?
Литерал не является объектом. Где компилятор захочет его подставить — там и подставит.

Если ты написал конструктор
struct T
{
    T() { cout << 123; }
    int g() { return 456; }
};

это не значит, что в каждом экземпляре класса T будет своя копия конструктора или указателя на конструктор, и уж тем более, что там будут копии чисел 123 и 456.
Всё это просто зашито в код.
Точно так же зашиты в код вызовы функции-члена.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re: есть ли логика в системе типов С
От: Андрей Коростелев Голландия http://www.korostelev.net/
Дата: 12.10.07 13:52
Оценка:
Здравствуйте, _hum_, Вы писали:

__>вопрос:


Потому что С задумывался как высокоуровневый ассемблер, а не как функциональный язык. Как следствие он обладает слабой типизацией, а это значит, что система типов не имеет в С сколько-нибудь серъезного влияния, как, например, в С# или Python.
-- Андрей
Re[6]: есть ли логика в системе типов С
От: _hum_ Беларусь  
Дата: 12.10.07 16:36
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, _hum_, Вы писали:


__>>О, это уже больше похоже на правду, где бы поподробнее про эту классификацию узнать?


К>Ну, погугли на слово first class objects...


К>Да, кстати. Ты на каком языке раньше писал? Смолток, Яваскрипт, Питон?


К>>>Неправильно понимаешь. Здесь ты объявил функцию-член у анонимной структуры. (Интересно, как ты её будешь определять )

__>>Почему ж неправильно, и, кстати, я объявлял не анонимную структуру, а переменную X заданного типа.
К>Вот это и показывает, что ты понимаешь неправильно.
К>Ты объявил тип "анонимная структура" и тут же объявил переменную этого типа.

__>> Можно, по-другому, например,

К>
__>>struct T{
__>>        int i;
__>>        int g(int);
__>>    };

__>>    T X;
__>>    X.i = 0;
К>

__>>будет работать и без объявления тела функции g, поскольку память под int g(int) отводить известно сколько.
К>Именно. И знаешь, сколько памяти отведено под int g(int)? РОВНО НОЛЬ!!!

К>Имена (ну, или объявления) функций — это, считай, литералы, ссылающиеся (!) (не указывающие, а именно ссылающиеся) на куски кода.

К>Сколько памяти отведено под число 123? А под число 123+456? А если это число упомянуто в программе несколько раз?
К>Литерал не является объектом. Где компилятор захочет его подставить — там и подставит.

К>Если ты написал конструктор

К>
К>struct T
К>{
К>    T() { cout << 123; }
К>    int g() { return 456; }
К>};
К>

К>это не значит, что в каждом экземпляре класса T будет своя копия конструктора или указателя на конструктор, и уж тем более, что там будут копии чисел 123 и 456.
К>Всё это просто зашито в код.
К>Точно так же зашиты в код вызовы функции-члена.

Действительно, нуль...Значится, я на ентот счет ошибался...

А еще, может быть подскажете, как лучше и проще оформить правила вывода типов. Сам пока я токо прикинул,
что хорошо бы было что-нибудь типа:

пусть Type — известный тип, NewType — определяемый, тогда

type_definition(NewType) ::= typedef Type Op(NewType) |
typedef struct NewType '{'Type1 name1';'...'Typen namen''}' |
typedef union NewType '{'Type1 name1';'...'Typen namen''}'

Op(NewType) :: = ArrayOp(NewType) |
PointerOp(NewType) |
FuncOp(NewType) |
Id(NewType) |

ArrayOp(Op(NewType)) |
PointerOp(Op(NewType)) |
FuncOp(Op(NewType)) |
Id(Op(NewType))



ArrayOp(NewType) ::= NewType'['n']' // массив из...
PointerOp(NewType) ::= '*'NewType // указатель на...
FuncOp(NewType) ::= NewType(Type1','...','Typen) // функция с аргументами типа Type1,..,Typen возвращающая...
IdOp(NewType) ::= NewType | '('NewType')'

При следующих условиях:
— не должно получаться массивов из функций
— не должно получаться функций, возврщающих функции
— не должно получаться функций, возвращающих массивы

И далее, правильно ли так говорить, что значения типов функций и значения ссылочных типов (кстати, куда бы их в сиснтаксисе всунуть) не являются значениями первого класса (для них, например, не могут создаваться переменные).
Re[7]: есть ли логика в системе типов С
От: Кодт Россия  
Дата: 15.10.07 08:17
Оценка:
Здравствуйте, _hum_, Вы писали:

<Оверквотинг вырезан. Пожалуйста, цитируй только существенное.>

__>А еще, может быть подскажете, как лучше и проще оформить правила вывода типов. Сам пока я токо прикинул,

__>что хорошо бы было что-нибудь типа:

__>пусть Type — известный тип, NewType — определяемый, тогда

__>type_definition(NewType) ::= typedef Type Op(NewType) |
__>                             typedef struct NewType  '{'Type1 name1';'...'Typen namen''}' |
__>                             typedef union  NewType  '{'Type1 name1';'...'Typen namen''}'

__>Op(NewType) :: = ArrayOp(NewType) |
__>                 PointerOp(NewType) |
__>                 FuncOp(NewType) |
__>                 Id(NewType) |

__>                 ArrayOp(Op(NewType)) |
__>                 PointerOp(Op(NewType)) |
__>                 FuncOp(Op(NewType)) |
__>                 Id(Op(NewType)) 
 
__> ArrayOp(NewType)   ::= NewType'['n']'  // массив из...
__> PointerOp(NewType) ::= '*'NewType      // указатель на...
__> FuncOp(NewType)    ::= NewType(Type1','...','Typen) // функция с аргументами типа Type1,..,Typen возвращающая...
__> IdOp(NewType)      ::= NewType | '('NewType')'


__>При следующих условиях:

__>- не должно получаться массивов из функций
__>- не должно получаться функций, возврщающих функции
__>- не должно получаться функций, возвращающих массивы

Эти условия как раз обеспечены тем, что у тебя typedef Type Op(NewType).
Потому что в С/С++ объявления функций и массивов — хитровывернутые. Вот если бы было в стиле паскаля (а также хаскеля, ML и т.д.) type NewType = Op(Type)...
Кстати, а чем они тебе помешали? Ну пусть функция возвращает функцию. Жалко, что ли?
Или это вопрос — как грамматику составить? Дык, просто. Только она будет уже не LL(1)

В С/С++ объявление можно представить в виде prefix Name suffix, где префикс и суффикс — какие-то строки, вместе образующие правильное выражение (сбалансированное по скобкам и т.д.)
Соответственно, производные типы получаются присобачиванием операторов (*, &, const, volatile, (), []) к префиксу/суффиксу.

__>И далее, правильно ли так говорить, что значения типов функций и значения ссылочных типов (кстати, куда бы их в сиснтаксисе всунуть) не являются значениями первого класса (для них, например, не могут создаваться переменные).


Семантика того, что является или не является первоклассными объектами — не зависит от синтаксиса типов.
Например, в C# массивы — первоклассные объекты.
Это во многом обусловлено рантаймом, который у С/С++ сознательно прибеднён.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[6]: есть ли логика в системе типов С
От: _hum_ Беларусь  
Дата: 15.10.07 09:19
Оценка:
Почему-то не увидел отправленного мной ранее сообщения, поэтому повторюсь.

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

Думаю, тот факт, что функции не являются объектами первого класса, во многом объясняет ситуацию, и снимает мой первоначальный вопрос.

Вот тут еще появился вопросик. Как по-вашему можно было бы записать правила вывода типов в C/C++. Хотелось бы что-нить вроде BNF-формы. Что-нить типа:

Пусть
Type — известный тип (базовый, или уже определенный по этой схеме ранее),
NewType — определяемый.
Тогда определение типа имеет вид

type_definition(NewType) ::= typedef Type Op(NewType) |
typedef struct NewType '{'Type1 name1';'...Typen namen';''}' |
typedef union NewType '{'Type1 name1';'...Typen namen';''}'

Op(NewType) ::= ArrOp(NewType) |
PtrOp(NewType) |
FunOp(NewType) |
Id(NewType) |

ArrOp(Op(NewType)) |
PtrOp(Op(NewType)) |
FunOp(Op(NewType)) |
Id(Op(NewType))



ArrOp(NewType) ::= NewType'['n']' // массив из...
PtrOp(NewType) ::= '*'NewType // указатель на...
FunOp(NewType) ::= NewType(Type1','...','Typen) // функция с арг. типа Type1,..,Typen возвращающая...
IdOp(NewType) ::= NewType | '('NewType')'

При следующих условиях:
— не должно получаться массивов из функций
— не должно получаться функций, возвращающих функции
— не должно получаться функций, возвращающих массивы
Re[8]: есть ли логика в системе типов С
От: _hum_ Беларусь  
Дата: 15.10.07 09:36
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, _hum_, Вы писали:


__>>При следующих условиях:

__>>- не должно получаться массивов из функций
__>>- не должно получаться функций, возврщающих функции
__>>- не должно получаться функций, возвращающих массивы

К>Эти условия как раз обеспечены тем, что у тебя typedef Type Op(NewType).


Как же эти условия обеспечены, если нчиегомне не запрещает написать typedef int (T(int))[10]

К>Потому что в С/С++ объявления функций и массивов — хитровывернутые. Вот если бы было в стиле паскаля (а также хаскеля, ML и т.д.) type NewType = Op(Type)...


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

К>Кстати, а чем они тебе помешали? Ну пусть функция возвращает функцию. Жалко, что ли?


Это запрещено в С и С++

К>Или это вопрос — как грамматику составить? Дык, просто. Только она будет уже не LL(1)


Да,именно, как записать соответствующие правила в виде формальной грамматики (обычной или атрибутивной?)

К>В С/С++ объявление можно представить в виде prefix Name suffix, где префикс и суффикс — какие-то строки, вместе образующие правильное выражение (сбалансированное по скобкам и т.д.)


Что значит "какие-то строки, образующие правильные выражения" — что именно считается правильным — в этом же и вопрос!

К>Соответственно, производные типы получаются присобачиванием операторов (*, &, const, volatile, (), []) к префиксу/суффиксу.


То есть *prefix Name *suffix будет считаться правильным — какой же в этом случае должны быть prefix и suffix, интересно...

__>>И далее, правильно ли так говорить, что значения типов функций и значения ссылочных типов (кстати, куда бы их в сиснтаксисе всунуть) не являются значениями первого класса (для них, например, не могут создаваться переменные).


К>Семантика того, что является или не является первоклассными объектами — не зависит от синтаксиса типов.

Вопрос же был не так поставлен. Спрашивалось, можно ли считать, что ссылочные типы в С/C++, как и функции, не являются объектами первого класса.

К>Например, в C# массивы — первоклассные объекты.

К>Это во многом обусловлено рантаймом, который у С/С++ сознательно прибеднён.
Re[7]: есть ли логика в системе типов С
От: Кодт Россия  
Дата: 15.10.07 09:37
Оценка:
Здравствуйте, _hum_, Вы писали:

__>Действительно, я ошибался, думая, что при декларировании в структуре функции там же отводится память под указатель на эту функцию.

__>Хотя, как по мне, так это было бы проще для восприятия семантики языка (механизм виртуальных функций-то, по сути, так и реализован).

Семантика С/С++ насквозь пропитана идеей минимализма. Ни одного лишнего байта, насколько это возможно.
А механизм виртуальных функций реализован по-другому. Обычно в теле объекта — не тыщща указателей на отдельные функции, а указатель на таблицу этих указателей.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[9]: есть ли логика в системе типов С
От: Кодт Россия  
Дата: 15.10.07 09:44
Оценка:
Здравствуйте, _hum_, Вы писали:

<>

Я не понимаю всё-таки, что ты хочешь выяснить.
— Как устроены синтаксис и семантика реальных языков C|C++? --> читай Стандарт, там синтаксис освещён.
— Как сделать собственный язык "по мотивам", обладающий нужными свойствами?
— Определиться с комплектом свойств, отличающих его от оригинала?
— Как сделать собственный парсер?
Или это попытка подойти к С/С++ как к чёрному ящику, а в качестве входов-выходов — расспрашивать экспертов?
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[10]: есть ли логика в системе типов С
От: _hum_ Беларусь  
Дата: 15.10.07 13:36
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, _hum_, Вы писали:


К><>


К>Я не понимаю всё-таки, что ты хочешь выяснить.

К>- Как устроены синтаксис и семантика реальных языков C|C++? --> читай Стандарт, там синтаксис освещён.
К>- Как сделать собственный язык "по мотивам", обладающий нужными свойствами?
К>- Определиться с комплектом свойств, отличающих его от оригинала?
К>- Как сделать собственный парсер?
К>Или это попытка подойти к С/С++ как к чёрному ящику, а в качестве входов-выходов — расспрашивать экспертов?

Ситуация такова — нужно другого человека вкратце ознакомить, что за штука язык С/C++ и с чем его едят.
Понятно, что "вкратце" требует, чтоб рассказ шел системно, с общих позиций. Вот тут-то при попытке составить это системное видение и возникают проблемы. Первая из них — определение типов и переменных данных типов, что собственно и явлилось темой эхи. Как я понял из наших разговоров, заковырки здесь появляются из-за того, что в каждом языке есть понятие первоклассных и нет объектов, и наличие вторых мешает строить общие правила. Вроде, понятно... Второй вопрос, который возникает — это как, с учетом наличия непервоклассных объектов, объяснить правила, по которым могут выводиться типы. В Стандарте к языку есть нечто подобное, но слишком все-таки расплывчатое с кучей комметов и примеров... Я хотел выяснить у Вас, какими по возможности формальными правилами Вы пользуетесь.
Re[12]: есть ли логика в системе типов С
От: Посторонним В. Беларусь  
Дата: 15.10.07 15:35
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Непервоклассные объекты невозможно создавать в рантайме, но они могут создаваться во время компиляции.

К>А функцию — вообще не можешь создать (впрочем, с использованием хаков — генерируя машинный код — пожалуйста).
А как же boost::lambda?
Re[13]: есть ли логика в системе типов С
От: Кодт Россия  
Дата: 15.10.07 16:14
Оценка:
Здравствуйте, Посторонним В., Вы писали:

К>>Непервоклассные объекты невозможно создавать в рантайме, но они могут создаваться во время компиляции.

К>>А функцию — вообще не можешь создать (впрочем, с использованием хаков — генерируя машинный код — пожалуйста).
ПВ>А как же boost::lambda?

А какой тип получается у этой самой буст-лямбды?
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[14]: есть ли логика в системе типов С
От: Посторонним В. Беларусь  
Дата: 15.10.07 17:12
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, Посторонним В., Вы писали:


К>>>Непервоклассные объекты невозможно создавать в рантайме, но они могут создаваться во время компиляции.

К>>>А функцию — вообще не можешь создать (впрочем, с использованием хаков — генерируя машинный код — пожалуйста).
ПВ>>А как же boost::lambda?

К>А какой тип получается у этой самой буст-лямбды?


Я не имел ввиду что boost::lambda создает какой-либо объект, тем более объект первого класса.
Я имел ввиду что boost::lambda позволяет создавать что-то похожее на функцию в runtime.
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...
Пока на собственное сообщение не было ответов, его можно удалить.