Когда кто-то пишет новый язык программирования, что они пишут на IN?

162

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

Когда вы пишете совершенно новый язык программирования, на чем вы его пишете ?

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

С моим слабым интеллектом я нахожу это увлекательным ... Пожалуйста, просветите меня!

Нарисовался
источник

Ответы:

193

Это не глупый вопрос. Это отличный вопрос.

Как уже ответили, короткий ответ: «Другой язык».

Хорошо, что приводит к некоторым интересным вопросам? Что, если это самый первый язык, написанный для вашего конкретного оборудования? Очень реальная проблема для людей, которые работают на встроенных устройствах. Как уже ответил "язык на другом компьютере". Фактически, некоторые встроенные устройства никогда не получат компилятор, их программы всегда будут компилироваться на другом компьютере.

Но вы можете отодвинуть его еще дальше. Как насчет первых программ, когда-либо написанных?

Ну, первые компиляторы для «языков высокого уровня» были бы написаны на так называемом «языке ассемблера». Язык ассемблера - это язык, где каждая инструкция на языке соответствует одной инструкции для CPU. Его язык очень низкого уровня и чрезвычайно многословный и очень трудоемкий, чтобы писать на нем.

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

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

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

И даже раньше компьютерные программы должны были быть жестко соединены с платами !

Мэтью
источник
20
+1, я думаю, что этот ответ действительно соответствует духу вопроса.
stderr
30
Однажды я взял класс Assembler II, и профессор спросил, почему мы выбрали факультативный. Я пошел на смешной ответ: «потому что я хотел легкий А.» Думаю, у меня был лучший ответ, но у нас был завод Honeywell в городе, и следующий парень сказал: «Я пишу микрокод весь день, и я хотел выучить язык высокого уровня».
T.Rob
3
Я настоятельно рекомендую Код: Скрытый язык компьютерного и программного обеспечения . По сути, он охватывает тот же материал, что и этот ответ, от вакуумных ламп до компиляторов для языков высокого уровня.
MatrixFrog
Компьютеры развивались так же, как люди, хотя и в сравнительно бесконечно малом количестве времени.
Гаурав Ойха
Теперь это будет неконструктивный комментарий, но его нужно написать ... это блестящий блестящий ответ во всех формах, формах и информации :-)
Lukáš Řádek
23

Наиболее распространенный ответ C. Большинство языков реализовано в C или в гибридном C с обратными вызовами и «лексером», таким как Flex, и генератором синтаксического анализатора, таким как YACC . Это языки, которые используются для одной цели - для описания синтаксиса другого языка. Иногда, когда дело доходит до компилируемых языков, они сначала реализуются на C. Затем первая версия языка используется для создания новой версии и так далее. (Как Хаскелл .)

Проф. Фалькен
источник
1
Некоторые языки написаны на ассемблере, например, picolisp. ( blog.kowalczyk.info/article/picoLisp-Arc-before-Arc.html )
Проф. Фалькен,
1
А как насчет программ lex / yacc (flex / bison)? Считаются ли эти дополнения для создания языков в C?
Дейв
1
У вас есть что-нибудь, чтобы доказать, что самый распространенный ответ - C?
RichardOD
Я начал просматривать список здесь: google.com/Top/Computers/Programming/Languages/Open_Source. Затем я случайно закрыл окно редактора примерно на языке 10 и потерял мотивацию. Во всяком случае, до сих пор около половины были реализованы на C, а остальные в основном загружались сами собой.
Профессор Фалькен
3
Я думаю, что вы должны упомянуть Lex / Yacc (или альтернативы). Как правило, не начинают писать язык на C, а используют лексер и парсер, которые затем поддерживаются кодом C.
Стив Роу
14

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

Статья в Википедии, на которую я ссылаюсь, обсуждает проблему курицы и яйца . Я думаю, вы найдете это довольно интересным.

RichardOD
источник
5
Что невозможно, когда вы только начинаете.
Майкл Боргвардт
1
Да, очевидно. Но многие языки написаны таким образом, как только это возможно. Я хотел указать на это, как никто другой, и я чувствую, что это важный момент.
RichardOD
+1 за использование термина бутстрап. Интересно, что вам придется компилировать ваш компилятор дважды. Первый раз, очевидно, с имеющимся у вас компилятором, а второй - с только что созданным компилятором. Скажем, вы добавили оптимизацию в свой компилятор. Компилятор, который вы создали, может генерировать код с этими оптимизациями, но сам он не выполняет оптимизированный код, пока вы не скомпилируете его снова с оптимизирующим компилятором.
Les
@ Les- Да, самозагрузка - интересная концепция.
RichardOD
2
Случайный комментарий здесь. Ответ на старый вопрос о том, кто пришел первым (курица или яйцо), заключается в том, что курица появилась первой. Причина в том, что для того, чтобы воспроизвести / воспроизвести что-либо, вы должны сначала иметь репродуктор / репликатор, уже готовый для воспроизведения / репликации.
SpicyWeenie
10

Практически любой язык, хотя использование одного, подходящего для работы с графиками и другими сложными структурами данных, облегчит многие вещи. Производственные компиляторы часто пишутся на C или C ++ по соображениям производительности, но такие языки, как OCaml, SML, Prolog и Lisp, возможно, лучше подходят для прототипирования языка.

Есть также несколько «маленьких языков», используемых в языковом дизайне. Например, Lex и yacc используются для задания синтаксиса и грамматики и компилируются в C. (Есть порты для других языков, таких как ocamllex / ocamlyacc и многих других подобных инструментов.)

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

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

silentbicycle
источник
4

