Часть 5: Создание оператора Parser for Looping and Branching

Эта статья является продолжением статьи: Часть 4: Создание парсера для присвоения переменных и печати

До сих пор мы делали минимум для калькулятора с присваиванием переменной. Мы поняли большую часть основных концепций синтаксического анализа оператора let и оператора печати. Последней статьи должно быть достаточно, чтобы начать разбор большинства утверждений. Добавление оператора if и while предназначено только для быстрого пересмотра, чтобы повысить уверенность.

Пока заявление

Общий синтаксис оператора While:

while (condition) {
   statememt1;   # blocks
   statement2;
}

У нас может быть список операторов внутри while. Мы называем это блоком. довольно часто можно увидеть блок кода в циклах и операторах ветвления или функциях. Сначала мы пишем код для него, поэтому нам не нужно переписывать его каждый раз, когда мы определяем новый сегмент. Давайте создадим узел со списком операторов.

Оператор eval for Block аналогичен интерпретатору. Мы проходим по каждому оператору один за другим и выполняем код. Теперь давайте создадим парсер для блочного оператора. Это прямой процесс. Я проверю, что { означает начало блока. Мы разбираем каждое выражение и добавляем его в список block пока не увидим }.

Теперь вернемся к разбору оператора while. Начнем с условий. Условия аналогичны инфиксным операциям. Мы будем использовать наш традиционный метод parse_expression, чтобы получить условие. Вы можете создать отдельный узел для условий и добавить его в parse_expression. Мне лень, поэтому я буду использовать только инфиксную операцию.

В текущем синтаксисе мы ожидаем, что внешние условия будут заключены в круглые скобки. Поэтому до и после того, как мы разберем выражение, мы проверим наличие скобок.

Теперь мы можем просто добавить анализатор в parse_statement.

Давайте посмотрим, работает ли наш оператор while или нет. Создайте новый файл сценария.

$ touch example/while.nmi

Я вычисляю последовательность Фибоначчи для числа n. Теперь запустим скрипт:

$ python3 src/repl.py example/while.nmi
3628800

Делать пока

Изначально я не добавлял токен для do. Но лучше поздно, чем никогда. Вам нужно будет добавить токен для выполнения в Token в tokens.py.

DO = re.compile(r’do’)

Узел для Do while будет иметь условие и операторы как while. Разница только в eval, где мы проверяем условие в конце.

Разбор do while почти такой же, как разбор while.

Если заявление

Общий синтаксис оператора if приведен ниже.

if (condition) {
  block_for_true_statements;
} else {                         
  block_for_false_statments;
}

У нас есть condition, который определяет ветвление. При true будет выполняться код под block_for_true_statements. Существует необязательный оператор else, который выполнит выполнение, если ни одно из условий не будет истинным. Узел для оператора If приведен ниже.

Мы создали простой парсер для блока if-else. Если блок else не указан, мы не передаем ничего.

Теперь давайте напишем простой код для проверки оператора if else. Создайте новый файл сценария.

$ touch example/if_else.nmi

Вывод:

$ python3 src/repl.py example/if_else.nmi 
number is odd!

В нашем языке поддерживается вложенные циклы

Для выписки

Я оставляю это в качестве упражнения для читателя.

Ссылка

  1. Часть 1: Создание лексера с использованием регулярных выражений
  2. Часть 2: Создание лексера с использованием манипуляций со строками
  3. Часть 3: Создание парсера для арифметических операций
  4. Часть 4: Создание парсера для присвоения переменных и печати
  5. Часть 5: Создание синтаксического анализатора для цикла и ветвления
  6. Написание интерпретатора на ходу Торстена Болла
  7. "Исходный код"