Бұл жазба автоматты түрде аударылған. Бастапқы тіл: Орысша
Бұл Tengri-Lang тілінің "капотының астына" қарайтын жаңа техникалық циклдің алғашқы мақаласы. Енді жоба GitHub-та ашық болғандықтан, біз оның практикалық іске асырылуының неден басталғанын егжей-тегжейлі көрсете аламыз. Бұл бөлімде біз компиляторымыздың алғашқы "шеберін" — Python-да енгізілген Лексерді талдаймыз.
Алдыңғы мақалаларда біз философия туралы көп айттық. Енді Код туралы сөйлесейік.
Go-да "жауынгерлік" компиляторды жасамас бұрын, біз идеяны тез тексеріп алуымыз керек еді. Машина негізінен біздің руникалық синтаксисті тани ала ма? Грамматикалық логика жұмыс істей ме? Мұндай тапсырмалар үшін Python-дан жақсы құрал жоқ. Ол бізге алғашқы "шебер" — "Тануши" (танушы) құруға мүмкіндік берді.
Оның жұмысы-сөйлемнің мағынасын толығымен зерттемей, жолды сырғытып, жеке сөздерді танитын оқырман сияқты.
Ең алдымен, біз жүйеде "танылған сөз" (токен) қандай болатынын анықтадық. Біз кодтың әр элементі туралы ақпаратқа арналған контейнер болып табылатын қарапайым Token класын жасадық.
- token.py:
Python
# token.py
class Token:
"""Кодтың бір" танылған " элементін сипаттайды."""
def __init__(self, type, value, line=1, column=1):
self.type = type # токен түрі (мысалы, 'Runa_Const', 'Identifier')
self.value = value # таңбалауыш мәні (мысалы,' Λ', 'san')
self.line = line # жол нөмірі
self.баған = баған # баған нөмірі
def __repr__(self):
"""Басып шығару кезінде әдемі таңбалауышты шығару әдісі."""
return f"Token({self.type}, '{self.value}')"
Әрбір таңбалауыштың түрі (түрі) және мәні (мәні) болады. Қарапайым және тиімді.
Енді — "танушының"өзі. Python-да оны Lexer класы ретінде енгізу өте ыңғайлы. Бұл сыныптың жүрегі-token_map сөздігі. Бұл сізге күрделі тексерулерсіз бірден кодтан таңбаны оның түріне сәйкестендіруге мүмкіндік береді.
- lexer.py (негізгі фрагменттер):
Python
# lexer.py
from token import Token
class Lexer:
""""Тануши" - танушы. Прототиптің соңғы нұсқасы."""
def __init__(self, source_code):
self.code = source_code
self.position = 0
# Бір таңбаны лезде тануға арналған толық сөздік
self.token_map = {
'Π': 'Runa_Func_Def', '—': 'Runa_Var',
'Λ': 'Runa_Const', 'Y': 'Runa_If',
'Q': 'Runa_True', 'I': 'Runa_False',
'↻': 'Runa_Loop', '→': 'Runa_Return',
# ... және т б барлық рундар мен операторлар үшін
}
Get_next_token негізгі әдісі ағымдағы таңбаны қарастырады және бірінші кезекте біздің сөздікте бар-жоғын тексереді. Егер солай болса, токен бірден жасалады.
Python
# get_next_token әдісінің үзіндісі lexer.py
def get_next_token(self):
# ... (Бос орындар мен түсініктемелерді өткізіп жіберу)
current_char = self.code[self.position]
# Бір таңбалар сөздігін тексеру
if current_char in self.token_map:
token_type = self.token_map[current_char]
token = Token(token_type, current_char)
self.position += 1
return token
# Егер таңба сөздікте болмаса, оның саны бар-жоғын тексеріңіз
if current_char.isdigit():
return self._read_number()
# Немесе бұл атау (идентификатор)болуы мүмкін
if current_char.isalpha():
identifier = self._read_identifier()
return Token('Identifier', identifier)
# ...
_read_identifier () әдісі таңбаларды әріптер немесе сандар болған кезде қатарынан оқиды және алынған сөзді қайтарады. Сондықтан tengri 5 жеке әріптен гөрі бір таңбалауыш ретінде танылады.
Python-дағы бұл қарапайым Лексер өзінің негізгі міндетін орындады: ол біздің руна және синтаксис жүйесінің өміршең екенін дәлелдеді. Ол біз оған жазған кодты дұрыс оқып, мағыналы бөліктерге бөле алды.
Осы растауды алғаннан кейін біз келесі деңгейге өту уақыты келгенін түсіндік. Нақты, жылдам және сенімді компилятор жасау үшін Сізге қолайлы құрал қажет болды. Сондықтан біздің тарихымыздағы келесі қадам осы дәлелденген логиканы "жауынгерлік" тілге — Go-ға көшіру болды.
Келесі мақалада біз компиляторымыздың жүрегімен танысамыз-тілдің барлық заңдылықтарын білетін" Құрастырушы " (талдаушы). Ол токендер ағынын алып, олардан керемет "ой Бәйтерегі" — ой Ағашын салады.
Бізбен бірге болыңыз және GitHub репозиторийін қараңыз!
Это первая статья из нового технического цикла, где мы заглянем «под капот» языка Tengri-Lang. Теперь, когда проект открыт на GitHub, мы можем в деталях показать, с чего начиналось его практическое воплощение. В этой части мы разберем самого первого «мастера» нашего компилятора — Лексер, реализованный на Python.
В предыдущих статьях мы много говорили о философии. Теперь давайте поговорим о коде.
Прежде чем браться за создание «боевого» компилятора на Go, нам нужно было быстро проверить саму идею. Сможет ли машина в принципе распознать наш рунический синтаксис? Будет ли логика грамматики работать? Для таких задач нет инструмента лучше, чем Python. Он позволил нам, не увязая в деталях, создать первого «мастера» — «Танушы» (Распознающего).
Его работа — как у чтеца, который скользит по строке и распознает отдельные слова, не вникая в смысл предложения целиком.
Прежде всего, мы определили, как будет выглядеть «распознанное слово» (токен) в нашей системе. Мы создали простой класс Token, который является контейнером для информации о каждом элементе кода.
- token.py:
Python
# token.py
class Token:
"""Описывает один 'распознанный' элемент кода."""
def __init__(self, type, value, line=1, column=1):
self.type = type # Тип токена (например, 'Runa_Const', 'Identifier')
self.value = value # Значение токена (например, 'Λ', 'san')
self.line = line # Номер строки
self.column = column # Номер колонки
def __repr__(self):
"""Метод для красивого вывода токена при печати."""
return f"Token({self.type}, '{self.value}')"
Каждый токен имеет тип (type) и значение (value). Просто и эффективно.
Теперь — сам «Танушы». В Python его очень удобно реализовать в виде класса Lexer. Сердце этого класса — словарь token_map. Он позволяет мгновенно, без сложных проверок, сопоставить символ из кода с его типом.
- lexer.py (ключевые фрагменты):
Python
# lexer.py
from token import Token
class Lexer:
"""«Танушы» — распознающий. Финальная версия прототипа."""
def __init__(self, source_code):
self.code = source_code
self.position = 0
# Полный словарь для мгновенного распознавания одиночных символов
self.token_map = {
'Π': 'Runa_Func_Def', '—': 'Runa_Var',
'Λ': 'Runa_Const', 'Y': 'Runa_If',
'Q': 'Runa_True', 'I': 'Runa_False',
'↻': 'Runa_Loop', '→': 'Runa_Return',
# ... и так далее для всех рун и операторов
}
Главный метод get_next_token смотрит на текущий символ и первым делом проверяет, есть ли он в нашем словаре. Если да — токен мгновенно создан.
Python
# фрагмент метода get_next_token в lexer.py
def get_next_token(self):
# ... (пропуск пробелов и комментариев)
current_char = self.code[self.position]
# Проверка по словарю одиночных символов
if current_char in self.token_map:
token_type = self.token_map[current_char]
token = Token(token_type, current_char)
self.position += 1
return token
# Если символ не в словаре, проверяем, не число ли это
if current_char.isdigit():
return self._read_number()
# Или, может быть, это имя (идентификатор)
if current_char.isalpha():
identifier = self._read_identifier()
return Token('Identifier', identifier)
# ...
Метод _read_identifier() просто читает символы подряд, пока они являются буквами или цифрами, и возвращает получившееся слово. Так tengri распознается как один токен, а не 5 отдельных букв.
Этот простой Лексер на Python выполнил свою главную задачу: он доказал, что наша система рун и синтаксиса жизнеспособна. Он смог правильно прочитать и разбить на осмысленные части код, который мы для него написали.
Получив это подтверждение, мы поняли, что пора переходить на следующий уровень. Для создания настоящего, быстрого и надежного компилятора нужен был более подходящий инструмент. Именно поэтому следующим шагом в нашей истории стал перенос этой выверенной логики на «боевой» язык — Go.
В следующей статье мы познакомимся с сердцем нашего компилятора — «Құрастырушы» (Парсером), который знает все законы языка. Именно он берет поток токенов и строит из них величественное «Ой Бәйтерегі» — Древо Мысли.
Оставайтесь с нами и заглядывайте в наш репозиторий на GitHub!