Примечание: когда я использовал «сложный» в заголовке, я имею в виду, что выражение имеет много операторов и операндов. Не то чтобы само выражение было сложным.
Недавно я работал над простым компилятором для сборки x86-64. Я закончил основной внешний интерфейс компилятора - лексер и парсер - и теперь могу генерировать представление абстрактного синтаксического дерева моей программы. И так как мой язык будет статически типизирован, я сейчас делаю следующий этап: проверка типа исходного кода. Тем не менее, я пришел к проблеме и не смог ее решить.
Рассмотрим следующий пример:
Парсер моего компилятора прочитал эту строку кода:
int a = 1 + 2 - 3 * 4 - 5
И преобразовал его в следующий AST:
=
/ \
a(int) \
-
/ \
- 5
/ \
+ *
/ \ / \
1 2 3 4
Теперь он должен проверить тип AST. он начинается с первой проверки типа =
оператора. Сначала проверяется левая сторона оператора. Он видит, что переменная a
объявлена как целое число. Поэтому теперь он должен проверить, что выражение в правой части имеет целое число.
Я понимаю, как это можно сделать, если выражение было только одно значение, например, 1
или 'a'
. Но как это сделать для выражений с несколькими значениями и операндами - сложного выражения, такого как приведенное выше? Чтобы правильно определить значение выражения, похоже, что средство проверки типов действительно должно быть выполнено само выражение и записать результат. Но очевидно, что это противоречит цели разделения фаз компиляции и выполнения.
Единственный другой способ, которым я могу представить, - это рекурсивно проверить лист каждого подвыражения в AST и убедиться, что все типы листа соответствуют ожидаемому типу оператора. Таким образом, начиная с =
оператора, средство проверки типов затем сканирует все AST левой стороны и проверяет, что все листы являются целыми числами. Затем он будет повторять это для каждого оператора в подвыражении.
Я пытался исследовать эту тему в своей копии «Книги Дракона» , но она, похоже, не вдавалась в подробности, а просто повторяет то, что я уже знаю.
Какой обычный метод используется, когда компилятор проверяет выражения со многими операторами и операндами? Используются ли какие-либо методы, которые я упоминал выше? Если нет, то какие методы и как именно они будут работать?
double a = 7/2
будет пытаться интерпретировать правую часть как двойную, следовательно, будет пытаться интерпретировать числитель и знаменатель как двойной и преобразовывать их при необходимости; в результате a = 3.5
. Восходящий вверх будет выполнять целочисленное деление и преобразовывать только на последнем шаге (присваивании), поэтому a = 3.0
.
int a = 1 + 2 - 3 * 4 - 5
ноint a = 5 - ((4*3) - (1+2))