Что именно является языком программирования? Что позволяет нам писать на таком языке?

26

Хорошо, я новичок в программировании, и я признаю, что это довольно абстрактный вопрос.

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

Допустим, мистер А. создает новый язык. Как это принимается машинами? Должен ли создатель общаться с машиной, используя машинный язык, чтобы создать новый язык? Какие гарантии того, что мы можем писать на языке при правильном понимании машиной?

Эрика Сюй
источник
1
Что позволяет нам писать на таком языке? - «Мозги: новый чудо-наполнитель головы!» - Спайк Миллиган.
Стивен С.
6
Немного широкий, но, тем не менее, хороший вопрос. Слишком много людей просто используют языки, не задумываясь о том, как они работают. Хорошо, что вам любопытно.
Rwalk
4
Это общий справочный вопрос, на который легко и тривиально отвечает Википедия .
Aaronaught

Ответы:

39

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

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

Если вы ответите на этот вопрос более подробно, вы попадете в теорию компиляции, которая является очень широкой темой. Если вы заинтересованы в этой теме, вы должны начать с чтения статьи Wikipedia для «компилятора» и проверки ссылок на нее, и если у вас есть конкретные вопросы, не стесняйтесь задавать их здесь.

Мейсон Уилер
источник
11
+1 - я бы также добавил, что когда вы пишете новый язык, вы должны написать компилятор или интерпретатор на каком-то другом языке. Более поздние версии компилятора или интерпретатора могут быть написаны на более ранних версиях языка и скомпилированы с более старым компилятором. Самый первый ассемблер был написан на машинном коде. Первый компилятор C был написан на ассемблере (скорее всего) и т. Д.
Скотт Уитлок
1
Я бы изменил определение компилятора. Они не все излучают машинный код. Особенно в наши дни, когда так много компиляторов генерируют «промежуточный код», такой как MSIL. Есть даже компиляторы, которые испускают JavaScript!
Нил Н
3
Я бы не стал утверждать, что компиляторы производят машинный код по определению, даже когда объясняют новичку. Это все равно что сказать, что функции возвращают действительные числа, бессмысленное упрощение. Вся конструкция компилятора справедлива при создании кода, который предназначен не для компьютера, на самом деле построенного из кремния, а только определенного абстрактно (будь то виртуальная машина или язык высокого уровня; есть причина, по которой говорят, что стандарт C определяет абстрактную машину , и там является компилятором от очень низкого уровня LLVM IR до чертова JavaScript). Начинающим нужно это получить, чем раньше, тем лучше.
2
Упрощение, которое использует большинство книг по компилятору, состоит в том, что компилятор применяет языковые правила для преобразования исходного языка в целевой язык в качестве выходных данных. (Например, компилировать в C довольно часто, особенно для вводного курса).
JasonTrue
4
@delnan, даже больше - каждый язык - это машинный код для собственной абстрактной машины. Неважно, насколько высок уровень языка.
SK-logic
11

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

Формальный язык - это язык, придуманный для той или иной цели. Язык программирования, такой как C, например, является формальным языком, изобретенным для целей программирования компьютеров.

Все языки, могут быть описаны с помощью грамматики. Иерархия грамматик была описана Ноамом Хомским в 1956 году. Она состоит из следующих уровней:

Грамматики типа 0 (неограниченные грамматики). Они являются наиболее общими и эквивалентны машине Тьюринга. Таким образом, проблема определения, является ли данная строка частью неограниченной грамматики, неразрешима.

Грамматики типа 1 (контекстно-зависимые грамматики). Почти все естественные языки, такие как английский, являются контекстно-зависимыми. Примером чувствительности к контексту в английском языке являются две фразы: «Время летит как стрелка». и "Фрукты летят как бананы". В общем, компьютерам трудно понимать контекстно-зависимые языки.

Тип 2 грамматики (без контекста). Контекстно-свободные языки являются теоретической основой синтаксиса большинства языков программирования.

Тип 3 грамматики (обычные грамматики). Семейство регулярных языков можно получить с помощью регулярных выражений. Обычные языки обычно используются для определения шаблонов поиска и лексической структуры языков программирования.

Грамматики типа 2 (без контекста) и типа 3 (обычные) чаще всего используются компьютерами, потому что парсеры для них могут быть эффективно реализованы.

BNF (нормальная форма Бэкуса или форма Бэкуса-Наура) - это техника обозначений для контекстно-свободных грамматик, часто используемая для описания синтаксиса языков, используемых в вычислительной технике.

Например, идентификатор может быть описан как:

<identifier> ::= <letter> { <letter> | <digit> }

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

Ранее буква была определена как «а» | 'б' | «c» и т. д., а цифра определяется как «0» - «9» с использованием обозначений того же типа.

Оператор AC for for может быть определен как:

 <for_statement> ::=
    'for' '(' <expression> ';' <expression> ';' <expression> ')' <statement> 

Лексические анализаторы и синтаксические анализаторы (первые этапы компилятора или интерпретатора) затем создаются для принятия конкретной грамматики, описанной BNF для конкретного языка. Лексические анализаторы обычно используются для разделения различных токенов языка (таких как ключевое слово, идентификатор или число), а синтаксический анализатор используется для выяснения того, как токены работают вместе, например, как создается оператор for. ,

tcrosley
источник
+1 отличная рецензия. Но я не удивлен, что это не было принято в качестве ответа. Это то, о чем я думал, спрашивал OP, но, исходя из ответа, который они выбрали, кажется, что они хотели чего-то гораздо более высокого уровня.
Мэтью Родатус
5

Во-первых, давайте определим «язык» с точки зрения того, что это такое. Язык требует сначала словарный запас (список слов, которые определяют понятия, которые являются объектами общения), а затем синтаксис («учебник для начинающих» или набор правил, которые определяют структуру общения).

На этом базовом уровне C # не сильно отличается от английского. Что делает C # «языком программирования», так это его намерение и, следовательно, его дизайн; он предназначен для обработки отдельными командами низкого уровня. Таким образом, предопределенный словарный запас ограничен, синтаксис очень жестко применяется, и весь язык разработан так, чтобы его «аудитория» (компьютер; точнее, компилятор, который будет переваривать), использовалась очень хорошо известным предопределенным способом. исходный код на «промежуточный язык» простых команд, которые затем могут быть далее переведены в машинный код «средой выполнения»). Вы не пишете прозу или поэзию на C #; Вы приказываете компьютеру выполнять работу самым недвусмысленным образом.

Для компьютеров да, инструмент, обычно называемый компилятором, необходим для того, чтобы взять то, что вы пишете в коде, и преобразовать его в инструкции, которые может использовать компьютер. Информатика, как и большинство технологий, является по своей сути итеративным, «многоуровневым» процессом. Когда компьютеры были впервые изобретены, они были запрограммированы путем ручного ввода двоичных инструкций. Эти инструкции стали стандартизированы для каждого процессора в шестнадцатеричные «машинные коды»; Разница только в том, как двоичные цифры сгруппированы для отображения людям. Затем в коде ассемблера список команд и некоторые базовые идентификаторы, такие как имена регистров, были заменены их шестнадцатеричными кодами при написании программ; ASM все еще можно конвертировать 1: 1 в машинный код. Квантовый скачок был к «императивному» программированию 3-го поколения, который в основном берет более понятные человеку абстрактные понятия, такие как переменные и логические циклы, и переваривает их в нативные инструкции, используя шаблоны, основанные на ключевых словах и синтаксисе. Ранние языки, такие как COBOL, FORTRAN, Pascal и C, все еще могут быть «переведены» человеком на определенный машинный язык (обычно 8086 ASM). Затем произошла революция объектно-ориентированного программирования, которая заключается в дополнительных правилах синтаксиса, которые определяют код как концептуально инкапсулированный в «объектах», которые имеют некоторую комбинацию состояния и логики. человеком на определенный машинный язык (обычно 8086 ASM). Затем произошла революция объектно-ориентированного программирования, которая заключается в дополнительных правилах синтаксиса, которые определяют код как концептуально инкапсулированный в «объектах», которые имеют некоторую комбинацию состояния и логики. человеком на определенный машинный язык (обычно 8086 ASM). Затем произошла революция объектно-ориентированного программирования, которая заключается в дополнительных правилах синтаксиса, которые определяют код как концептуально инкапсулированный в «объектах», которые имеют некоторую комбинацию состояния и логики.

