Языки программирования интерпретация. Большая энциклопедия нефти и газа. Комбинирование компиляции и интерпретации

Существует несколько подходов к определению семантики языков программирования.

Наиболее широко распространены разновидности следующих трёх: операционного, денотационного (математического) и деривационного (аксиоматического).

При описании семантики в рамках операционного подхода обычно исполнение конструкций языка программирования интерпретируется с помощью некоторой воображаемой (абстрактной) ЭВМ.

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

Язык программирования строится в соответствии с той или иной базовой моделью вычислений и парадигмой программирования.

Несмотря на то, что большинство языков ориентировано на императивную модель вычислений, задаваемую фоннеймановской архитектурой ЭВМ, существуют и другие подходы. Можно упомянуть языки со стековой вычислительной моделью (Forth, Factor, Postscript и др.), а также функциональное (Лисп, Haskell, ML и др.) и логическое программирование (Пролог) и язык Рефал, основанный на модели вычислений, введённой советским математиком А.А. Марковым-младшим.

В настоящее время также активно развиваются проблемно-ориентированные, декларативные и визуальные языки программирования.

Компилируемые и интерпретируемые языки

Языки программирования могут быть разделены на компилируемые и интерпретируемые.

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

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

Кратко говоря, компилятор переводит исходный текст программы на машинный язык сразу и целиком, создавая при этом отдельную исполняемую программу, а интерпретатор выполняет исходный текст прямо во время исполнения программы.

Разделение на компилируемые и интерпретируемые языки является несколько условным. Так, для любого традиционно компилируемого языка, как, например, Паскаль, можно написать интерпретатор. Кроме того, большинство современных «чистых» интерпретаторов не исполняют конструкции языка непосредственно, а компилируют их в некоторое высокоуровневое промежуточное представление (например, с разыменованием переменных и раскрытием макросов).

Для любого интерпретируемого языка можно создать компилятор -- например, язык Лисп, изначально интерпретируемый, может компилироваться без каких бы то ни было ограничений. Создаваемый во время исполнения программы код может так же динамически компилироваться во время исполнения.

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

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

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

Некоторые языки, например, Java и C#, находятся между компилируемыми и интерпретируемыми. А именно, программа компилируется не в машинный язык, а в машинно-независимый код низкого уровня, байт-код. Далее байт-код выполняется виртуальной машиной. Для выполнения байт-кода обычно используется интерпретация, хотя отдельные его части для ускорения работы программы могут быть транслированы в машинный код непосредственно во время выполнения программы по технологии компиляции «на лету» (Just-in-time compilation, JIT). Для Java байт-код исполняется виртуальной машиной Java (Java Virtual Machine, JVM), для C# -- Common Language Runtime.

Подобный подход в некотором смысле позволяет использовать плюсы как интерпретаторов, так и компиляторов. Следует упомянуть также оригинальный язык Форт(Forth) имеющий и интерпретатор и компилятор.

Современные языки программирования рассчитаны на использование ASCII, то есть доступность всех графических символов ASCII является необходимым и достаточным условием для записи любых конструкций языка. Управляющие символы ASCII используются ограниченно: допускаются только возврат каретки CR, перевод строки LF и горизонтальная табуляция HT (иногда также вертикальная табуляция VT и переход к следующей странице FF).

Подробнее по этой теме см.: Переносимый набор символов.

Ранние языки, возникшие в эпоху 6-битных символов, использовали более ограниченный набор. Например, алфавит Фортрана включает 49 символов (включая пробел): A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 = + - * / () . , $ " :

Заметным исключением является язык APL, в котором используется очень много специальных символов.

Использование символов за пределами ASCII (например, символов KOI8-R или символов Юникода) зависит от реализации: иногда они разрешаются только в комментариях и символьных/строковых константах, а иногда и в идентификаторах. В СССР существовали языки, где все ключевые слова писались русскими буквами, но большую популярность подобные языки не завоевали (исключение составляет. Встроенный язык программирования 1С: Предприятие).

