【问题标题】:How does a compiler evaluate a parsed token tree?编译器如何评估已解析的令牌树?
【发布时间】:2016-04-19 15:10:18
【问题描述】:

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

【问题讨论】:

  • “令牌树”???你需要做的是阅读一本关于编译器如何工作的书。对于这种复杂的技术,没有简单、简短的答案。
  • 理论上,您可以将源代码解析为其令牌组件,例如文字字符串运算符等,然后按顺序将其评估为树。

标签: compilation compiler-construction


【解决方案1】:

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

假设一个 AST 节点由一个告诉节点类型的枚举和一个子节点数组组成,评估一个简单的纯 int 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
   }
}

上面的代码将汇编代码直接写入标准输出,这不是真正的编译器会做的。它也充满了不良的工程实践,并假设一个相当简化的装配方言作为目标。但希望它能够传达这个想法。


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

【讨论】:

  • 哇,谢谢你帮了大忙。谢谢你的解释。我肯定会对此进行更多阅读。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-04
  • 1970-01-01
  • 2020-08-22
  • 1970-01-01
相关资源
最近更新 更多