Поможем написать учебную работу
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.
Понятие о языках программирования
Языки программирования это формальные языки, специально созданные для общения человека с компьютером. Каждый язык программирования, равно как и «естественный» язык (русский, английский и т.д.), имеет алфавит, словарный запас свои грамматику и синтаксис, а также семантику.
Алфавит фиксированный для данного языка набор основных символов, допускаемых для составления текста программы на этом языке.
Синтаксис система правил, определяющих допустимые конструкции языка программирования из букв алфавита.
Семантика система правил однозначного толкования отдельных языковых конструкций, позволяющих воспроизвести процесс обработки данных.
Взаимодействие синтаксических и семантических правил определяют те или иные понятия языка, например, операторы, идентификаторы, переменные, функции и процедуры, модули и т.д. В отличие от естественных языков правила грамматики и семантики для языков программирования', как и для всех формальных языков, должны быть явно, однозначно и четко сформулированы.
Синтаксис описывает структуру программ как наборов символов (обычно говорят безотносительно к содержанию).
Пример синтаксической ошибки : употребление оператора цикла For без To или Next, или отсутствие знака равенства в приведенной на рисунке программе.
Синтаксические ошибки распознаются встроенным синтаксическим анализатором.
Синтаксису языка противопоставляется его семантика. Синтаксис языка описывает «чистый» язык, в то же время семантика приписывает значения (действия) различным синтаксическим конструкциям.
Семантика определяет смысловое значение предложений алгоритмического языка.
Пример семантической ошибки :
1) For i As Integer = 1 To 10 Step -2
2) Если надо вычислить , то запись x = a / b * c содержит семантическую ошибку, т.к. приоритет операций деления и умножения одинаков, то вначале а делиться на b , а затем полученный результат умножает на с .
Поиск этих ошибок происходит с помощью логического анализа работы программы и ее тестирования.
Классы языков программирования
1.
Императивные языки программирования Бейсик, Паскаль, Си и прочие (включая объектно-ориентированные). Характеризуются последовательным, пошаговым изменением состояния вычислителя. При этом управление изменениями полностью определено и полностью контролируемо.
Одна из характерных черт императивного программирования наличие переменных с операцией "разрушающего присвоения". То есть, была переменная А, было у нее значение Х. Алгоритм предписывает на очередном шаге присвоить переменной А значение Y. То значение, которое было у А, будет "навсегда забыто".
Если задача описывается последовательным исполнением операций ("открыть кран, набрать воды"), то такие задачи идеальные кандидаты на императивную реализацию.
Декларативные языки программирования:
Функциональные языки программирования LISP , ISWIM ( If you See What I Mean ), ML ( Meta Language ), Miranda
В языках функционального программирования основными конструктивными элементами являются функции. Тексты программ на функциональных языках программирования описывают «как решить задачу», но не предписывают последовательность действий для решения.
Способ решения задачи описывается при помощи зависимости функций друг от друга без указания последовательности шагов.
Функциональное программирование, как и другие модели "неимперативного" программирования, обычно применяется для решения задач, которые трудно сформулировать в терминах последовательных операций. Это, например, задачи распознавания образов, общение с пользователем на естественном языке, реализация экспертных систем, автоматизированное доказательство теорем, символьные вычисления. Логические языки программирования Prolog.
В логическом программировании программа представляет из себя некоторую теорию (описанную на достаточно ограниченном языке), и утверждение, которое нужно доказать. В доказательстве этого утверждения и будет заключаться исполнение программы.
Логическое программирование оказывается удобным для реализации сложных задач; например, диспетчерская система лондонского аэропорта Хитроу в настоящий момент переписывается на Прологе.
2.
Процедурные языки программирования используют процедуры (подпрограммы, методы или функции). Процедуры содержат последовательность шагов для выполнения. В ходе выполнения программы любая процедура может быть вызвана из любой точки. При процедурном программировании программа разбивается на части в соответствии с алгоритмом: каждая часть ( подпрограмма, функция , процедура ) является составной частью алгоритма. Языки: Ада, Бейсик, Си, C++, С# (из Microsoft) КОБОЛ, Паскаль, Delphi, Фортран, Java, Перл, Visual Basic, PHP
Объектно-ориентированные подход к программированию - это подход к разработке программного обеспечения, основанный на объектах, а не на процедурах. При объектно-ориентированном программировании программа строится как совокупность взаимодействующих объектов. Языки: Java, Си, Visual Basic
Объект это базовое понятие ООП. Любой объект принадлежит одному или нескольким классам, которые в свою очередь определяют, описывают поведение объекта.
Примеры классов: "Птицы", "Автомобили". Примеры объектов: "птица грач", "автомобиль Audi".
Каждый объект характеризуется свойствами, методами и событиями.
Свойства описание объекта. Примеры атрибутов: "имя", "рост". Набор конкретных значений определяет текущее состояние объекта.
Метод это действие объекта, изменяющее его состояние или реализующее другое его поведение. Пример методов: "назвать свое имя", "стать невидимым".
К концепции ООП относится:
Полиморфизм это взаимозаменяемость объектов с одинаковым интерфейсом. Кратко смысл полиморфизма можно выразить фразой: «Один интерфейс, множество методов». В зависимости от типа объекта одно и то же сообщение может соответствовать различным действиям методам для достижения требуемого результата.
Наследование - возможность порождать один класс от другого с сохранением всех свойств и методов класса-предка (иногда его называют суперклассом) и добавляя, при необходимости, новые свойства и методы. Наследование призвано отобразить такое свойство реального мира, как иерархичность.
Инкапсуляция это принцип, согласно которому любой класс должен рассматриваться как чёрный ящик пользователь класса должен видеть и использовать только интерфейс (от английского interface внешнее лицо, т. е. список декларируемых свойств и методов) класса и не вникать в его внутреннюю реализацию. Этот принцип позволяет минимизировать число связей между классами и, соответственно, упростить независимую реализацию и модификацию классов. Смысл инкапсуляции состоит в том, что внешний пользователь не знает детали реализации объекта, работая с ним путём предоставленного объектом интерфейса.
3.
Неструктурное программирование допускает использование в явном виде команды безусловного перехода (в большинстве языков GOTO). Типичные представители -- ранние версии Бейсика и Фортрана. Однако в языках высокого уровня наличие команды перехода приводит к бесконечным переходам вверх-вниз, и программу трудно сопровождать и модифицировать.
В структурном программировании задача разбивается на большое число мелких подзадач, каждая из которых решается своей процедурой или функцией (декомпозиция задачи). При этом проектирование программы идет по принципу сверху вниз: сначала определяются необходимые для решения программы модули, их входы и выходы, а затем уже эти модули разрабатываются. Такой подход вместе с локальными именами переменных позволяет разрабатывать проект силами большого числа программистов.
Классификация языков программирования
Языки программирования искусственные языки. Они отличаются от естественных человеческих языков малым количеством слов, значение которых понятно транслятору (эти слова называются ключевыми), и довольно жесткими требованиями по форме записи операторов (совокупность этих требований образует грамматику и синтаксис языка программирования). Нарушения формы записи приводят тому, что транслятор не может правильно выполнить перевод и выдает сообщение об ошибке.
Существует два уровня языков программирования:
Язык программирования низкого уровня это язык программирования, созданный для использования со специальным типом процессора и учитывающий его особенности. Он близок к машинному коду и позволяет непосредственно реализовать некоторые команды процессора. Они мало похожи на привычный человеку язык. Большие программы на таких языках пишутся редко. Но программы работают быстро, занимая маленький объем и допуская минимальное количество ошибок. Чем ниже и ближе к машинному уровень языка, тем меньше и конкретнее задачи, которые ставятся перед каждой командой.
Для каждого типа процессоров самым низким уровнем является язык ассемблера, который позволяет представить машинный код не в виде чисел, а в виде условных обозначений, называемых мнемониками. У каждого типа процессора свой язык ассемблера; его можно рассматривать одновременно и как особую форму записи машинных команд, и как язык программирования самого низкого уровня.
Достоинством языков низкого уровня является то, что с их помощью создают самые эффективные программы (краткие и быстрые). Недостаток таких языков в том, что их трудно изучать из-за необходимости понимать устройство процессора и в том, что программа, созданная на таком язык, неприменима для процессоров других типов.
Языки программирования высокого уровня заметно проще в изучении и применении. Программы, написанные с их помощью, можно использовать на любой компьютерной платформе при условии, что для нее существует транслятор данного языка. Эти языки вообще никак не учитывают свойства конкретного процессора и не предоставляют прямых средств для обращения к нему. В некоторых случаях это ограничивает возможности программистов, но зато и оставляет меньше возможностей для совершения ошибок.
Языки высокого уровня в большей степени ориентированы на человека; команды этих языков понятные человеку английские слова.
Достоинства языков программирования высокого уровня:
Каждый язык используется для решения определённого типа задач:
Транслятор, компилятор, интерпретатор
Транслятор (англ. translator переводчик) это программа-переводчик. Она преобразует программу, написанную на одном из языков высокого уровня, в программу, состоящую из машинных команд. Транслятор обычно выполняет также диагностику ошибок, формирует словари идентификаторов, выдаёт для печати тексты программы и т. д. Язык, на котором представлена входная программа, называется исходным языком, а сама программа исходным кодом. Выходной язык называется целевым языком или объектным кодом.
В общем случае понятие трансляции относится не только к языкам программирования, но и к другим языкам как формальным компьютерным (вроде языков разметки типа HTML), так и естественным (русскому, английскому и т. п.).
Виды трансляторов
Трансляторы реализуются в виде компиляторов или интерпретаторов. С точки зрения выполнения работы компилятор и интерпретатор существенно различаются.
Компилятор (англ. compiler составитель, собиратель) читает всю программу целиком, делает ее перевод и создает законченный вариант программы на машинном языке, который затем и выполняется. Входной информацией для компилятора (исходный код) является описание алгоритма или программа на проблемно-ориентированном языке, а на выходе компилятора эквивалентное описание алгоритма на машинно-ориентированном языке (объектный код).
Виды компиляторов
Виды компиляции
Структура компилятора
Генерация кода
Большинство компиляторов переводит программу с некоторого высокоуровневого языка программирования в машинный код, который может быть непосредственно выполнен процессором. Как правило, этот код также ориентирован на исполнение в среде конкретной операционной системы, поскольку использует предоставляемые ею возможности (системные вызовы, библиотеки функций). Архитектура (набор программно-аппаратных средств), для которой производится компиляция, называется целевой машиной.
Результат компиляции исполнимый модуль обладает максимальной возможной производительностью, однако привязан к определённой операционной системе и процессору (и не будет работать на других).
Для каждой целевой машины (IBM, Apple, Sun и т. д.) и каждой операционной системы или семейства операционных систем, работающих на целевой машине, требуется написание своего компилятора. Существуют также так называемые кросс-компиляторы, позволяющие на одной машине и в среде одной ОС генерировать код, предназначенный для выполнения на другой целевой машине и/или в среде другой ОС. Кроме того, компиляторы могут оптимизировать код под разные модели из одного семейства процессоров (путём поддержки специфичных для этих моделей особенностей или расширений наборов инструкций). Некоторые компиляторы переводят программу с языка высокого уровня не прямо в машинный код, а на язык ассемблера. Это делается для упрощения части компилятора, отвечающей за кодогенерацию, и повышения его переносимости (задача окончательной генерации кода и привязки его к требуемой целевой платформе перекладывается на ассемблер), либо для возможности контроля и исправления результата компиляции программистом.
Результатом работы компилятора может быть программа на специально созданном низкоуровневом языке, подлежащем интерпретации виртуальной машиной. Такой язык называется псевдокодом или байт-кодом. Как правило, он не является машинным кодом какого-либо компьютера, и программы на нём могут исполняться на различных архитектурах, где имеется соответствующая виртуальная машина, но в некоторых случаях создаются аппаратные платформы, напрямую поддерживающие псевдокод какого-либо языка. Некоторые реализации интерпретируемых языков высокого уровня (например, Perl) используют байт-код для оптимизации исполнения: затратные этапы синтаксического анализа и преобразование текста программы в байт-код выполняются один раз при загрузке, затем соответствующий код может многократно использоваться без промежуточных этапов.
Динамическая компиляция
Из-за необходимости интерпретации байт-код выполняется значительно медленнее машинного кода сравнимой функциональности, однако он более переносим (не зависит от операционной системы и модели процессора). Чтобы ускорить выполнение байт-кода, используется динамическая компиляция, когда виртуальная машина транслирует псевдокод в машинный код непосредственно перед его первым исполнением (и в при повторных обращениях к коду исполняется уже скомпилированный вариант).
Декомпиляция
Существуют программы, которые решают обратную задачу перевод программы с низкоуровневого языка на высокоуровневый. Этот процесс называют декомпиляцией, а такие программы декомпиляторами. Но поскольку компиляция это процесс с потерями, точно восстановить исходный код, скажем, на C++, в общем случае невозможно. Более эффективно декомпилируются программы в байт-кодах например, существует довольно надёжный декомпилятор для Flash. Разновидностью декомпилирования является дизассемблирование машинного кода в код на языке ассемблера, который почти всегда выполняется успешно (при этом сложность может представлять самомодифицирующийся код или код, в котором собственно код и данные не разделены). Связано это с тем, что между кодами машинных команд и командами ассемблера имеется практически взаимно-однозначное соответствие.
Раздельная компиляция
Раздельная компиляция трансляция частей программы по отдельности с последующим объединением их компоновщиком в единый загрузочный модуль. При трансляции каждой части программы компилятор порождает объектный модуль, содержащий дополнительную информацию, которая потом, при компоновке частей в исполнимый модуль, используется для связывания и разрешения ссылок между частями.
Интерпретатор (англ. interpreter истолкователь, устный переводчик) переводит и выполняет программу строка за строкой, производит пооператорный (покомандный, построчный) анализ, обрабатывает и тут же выполняет исходную программу или запроса (в отличие от компиляции, при которой программа транслируется без её выполнения.
После того, как программа откомпилирована, ни сама исходная программа, ни компилятор более не нужны. В то же время программа, обрабатываемая интерпретатором, должна заново переводиться на машинный язык при каждом очередном запуске программы.
Откомпилированные программы работают быстрее, но интерпретируемые проще исправлять и изменять.
Типы интерпретаторов
В случае разделения интерпретатора компилирующего типа на компоненты получаются компилятор языка и простой интерпретатор с минимизированным анализом исходного кода. Причём исходный код для такого интерпретатора не обязательно должен иметь текстовый формат или быть байт-кодом, который понимает только данный интерпретатор, это может быть машинный код какой-то существующей аппаратной платформы.
Некоторые интерпретаторы (например, для языков Лисп, Scheme, Python, Бейсик и других) могут работать в режиме диалога или так называемого цикла чтения-вычисления-печати. В таком режиме интерпретатор считывает законченную конструкцию языка, выполняет её, печатает результаты, после чего переходит к ожиданию ввода пользователем следующей конструкции.
Уникальным является язык Forth, который способен работать как в режиме интерпретации, так и компиляции входных данных, позволяя переключаться между этими режимами в произвольный момент, как во время трансляции исходного кода, так и во время работы программ.
Следует также отметить, что режимы интерпретации можно найти не только в программном, но и аппаратном обеспечении. Так, многие микропроцессоры интерпретируют машинный код с помощью встроенных микропрограмм, а процессоры семейства x86, начиная с Pentium, во время исполнения машинного кода предварительно транслируют его во внутренний формат (в последовательность микроопераций).
Алгоритм работы простого интерпретатора
Достоинства и недостатки интерпретаторов
Достоинства
Недостатки
Каждый конкретный язык ориентирован либо на компиляцию, либо на интерпретацию в зависимости от того, для каких целей он создавался. Например, Паскаль обычно используется для решения довольно сложных задач, в которых важна скорость работы программ. Поэтому данный язык обычно реализуется с помощью компилятора.
С другой стороны, Бейсик создавался как язык для начинающих программистов, для которых построчное выполнение программы имеет неоспоримые преимущества.
Иногда для одного языка имеется и компилятор, и интерпретатор. В этом случае для разработки и тестирования программы можно воспользоваться интерпретатором, а затем откомпилировать отлаженную программу, чтобы повысить скорость ее выполнения.
Преимуществом компиляторов по сравнению с интерпретаторами является быстродействие, а недостатком громоздкость.
В некоторых языках, вместо машинного кода генерируется интерпретируемый двоичный код " виртуальной машины ", также называемый байт-кодом. Такой подход применяется в Forth, Lisp, Java , Perl, Python, а также в языках платформы Microsoft .NET.
Программы на Java выполняются в два этапа. Сначала исходный текст компилятором переводится на промежуточный аппаратно-независимый язык. В таком виде байт-код хранится на интернет-сервере, откуда по запросу клиента пересылается ему по сети. У клиента байт-код исполняется специальным интерпретатором, этот интерпретатор называется виртуальной Java-машиной, он встроен во все современные браузеры.