Для генерации кода на моем языке программирования я использую шаблон посетителя и хотел бы найти лучший способ обработки операторов присваивания.
Моя виртуальная машина зарегистрирована на основе, и каждый посещаемый узел выражения просто PUSH номер регистра в глобальный стек, поэтому, когда я посещаю узел двоичного выражения, я выполняю такой код:
static void visit_binary_expr (gvisitor_t *self, gnode_binary_expr_t *node) {
DECLARE_CODE();
bool is_assignment = (node->op == TOK_OP_ASSIGN);
if (is_assignment) {
// assignment is right associative
visit(node->right);
visit(node->left);
} else {
// visiting binary operation from left to right
visit(node->left);
visit(node->right);
}
if (!is_assignment) {
uint32_t r3 = ircode_register_pop(code);
uint32_t r2 = ircode_register_pop(code);
uint32_t r1 = ircode_register_push_temp(code);
opcode_t op = token2opcode(node->op);
ircode_add(code, op, r1, r2, r3);
}
}
С помощью этого кода я могу обрабатывать такие инструкции, как: a + b Предполагая, что переменная a в регистре 1 и переменная b в регистре 2 сгенерированный код будет:
ADD 3 1 2
Проблема в том, что для присваивания требуется другой набор инструкций, а наличия в стеке только номеров регистров недостаточно. Например, чтобы получить доступ (прочитать) к глобальной переменной, я должен использовать инструкцию GLOAD, а для сохранения (записи) в глобальную переменную я должен использовать инструкцию GSTORE.
В настоящее время я решаю проблему, сохраняя логическое значение is_assignment в каждом узле, поэтому я могу рекурсивно проверять, какую инструкцию генерировать, но для этого требуется много логики, распределенной по каждому посещаемому узлу, и я действительно хотел бы найти более элегантный способ, где только функция visit_binary_expr может решить, какую инструкцию генерировать лучше всего.