编译原理:super-tiny-compiler源码阅读

在日常工作中我们很少能接触到编译相关,但是确是一个很重要的一个知识。作者@ jamiebuilds通过一个简单的案例用最小的实现方式展现了一个简单demo的编译器。https://github.com/jamiebuilds/the-super-tiny-compiler。

super-tiny-compiler 主要是将lisp语言的函数调用转换成C语言(你也可以理解JS的函数调用)

Aim LISP C
2 + 2 (add 2 2) add(2, 2)
4 - 2 (subtract 4 2) subtract(4, 2)
2 + (4 - 2) (add 2 (subtract 4 2)) add(2, subtract(4, 2))

编译分为哪几个阶段(Stage)?

  1. 词法解析parse,将原始的代码经过词法分析转成抽象树
  2. 转换器Transformation,将抽象树转换成编译器需要的结构
  3. 代码生成Code Generation,将转换过的抽象树转换成目标代码

tokenizer

将代码拆解成一个一个的token

(add 2 (subtract 4 2))转换成:

[
  { type: 'paren', value: '(' },
  { type: 'string', value: 'add' }
  // ...
]

parser

接收一个tokens,将tokens转换成AST。

function parser(tokens) {
  let current = 0;
  
  function walk() {
    // 匹配左括号
    let token = tokens[current]; 
    if (token.type === 'number') {

      current++;

      return {
        type: 'NumberLiteral',
        value: token.value,
      };
    }
    if (token.type === 'string') {
      current++;

      return {
        type: 'StringLiteral',
        value: token.value,
      };
    }
    if (
      token.type === 'paren' &&
      token.value === '('
    ) {
      token = tokens[++current];
      let node = {
        type: 'CallExpression',
        name: token.value,
        params: [],
      };
      token = tokens[++current];

      while (
        (token.type !== 'paren') ||
        (token.type === 'paren' && token.value !== ')')
      ) {
        node.params.push(walk());
        token = tokens[current];
      }
      
      current++;
      return node
    }
  }
  let ast = {
    type: 'Program',
    body: [],
  };

  while (current < tokens.length) {
    ast.body.push(walk());
  }

  return ast;
}

transformer

将旧AST转换成与之相代码结构对应的新AST

你可能感兴趣的:(编译原理:super-tiny-compiler源码阅读)