Tw-city.info

IT Новости
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Как создать язык программирования с нуля

Как создать свой язык программирования: теория, инструменты и советы от практика

  • Переводы, 11 апреля 2017 в 21:59
  • Саша

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

Введение

Я не эксперт. Когда я начал работу над этим проектом, я понятия не имел, что делаю, и всё еще не имею. Я никогда целенаправленно не изучал принципы создания языка — только прочитал некоторые материалы в Сети и даже в них не нашёл для себя почти ничего полезного.

Тем не менее, я написал абсолютно новый язык. И он работает. Наверное, я что-то делаю правильно.

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

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

Первые шаги

«А с чего вообще начинать?» — вопрос, который другие разработчики часто задают, узнав, что я пишу свой язык. В этой части постараюсь подробно на него ответить.

Компилируемый или интерпретируемый?

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

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

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

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

Выбор языка

Своеобразный мета-шаг: язык программирования сам является программой, которую надо написать на каком-то языке. Я выбрал C++ из-за производительности, большого набора функциональных возможностей, и просто потому что он мне нравится.

Но в целом совет можно дать такой:

  • интерпретируемый ЯП крайне рекомендуетсяписать на компилируемом ЯП (C, C++, Swift). Иначе потери производительности будут расти как снежный ком, пока мета-интерпретатор интерпретирует ваш интерпретатор;
  • компилируемый ЯП можно писать на интерпретируемом ЯП (Python, JS). Возрастёт время компиляции, но не время выполнения программы.

Проектирование архитектуры

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

Лексический анализатор / лексер

Строка исходного кода проходит через лексер и превращается в список токенов.

Первый шаг в большинстве ЯП — это лексический анализ. Говоря по-простому, он представляет собой разбиение текста на токены, то есть единицы языка: переменные, названия функций (идентификаторы), операторы, числа. Таким образом, подав лексеру на вход строку с исходным кодом, мы получим на выходе список всех токенов, которые в ней содержатся.

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

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

Одним из основных таких инструментов является 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 — инструмент мне нравится и руководства к нему хорошие. Пока что интерпретатора хватает для примитивных программ, а транспайлер справляется с более сложными.

Заключение

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

Вот общие советы от меня (разумеется, довольно субъективные):

  • если у вас нет предпочтений и вы сомневаетесь, компилируемый или интерпретируемый писать язык, выбирайте второе. Интерпретируемые языки обычно проще проектировать, собирать и учить;
  • с лексерами и парсерами делайте, что хотите. Использование средств автоматизации зависит от вашего желания, опыта и конкретной ситуации;
  • если вы не готовы / не хотите тратить время и силы (много времени и сил) на придумывание собственной стратегии разработки ЯП, следуйте цепочке действий, описанной в этой статье. Я вложил в неё много усилий и она работает;
  • опять же, если не хватает времени / мотивации / опыта / желания или ещё чего-нибудь для написания классического ЯП, попробуйте написать эзотерический, типа Brainfuck. (Советуем помнить, что если язык написан развлечения ради, это не значит, что писать его — тоже сплошное развлечение. — прим. перев.)

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

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

Как создать язык программирования с нуля

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

Желание создать что-то своё и оставить след в истории посещает всех людей, в том числе программистов. Создание собственного языка программирования – это подходящая возможность. Мотивы бывают различные: от нечего делать, решения вечных проблем в других языках, разработка комфортного варианта для себя.

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

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

Изучение компьютера

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

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

Заранее определитесь с предназначением языка. Существует 2 основных направления – универсальный инструмент или узкоспециализированное решение.

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

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

Каких концепций будет придерживаться новый язык?

На этапе планирования следует ответить на ряд ключевых вопросов, они зададут направление развития:

  • интерпретация или компиляция? Код для компилирования будет преобразовываться в машинный, затем исполняться. При использовании интерпретатора код обрабатывается построчно. На вопрос нет правильного ответа, перед разработчиком стоит сложный выбор, в какую сторону уклон делать: функциональность, безопасность, скорость работы, удобство и т. д.;
  • типизация? Если да, то разработчику будет необходимо вручную устанавливать типы данных. В противном случае придётся описывать систему, которая будет определять типы;
  • в языке будет встроен автоматический алгоритм очистки мусора или управление отдать в руки пользователя?
  • планируемая модель языка программирования: структурное, ООП, функциональная логика. Кто знает, может вам удастся разработать что-то совсем иное;
  • как язык будет себя вести в отношении конкурентов, вставка из других языков планируется? Учитывать этот аспект важно при изначальной разработке языка;
  • планируется поддержка базового функционала языка или передать все функции на сторону фреймворков?
  • какой ожидается конечный вид архитектуры программы?

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

Придумайте синтаксис для языка

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

