Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Компилятор генерирует ошибочный код при совпадении имени функции и идентификатора #13

Closed
Mazdaywik opened this issue Jan 16, 2016 · 3 comments
Assignees
Milestone

Comments

@Mazdaywik
Copy link
Member

Если в одной единице трансляции объявить/определить функцию и где-нибудь использовать идентификатор с одним и тем же именем, компиляция в C++ пройдёт успешно, но сгенерированный файл будет приводить к ошибкам компиляции. Например, для следующего файла получим такие ошибки компиляции (компилятор g++):

$ENTRY Go { = #Go; }
labels.cpp:9:8: error: 'template<class SREFAL_PARAM_INT> struct Go' redeclared as different kind of symbol
 struct Go {
        ^
labels.cpp:5:27: error: previous declaration of 'refalrts::FnResult Go(refalrts::Iter, refalrts::Iter)'
 extern refalrts::FnResult Go(refalrts::Iter arg_begin, refalrts::Iter arg_end);
                           ^
labels.cpp: In function 'refalrts::FnResult Go(refalrts::Iter, refalrts::Iter)':
labels.cpp:57:43: error: expected primary-expression before 'int'
     if( ! refalrts::alloc_ident( n0, & Go<int>::name ) )

Пути исправления:

  1. Декорировать объекты идентификаторов и/или имена функций.
  2. Запретить совпадения имён функций и идентификаторов на уровне языка.
@Mazdaywik Mazdaywik self-assigned this Jan 16, 2016
@Mazdaywik Mazdaywik added this to the feburary 2016 milestone Jan 16, 2016
@Mazdaywik
Copy link
Member Author

Более предпочтителен первый путь.

Допустим, выбран второй путь. Пишется программа, компилируется, выскакивает сообщение об ошибке:

FooBar.sref:42:Identifier Baz: function with same name already defined.

WTF? Если функция локальная или идентификатор используется только в текущей единице трансляции, то можно переименовать. Если только функция локальная, то можно переименовать идентификатор. Если идентификатор используется только здесь, то можно переименовать его. А если и то, и другое является частью интерфейса с другими компонентами?

Вариант обхода — использовать венгерскую нотацию, например, начинать все идентификаторы с префикса C…, например, # CExistVariable, # CNone (а такие примеры есть в коде — я подозревал, что может быть проблема, но не проверял явно, есть ли она). Но правильная венгерская нотация, должна быть (так же, как как и имена переменных/функций/типов и комментарии) на уровень выше, чем синтаксис языка, а не повторять синтаксические конструкции (как неправильная венгерская нотация) и не служить костылями для языка программирования. Так что это костыль.

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

Рассмотрим подробнее первый путь: декорирование имён функций и/или имён идентификаторов (для каждого используемого идентификатора в единице трансляции генерируется довольно хитрая конструкция, представляющая собой шаблонную структуру, именно между ней и одноимённой функцией происходит конфликт). Можно декорировать функции, объекты идентификаторов и то и другое.

Во-первых, согласно описанию языка, имена функций и идентификаторов должны начинаться с большой латинской буквы, могут затем содержать любые латинские буквы (в любом регистре), цифры и знаки - и _, причём последние два эквивалентны и отображаются в знак _ в идентификаторах в целевом коде. Следовательно, чтобы не возникло конфликтов между именами C++ при любых именах функций и идентификаторов, описанных пользователем, необходимо использовать префиксы, причём префиксы должны начинаться с маленькой буквы. (Допустим, используется суффикс _ident для идентификаторов. Тогда, введя в программу идентификатор Foo и функцию Foo-ident, пользователь заставит компилятор сгенерировать невалидный код.)

Во-вторых, лучше декорировать идентификаторы. Первый аргумент (слабый). В документации описана компиляция функций в целевой код — указано, что любое имя функции на Рефале отображается в такое же имя функции на C++ (есть небольшая недоработка: не указано, что знак - отображается в знак _, но, с другой стороны, глава про интерфейс с C++ ещё не написана), а про идентификаторы ничего не сказано. Второй аргумент (чуть более сильный): программист, при написании внешних функций на C++, чаще пишет функции, чем идентификаторы (а с учётом выполнения задачи #11, идентификаторы объявлять даже не надо будет), поэтому, ради упрощения, лучше декорировать идентификаторы.

Подытоживая. Для исправления настоящей ошибки используется подход с декорированием, идентификаторы получают префикс ident_.

@Mazdaywik
Copy link
Member Author

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

@Mazdaywik
Copy link
Member Author

Появление второго коммита выше связано с перезаписью коммита (ошибка в сообщении коммита).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant