Напиши интерпретатор за малък език с ключови думи на български: от разпознаване на думите в текста, през синтактично дърво, до функции и рекурсия. Накрая има и собствена виртуална машина. Без готови парсери и без генератори на парсери.
Ето как изглежда програма на него. Синтаксисът е предложение, можеш да го промениш, стига да е последователен.
функция оценка(точки, общо) { върни 2 + точки / общо * 4 } нека о = оценка(13, 20) покажи "Оценка: " + о ако о >= 5.5 { покажи "Отличен" } иначе ако о >= 4.5 { покажи "Много добър" } иначе { покажи "Продължавай да учиш" }
Изход:
Оценка: 4.6 Много добър
Програмата се пуска така: dotnet run -- programa.bg. Без файл се отваря интерактивен режим (REPL).
git commit..bg плюс файл с очаквания изход.Превръща текста в поредица от токени: числа, низове, идентификатори (на кирилица!), ключови думи, оператори и скоби. Всеки токен помни реда и колоната, на които е намерен.
нека x = 2.5 * (y + 1) → [НЕКА] [ИДЕНТ x] [=] [ЧИСЛО 2.5] [*] [(] [ИДЕНТ y] [+] [ЧИСЛО 1] [)]
>= е един токен, а не два. Как лексерът разбира това?# до края на реда.Готово, когато: низ без затварящи кавички дава грешка с ред и колона, а не срив.
Парсер с рекурсивно спускане, който строи синтактично дърво, и оценител, който го обхожда. Първо запиши граматиката на хартия, после я превърни в код: по един метод за всяко ниво на приоритет.
| Вход | Изход | Какво проверява |
|---|---|---|
покажи 2 + 3 * 4 | 14 | приоритет |
покажи (2 + 3) * 4 | 20 | скоби |
покажи 7 / 2 | 3.5 | числата са реални |
покажи 10 - 4 - 3 | 3 | лява асоциативност |
покажи 2 ^ 3 ^ 2 | 512 | степента е дясно асоциативна |
покажи -2 ^ 2 | ? | реши сама и го защити: -4 или 4? |
Готово, когато: има команда --дърво, която отпечатва синтактичното дърво на израз. Ще ти трябва за отстраняване на грешки.
нека декларира, а = присвоява на вече декларирана променлива.+ за слепване, логически оператори и, или, не.ако / иначе ако / иначе и докато.нека сума = 0
нека i = 1
докато i <= 100 {
сума = сума + i
i = i + 1
}
покажи сума # 5050
Готово, когато: програмата за оценки от горе тръгва, в началото без функцията.
функция факт(n) {
ако n <= 1 { върни 1 }
върни n * факт(n - 1)
}
покажи факт(10) # 3628800
функция фиб(n) {
ако n < 2 { върни n }
върни фиб(n - 1) + фиб(n - 2)
}
покажи фиб(20) # 6765
нека x = 1
функция f() {
нека x = 2
покажи x # 2
}
f()
покажи x # 1
върни от дълбоко в цикъл или вложено ако? Има поне два начина. Сравни ги.StackOverflowException, който не може да се прихване.Добрият език се познава по съобщенията за грешка.
> покажи 2 + * 3
Грешка на ред 1, колона 12: очаквах израз, намерих '*'
покажи 2 + * 3
^
> покажи у + 1
Грешка на ред 1: непозната променлива 'у'
> покажи 5 / 0
Грешка на ред 1: деление на нула
Капан: у на кирилица и y на латиница изглеждат еднакво. Ще предупреди ли езикът ти?
Готово, когато: 20 програми с грешки дават 20 разбираеми съобщения и нито един срив.
Интерпретаторът обхожда дървото, а истинските езици (C#, Java, Python) правят друго: превеждат програмата в байткод, прост списък от инструкции за стекова машина.
2 + 3 * 4 → PUSH 2
PUSH 3
PUSH 4
MUL
ADD
PRINT
ако и докато стават инструкции за скок.Stopwatch колко време отнема фиб(25) (резултат 75025) с интерпретатора и с машината. Колко пъти е по-бърза машината и защо?--байткод, който показва инструкциите, в които се превежда програмата.Съучениците ти в момента пишат машинка за оценки на JavaScript. Покажи им същата програма на език, който си написала сама, и дървото ѝ с --дърво. Десет минути, без слайдове, само терминал. Това е и добра тренировка за защитата пред журито.
10 - 4 - 3 и 2 ^ 3 ^ 2 се групират по различен начин? Как се вижда това в граматиката ти?фиб(25)?