Предизвикателство 2 · C# · .NET

Собствен език за програмиране

Напиши интерпретатор за малък език с ключови думи на български: от разпознаване на думите в текста, през синтактично дърво, до функции и рекурсия. Накрая има и собствена виртуална машина. Без готови парсери и без генератори на парсери.

ЗащоВсеки език, който ползваш (C#, JavaScript, SQL), минава през същите стъпки. След тази задача няма да изглеждат като магия.
Какво тренираРекурсия, дървета, граматики, области на видимост, обработка на грешки. Това е теорията, която липсва на повечето самоуки.
Как ще разбереш, че е готовоПрограмата за оценки от часа тръгва на твоя език и дава същия резултат.

Езикът

Ето как изглежда програма на него. Синтаксисът е предложение, можеш да го промениш, стига да е последователен.

функция оценка(точки, общо) {
    върни 2 + точки / общо * 4
}

нека о = оценка(13, 20)
покажи "Оценка: " + о

ако о >= 5.5 {
    покажи "Отличен"
} иначе ако о >= 4.5 {
    покажи "Много добър"
} иначе {
    покажи "Продължавай да учиш"
}

Изход:

Оценка: 4.6
Много добър

Програмата се пуска така: dotnet run -- programa.bg. Без файл се отваря интерактивен режим (REPL).

Правила на играта

Етапи

1

Лексер: от текст към думи

Превръща текста в поредица от токени: числа, низове, идентификатори (на кирилица!), ключови думи, оператори и скоби. Всеки токен помни реда и колоната, на които е намерен.

нека x = 2.5 * (y + 1)
→ [НЕКА] [ИДЕНТ x] [=] [ЧИСЛО 2.5] [*] [(] [ИДЕНТ y] [+] [ЧИСЛО 1] [)]

Готово, когато: низ без затварящи кавички дава грешка с ред и колона, а не срив.

2

Изрази: калкулатор с правилен приоритет

Парсер с рекурсивно спускане, който строи синтактично дърво, и оценител, който го обхожда. Първо запиши граматиката на хартия, после я превърни в код: по един метод за всяко ниво на приоритет.

ВходИзходКакво проверява
покажи 2 + 3 * 414приоритет
покажи (2 + 3) * 420скоби
покажи 7 / 23.5числата са реални
покажи 10 - 4 - 33лява асоциативност
покажи 2 ^ 3 ^ 2512степента е дясно асоциативна
покажи -2 ^ 2?реши сама и го защити: -4 или 4?

Готово, когато: има команда --дърво, която отпечатва синтактичното дърво на израз. Ще ти трябва за отстраняване на грешки.

3

Променливи, условия, цикли

нека сума = 0
нека i = 1
докато i <= 100 {
    сума = сума + i
    i = i + 1
}
покажи сума          # 5050

Готово, когато: програмата за оценки от горе тръгва, в началото без функцията.

4

Функции, рекурсия, области на видимост

функция факт(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
5

Грешки, които помагат

Добрият език се познава по съобщенията за грешка.

> покажи 2 + * 3
Грешка на ред 1, колона 12: очаквах израз, намерих '*'
    покажи 2 + * 3
               ^
> покажи у + 1
Грешка на ред 1: непозната променлива 'у'
> покажи 5 / 0
Грешка на ред 1: деление на нула

Капан: у на кирилица и y на латиница изглеждат еднакво. Ще предупреди ли езикът ти?

Готово, когато: 20 програми с грешки дават 20 разбираеми съобщения и нито един срив.

★ 6

Виртуална машина

Интерпретаторът обхожда дървото, а истинските езици (C#, Java, Python) правят друго: превеждат програмата в байткод, прост списък от инструкции за стекова машина.

2 + 3 * 4   →   PUSH 2
                PUSH 3
                PUSH 4
                MUL
                ADD
                PRINT
★ 7

Покажи го на класа

Съучениците ти в момента пишат машинка за оценки на JavaScript. Покажи им същата програма на език, който си написала сама, и дървото ѝ с --дърво. Десет минути, без слайдове, само терминал. Това е и добра тренировка за защитата пред журито.

Въпроси за размисъл