Как работает процессор и языки программирования
Эта статья будет полезна всем, кто по каким-либо причинам не знает, как работает процессор, как и зачем появились языки программирования и принцип их работы.
Все описанное ниже как всегда упрощено для лучшего понимания.
Процессор и оперативная память
Все вы знаете, что процессор в компьютере — это мозг. Он управляет всеми процессами, происходящими внутри этой консервной банки. Но знаете ли вы, как он работает?
Начнем вот с чего. Процессор не понимает русский, английский и другие языки. Он понимает числа, которые являются для него простыми командами, например: взять из памяти какие-то данные, добавить какие-то данные, сложить и т.д.
Процессор знает много команд и у каждой из них есть свой числовой код, например:
Совокупность всех команд и их числовых кодов, заложенных инженерами в процессор, называется архитектурой процессора. Это не аппаратная архитектура, а программная. Каждый производитель процессоров закладывает свою архитектуру. Это значит, что у одной и той же команды будут разные числовые коды на разных процессорах.
Понимаете прикол? Это значит, что вам нужно писать код для каждой архитектуры процессора. Жуть.
Так. Понятно. Процессор может выполнять маленькие числовые команды. Но откуда он их берет? Из оперативной памяти. Думайте об оперативке, как о большом количестве маленьких ячеек. Каждая ячейка имеет свой адрес — это обычное число, например 2001. По адресу ячейки процессор может запросить данные и оперативная память вернет их ему. Также в эту ячейку процессор может записать новые данные.
Как я уже сказал, в ячейках оперативной памяти хранятся команды для процессора. Но также в них могут храниться любые другие данные, которые можно представить в числовом виде, например: буквы, изображения, музыка или видео.
Получается такая картина: процессор обращается к оперативной памяти по адресу ячейки, оперативка возвращает ему команду из этой ячейки, процессор выполняет команду. А что дальше? А дальше процессор опять обращается к памяти (уже в другую ячейку), получает команду, выполняет ее и этот цикл повторяется снова и снова. То есть процессор все время выполняет какую-то заданную последовательность команд (числовых кодов). Эта последовательность команд называется машинным кодом.
Ассемблер
Как мы помним, процессор спроектирован таким образом, чтобы выполнять простые команды, загруженные из оперативной памяти.
Для того, чтобы заставить процессор выполнить какую-то программу, например решить уравнение 2 + 2 * 2, нам нужно написать цепочку простых числовых команд.
Согласитесь, что писать такой код очень сложно и легко запутаться. И это мы всего лишь написали код для решения простого уравнения. А теперь представьте, как написать ВКонтактик или Инстаграм.
Для упрощения жизни люди придумали инструмент Ассемблер и язык программирования на ассемблере.
Теперь все числовые коды команд процессора заменили на буквенные аббревиатуры, которые стало легче запоминать и читать.
Помните примеры кодов команд, которые были указаны выше? Теперь они выглядят так:
Также к названию команд были добавлены операнды (один или более), которые дают дополнительную информацию для выполнения команды.
Рассмотрим еще один пример программы на ассемблере, которая выводит фразу «Hello, World!«. Пример ассемблированного кода:
Что-то слишком много непонятного кода для такой пустяковой задачи, не правда ли?
Языки программирования высшего уровня
Помните в самом начале я писал, что каждый производитель процессоров делает свою архитектуру? И что у каждой архитектуры свои числовые коды команд?
Так вот одну и ту же программу на ассемблере вам придется «пересобирать» под каждую из архитектур процессора. Для каждой архитектуры нужно скачивать отдельный инструмент Ассемблер и прогонять через него свой код.
Это усложняет портативность. Добавим сюда сложность в написании больших программ и получим необходимость в создании новых инструментов.
Так стали появляться языки программирования высокого уровня.
Их суть заключается в том, что цепочки команд на ассемблере были объединены в отдельные функции. Теперь вам достаточно написать одну команду, чтобы показать сообщение «Hello, World!».
Компилируемые языки
Первыми появились компилируемые языки программирования. К ним относится С, С++, Java и другие.
Компилируемый язык программирования означает, что есть инструмент компилятор, который преобразует код высшего порядка в код, понятный процессору.
Рассмотрим чуть подробнее. Например на языке С вывод фразы «Hello, World!» будет выглядеть так: printf(«Hello, World!»). Просто и понятно.
Но процессор не поймет этой команды. Как мы помним, он знает и понимает только маленькие числовые команды. Поэтому компилятор языка C преобразует команду в ассемблированный код, а затем в машинный код, понятный процессору.
Программа, написанная на компилируемом языке программирования, перед запуском всегда проходит процесс компиляции. То есть весь написанный код высшего порядка преобразуется в машинный код, понятный процессору.
Затем компилятор делает исполняемый файл, который можно скинуть другу, чтобы он запустил вашу программу на своем компьютере.
Но у некоторых компиляторов есть свой прикол: чтобы ваша программа работала на всех операционных системах и всех архитектурах процессоров, вам нужно скомпилировать ее для этих вещей. И это может быть не так удобно.
Интерпретируемые языки
Компилируемые языки намного упростили задачу написания кода. Но что, если я скажу, что можно написать программу, которая будет работать на всех архитектурах процессоров и любой операционной системе?
Вот тут в ход идут интерпретируемые языки программирования такие как: Python, PHP, Perl, Pascal и другие.
Это тоже языки высшего порядка, которые также упрощают написание кода. Но у них есть как минимум два преимущества перед компилируемыми языками:
Интерпретатор работает почти так же, как и компилятор, но с одной маленькой, но значительной особенностью: он преобразует код высшего порядка не в машинный код, а еще ниже — в байткод.
Байткод — это код, который понимают все процессоры не зависимо от архитектуры.
Конечно, в этом решении есть свой недостаток. В силу своей гибкости интерпретируемые языки подвержены низкой скорости работы из-за большего числа инструкций, которые генерирует интерпретатор. Но это напрямую зависит от того, насколько круто написан интерпретатор.
Подытожим
Байткод — саааамый низкий язык, который понимает процессор.
Машинный код — цепочка числовых команд. Все числовые команды процессора создают архитектуру процессора, заложенную инженерами при проектировании. У разных производителей процессоров могут отличаться номера одних и тех же команд.
Ассемблер — инструмент, который преобразует ассемблированный код в машинный. Программы на ассемблированном языке писать проще, чем машинный код, но все равно гемор.
Компилятор и Интерпретатор — инструменты, преобразующие код высшего уровня в код, понятный процессору.
Язык высшего уровня — это сказка, позволяющая создавать большие программы с помощью простых и понятных функций.
Я надеюсь, что теперь вы лучше представляете, как работает ваш компьютер или смартфон и будете терпеливее относится к их затупам 🙂 Ведь железка не виновата, что тупит, а виноват горе-программист, который написал плохой код.
Если вы с чем-то не согласны, у вас есть вопросы или просто хотите сказать спасибо — прошу в комментарии. Пообщаемся 🙂
Языки программирования: что это такое, зачем нужны и какой выбрать новичку
Разбираемся, как устроены языки программирования, почему их так много и чем они отличаются от алгоритмов.
Что такое язык программирования
Язык программирования — это набор формальных правил, по которым пишут программы. Обычный язык нужен для общения людей, а язык программирования — для общения с компьютером. Как и в любом естественном языке, тут есть лексика — слова, функции и операторы, из которых по правилам синтаксиса составляются выражения. Они имеют чёткий, вполне определённый смысл, понятный компьютеру, — семантику.
Вот, например, программа на языке JavaScript:
Здесь слово alert — лексика, один из принятых в языке методов обработки текста. Текст в одинарных кавычках, скобки, точка с запятой — правила синтаксиса. А то, что нужно сделать в итоге, — семантика. Получив эти инструкции, компьютер выведет на экран всплывающее окно с кнопкой и сообщением: «Это программа на JavaScript».
Фанат Free Software Foundation, использую Linux и недолюбливаю Windows. Пишу истории про кодинг и программы на Python. Влюблен в LISP, но пока что не умею на нем программировать.
Чем языки программирования отличаются от алгоритмов
Программы нужны для того, чтобы машина сделала что-то полезное. Это невозможно, если нет чёткого порядка действий и правил их выполнения — алгоритма.
Алгоритм работает как маршрут в навигаторе: «Из пункта А едем в пункт Б, поворот через 150 метров». Англичанин понимает его по-английски, китаец —
по-китайски, а мы с вами — по-русски. Языки разные, а порядок действий один и все должны добраться до нужного места.
Любая программа начинается с алгоритма, но на разных языках это может выглядеть по-разному. Например, вот эта — на языке С — проверяет, чтобы делитель не был нулём, а затем делит одно число на другое. Или пишет, что так делать нельзя.
То же самое, но на Python.
В программе на Python нет фигурных скобок и точек с запятой, но алгоритм и результат работы такой же, как у программы на C, да и слова похожи.
Перейти с одного языка программирования на другой легко: если знаешь Java — быстро начнёшь кодить, например, на Python или C#.
Как компьютер понимает разные языки программирования
На самом деле язык программирования — это не язык компьютера. Машина понимает последовательности нулей и единичек: есть напряжение в цепи — единица, нет — ноль. Поэтому любую программу сначала надо перевести в набор таких машинных команд.
Для этого есть два инструмента — компилятор и интерпретатор. Компилятор работает как бюро переводов: вы отдаёте ему весь текст программы, а он превращает его в исполняемый код, набор команд для процессора. Интерпретатор больше похож на переводчика-синхрониста: сказали фразу — синхронист тут же её перевёл, а компьютер выполнил.
Внутри компиляторов и интерпретаторов — сложные наборы правил по превращению языка программирования в машинный код, понятный компьютеру. Это тоже программы. Их пишут создатели нового языка — на каком-то другом, уже существующем. Например, интерпретатор Python написан на C, а сам C — на ассемблере, практически машинном коде.
Что такое библиотеки
Библиотеки — наборы функций, готовых шаблонов, написанных на каком-то из языков программирования. Это удобно и похоже на книги в обычной библиотеке: на них можно ссылаться внутри программ и сразу получать результат без необходимости каждый раз писать много кода.
Например, в Python есть модуль — библиотека yandex_translate, которая переводит тексты на разные языки. Программистам не надо создавать программу-переводчик с нуля, достаточно подключить этот модуль и обратиться к нему из любой точки кода.
На чём написаны языки программирования?)
языки программирования
На каких языках программирования сейчас в основном пишится весь софт
Языки программирования
Как вы считаете который из языков программирование легче и лучше изучать? Дельфи,С++ и т.д

