Простой анализатор выражений
Создайте анализатор арифметических выражений методом рекурсивного спуска на чистом Lua.
«Простой анализатор выражений» — бесплатный урок Lua Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Lua Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Lua Academy содержит 4 уроков всего.
Цель: разбор арифметических выражений
Создайте парсер с рекурсивным спуском на чистом Lua, который разбирает и вычисляет выражения вроде 3 + 4 * (2 - 1), соблюдая приоритет операторов.
Токенизация
Сначала разбейте входные данные на числа, операторы и круглые скобки.
local function tokenize(expr)
local tokens = {}
for tok in expr:gmatch("[%d%.]+|[%+%-%*/%(%)%^]|%S") do
tokens[#tokens+1] = tok
end
return tokens
endУлучшенный токенизатор
Более надёжный токенизатор с использованием шаблонов gmatch.
local function tokenize(expr)
local tokens = {}
for tok in expr:gmatch("%d+%.?%d*|[%+%-%*/%(%)%^]") do
tokens[#tokens+1] = tok
end
return tokens
endСостояние парсера
Парсер хранит список токенов и позицию. Вспомогательные функции peek и consume перемещаются по токенам.
local function newParser(tokens)
local pos = 1
local function peek() return tokens[pos] end
local function consume() pos = pos + 1; return tokens[pos-1] end
return {peek=peek, consume=consume}
endГрамматика выражений
Грамматика соблюдает приоритет:
- выражение = член ((+ | -) член)*
- член = множитель ((* | /) множитель)*
- множитель = число | (выражение) | -множитель
Разбор членов выражения
Разбирайте выражения сложения и вычитания, разбирая члены и последовательно слева направо объединяя результаты операций + и -.
local parseExpr, parseTerm, parseFactor
parseExpr = function(p)
local val = parseTerm(p)
while p.peek() == "+" or p.peek() == "-" do
local op = p.consume()
local right = parseTerm(p)
if op == "+" then val = val + right
else val = val - right end
end
return val
endРазбор множителей
Разбирайте выражения умножения, включая возведение в степень.
parseTerm = function(p)
local val = parseFactor(p)
while p.peek() == "*" or p.peek() == "/" do
local op = p.consume()
local right = parseFactor(p)
if op == "*" then val = val * right
else val = val / right end
end
return val
endРазбор чисел и скобок
Разбирайте атомарные элементы: литералы, подвыражения в скобках и унарное отрицание.
parseFactor = function(p)
local tok = p.peek()
if tok == "(" then
p.consume() -- (
local val = parseExpr(p)
p.consume() -- )
return val
elseif tok == "-" then
p.consume()
return -parseFactor(p)
else
return tonumber(p.consume())
end
endСобираем всё вместе
Выполните токенизацию, разберите и вычислите выражение.
local function eval(expr)
local tokens = tokenize(expr)
local parser = newParser(tokens)
return parseExpr(parser)
end
print(eval("3 + 4 * 2")) -- 11
print(eval("(3 + 4) * 2")) -- 14
print(eval("2 ^ 10")) -- 1024 (if ^ is supported)Расширение парсера
Добавляйте переменные, функции, операторы сравнения и строковые литералы, расширяя грамматику и добавляя новые варианты в parseFactor.
Вывод сообщений об ошибках
Отслеживайте номер строки и столбца в токенизаторе. Выдавайте понятные ошибки: "Expected ')' at position 7, got '+'".
Генераторы парсеров
Для сложных грамматик используйте генераторы парсеров, например LPEG (грамматики разбора выражений). LPEG гораздо мощнее и выразительнее написанного вручную рекурсивного спуска при работе с большими грамматиками.
Вопрос о парсере
Что использует парсер с рекурсивным спуском для обеспечения приоритета операторов?
Итоги: простой парсер выражений
Парсер с рекурсивным спуском использует одну функцию для каждого правила грамматики, естественным образом обеспечивая приоритет операторов за счёт иерархии вызовов. Сначала выполните токенизацию, затем реализуйте функции выражение → член → множитель. Расширьте его переменными и функциями, чтобы получить полноценный язык выражений.
Часто задаваемые вопросы
Урок «Простой анализатор выражений» бесплатный?
Да — полный текст урока «Простой анализатор выражений» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Lua Academy, подпишись на CoddyKit PRO. Курс Lua Academy содержит 4 уроков всего.
Чему я научусь в уроке «Простой анализатор выражений»?
Создайте анализатор арифметических выражений методом рекурсивного спуска на чистом Lua. Ты практикуешь Lua Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Lua Academy?
Предыдущий опыт не требуется. Lua Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Простой анализатор выражений»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Lua Academy?
Да. Каждый урок Lua Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Принципы проектирования DSL в Lua
- Перегрузка операторов для удобной работы с DSL
- Создание DSL конфигурации
- Простой анализатор выражений