The post has been translated automatically. Original language: Russian Russian
This is the third part of our series on the creation of a new Kazakh programming language. In previous articles, we talked about his philosophy and created a runic alphabet for him.
So we have a concept and we have an alphabet full of deep images. But how can you make the soulless silicon of a computer understand that Λ is not just an icon, but an unshakable Mountain-a Constant? How can I teach him to read our runes?
This post is about how we created the "brain" of our language. About the three "masters" who breathe life into our code.
In computer science they are called Lexer, Parser and Interpreter, but in our philosophy they got their names: Tanusha, Kurastyrusha and Ike Asyrusha.
Imagine that our code is just a continuous stream of characters. The computer doesn't see any runes or names in it. The task of the first master, "Tanusha" (the Discerner), is to peer into this stream and recognize familiar images.
He doesn't try to understand the meaning of the sentence. It only identifies individual "words" — tokens or tokens.
- When he sees it, he says, "It's a Rune."_A variable."
- When he sees the san, he says, "This is the ID (name)."
- When he sees:, he says, "This is the Operator_Assignments".
- When he sees 10, he says, "This is an integer literal."
For example, a simple line of code:
— □ a : 10
"Tanusha" turns into a meaningful sequence of tokens:
[Runa_Var] [Runa_Type_Int] [Identifier: "a"] [Op_Assign: ":"] [IntegerLiteral: 10]
After its operation, instead of a chaos of symbols, we have a clear list of recognized elements. But how they are connected to each other, the system still does not know.
This is where the second master, "Kurastyrushy" (the Collector or Architect) comes into play. He takes a stream of tokens from Tanusha and checks if they match the grammar of our language.
He is the guardian of the laws.
He looks at the sequence [Runa_Var] [Runa_Type_Int] [Identifier] [Op_Assign] [IntegerLiteral] and says: "Yes, this corresponds to the rule "Variable declaration". That's right." If the order had been violated, Kurastyrushi would have reported an error.
The main result of his work is "Oh Bayteregi" (The Tree of Thought). In science, this is called an Abstract Syntax Tree (AST). It turns a flat list of tokens into a hierarchical, tree-like structure that reflects the logic of the program.
For the code
— □ c : a * (b + 2)
The Tree of Thought will look something like this, accurately reflecting the priority of operations (first addition in parentheses, then multiplication):
(Node: Variable Declaration, Name: "c")
|
|-- (Value: Binary Operation Node, Operator: '*')
|
|-- Left side: (Node: Variable Access, Name: "a")
|
|-- Right side: (Binary Operation Node, Operator: '+')
|
|-- Left part: (Node: Variable Access, Name: "b")
|-- Right part: (Node: Number, Value: 2)
Now we have not just words, but the perfect logical blueprint for our program.
We have a blueprint, but the house hasn't been built yet. Here the last master appears — "Ike Asyrusha" (Performer or Incarnator). His task is to take the "Tree of Thought" and bring it to life.
It traverses the Tree node by node and executes commands:
- After seeing the node of the exchange declaration, it allocates a cell in the computer's memory.
- After seeing the Binary Operation node, it performs a mathematical operation.
- When he sees the Output node (⁞), he gives the command to display the characters on the screen.
It is he who produces the final, visible result of our program.
These three masters—the Recognizer, the Architect, and the Embodier— are our compiler. It's an eternal cycle: to recognize symbols, to build a structure out of them, to execute this structure.
Now that you know how our language "thinks", in the next article we will finally show it in action. We will write our first full-fledged program using runic syntax, and see how it passes through the hands of all three masters to produce the final result.
Это третья часть нашего цикла о создании нового казахстанского языка программирования. В предыдущих статьях мы рассказали о его философии и создали для него рунический алфавит.
Итак, у нас есть концепция и есть алфавит, полный глубоких образов. Но как заставить бездушный кремний компьютера понять, что Λ — это не просто значок, а незыблемая Гора-Константа? Как научить его читать наши руны?
Этот пост — о том, как мы создавали «мозг» нашего языка. О трех «мастерах», которые вдыхают жизнь в наш код.
В компьютерной науке их называют Лексер, Парсер и Интерпретатор, но в нашей философии они получили свои имена: Танушы, Құрастырушы и Іске Асырушы.
Представьте, что наш код — это просто непрерывный поток символов. Компьютер не видит в нем ни рун, ни имен. Задача первого мастера, «Танушы» (Распознающего), — всмотреться в этот поток и распознать знакомые образы.
Он не пытается понять смысл предложения. Он лишь идентифицирует отдельные «слова» — лексемы или токены.
- Увидев —, он говорит: «Это Руна_Переменной».
- Увидев san, он говорит: «Это Идентификатор (имя)».
- Увидев :, он говорит: «Это Оператор_Присвоения».
- Увидев 10, он говорит: «Это Целочисленный_Литерал».
Например, простую строку кода:
— □ a : 10
«Танушы» превращает в осмысленную последовательность токенов:
[Runa_Var] [Runa_Type_Int] [Identifier: "a"] [Op_Assign: ":"] [IntegerLiteral: 10]
После его работы вместо хаоса символов у нас появляется четкий список распознанных элементов. Но как они связаны друг с другом, система все еще не знает.
Здесь в дело вступает второй мастер, «Құрастырушы» (Собирающий или Архитектор). Он берет поток токенов от «Танушы» и проверяет, соответствуют ли они грамматике нашего языка.
Он — хранитель законов.
Он смотрит на последовательность [Runa_Var] [Runa_Type_Int] [Identifier] [Op_Assign] [IntegerLiteral] и говорит: «Да, это соответствует правилу «Объявление переменной». Все верно». Если бы порядок был нарушен, «Құрастырушы» сообщил бы об ошибке.
Главный результат его работы — это «Ой Бәйтерегі» (Древо Мысли). В науке это называют Абстрактным Синтаксическим Деревом (AST). Он превращает плоский список токенов в иерархическую, древовидную структуру, которая отражает логику программы.
Для кода
— □ c : a * (b + 2)
Древо Мысли будет выглядеть примерно так, точно отражая приоритет операций (сначала сложение в скобках, потом умножение):
(Узел: ОбъявлениеПеременной, Имя: "c")
|
|-- (Значение: Узел_БинарнойОперации, Оператор: '*')
|
|-- Левая часть: (Узел: ДоступКПеременной, Имя: "a")
|
|-- Правая часть: (Узел_БинарнойОперации, Оператор: '+')
|
|-- Левая часть: (Узел: ДоступКПеременной, Имя: "b")
|-- Правая часть: (Узел: Число, Значение: 2)
Теперь у нас есть не просто слова, а идеальный логический чертеж нашей программы.
У нас есть чертеж, но дом еще не построен. Здесь появляется последний мастер — «Іске Асырушы» (Исполнитель или Воплощающий). Его задача — взять «Древо Мысли» и воплотить его в жизнь.
Он обходит Древо узел за узлом и выполняет команды:
- Увидев узел ОбъявлениеПеременной, он выделяет в памяти компьютера ячейку.
- Увидев узел БинарнаяОперация, он выполняет математическую операцию.
- Увидев узел Вывод (⁞), он отдает команду вывести символы на экран.
Именно он производит финальный, видимый результат работы нашей программы.
Эти три мастера — Распознающий, Архитектор и Воплощающий — и есть наш компилятор. Это вечный цикл: распознать символы, выстроить из них структуру, исполнить эту структуру.
Теперь, когда вы знаете, как «мыслит» наш язык, в следующей статье мы наконец-то покажем его в действии. Мы напишем нашу первую полноценную программу, используя рунический синтаксис, и посмотрим, как она пройдет через руки всех трех мастеров, чтобы выдать финальный результат.