Подробнее по этой теме см.: Русские языки программирования.

Расширение набора используемых символов сдерживается тем, что многие проекты по разработке программного обеспечения являются международными. Очень сложно было бы работать с кодом, где имена одних переменных записаны русскими буквами, других -- арабскими, а третьих -- китайскими иероглифами. Вместе с тем, для работы с текстовыми данными языки программирования нового поколения (Delphi 2006, C#, Java) поддерживают Unicode.

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

Целью компиляции является реализация возможности выполнения реальным компьютером кода, написанного для абстрактной машины. Компиляция , однако, – лишь одна из двух базисных технологий, применяемых для достижения нашей цели.

Базисные схемы

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


Рис. 3.6.

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

Интерпретатор должен быть способен определить эффект выполнения каждой конструкции языка программирования. Как пример того, как интерпретатор выполняет свою задачу, рассмотрим интерпретацию присваивания x: = x +1 . Интерпретатор должен хранить таблицу всех используемых переменных и связанных с ними значений. Он вычисляет новое значение x , добавляя 1 к старому значению, хранящемуся в таблице, а затем выполняет присваивание, заменяя старое значение x значением вычисленного выражения.

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

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

Если рассматривать язык программирования как машинный код для абстрактной машины, можно сказать, что интерпретатор – это программа, моделирующая вычисление на этой машине. Машинная память в этом случае также абстрактна и представляет структуры данных в виде таблиц интерпретатора "переменные – значения".

На следующем рисунке процессы компиляции и интерпретации дополнены вводом данных:


Рис. 3.7.

Рисунок демонстрирует еще одну разницу между компилятором и интерпретатором. У интерпретатора два источника ввода – исходная программа и входные данные; а компилятору подается только программа. В последующем обсуждении этому различию придадим математическую форму.

Компилировать или интерпретировать? Эта проблема – предмет широко рассмотрения в компьютерных науках. Что лучше: непосредственно обрабатывать исходную информацию в том виде, как она есть, или предварительно привести ее к более удобной форме? Этот вопрос стоит не только при обработке программ, мы будем сталкиваться с ним и при изучении алгоритмов.

У компиляторов и интерпретаторов имеются свои достоинства. Возможны различные критерии. По производительности – времени выполнения программы – компиляторы побеждают.

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

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

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

Еще один критерий, согласно которому предпочтение опять-таки отдается компиляции, состоит в надежности программы. Компиляторы не просто транслируют программу – в процессе компиляции они осуществляют различные проверки, например, контроль типов для статически типизированных языков . Тем самым многие ошибки устраняются еще на этапе компиляции, в то время как для режима интерпретации ошибки обнаруживаются в процессе выполнения на одном из сеансов работы.

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

Комбинирование компиляции и интерпретации

Схемы чистой компиляции и чистой интерпретации являются предельными вариантами: большинство практических решений является смесью. Это верно и для процесса компиляции в EiffelStudio, который будет рассмотрен позже в этой лекции.

Заметим, что 100% схема интерпретации имеет мало смысла: каждый раз, когда интерпретатор выполнял очередной оператор, например, оператор цикла, он должен был бы возвращаться многократно к фактической последовательности символов и осуществлять ее разбор. Любое реалистическое решение не могло бы согласиться с такой неразумной тратой ресурсов. Так что фактически интерпретатор также начинает с преобразования входа в форму, приемлемую для интерпретации, например, строя абстрактное синтаксическое дерево. В ходе этого процесса, как отмечалось, возможен контроль проверки типов. Так что даже тогда, когда можно прочесть, что используется интерпретатор языка, частичная компиляция подразумевается.

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


Рис. 3.8.

Смешанная стратегия предполагает, что компилятор создает код на промежуточном языке , понимаемом некоторой виртуальной машиной – VM на рисунке. Такой подход объединяет преимущества компиляции и интерпретации. Благодаря тщательно спроектированной виртуальной машине возможно получить:

  • переносимость, так как VM-код не зависит от специфики физических процессоров;
  • повышение эффективности, поскольку создаваемый промежуточный код легко интерпретируется.

Виртуальные машины, байт-код и JIT (Just In Time) компиляторы

Реализация современных языков – Java, C#, других языков.Net – основана на смешанном решении. Промежуточный код для Java называется байт-кодом. В термине отражается тот факт, что виртуальная машина использует компактные команды, подобные командам фактического процессора, где каждая команда содержит код команды – типично задаваемый одним байтом, – после которого следует 0, 1 или 2 аргумента команды.

Альтернативой байт-коду могла бы выступать виртуальная машина, непосредственно работающая со структурами данных, например, с абстрактным синтаксическим деревом для представления структуры программы и с хэш-таблицами для хранения свойств переменных. Но байт-код обеспечивает лучшую эффективность периода выполнения, как по времени, так и по памяти.

Прием двухэтапной компиляции был использован еще в семидесятые годы при реализации компилятора с языка Паскаль. Он получил второе рождение с распространением Интернета, так как хорошо был приспособлен для локального выполнения Web-клиентами. Поставщики апплетов – небольших программ – могли компилировать их в байт-код и поставлять их в такой форме. Дополнительным преимуществом к компактности стала переносимость кода, поскольку в противном случае машинный код пришлось бы создавать для каждой возможной целевой платформы .

Для выполнения апплета пользователям необходим только интерпретатор байт-кода. Они даже не должны знать, что такой интерпретатор существует, если он встроен в их Web-браузер, Поскольку при таком подходе возникают потенциальные риски, связанные с безопасностью, – жульнические или некорректные апплеты могут повредить ваш компьютер, – по этой причине для апплетов необходим интепретатор, который будет строго контролировать операции, разрешенные для апплетов.

Поставка программ через апплеты достигла некоторого успеха, но не стала основным способом распределенного ПО, как ожидалось в момент появления Java. Частично это связано с проблемами безопасности, но главная причина – в потере эффективности, возникающей по причине интерпретации. Большинство успешных апплетов являются небольшими программами, предназначенными для выполнения на Web-странице, включающие визуальную компоненту, при наличии которой потери времени представляются несущественными.

Для улучшения эффективности времени выполнения байт-кода применяются JIT (Just In Time) компиляторы, называемые джитерами, – осуществляющие компиляцию по требованию. Основная идея состоит в том, что машинный код для некоторого модуля создается "на лету", в тот момент, когда он первый раз вызывается на выполнение (не следует путать любителя джаза –jitterbug, с ошибками такого компилятора – jitter bug ). Внесем соответствующие дополнения в предыдущий рисунок, который теперь выглядит так:


Рис. 3.9.

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

С первого взгляда кажется, что при таком подходе не стоит выполнять проверки типов и другой контроль, поскольку кому же хочется во время выполнения получать сообщения о нарушении согласованности типов ? Это возвращало бы нас к проблемам динамически типизированных языков . Конечно, нам хотелось бы, чтобы все необходимые проверки выполнялись на первом шаге компиляции при создании байт-кода, так, чтобы любой код, передаваемый джитеру, был безопасным. К сожалению, эти утешительные предположения нереалистичны в распределенной среде, где опять возникают проблемы безопасности. Если вы загружаете байт-код из сайта, то можете ли вы знать, прошел ли он проверку? В общем случае – нет. Но тогда нарушения типа могут стать не только причиной нарушения надежности и аварийного завершения программы, все может быть гораздо хуже: в результате атаки становится возможным нарушение безопасности.

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

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

Стратегия компиляции в EiffelStudio также включает байт-код, но, как мы увидим, она использует различные способы комбинирования интерпретации и компиляции.

Этого цикла, я хочу обратить ваше внимание на ключевые принципы программирования, которые влияют на всё то, что мы делаем, но с которыми мы редко сталкиваемся напрямую и поэтому не до конца их понимаем. Тема сегодняшней статьи - компилируемые и интерпретируемые языки.

Будучи разработчиками, мы часто сталкиваемся с такими понятиями, как компилятор и интерпретатор, но я считаю, что многие не совсем понимают, что они означают. Между тем, компиляция и интерпретация - это основы работы всех языков программирования. Давайте взглянем на то, как на самом деле устроены эти понятия.

Вступление

Мы полагаемся на такие инструменты, как компиляция и интерпретация, чтобы преобразовать наш код в форму, понятную компьютеру. Код может быть исполнен нативно, в операционной системе после конвертации в машинный (путём компиляции) или же исполняться построчно другой программой, которая делает это вместо ОС (интерпретатор).

Компилируемый язык - это такой язык, что программа, будучи скомпилированной, содержит инструкции целевой машины; этот машинный код непонятен людям. Интерпретируемый же язык - это такой, в котором инструкции не исполняются целевой машиной, а считываются и исполняются другой программой (которая обычно написана на языке целевой машины). Как у компиляции, так и у интерпретации есть свои плюсы и минусы, и именно это мы и обсудим.

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

Компилируемые языки

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

Низкоуровневые языки как правило являются компилируемыми, поскольку эффективность обычно ставится выше кроссплатформенности. Кроме того, компилируемые языки дают разработчику гораздо больше возможностей в плане контроля аппаратного обеспечения, например, управления памятью и использованием процессора. Примерами компилируемых языков являются , Erlang, и более современные языки, такие как и .

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

Интерпретируемые языки

В отличие от компилируемых языков, интерпретируемым для исполнения программы не нужен машинный код; вместо этого программу построчно исполнят интерпретаторы. Раньше процесс интерпретации занимал очень много времени, но с приходом таких технологий, как , разрыв между компилируемыми и интерпретируемыми языками сокращается. Примерами интерпретируемых языков являются , и . Вот некоторые из концептов, которые стали проще благодаря интерпретируемым языкам:

  • Независимость от платформы;
  • Меньший размер исполняемых файлов:

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

Бонус: байткод-языки

Байткод-языки - это такие языки, которые используют для исполнения кода как компиляцию, так и интерпретацию. Java и фреймворк.NET - это типичные примеры байткод-языков. На самом деле, Java Virtual Machine (JVM) - это настолько популярная виртуальная машина для интерпретации байткода, что на ней работают реализации нескольких языков . Кстати, недавно , что в новой версии Java будет также поддерживаться и статическая компиляция.

В байткод-языке сперва происходит компиляция программы из человекочитаемого языка в байткод. Байткод - это набор инструкций, созданный для эффективного исполнения интерпретатором и состоящий из компактных числовых кодов, констант и ссылок на память. С этого момента байткод передаётся в виртуальную машину, которая затем интерпретирует код также, как и обычный интерпретатор.

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

Заключение

Многие языки в наши дни имеют как компилируемые, так и интерпретируемые реализации, сводя разницу между ними на нет. У каждого вида исполнения кода есть преимущества и недостатки.

Вкратце, компилируемые языки являются самыми эффективными, поскольку они исполняются как машинный код и позволяют использовать аппаратное обеспечение системы. Однако это вводит дополнительные ограничение на написание кода и делает его платформо-зависимым. Интерпретируемые же языки не зависят от платформы и позволяют использовать такие техники динамического программирования, как метапрограммирование. Тем не менее, в скорости исполнения они значительно уступают компилируемым языкам.

Байткод-языки, в свою очередь, пытаются использовать сильные стороны обоих видов языков, и у них это неплохо получается.

Языки программирования делятся на три типа:

1. Комплируемые языки

Работу компилируемых языков можно представить следующей схемой:

То есть жизненный цикл программы представляет собой следующие этапы:
1. Написание исходного текста программы (source code)
2. Компиляция в исполнимый файл (.exe например)
3. Выполнение программы на ПК

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

Примеры таких языков: assembler, C, C++, Pascal

2. Интерпретируемые языки

Соответственно, жизненный цикл программы сводится к:
1. Написание
2. Выполнение

По сути интерпретируемые программы это так называемые "скрипты" - описание набора действий которые должен выполнить интерпретатор.
То есть, интерпретатор это большая программа со множеством различных функций. А программа это указание какие функции в каком порядке вызвать, описание взаимодействия этих функций

Это специфические языки, например языки для создания веб-страниц.
Примеры: PHP, JavaScript, Python

3. Смешанного типа

Принцип работы языков смешанного типа (компилируемо-интерпретируемые) проиллюстрируем такой схемой:


Java относится именно к компилируемо-интерпретируемым языкам программирования. Интерпретатор в Java называется "виртуальная машина", именно поэтому он так обозначен на рисунке.

Возникает вопрос, зачем такая сложность? Дело в том что такой подход объединяет преимущества компилируемых языков (скорость выполнения) и интерпретируемых (независимость от ОС и безопасность)

Примеры таких языков: Java, C#

Эти три подхода можно проиллюстрировать следующим образом:

1. Компилируемые языки это готовая еда. Хорошо иметь ее под рукой, но она быстро портится.
Программы, написанные на компилируемых языках зависят от ОС и от аппаратного оборудования

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

3. Комбинированные языки можно сравнить с полуфабрикатом. Его быстро готовить, он долго хранится. Но как вы понимаете, вкус будет хуже, чем у свежеприготовленной пищи.
Программы написанные на комбинированных языках программирования, ограничены функциональностью своего интерпретатора. То есть возможностей которые может использовать такая программа всегда будет меньше чем возможностей, которые может использовать программа написанная на компилируемом языке

Лекция 1 – Языки программирования. Visual Basic

{Материал из Википедии - свободной энциклопедии}Язы́к программи́рования - формальнаязнаковая система, предназначенная для описанияалгоритмов в форме, которая удобна для исполнителя (например,компьютера ). Язык программирования определяет наборлексических ,синтаксических исемантических правил, используемых при составлениикомпьютерной программы . Он позволяетпрограммисту точно определить то, на какие события будет реагировать компьютер, как будут храниться и передаватьсяданные , а также какие именно действия следует выполнять над этими данными при различных обстоятельствах. Со времени создания первых программируемых машин человечество придумало уже более двух с половиной тысяч языков программирования (См.Список языков программирования (англ.)). Каждый год их число пополняется новыми. Некоторыми языками умеет пользоваться только небольшое число их собственных разработчиков, другие становятся известны миллионам людей. Профессиональные программисты иногда применяют в своей работе более десятка разнообразных языков программирования.Cоздатели языков по-разному толкуют понятиеязык программирования . Среди общих мест, признаваемых большинством разработчиков, находятся следующие:

    Функция: язык программирования предназначен для написания компьютерных программ, которые применяются для передачи компьютеруинструкций по выполнению того или иноговычислительного процесса и организации управления отдельнымиустройствами .

    Задача: язык программирования отличается отестественных языков тем, что предназначен для передачикоманд и данных от человека компьютеру, в то время, как естественные языки используются для общениялюдей между собой. В принципе, можно обобщить определение "языков программирования" - это способ передачи команд, приказов, четкого руководства к действию; тогда как человеческие языки служат также для обмена информацией.

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

Особенности языков программирования

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

    Типов и структур данных

    Операционную семантику (алгоритм вычисления конструкций языка)

    Семантические конструкции языка

    Библиотеки примитивов (например, инструкции ввода-вывода)

    Философии назначения и возможностей языка

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

Типы данных

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

Особая система, по которой данные организуются в программе, - это система типов языка программирования; разработка и изучение систем типов известна под названиемтеория типов . Языки могут быть классифицированы как системысо статической типизацией и языки сдинамической типизацией . Статически-типизированные языки могут быть в дальнейшем подразделены на языки собязательной декларацией , где каждая переменная и объявление функции имеет обязательное объявление типа, и языки свыводимыми типами . Иногда динамически-типизированные языки называютсялатентно типизированными .

Структуры данных

Системы типов в языках высокого уровня позволяют определять сложные, составные типы, так называемые структуры данных . Как правило, структурные типы данных образуются какдекартово произведение базовых (атомарных) типов и ранее определённых составных типов. Основные структуры данных (списки, очереди, хэш-таблицы, двоичные деревья и пары) часто представлены особыми синтаксическими конструкциями в языках высокого уровня. Такие данные структурируются автоматически.

Компилируемые и интерпретируемые языки

Языки программирования делятся на два класса - компилируемые иинтерпретируемые . Программа на компилируемом языке при помощи специальной программыкомпилятора преобразуется (компилируется ) в набор инструкций для данного типа процессора (машинный код) и далее записывается висполняемый файл , который может быть запущен на выполнение как отдельная программа. Другими словами, компилятор переводит программу с языка высокого уровня на низкоуровневый язык, понятный процессору. Если программа написана на интерпретируемом языке, тоинтерпретатор непосредственно выполняет (интерпретирует ) ее текст без предварительного перевода. При этом программа остается на исходном языке и не может быть запущена без интерпретатора. Можно сказать, что процессор компьютера - это интерпретатор машинного кода. Кратко говоря, компилятор переводит программу на машинный язык сразу и целиком, создавая при этом отдельную программу, а интерпретатор переводит на машинный язык прямо во время исполнения программы. Разделение на компилируемые и интерпретируемые языки является несколько условным. Так, для любого традиционно компилируемого языка, как, например,Паскаль , можно написать интерпретатор. Кроме того, большинство современных «чистых» интерпретаторов не исполняют конструкции языка непосредственно, а компилируют их в некоторое высокоуровневое промежуточное представление (например, с разыменованием переменных и раскрытием макросов). Для любого интерпретируемого языка можно создать компилятор - например, язык Лисп, изначально интерпретируемый, может компилироваться без каких бы то ни было ограничений. Создаваемый во время исполнения программы код может так же динамически компилироваться во время исполнения. Как правило, скомпилированные программы выполняются быстрее и не требуют для выполнения дополнительных программ, так как уже переведены на машинный язык. Вместе с тем при каждом изменении текста программы требуется ее перекомпиляция, что создает трудности при разработке. Кроме того, скомпилированная программа может выполняться только на том же типе компьютеров и, как правило, под той же операционной системой, на которую был рассчитан компилятор. Чтобы создать исполняемый файл для машины другого типа, требуется новая компиляция. Интерпретируемые языки обладают некоторыми специфическими дополнительными возможностями (см. выше), кроме того, программы на них можно запускать сразу же после изменения, что облегчает разработку. Программа на интерпретируемом языке может быть зачастую запущена на разных типах машин и операционных систем без дополнительных усилий. Однако интерпретируемые программы выполняются заметно медленнее, чем компилируемые, кроме того, они не могут выполняться без дополнительной программы-интерпретатора. Некоторые языки, например,Java иC# , находятся между компилируемыми и интерпретируемыми. А именно, программа компилируется не в машинный язык, а в машинно-независимый код низкого уровня,байт-код . Далее байт-код выполняетсявиртуальной машиной . Для выполнения байт-кода обычно используется интерпретация, хотя отдельные его части для ускорения работы программы могут быть транслированы в машинный код непосредственно во время выполнения программы по технологии компиляции «на лету» (Just-in-time compilation,JIT ). Для Java байт-код исполняется виртуальной машиной Java (Java Virtual Machine,JVM ), для C# -Common Language Runtime . Подобный подход в некотором смысле позволяет использовать плюсы как интерпретаторов, так и компиляторов. Следует упомянуть также оригинальный языкФорт(Forth) , который является как бы одновременно интерпретируемым и компилируемым.