0Pricing
Lua Academy · Lekcja

Prosty parser wyrażeń

Proszę zbudować parser rekurencyjnego zejścia dla wyrażeń arytmetycznych w czystym Lua.

Prosty parser wyrażeń to bezpłatna lekcja Lua Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Lua Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Lua Academy zawiera 4 lekcji w sumie.

Cel: parsowanie wyrażeń arytmetycznych

Należy zbudować w czystym Lua parser rekurencyjnego zejścia, który parsuje i oblicza wyrażenia takie jak 3 + 4 * (2 - 1), z uwzględnieniem priorytetu operatorów.

Tokenizator

Najpierw należy podzielić dane wejściowe na tokeny reprezentujące liczby, operatory i nawiasy.

local function tokenize(expr)
  local tokens = {}
  for tok in expr:gmatch("[%d%.]+|[%+%-%*/%(%)%^]|%S") do
    tokens[#tokens+1] = tok
  end
  return tokens
end

Ulepszony tokenizator

Bardziej niezawodny tokenizator korzystający ze wzorców gmatch.

local function tokenize(expr)
  local tokens = {}
  for tok in expr:gmatch("%d+%.?%d*|[%+%-%*/%(%)%^]") do
    tokens[#tokens+1] = tok
  end
  return tokens
end

Stan parsera

Parser przechowuje listę tokenów i pozycję. Funkcje pomocnicze peek i consume przesuwają się po tokenach.

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

Gramatyka wyrażeń

Gramatyka uwzględnia priorytet operatorów:

  • expr = term ((+ | -) term)*
  • term = factor ((* | /) factor)*
  • factor = number | (expr) | -factor

Parsowanie składników

Wyrażenia addytywne należy parsować przez parsowanie składników i składanie operatorów +/- od lewej do prawej.

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

Parsowanie czynników

Należy parsować wyrażenia multiplikatywne, w tym potęgowanie.

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

Parsowanie liczb i nawiasów

Należy parsować atomy: literały, podwyrażenia w nawiasach i negację jednoargumentową.

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

Połączenie elementów

Należy podzielić wyrażenie na tokeny, sparsować je i obliczyć jego wartość.

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)

Rozszerzanie parsera

Należy dodać zmienne, funkcje, operatory porównania i literały łańcuchów, rozszerzając gramatykę oraz dodając nowe przypadki do parseFactor.

Zgłaszanie błędów

W tokenizatorze należy śledzić wiersz i kolumnę. Należy zgłaszać zrozumiałe błędy: "Expected ')' at position 7, got '+'".

Generatory parserów

W przypadku złożonych gramatyk należy używać generatorów parserów, takich jak LPEG (gramatyki wyrażeń parsowania). LPEG jest znacznie bardziej zaawansowany i ekspresywny niż ręcznie napisany parser rekurencyjnego zejścia w przypadku dużych gramatyk.

Pytanie o parser

Czego używa parser rekurencyjnego zejścia, aby wymusić priorytet operatorów?

Podsumowanie: prosty parser wyrażeń

Parser rekurencyjnego zejścia używa jednej funkcji dla każdej reguły gramatycznej, naturalnie wymuszając priorytet operatorów poprzez hierarchię wywołań. Najpierw należy podzielić dane na tokeny, a następnie zaimplementować funkcje expr → term → factor. Aby uzyskać pełny język wyrażeń, można rozszerzyć parser o zmienne i funkcje.

Często zadawane pytania

Czy lekcja „Prosty parser wyrażeń” jest bezpłatna?

Tak — pełny tekst „Prosty parser wyrażeń” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Lua Academy, przejdź na CoddyKit PRO. Kurs Lua Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Prosty parser wyrażeń”?

Proszę zbudować parser rekurencyjnego zejścia dla wyrażeń arytmetycznych w czystym Lua. Ćwiczysz Lua Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Lua Academy?

Nie wymagamy żadnego doświadczenia. Lua Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „Prosty parser wyrażeń”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Lua Academy?

Tak. Każda lekcja Lua Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Zasady projektowania DSL w Lua
  2. Przeciążanie operatorów na potrzeby płynnego DSL
  3. Tworzenie DSL konfiguracji
  4. Prosty parser wyrażeń
← Powrót do Lua Academy