Особенности реализации функций ввода-вывода

В приведенном языке для ввода и вывода данных определены две «встроенные» функции print и input, реализация которых не может быть переопределена пользователем. Тем не менее на самом деле обе они не имеют под собой реализации на этом языке, и в местах их вызова происходит обращение к стандартной библиотеке языка Си.

Более того, в силу специфики использования функции print и input можно считать в большей степени языковыми конструкциями, нежели функциями. Функция print может принимать одно выражение любого из поддерживаемых типов в качестве аргумента (в языке C++, например, такое поведение функций называется перегрузкой), что для пользовательских функций запрещено. Функция input ведет себя еще более нестандартно: она может находиться только в операциях присваивания и только в качестве правого операнда, при этом не принимает аргументов, но тип возвращаемого значения при ее вызове определяется типом переменной в роли левого операнда того же выражения (фигурально такое поведение можно назвать «перегрузкой по типу возвращаемого значения», по аналогии с обычными перегрузками из C++).

Рассмотрим теперь, каким образом вызовы этих функций компилируются во время генерации кода LLVM IR.

В месте вызова функции print происходит вставка инструкции LLVM IR, декларирующей вызов функции printf. Как известно, эта функция принимает форматирующую строку и список выражений, тип которых должен совпадать с типами, соответствующим шаблонным последовательностям в форматирующей строке. Таким образом, при генерации кода инструкция вызова printf содержит два передаваемых аргумента:

  • форматирующую строку, состоящую из одной шаблонной последовательности (типу int соответствует %d, типу float соответствует %lf, типу str соответствует %s, остальные типы содержат фиксированное множество значений и свою строку для каждого из значений: True, False, None);

  • значение выражения определенного типа, которое должно быть выведено в стандартный поток вывода (stdout).

В месте вызова функции input происходит аналогичная вставка вызова функции scanf. Принцип использования этой функции отличается тем, что вместо значения выражения должен передаваться адрес переменной, в которую будет записано значение, полученное из стандартного потока ввода (stdin).

Назад