Как люди создают новые языки программирования?

Как люди создают новые языки программирования? В частности:

  1. На каком языке они пишут это?
  2. Должен ли язык быть между языком высокого уровня и машинным кодом?
  3. Каковы этапы/элементы создания языка программирования Например - C или C++ (Из моего базового исследования я понял, что все языки программирования либо нуждаются в компиляторе или интерпретаторе, но я не совсем понимаю разницу между два)

Ответы

Ответ 1

I will give you a good idea of where computers started and how they've progressed.

If you want to get into the history of computers I'd look at things such as the Jacquard loom and Babbage difference engine. These two inventions probably had the greatest early influence on early modern computing. Usage of punch cards (Jacquard) and the mechanical 'calculation' (Babbage) provided a great foundation.

Итак, начнем с того, как работает компьютер. В основе каждого компьютера лежит транзистор (а до этого вакуумные трубки). Главное, что стоит за транзистором, это то, что он может передавать электричество двумя различными способами, в зависимости от его состояния *. Это позволяет создавать логические потоки электроэнергии. С помощью этого мы можем создавать всевозможные замечательные вещи **: ворота и ворота, ворота, половинные сумматоры, мультиплексы и т.д.

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

Эти двоичные команды являются машинным кодом, необходимым для "установки" ЦПУ.

До сих пор я не отвечал на ваши вопросы, но я заложил некоторые основы, чтобы понять, что происходит. (Вы сказали, что хотите узнать все = P)

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

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

Итак, давайте добавим третий,

2- Язык высокого уровня.

Язык высокого уровня - это то, что больше напоминает английский, например C. У нас есть циклы, структуры данных и другие полезные вещи. Чтобы использовать C, мы должны написать компилятор. Компилятор берет код, написанный на языке C, и создает объектный код (аналогично языку ассемблера). Затем другая программа превращает этот объектный код в машинный язык. В настоящее время эти два шага обычно объединены в один для повышения эффективности. Теперь у нас есть ваше первое определение. Компилятор превращает язык высокого уровня в объектный (или машинный) код ***.

Теперь, когда у нас появился наш первый язык высокого уровня (C), вероятно, кажется глупым и болезненным снова работать с языком ассемблера, если не нужно. Так что теперь мы можем писать новые языки и компиляторы на C или на любом другом языке, который мы сейчас создали ****.

Так что теперь давайте врываться в переводчика. Интерпретатор - это программа, которая читает и выполняет программу самостоятельно. Вместо того, чтобы превращать программу, которая превращает высокоуровневый код в машинный код, он читает высокоуровневый код (обычно строку за раз) и выполняет его.

Давайте возьмем Java для примера. По сути, Java - это интерпретируемый язык, который означает, что кто-то создал программу (скажем, C). Эта программа на C читает код Java и выполняет его. Таким образом, существует еще один слой между компьютером и кодом.

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

Ответ 2

1) На каком языке они пишут?

Это полностью зависит от программиста. На C, С++ реализовано несколько языков. Некоторые другие загружаются. (C написано на C). Выдержка из ссылки:

Bootstrapping:
Basically you start with a very minimal process/set of functions that can be used to 
compile the code that defines a slightly more functional compiler. 
This creates your next compiler which then can then be used to build code that can do even 
more. 
You repeat this process until you have a full blown compiler that can 
compile all the language features. 

Собственно, это compiler или interpreter, который написан на некотором языке. Например, Go является языком и имеет два компилятора: gc и gccgo. gc записывается на C и gccgo является фронтом gcc, написанным главным образом в C++.

2) Должен ли быть язык, находящийся между языком высокого уровня и машинным кодом?

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

3) Каковы этапы/элементы создания языка программирования Например - C или С++ (Из моих основных исследований я понял, что на всех языках программирования нужен компилятор или интерпретатор, но я действительно не понимаю разница между ними)

Простыми словами:

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

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

Компилятор принимает всю программу в качестве входных данных. Интерпретатор принимает в качестве входной команды одну команду.

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

  1. Запишите переднюю часть: как пользователи будут видеть ошибки, предупреждения и т.д.

  2. Используйте информацию парсера для записи объектного кода или промежуточного представления.

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

  4. Тестирование и документация.

Ответ 3