У меня возник такой любительский вопрос. как создают языки программирования и как создали первый.

Всем привет! Решил изучать язык программирования, но вот какой? Какие то языки сдают позиции.
Это в итоге всем надоело. И поэтом умные дядьки придумали, что они будут писать на более понятном и им
синтаксисе. И когда они хотели в программе сложить A+B, вычесть из этого C, получив это в D, они стали писать на бумаге:
Mov AX,A
Add AX,B
Sub AX,C
Mov D,AX
Затем они отдавали это дело молодым, зелёным программистам-лаборантам, которые уже имея таблички команд, и опыт перевода из таблиц символов-чисел, чисел и команд непосредственно в 010111110, щелкали также тумблерами.
Таким образом, был придуман «живой» компилятор в ассемблер. Затем уже кто-то написал на живом ассемблере, программу, которая могла понимать «человеческие» текстовые команды, числа в десятичной системе и переводить это всё самостоятельно в машинный код. При этом кто-то придумал и «человеческие» терминалы в замен тумблера. И понеслось. Также в этих программах (компиляторы, интерпретаторы) была возможность вставлять команды и на языке ассмеблера).
Итог:
1-й компилятор был сделан из людей
2-й компилятор (читай,и-или интерпретатор, но тут не суть) был сделан уже с помощью 1-ого компилятора
3-й компилятор был доработан и допилен с помощью 2-ого компилятора
.
Добавлено через 11 минут
ошибка: следует читать » был придуман «живой» компилятор в машинный код.» а не в ассемблер.
Добавлено через 1 минуту
Ну и если пойти глубже в суть, то конечно, программа, которая переводит из ассеблера в машинный код, это не совсем компилятор. Это скорее всего просто переводчик, с синтаксическим разбором просто. ну т.е. очень тривиальный компилятор.
Как создать свой язык программирования: теория, инструменты и советы от практика
Авторизуйтесь
Как создать свой язык программирования: теория, инструменты и советы от практика
На протяжении последних шести месяцев я работал над созданием языка программирования (ЯП) под названием Pinecone. Я не рискну назвать его законченным, но использовать его уже можно — он содержит для этого достаточно элементов, таких как переменные, функции и пользовательские структуры данных. Если хотите ознакомиться с ним перед прочтением, предлагаю посетить официальную страницу и репозиторий на GitHub.
Введение
Я не эксперт. Когда я начал работу над этим проектом, я понятия не имел, что делаю, и всё еще не имею. Я никогда целенаправленно не изучал принципы создания языка — только прочитал некоторые материалы в Сети и даже в них не нашёл для себя почти ничего полезного.
Тем не менее, я написал абсолютно новый язык. И он работает. Наверное, я что-то делаю правильно.
В этой статье я постараюсь показать, каким образом Pinecone (и другие языки программирования) превращают исходный код в то, что многие считают магией. Также я уделю внимание ситуациям, в которых мне приходилось искать компромиссы, и поясню, почему я принял те решения, которые принял.
Текст точно не претендует на звание полноценного руководства по созданию языка программирования, но для любознательных будет хорошей отправной точкой.
Первые шаги
«А с чего вообще начинать?» — вопрос, который другие разработчики часто задают, узнав, что я пишу свой язык. В этой части постараюсь подробно на него ответить.
Компилируемый или интерпретируемый?
Компилятор анализирует программу целиком, превращает её в машинный код и сохраняет для последующего выполнения. Интерпретатор же разбирает и выполняет программу построчно в режиме реального времени.
Технически любой язык можно как компилировать, так и интерпретировать. Но для каждого языка один из методов подходит больше, чем другой, и выбор парадигмы на ранних этапах определяет дальнейшее проектирование. В общем смысле интерпретация отличается гибкостью, а компиляция обеспечивает высокую производительность, но это лишь верхушка крайне сложной темы.
Я хотел создать простой и при этом производительный язык, каких немного, поэтому с самого начала решил сделать Pinecone компилируемым. Тем не менее, интерпретатор у Pinecone тоже есть — первое время запуск был возможен только с его помощью, позже объясню, почему.
Прим. перев. Кстати, у нас есть краткий обзор серии статей по созданию собственного интерпретатора — это отличное упражнение для тех, кто изучает Python.
Выбор языка
Своеобразный мета-шаг: язык программирования сам является программой, которую надо написать на каком-то языке. Я выбрал C++ из-за производительности, большого набора функциональных возможностей, и просто потому что он мне нравится.
Но в целом совет можно дать такой:
Проектирование архитектуры
У структуры языка программирования есть несколько ступеней от исходного кода до исполняемого файла, на каждой из которых определенным образом происходит форматирование данных, а также функции для перехода между этими ступенями. Поговорим об этом подробнее.
Лексический анализатор / лексер
Строка исходного кода проходит через лексер и превращается в список токенов.
Первый шаг в большинстве ЯП — это лексический анализ. Говоря по-простому, он представляет собой разбиение текста на токены, то есть единицы языка: переменные, названия функций (идентификаторы), операторы, числа. Таким образом, подав лексеру на вход строку с исходным кодом, мы получим на выходе список всех токенов, которые в ней содержатся.
Обращения к исходному коду уже не будет происходить на следующих этапах, поэтому лексер должен выдать всю необходимую для них информацию.
При создании языка первым делом я написал лексер. Позже я изучил инструменты, которые могли бы сделать лексический анализ проще и уменьшить количество возникающих багов.
Одним из основных таких инструментов является Flex — генератор лексических анализаторов. Он принимает на вход файл с описанием грамматики языка, а потом создаёт программу на C, которая в свою очередь анализирует строку и выдаёт нужный результат.
Моё решение
Я решил оставить написанный мной анализатор. Особых преимуществ у Flex я в итоге не увидел, а его использование только создало бы дополнительные зависимости, усложняющие процесс сборки. К тому же, мой выбор обеспечивает больше гибкости — например, можно добавить к языку оператор без необходимости редактировать несколько файлов.
Синтаксический анализатор / парсер
Список токенов проходит через парсер и превращается в дерево.
Следующая стадия — парсер. Он преобразует исходный текст, то есть список токенов (с учётом скобок и порядка операций), в абстрактное синтаксическое дерево, которое позволяет структурно представить правила создаваемого языка. Сам по себе процесс можно назвать простым, но с увеличением количества языковых конструкций он сильно усложняется.
Bison
На этом шаге я также думал использовать стороннюю библиотеку, рассматривая Bison для генерации синтаксического анализатора. Он во многом похож на Flex — пользовательский файл с синтаксическими правилами структурируется с помощью программы на языке C. Но я снова отказался от средств автоматизации.
Преимущества кастомных программ
С лексером моё решение писать и использовать свой код (длиной около 200 строк) было довольно очевидным: я люблю задачки, а эта к тому же относительно тривиальная. С парсером другая история: сейчас длина кода для него — 750 строк, и это уже третья попытка (первые две были просто ужасны).
Тем не менее, я решил делать парсер сам. Вот основные причины:
В целесообразности решения меня убедило высказывание Уолтера Брайта (создателя языка D) в одной из его статей:
Я бы не советовал использовать генераторы лексических и синтаксических анализаторов, а также другие так называемые «компиляторы компиляторов». Написание лексера и парсера не займёт много времени, а использование генератора накрепко привяжет вас к нему в дальнейшей работе (что имеет значение при портировании компилятора на новую платформу). Кроме того, генераторы отличаются выдачей не релевантных сообщений об ошибках.
Абстрактный семантический граф
Переход от синтаксического дерева к семантическому графу
В этой части я реализовал структуру, по своей сути наиболее близкую к «промежуточному представлению» (intermediate representation) в LLVM. Существует небольшая, но важная разница между абстрактным синтаксическим деревом (АСД) и абстрактным семантическим графом (АСГ).
АСГ vs АСД
Грубо говоря, семантический граф — это синтаксическое дерево с контекстом. То есть, он содержит информацию наподобие какой тип возвращает функция или в каких местах используется одна и та же переменная. Из-за того, что графу нужно распознать и запомнить весь этот контекст, коду, который его генерирует, необходима поддержка в виде множества различных поясняющих таблиц.
Запуск
После того, как граф составлен, запуск программы становится довольно простой задачей. Каждый узел содержит реализацию функции, которая получает некоторые данные на вход, делает то, что запрограммировано (включая возможный вызов вспомогательных функций), и возвращает результат. Это — интерпретатор в действии.
Варианты компиляции
Вы, наверное, спросите, откуда взялся интерпретатор, если я изначально определил Pinecone как компилируемый язык. Дело в том, что компиляция гораздо сложнее, чем интерпретация — я уже упоминал ранее, что столкнулся с некоторыми проблемами на этом шаге.
Написать свой компилятор
Сначала мне понравилась эта мысль — я люблю делать вещи сам, к тому же давно хотел изучить язык ассемблера. Вот только создать с нуля кроссплатформенный компилятор — сложнее, чем написать машинный код для каждого элемента языка. Я счёл эту идею абсолютно не практичной и не стоящей затраченных ресурсов.
LLVM — это коллекция инструментов для компиляции, которой пользуются, например, разработчики Swift, Rust и Clang. Я решил остановиться на этом варианте, но опять не рассчитал сложности задачи, которую перед собой поставил. Для меня проблемой оказалось не освоение ассемблера, а работа с огромной многосоставной библиотекой.
Транспайлинг
Мне всё же нужно было какое-то решение, поэтому я написал то, что точно будет работать: транспайлер (transpiler) из Pinecone в C++ — он производит компиляцию по типу «исходный код в исходный код», а также добавил возможность автоматической компиляции вывода с GCC. Такой способ не является ни масштабируемым, ни кроссплатформенным, но на данный момент хотя бы работает почти для всех программ на Pinecone, это уже хорошо.
Дальнейшие планы
Сейчас мне не достаёт необходимой практики, но в будущем я собираюсь от начала и до конца реализовать компилятор Pinecone с помощью LLVM — инструмент мне нравится и руководства к нему хорошие. Пока что интерпретатора хватает для примитивных программ, а транспайлер справляется с более сложными.
Заключение
Надеюсь, эта статья окажется кому-нибудь полезной. Я крайне рекомендую хотя бы попробовать написать свой язык, несмотря на то, что придётся разбираться во множестве деталей реализации — это обучающий, развивающий и просто интересный эксперимент.
Вот общие советы от меня (разумеется, довольно субъективные):
Я делал довольно много ошибок по ходу разработки, но большую часть кода, на которую они могли повлиять, я уже переписал. Язык сейчас неплохо функционирует и будет развиваться (на момент написания статьи его можно было собрать на Linux и с переменным успехом на macOS, но не на Windows).
О том, что ввязался в историю с созданием Pinecone, ни в коем случае не жалею — это отличный эксперимент, и он только начался.






