При этом синтаксис может быть каким вы только сами захотите. К примеру, существует язык от отечественных разработчиков, который называется YoptaScript . Он имеет очень забавный синтаксис и писать программы на нем приносит лишь смех 🙂

PS: этот язык является лишь шуткой и его не стоит воспринимать как реальный язык. Посмотреть язык вы можете на их официальном сайте .

Назовите ваше детище

Вопрос с одной стороны простой, с другой – нет. Многие разработчики не выбирают глубокое и замысловатое название, отдают предпочтение простоте и лёгкости запоминания. Особенно эффективно давать имя языку с явной ассоциацией, чтобы потенциальный пользователь запоминал название после первого-второго произнесения. Сложные аббревиатуры и названия из 3 и больше слов – сложно запоминаются и быстро теряются в памяти. Имя должно быть относительно коротким и запоминающимся.

Выберите фундамент языка

Выбор языка, который будет взят за основу – это важнейший шаг. Если знаний достаточно, можно писать на ассемблере или даже машинном коде, но в современном мире лучше присмотреться к другим высокоуровневым языкам: C, C++ , Swift , Pascal и другие компилируемые варианты пригодные для интерпретируемых решений. В качестве достойных языков с интерпретаторами стоит присмотреться к: Java , JavaScript , Ruby, Python – для компиляторов. Перечисленные пары снизят потерю скорости работы.

Лексер и парсер

Лексер – это инструмент для анализа лексики, деления написанного кода на отдельные элементы, их называют токены. Далее вступает в работы парсер для синтаксического анализа, его роль – организация иерархии с учётом токенов, он восстанавливает цепь событий. В качестве графического примера рассмотрим простую схему:

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

Создание основной библиотеки

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

Создание и написание тестов

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

Выпуск языка в свет

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

Обучение программированию с нуля: с чего начать изучение в домашних условиях

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

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

Что нужно знать «чайнику»

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

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

Многие начинающие обучение считают написание кода чуть ли не самой романтической профессией. Особенно увеличилось количество желающих познать программирование после просмотра фильма « Матрица ». Именно главный герой этой картины Нео подтолкнул многих к становлению на путь постижения программных наук:

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

Особенности обучения программированию на постсоветском пространстве

После развала СССР все отечественные ВУЗы долгое время даже и не пытались перекроить свою систему обучения под потребности современного рынка. Не являлись исключением из этого правила и технические ВУЗы.

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

Ситуация кардинально не изменилась и через 10 лет. Лишь некоторые учебные заведения, учуяв веяния нового времени, в начале двухтысячных года начали перекраивать свое обучение под мировые стандарты. И только с этого момента программирование стало восприниматься как отдельная профессия и специализация обучения:

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

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

В некоторой мере такая тенденция сохраняется и по сей день. Хотя в наше время количество профессионалов, занимающихся преподаванием, заметно возросло.

С какого языка начать изучать программирование

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

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

Чаще всего выбор падает на язык программирования C ( си) . Именно с него большинство новичков во всем мире начинают свое обучение. На основе C было создана основная часть программных языков, и во многом они наследуют его структуру и синтаксис.


Рассмотрим особенности этого языка, делающего его оптимальным для изучения:

  • Простая для понимания основа – часть встроенных возможностей языка для простоты вынесена в отдельно подключаемые библиотеки. К таким элементам относится большая часть математических функций и методов для работы с файловой системой;
  • Оптимально подогнанная система типов – благодаря простому набору типов данных и строгой типизации уменьшается риск допущения ошибок в процессе написания программного кода;
  • Направленность C на процедурный тип программирования, при котором соблюдается четкая иерархия всех элементов кода;
  • Доступ к памяти машины с помощью указателей;
  • Минимальное количество поддерживаемых ключевых слов;
  • Поддержка области действия имен;
  • Поддержка пользовательских типов данных ( объединения и структуры ).

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

Программы (компиляторы) для программирования

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

Вот несколько специализированных компиляторов с поддержкой языка C:

  • Microsoft Visual Studio – профессиональный инструмент, поддерживающий множество языков, в том числе и несколько серверных. Подойдет для новичков, если брать его «на вырост»:

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

  • Code::Blocks – бесплатная среда разработки, поддерживающая написание кода на нескольких языках. Средний по сложности освоения вариант:


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

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

Тенденции на рынке программирования

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

  • Веб-программирование – здесь понадобятся знания PHP , CSS и HTML ;
  • Разработка приложений под мобильную операционную систему Android – данная платформа построена на основе Java . Поэтому потребуется знание основ этого языка;
  • C# (си sharp) – дальний потомок C . На основе C# построена веб-технология ASP.net от Microsoft .