В настоящее время мы хорошо разбираемся в «четвертом поколении» языков, которые являются языками, написанными для определения связи с другими программами, а не непосредственно с машиной. В широком смысле это включает языки «разметки», такие как XML / HTML, языки «сценариев», такие как JavaScript и SQL, и большинство языков «песочницы», таких как Java и .NET Framework (которые компилируются в IL, который затем интерпретируется среда выполнения, которая абстрагирует детали машины и платформы). Можно также сказать, что он охватывает область функциональных языков программирования, которые ТЯЖЕЛО зависят от среды выполнения, чтобы обеспечить абстракцию не только специфических для машины деталей, но и специфичных для операции деталей. Эти языки четвертого поколения для человека более или менее невозможны для перевода на машинные инструкции, и дело в том, что это не будет стоящим усилием; Сила этих языков - многоуровневый процесс, в котором они используются, чтобы в конечном итоге сказать компьютеру, что делать на низких уровнях.

Keiths
источник
Спасибо. Я имею представление об истории развития языка программирования.
Эрика Сюй
2
@KeithS: Вы можете переформатировать последний абзац, чтобы сделать его немного более читабельным.
Иван Вучица
4

Это хороший вопрос. Правильный ответ составляет добрую половину того, что называется «компьютерная наука».

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

Если вышесказанное слишком академично, вы можете начать с Petzold, «Код» , а затем вернуться к семантике.

SK-логика
источник
1
Вы действительно ожидаете, что 18-летний новичок прочитает какую-то тяжелую теорию, чтобы ответить на этот вопрос?
Работа
2
@Job, согласно его предыдущему вопросу, он получает дозы Scheme (и, по-видимому, SICP) в университете. Тогда должно быть немного с семантикой. Во всяком случае, нет правильного ответа на этот вопрос без тяжелой теории.
SK-logic
+1 за упоминание "Код". Эту книгу нужно обязательно прочитать каждому ученику начального уровня CS.
Даниэль Приден
4

Если вы пишете программу на языке программирования, другая программа преобразует символы в вашей программе в символы, понятные компьютеру. Иногда это занимает несколько шагов. Например, в C:

  1. Пользователь пишет программу на языке высокого уровня (C), который не понимается ЦП, но непосредственно понимается программистом (мы надеемся!).

  2. Компилятор преобразует C в язык Assmebly, который непосредственно не понимается процессором, но его легко преобразовать во что-то еще.

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

Чтобы гарантировать, что компьютер понимает вашу программу, компилятор или интерпретатор выдаст вам ошибку и, как правило, остановит ее, если обнаружит что-то не компилируемое, например, синтаксическую ошибку. Если ваша программа не может быть скомпилирована, она никогда не сможет достичь той стадии, когда ваша программа попытается запустить ее и потерпит неудачу, потому что она не «поняла» ее.

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

FrustratedWithFormsDesigner
источник
2
На самом деле, нет; современные компиляторы не выполняют шаг 2 и просто генерируют двоичный код напрямую. Но сборка и бинарный код в любом случае почти эквивалентны; Вы можете разобрать (преобразовать двоичный код обратно в сборку) с очень высокой точностью.
MSalters