3

对于我的编程语言中的代码生成,我使用访问者模式,我想找到处理赋值语句的更好方法。访客模式和编译器代码生成,如何处理分配?

我的虚拟机是基于注册的每个表情节点走访只需按下一个注册号为全球性的栈,所以当我访问二进制表示节点正进行类似代码:

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 假设变量在寄存器1和变量b在寄存器产生2代码将是:

ADD 3 1 2 

的问题是,分配需要一组不同的指令,并且具有上在堆栈上注册号码是不够的。例如,为了访问(读取)全局变量,我应该使用GLOAD指令,同时将(写入)存储到全局变量中,我应该使用GSTORE指令。

我目前正在通过将布尔is_assignment值存储到每个节点来解决该问题,所以我可以递归地检查要生成哪个指令,但这需要将大量逻辑分布到每个访问节点中,我真的很想找出更优雅的方式,其中只有visit_binary_expr函数可以决定什么是最好的生成指令。

回答

1

由于赋值与其他二元操作(它具有改变左手边操作数的副作用)有很大不同,所以将它作为完全独立的操作进行处理是有意义的,根本不涉及二元操作。在这种情况下,你会得到类似visit_assignment这样的对应类型的第二个参数。

然后,您可以避免当前代码中存在的所有检查。此外,根据您的语言允许的目标类型,处理分配目标可以使用一组不同的遍历函数,不同的访问者或具有标志的同一访问者,该标志指示正在处理目标,而不是正则表达式。哪种方法更好的决定取决于您需要生成的语言和代码。