И последний совет всем начинающим. Перед тем, как приступить к обучению программированию с нуля, следует запастить терпением. А также: таблетками от головной боли, кофе, чаем и побрить череп наголо. Потому что во время постижения программных наук, обучающиеся часто вырывают волосы со своей головы вместе с корнем. Удачного старта!

Дмитpий Hecтepук

Блог о программировании — C#, F#, C++, архитектура, и многое другое

Не нравится ООП? Делайте свой язык программирования!

В интернете нынче модно говорить что «ООП это шлак», и многие мечтают сделать свой собственный язык программирования но чего-то боятся. А на самом деле, если подойти с умом, тут все просто. Серьезно! Я знаю, вы хотите мне возразить, что дескать…

Писать свой компилятор в native code/IL/bytecode слишком сложно — а и не надо!! Вы понимаете, что существующие компиляторы вроде С или Java оттачивались годами, сотнями людей? Почему бы не воспользоваться всем этим богатством, компилируя ваш язык в тот же С/C++, и потом получая от С/C++ компилятора все оптимизации и плюшки?

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

У меня сейчас весь код на Java/C#/C++ написан, как я сделаю interop? — да очень просто, ведь с подходом транскомпиляции, вы можете транслировать свой язык в любой из вышеперечисленных, генеря и потом потребляя любой интерфейс, причем в обе стороны.

Язык-то я сделаю, а как насчет поддержки языка в моей любимой IDE? — о, ну это уже высший полет. Для начала, постарайтесь сделать лаконичный маленький язык, для которого инструменты не критичны. А потом можно научиться и тулы поддерживать (или писать свои).

Чтобы показать насколько это все просто, вот небольшой пример: представим, что вы хотите расширить определение С-образной глобальной функции, добавив следующие фичи:

Определить свой набор «коротких» типов переменных, вроде i32 или f64 на замену int и double .

Передавать аргументы в формате x,y : i32 , то есть переиспользуя определение типа для нескольких сразу.

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

Для начала такой фичесет подойдет? Я знаю что мало, но я тут и не пытаюсь целый язык сделать. Вот как это будет выглядеть:

Структуры для языка

Во всех языках есть механизмы построения парсеров. Я возьму C++ и Boost.Spirit, для примера, но вообще язык тут особого значения не имеет. Для начала давайте сделаем новые типы вроде f32 вместо float :

Теперь определяем функцию:

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

Поскольку мы умеем определять аргументы в стиле x,y:i32 , т.е. несколько с одним типом, собственно структур parameter мы определим вот так:

Ну и наконец присвоение значений переменным можно сделать вот так:

Выше показан г~код для определения типа, думаю вы понимаете что в последствии это можно пофиксить.

Всё, структуры готовы, можно строить парсер. (На самом деле есть еще этап их адаптации через Boost.Fusion, но это implementation-specific деталь, если что гляньте в сорцы.)

Парсер

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

Для начала, вот эти qi::rule просто говорят парсеру как то что он распарсит ложится на структуры что мы определили ранее. Например, вот хочется распарсить присваивание вроде x = 3 , что это? Это идентификатор (то есть, 1 и более alphanumeric символов), потом = , потом еще раз набор символов и в конце ; .

Конкретно в Boost.Sprit, в отличии от регулярок, «один и более» записывается как + до типа символа, т.е. +alnum . То есть + означает «один и более», * — «сколько угодно», и так далее. Вот и получается что присваивание мы распарсили, а поскольку наш qi::rule мэпит его на assignment_statement , поля этой структуры будут присвоены автоматически. Это гениально, или как?

То же и с другими частями языка. Хочешь распарсить несколько переменных через запятую и запихнуть их в вектор? Пишем +alnum % ‘,’ где оператор % – это как сказать *(+alnum >> ‘,’) , только короче. Что тоже удобно.

Так вот, парсер у нас готов, можно парсить. На Spirit это делается вот так:

…где render() – это функция которая обходит то что мы напарсили и генерит из этого чистейший, готовый к компиляции С (никто не мешает вам выводить сразу в N разных языков).

Pretty print

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

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

А потом, аккуратненько, присваивания. Не забываем что тип нужно прописывать только если переменная не фигурирует где-то в параметрах функции:

Вот собственно и всё. Тут в принципе можно реализовать «полноценный» Visitor, если хочется.

Заключение

Как вы поняли, тут остался шаг компиляции полученного кода — думаю всем итак очевидно как это делать, это зависит от языка который вы нагенерили. Вообще я ратую за «портативный» C/C++, но решать в конечном счете вам.

Если хотите сорцы проекта, они тут. Мой пример на С++, но вы можете реализовать свой язык на чем угодно. Мораль в том что создать сейчас свой кросс-компилируемый язык легко, поэтому вместо того чтобы ныть про ООП и воевать с ветряными мельницами, проще сесть и запилить что-то своё. Так что садитесь и пишите спеку вашего чудо-юдо языка. Удачи!