На самом деле вы можете писать практически на любом языке, который вам нравится. Нет ничего, что мешало бы вам написать компилятор C на Ruby. «Все», что вам нужно сделать, - это проанализировать программу и выдать соответствующий машинный код. Если вы можете читать / писать файлы, ваш язык программирования, вероятно, будет достаточно.

Если вы начинаете с нуля на новой платформе, вы можете сделать кросс-компиляцию: написать компилятор для вашей новой платформы, который работает на Java или изначально на x86. Разработайте на своем ПК, а затем перенесите программу на новую целевую платформу.

Самыми основными компиляторами являются, вероятно, Assembler и C.

ziggystar
источник
Однако этот «любой» язык должен поддерживать рекурсивные вызовы. В противном случае реализация синтаксического анализатора и синтаксического анализатора будет реальной проблемой.
2
Если вы выбрали неподходящий язык для задачи, это ваша вина. Это может произойти для любого проекта, а не только для компиляторов / интерпретаторов.
Ziggystar
4

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

Переводчик вводит программу на одном языке и выводит эквивалентную программу на другом языке. Переводчик вводит программу на каком-то языке и запускает ее.

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

Многие языки реализованы по-разному. Например, javacэто переводчик, который преобразует исходный код Java в байт-код JVM. JVM - это интерпретатор [1], который выполняет байт-код Java. После того, как вы запустите javacи получите байт-код, вам больше не нужно javac. Однако всякий раз, когда вы хотите запустить свою программу, вам понадобится JVM.

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

[1] Большинство JVM выполняют перевод за кулисами, но на самом деле они не являются переводчиками, так как интерфейс к JVM не «язык ввода -> язык вывода».

Каннан Гундан
источник
3

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

Kaivosukeltaja
источник
2
Вам не нужно компилировать машинный код. это родной язык процессора по определению.
Стю Томпсон
1
Правда. Что я хотел сказать, так это «скомпилировать машинный код из ассемблера или чего-то подобного вручную». Я могу ошибаться, но я предполагаю, что мало кто сразу вводит код как двоичный / шестнадцатеричный.
Кайвосукелтая
2

Многие языки были сначала написаны на другом доступном языке, а затем переопределены сами по себе и загружены таким образом (или просто сохранили реализацию на иностранном языке, таком как PHP и perl), но некоторые языки, такие как первый ассемблер, были скомпилированы вручную для машинного кода, например первый C-компилятор был скомпилирован вручную для сборки.

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

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

Эдмунд Гримли Эванс сделал нечто подобное со своим языком HEX

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

Сильвестер
источник
1

Обычно с языком программирования общего назначения, подходящим для разработки систем, например, C, Haskell, ML, Lisp и т. Д., Но список вариантов длинный. Кроме того, обычно с некоторыми предметно-ориентированными языками для реализации языка, например генераторами синтаксического анализатора и лексического анализатора, промежуточными языками, такими как LLVM и т. Д. И, возможно, некоторыми сценариями оболочки, средами тестирования и системой конфигурации сборки, например, autoconf.

Джеймс Вудьятт
источник
1

Большинство компиляторов были написаны на языке C или ac, если нет, то ассемблерный язык - это путь. Однако при написании нового языка с нуля, когда у вас нет макробиблиотеки или исходного кода из языка-прототипа, вы должны определить свои собственные функции. Теперь на каком языке? Вы можете просто написать «форму» исходного кода, называемого psedocode, на машине, которая выглядит как грамматика bnf из спецификации объектно-ориентированного структурированного языка, такой как базовый algo lisp на языке Fortran. Таким образом, изображение записывает кросс-код, напоминающий любой из этих синтаксисов языка. Это код psedo.

Крис Андерсон
источник
1
Я не верю, что код psedo должен быть машиночитаемым
Ричард Тингл,
0

Даже дальнейшие двоичные или сборочные операции должны быть преобразованы в функции, то есть в работу ассемблеров / компиляторов, а затем в объект, из данных и функций, если у вас нет исходного файла, чтобы увидеть, «как эти функциональные объекты должны быть представлены в вашем Реализация языка. Затем вы должны распознать «увидеть» реализацию или определить свои собственные функции, процедуры и структуры данных. Это требует много знаний, вам нужно спросить себя, что такое функция. Тогда ваш ум становится симуляцией языка. Это отделяет мастера-программиста от остальных.

user3093481
источник
0

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

Основные вещи, которые вы должны знать, это то, как работает компилятор, когда он должен выполнить фрагмент кода. Компилятор имеет много фаз, таких как лексический анализ, семантический анализатор, AST (абстрактное синтаксическое дерево) и т. Д.

То, что я сделал на своем новом языке, можно найти здесь - http://www.singhajit.com/writing-a-new-programming-language/

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

Аджит Сингх
источник
0

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

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

например, если у нас была инструкция вроде:

11001101

в сборке это будет называться:

LOAD_A 15

это означает, что загружается содержимое регистра a в ячейку памяти 15. Как я уже сказал, это было просто соглашение, подобное выбору 0 и 1 для двух состояний транзисторов или чего-либо еще в компьютере. Таким образом, имеется программа с 50 инструкциями, запомнить язык ассемблера было бы проще. таким образом, пользователь будет писать ассемблерный код, а некоторая программа (в данном случае ассемблер) будет переводить коды в двоичные инструкции или машинный язык, как они его называют.

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

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

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

скажем так, вы упаковали много разных кодов в python и создали модуль (libray, package или все, что хотите, чтобы он вызывался), и вы называете этот модуль mgh (только мое имя). Теперь давайте предположим, что мы создали этот MHG как-то, что любой, кто говорит:

import mgh
mgh.connect(ip,port.data)...

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

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

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

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

Mgh Gh
источник