Вы когда-нибудь задумывались, как?

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

Я расскажу вам то, что я понял, очень простыми словами и идеями.

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

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

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

То же самое и с компьютерами: мы просто меняем строительные блоки на 0 и 1, архитектора на разработчика программного обеспечения, а план на код.

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

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

Значение языка программирования

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

Этот код просто сообщает компьютеру получить дату и отобразить ее на экране в виде текста.

выражение «display()» называется вызовом функции/процедуры, что очень похоже на математические функции: оно принимает параметр (дату) или более и возвращает что-то обратно. Однако в языке программирования он может возвращать что-то еще, что интерпретируется как ничто.

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

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

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

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

"Мистер. «Переводчик» имеет различные методы для достижения одной и той же цели — преобразования нашего кода в полезное программное обеспечение. Он очень услужливый и тщательный, проверяя наш код на наличие ошибок, не меняя при этом задуманную концепцию, которую мы пытаемся передать компьютеру. Кроме того, он самостоятельно оптимизирует код, чтобы сделать его максимально кратким и эффективным. Иногда он даже предлагает предложения, которые сделают наши идеи более ясными.

"Мистер. Переводчик» — очаровательный персонаж, и было бы здорово узнать больше о его личности.

Перевод в машинный код. Секрет мистера переводчика

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

  • Компиляция: во время этого процесса Mr.Translator сначала проверяет наш код на наличие синтаксических ошибок, а затем приступает к его переводу в машинный код, здесь Mr.Translator принимает на себя роль «Компилятора».
  • Интерпретация. Здесь г-н Переводчик выполняет каждую строку кода, которую он читает, без компиляции. Эта стратегия предлагает несколько преимуществ, в том числе возможность быстро тестировать и отлаживать логику вашего кода, вносить изменения в режиме реального времени и сосредоточиться на получении желаемого результата. В этом сценарии г-н Переводчик играет роль «Переводчика».
  • Трансляция. При транспиляции мистер-переводчик преобразует наш код с одного языка программирования на другой, чтобы другой мистер-переводчик мог перевести его в пригодное для использования программное обеспечение. В этом случае г-н Переводчик выступает в роли «Транспилера».

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

Процесс компиляции

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

Исполняемый файл содержит не только машинный код, но и дополнительные метаданные в качестве подсказок для ОС, поэтому формат файла может различаться в каждой ОС, например, Linux использует формат ELF, Windows использует формат PE, Mac использует Mach-формат. О формат и так далее, вы поняли.

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

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

преимущества

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

недостатки

  • Придется рассмотреть другие платформы.
  • сложно создать его с нуля.

Интерпретация

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

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

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

преимущества

  • относительно легко построить.

недостатки

  • дополнительные затраты на использование другого программного обеспечения для выполнения нашего собственного делают это программное обеспечение менее производительным.

Транспиляция

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

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

преимущества

  • Изменяет экосистему языков программирования.

недостатки

  • Зависимость от целевого языка программирования.

За кулисами Mr.Translator

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

Этап 1: Токенизация

В этом состоянии Mr.Translator идентифицирует ключевые слова и символы в соответствии с исходным языком программирования, однако не несет ответственности за проверку семантических ошибок.

Это то же самое, что попросить человека идентифицировать символы из текстов в математической задаче. Иногда Mr.Translator может полностью игнорировать этот этап.

Также называется лексическим анализом, сканированием.

Этап 2: Анализ

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

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

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

Этап 3: Оценка/генерация другого кода

Оценка

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

Генерация другого кода

Это общая единица транспилятора и компилятора, поскольку первый будет генерировать код другого языка программирования, а второй — машинный/байтовый код.

Примеры из реального мира.

Языки программирования

Существует МНОГО языков программирования, но те, о которых вы слышите, обычно являются самыми популярными, например

Python, C++, C, Java, JavaScript, TypeScript, Lua, Ruby, Elixir, Golang, Dart, Rust, Fortran, PHP, Pascal, Basic, Cobol, Nim, Julia, Kotlin, Swift, Haskell, LISP, Scala и т. д.

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

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

Составители

  • Коллекция компиляторов GNU (GCC) для Ada, C++, C, Fortran, Objective C и Pascal
  • Clang для C++ и C
  • Rust для ржавчины
  • Перейти на Голанг или Go
  • Cython для Python
  • Ним для Нима

Переводчики

  • Python (программное обеспечение) для Python (языка программирования)
  • Руби для Руби
  • Луа для Луа

Транспиллеры

  • tsc для TypeScript
  • cppfront для C++ (старый)
  • CoffeScript для CoffeScript

типы языков программирования

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

  • компилируемый язык
  • интерпретируемый язык
  • транспилированный язык
  • статически типизированный язык
  • динамически типизированный язык
  • язык высокого уровня
  • язык низкого уровня

Я просто выбрал их, потому что их достаточно, чтобы дать представление о языках программирования (полный список можно посмотреть: https://en.wikipedia.org/wiki/List_of_programming_languages_by_type)

Теперь давайте разберем каждый тип:

скомпилированный, интерпретированный, транспилированный язык

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

например, C++ — это ГЛАВНОкомпилируемый язык, Python — ГЛАВНО интерпретируемый, TypeScript ГЛАВНО — транспилируемый.

(В основном потому, что может быть реализация другого типа)

статически и динамически типизированный язык

Итак, вы знакомы с термином «переменная», если не просто думать о нем как о контейнере, хранящем значения.

Вы тоже знакомы с «типами»? Если нет, не бойтесь, мой друг, «тип» — это способ сообщить Mr.Translator, какие значения следует поместить в контейнер. Например, вы называете контейнер «Чад», вы явно говорите, что этот контейнер может хранить только числа, и если в него поместить что-то кроме чисел, то это большая чушь, и Mr.Translator злится и не будет компилировать ваш код.

Давайте возьмем два языка программирования A, B. A — злой и очень строгий, он продолжает настаивать на присвоении каждому контейнеру правильного типа и наказывает вас, если вы помещаете в контейнер неподходящее значение. B является противоположностью A: он не требует связывания типов с каждым контейнером, но последствия зависят от вас.

Язык A называется статически типизированным, а язык B — динамически типизированным.

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

язык программирования высокого и низкого уровня

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

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

Высокий уровень = больше абстракций, реализованных в языке за вас. (питон, яваскрипт, рубин)

Низкий уровень = меньше абстракций, и если вы хотите что-то необычное, напишите это сами, smh. (C, Сборка, Голанг)

Высокий уровень с доступом низкого уровня = и то, и другое, и если ваш код не работает, это проблема навыков. (например, C++ и Rust)

Некоторые примечания

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

Вы увидите, что люди называют интерпретатор компилятором, а транспилятор — компилятором. Названия не используются точно по тому, что они означают, поэтому «компилятор» будет означать весь процесс.

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

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

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

Заключение

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

Как всегда, я открыт для отзывов, не стесняйтесь :).