Как создать язык программирования с нуля

Репозиторий проекта: https://github.com/aNNiMON/Own-Programming-Language-Tutorial
Плейлист на YouTube: https://www.youtube.com/playli…soWX0qTeQ9_-MFBE552C

#1. Заготовка, калькулятор

#1. Заготовка, калькулятор

#2. Вещественные числа, константы

#2. Вещественные числа, константы

#3. Оператор присвоения, переменные

#3. Оператор присвоения, переменные

#4. Строки, оператор print

#4. Строки, оператор print

#5. Логические выражения, if/else

#5. Логические выражения, if/else

#6. Улучшаем логические выражения и лексер

#6. Улучшаем логические выражения и лексер

#7. Циклы, блок операторов

#7. Циклы, блок операторов

#8. break, continue, цикл do/while

#8. break, continue, цикл do/while

#10. Пользовательские функции

#10. Пользовательские функции

#11. Одномерные массивы

#11. Одномерные массивы

11 шагов к созданию языка программирования

#12. Многомерные массивы

#13. Шаблон проектирования «Посетитель» (Visitor)

#13. Шаблон проектирования «Посетитель» (Visitor)

Программируем на OwnLang

#14. Программируем на OwnLang

Также прикрепляю плагин OwnLang для Netbeans. Для установки заходим в меню Tools -> Plugins -> вкладка Downloaded -> Add Plugins и выбираем nbm файл.
com-annimon-ownlang.nbm

Как создать свой язык программирования: теория, инструменты и советы от практика

Желание создать что-то своё и оставить след в истории посещает всех людей, в том числе программистов. Создание собственного языка программирования – это подходящая возможность. Мотивы бывают различные: от нечего делать, решения вечных проблем в других языках, разработка комфортного варианта для себя.

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

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

Изучение компьютера

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

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

Заранее определитесь с предназначением языка. Существует 2 основных направления – универсальный инструмент или узкоспециализированное решение.

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

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

Каких концепций будет придерживаться новый язык?

На этапе планирования следует ответить на ряд ключевых вопросов, они зададут направление развития:

  • интерпретация или компиляция? Код для компилирования будет преобразовываться в машинный, затем исполняться. При использовании интерпретатора код обрабатывается построчно. На вопрос нет правильного ответа, перед разработчиком стоит сложный выбор, в какую сторону уклон делать: функциональность, безопасность, скорость работы, удобство и т. д.;
  • типизация? Если да, то разработчику будет необходимо вручную устанавливать типы данных. В противном случае придётся описывать систему, которая будет определять типы;
  • в языке будет встроен автоматический алгоритм очистки мусора или управление отдать в руки пользователя?
  • планируемая модель языка программирования: структурное, ООП, функциональная логика. Кто знает, может вам удастся разработать что-то совсем иное;
  • как язык будет себя вести в отношении конкурентов, вставка из других языков планируется? Учитывать этот аспект важно при изначальной разработке языка;
  • планируется поддержка базового функционала языка или передать все функции на сторону фреймворков?
  • какой ожидается конечный вид архитектуры программы?

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

Придумайте синтаксис для языка

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

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

PS: этот язык является лишь шуткой и его не стоит воспринимать как реальный язык. Посмотреть язык вы можете на их .

Назовите ваше детище

Вопрос с одной стороны простой, с другой – нет. Многие разработчики не выбирают глубокое и замысловатое название, отдают предпочтение простоте и лёгкости запоминания. Особенно эффективно давать имя языку с явной ассоциацией, чтобы потенциальный пользователь запоминал название после первого-второго произнесения. Сложные аббревиатуры и названия из 3 и больше слов – сложно запоминаются и быстро теряются в памяти. Имя должно быть относительно коротким и запоминающимся.

Выберите фундамент языка

Выбор языка, который будет взят за основу – это важнейший шаг. Если знаний достаточно, можно писать на ассемблере или даже машинном коде, но в современном мире лучше присмотреться к другим высокоуровневым языкам: C, , , Pascal и другие компилируемые варианты пригодные для интерпретируемых решений. В качестве достойных языков с интерпретаторами стоит присмотреться к: , , Ruby, – для компиляторов. Перечисленные пары снизят потерю скорости работы.

Лексер и парсер

Лексер – это инструмент для анализа лексики, деления написанного кода на отдельные элементы, их называют токены. Далее вступает в работы парсер для синтаксического анализа, его роль – организация иерархии с учётом токенов, он восстанавливает цепь событий. В качестве графического примера рассмотрим простую схему:

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

Приложения упростят выполнение сложного этапа работы.

Создание основной библиотеки

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

Создание и написание тестов

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

Выпуск языка в свет

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

Читать еще:  Знак не равно в программировании
Ссылка на основную публикацию
Adblock
detector