编译器如何评估解析的令牌树?

时间:2016-04-19 15:10:18

标签: compilation compiler-construction

我对编译器感兴趣,并且只是为了体验而用C ++编写一个基本编译器!我理解编译器如何解析源代码,然后创建一个令牌树。我不明白的是如何评估该树,然后在必要时返回一个值。例如,如果有一个语句(a + b),我是否有一个函数来处理+令牌,它将传递给a和b?是否会遵循我会对比较操作做同样的事情,然后即使是陈述?

1 个答案:

答案 0 :(得分:1)

编译器不评估AST,这就是(天真)解释器的作用。编译器从AST生成代码。

评估一个简单的int-only AST可能看起来像这样,假设一个AST节点包含一个告诉节点类型和一个子节点数组的枚举:

int eval_expression(node) {
  switch(node.type) {
  case ADD:
    return eval_expression(node.children[0]) + eval_expression(node.children[1]);
  case IF:
     if(eval_expression(node.children[0])) {
       return eval_expression(node.children[1]);
     } else {
       return eval_expression(node.children[2]);
     }
   // and so on
   }
}

根据您的语言以及您如何表示AST,这看起来可能会有很大不同,但希望这会给您一个想法。

一个(非常简单的)编译器可能会做什么,看起来更像这样:

void compile_expression(Node node, const char* target_register) {
  switch(node.type) {
  case ADD:
    const char* temp_register = find_unused_register();
    compile_expression(node.children[0], target_register);
    compile_expression(node.children[1], temp_register);
    printf("ADD %s %s\n", target_register, temp_register);
    free_register(temp_register);
  case IF:
    const char* condition_register = find_unused_register();
    compile_expression(node.children[0], condition_register);
    const char* elseLabel = generate_label();
    const char* labelAfterIf = generate_label();

    // If the condition was zero, jump to the else case
    printf("JZ %s %s\n", condition_register, elseLabel);
    compile_expression(node.children[1], target_register);
    printf("JUMP %s\n", labelAfterIf);

    printf("%s:\n", elseLabel);
    compile_expression(node.children[2], target_register);

    printf("%s:\n", labelAfterIf);
    free_register(temp_register);
   // and so on
   }
}

上面的代码直接将汇编代码写入stdout,这与真正的编译器不同。它也充满了糟糕的工程实践,并假设一个相当简化的汇编方言作为目标。希望它能解决这个问题。

请注意,实际编译器不会直接从AST生成程序集(或机器代码),解释器也不会直接评估AST。相反,两者都将首先从AST生成某种形式的中间代码(如三地址代码),然后再进一步工作。