Относительно вашего первого вопроса. Все языки нуждаются в компиляторе, это правда, однако каждый язык имеет свой собственный другой способ компиляции. Например, Java использует JDK для компиляции и JVM для выполнения. Независимо от того, какой язык вы запрограммировали (как всегда, как язык высокого уровня), у вас будут средние слои, которые преобразуют ваш код в машинный код (aka двоичный код). Эти средние слои сделаны на языках среднего уровня (там есть куча их, вы можете прочитать их здесь http://en.wikipedia.org/wiki/Timeline_of_programming_languages) и большинство широко используемый на сегодняшний день для программирования низкого уровня (еще не машинный код) - C.

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

До сих пор я надеюсь, что ответил на два из ваших вопросов.

О третьем, трюк всегда находится в компиляторе, если вам нужен новый язык программирования, вам нужен компилятор, чтобы вы могли перевести свой код в машинный код. Все, что вы можете видеть сейчас, как некоторые ключевые слова с цветом и проверкой ошибок, прежде чем компилировать свой код, это IDES (вы можете прочитать о них здесь http://en.wikipedia.org/wiki/Integrated_development_environment).

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

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

Надеюсь, это даст вам немного света.

Ответ 4

1) На каком языке они пишут?

Что бы они ни хотели; это зависит от фокуса языка и от того, что им удобно. Вы можете написать компилятор в чем угодно: от сборки до Haskell. Это зависит от того, насколько сложна реализация, которая зависит от правил создаваемого вами языка. Например, относительно легко написать компилятор C, потому что правила языка довольно просты. С++. не так много.

2) Должен ли быть язык, находящийся между языком высокого уровня и машинным кодом?

Неа. Компилятор - это еще одна программа; он читает в кучу текста и испускает либо другой текстовый файл, либо двоичный файл машинного кода. Он не должен быть написан на языке низкого уровня. Многие компиляторы написаны на C, потому что многие знают о них лучше, но это не значит, что все компиляторы должны быть написаны C или ассемблером. Использование языка более высокого уровня, вероятно, сделает задачу намного проще.

3) Каковы этапы/элементы создания языка программирования Например - C или С++ (Из моих основных исследований я понял, что на всех языках программирования нужен компилятор или интерпретатор, но я действительно не понимаю разница между ними)

Обычно интерпретатор запускает программу по мере ее перевода, тогда как компилятор просто переводит код без его выполнения. Эта линия довольно размыта в эти дни (например, код Java скомпилирован с независимым от платформы байтовым кодом, который затем интерпретируется JVM в собственный машинный код).

Большие части компилятора:

  • Лексер, который разбивает ваш исходный текст на токены (литералы, идентификаторы, пунктуаторы и т.д.);
  • Парсер, который берет эти жетоны и сопоставляет их с грамматикой языка;
  • Генератор кода, который испускает целевой код на основе результатов анализатора.

Генератор кода может также содержать какую-то оптимизационную логику для генерации машинного кода, который более эффективен, чем буквальный перевод исходного кода. Например, gcc делает аккуратный маленький трюк, когда вы умножаете что-то на целочисленный литерал, например i = a * 10; Вместо генерации кода типа

movl     a, %edx  ;; write value of a to register edx
movl   $10, %eax  ;; write value of 10 to register eax
imull %edx, %eax  ;; multiply %edx by %eax, store in %eax

он генерирует

movl    a, %edx ;; same as above
movl %edx, %eax ;; copy %edx to %eax
sall   $2, %eax ;; shift %eax left by 2 places, effectively multiplying by 4
addl %edx, %eax ;; add %edx to %eax
addl %eax, %eax ;; double %eax

Если a - 3, то это дает нам

 3 << 2 == 12
12 +  3 == 15
15 + 15 == 30

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

Я взял класс компилятора над летней сессией 1 почти 30 лет назад, поэтому мои навыки не совсем актуальны. Но большой материал не меняется со временем. Трудная работа по созданию нового языка: а) принятие решения о том, что вы хотите сделать, б) появление синтаксиса, который легко читается и достаточно легко разбирается, и в) правильное использование семантики.


1. Не делай этого. Составление компилятора будет одним из более сложных классов в учебной программе CS и не должно быть принято в короткий сеанс.

Ответ 5

Это отличная книга, которая поможет начать http://www.amazon.com/Language-Implementation-Patterns-Domain-Specific-Programming/dp/193435645X/

Этапы построения языка

  • Lexing. Лексинг означает возможность читать определенные категории токенов. Токеном может быть серия цифр 12376 или текстовые строки типа "Hello". Лексинг смотрит на первого символа (и он также может смотреть вперед на второй символ), чтобы определить, что это такое. В случае числа он видит цифру, а затем переходит к чтению ряда цифр (путем вызова подпрограммы), или в случае строки, в которой он видит цитату, затем переходит к чтению строки. Результат lexer - это токен, который является типом (числом или строкой в ​​этом примере) и текстом токена. Обычно это хранится в структуре как строка типа Kind и Text с константами, объявленными для представления видов.

  • Следующий строительный блок - это синтаксический анализатор. Парсер видит серию токенов, поэтому он может видеть, что Идентификатор, а затем смотрит вперед, увидит a =. Затем он перейдет в задание. Парсер строит дерево. В случае назначения он построит "node" типа "assign", затем он сохранит идентификатор в первом дочернем элементе и выражение во втором дочернем элементе. Все узлы дерева являются "операциями", что означает, что они что-то делают. Вы не будете просто строкой или целым числом в качестве Node, у вас будут "Добавить" или "Добавить" и т.д. Как узлы (если это не выражение, а выражения содержатся в операциях).

  • Последняя часть - это исполнение. Это делается путем ходьбы по дереву и выполнения узлов.

Существует много других механизмов, таких как "Память", "Сфера применения" и "Механизм поиска". Это объясняется в ссылке выше.