Compiler Basic Notes
Basic Concepts
Definition of compilers
program_code---compiler---> executable- data ---executable---> output
 
e.g Fortran(formula translation) 1 project
Structure of compilers
front-end to back-end:
- front-end: src ---lexical analysis---> tokens ---parsing/syntax analysis---> AST(Abstract Syntax Tree) ---semantic analysis---> intermediate
 - back-end: intermediate ---...---> ... ---...---> ... ---code generation---> dist
 
details:
- lexical analysis(词法分析)
 - parsing/syntax analysis(语法分析)
 - semantic analysis(语义分析): type and scope
 - optimization
 - code generation: translate to other high level language/assembly code/machine code
 
文法与语言
符号与符号串
- 字母表/符号集: 元素的非空有穷集合
 - 符号串: 字母表中的符号组成的任何有穷序列
 - 固有头/尾: 非空首/尾子串
 - 闭包: 
Σ* = Σ0 U Σ1 U ... U Σn .... - 正闭包: 
Σ* = Σ1 U ... U Σn .... 
文法与语言的形式化表示
- 文法 (Grammar): 
G = (Vn, Vt, P, S), 非终结符集, 终结符集, 规则/产生式集, 开始符号. - 语言 (Language): 
L(G) = {x | S -> x, x <- Vt}文法 G 一切句子的集合. - 句型: rhs of P, 句子: 不含非终结符的右部
 - 直接推导: 
v -> w, 闭包推导:v -*> w, 正闭包推导:v -+> w. 
乔姆斯基文法体系
- ((((3)2)1)0)
 - 0 型文法: 任意文法
 - 1 型文法: 上下文有关文法(context sensitive) αAβ -> αηβ
 - 2 型文法(语法工具): 上下文无关文法 A -> α
 - 3 型文法(词法工具): 正规文法
 
上下文无关文法
文法表示
G = (S, N, T, P):
- S: 开始符
 - N: 非终结符集合
 - T: 终结符集合
 - P: 产生式规则集合 X -> beta1, beta2, ..., betaN, X <- N, beta <- N+T
 
形式化表示
简易表示
Sentence -> Noun Verb Noun
Noun -> sheep
  | tiger
  | grass
  | water
Verb -> eat
  | drink
S: Sentence, N: Sentence/Verb/Noun, T: sheep/tiger/grass/water/eat/drink
E -> num
  |id
  |E + E
  |E `*` E
S: E, N: E, T: num/id/+/*.
巴科斯范式
Backus-Naur Form:
::=:被定义为.word: 字符本身.- 双引号外的字: 语法部分.
 - 尖括号(
< >): 必选项(非终结符). - 方括号(
[ ]) : 0/1. - 大括号(
{ }) : 0/n. - 竖线(
|) :OR. 
正规文法
正规文法可与正则语言相互转化:
- A -> aB|Ba
 - A -> a
 
正则语言(Regular Expressions)
基本定义
对于给定的字符集 C:
- 空串 
"\0"是正则表达式. - 任意 
char <- C是正则表达式. - 若 
M,N是正则表达式, 则M|N = {M, N},MN = {mn|m <- M, n <- N},M* = {"\0", M, MM, MMM, ...}(选择/连接/闭包) 也是正则表达式. 
形式表示
# 具有顺序性
e -> "\0" # basic definition
  | c # basic definition
  | e | e # recursive definition
  | ee # recursive definition
  | e* # recursive definition
正则语法糖(Syntax Sugar)
[a-z]: a|...|z- c? : 0/1 个 c
 - c+ : 1/n 个 c
 - c{i, j} : i-j 个 c
 - "a" : a 自身(非 Kleene Closure)
 - . : 除 ‘\n’ 外的任意字符
 
// 标识符
const identifier = /[a-zA-Z\_][a-zA-Z\_0-9]*/g;
// decimal integer
const integer = /(+|-)?(0|[1-9][0-9]*)/g;
// decimal float
const float = /(+|-)?(0|[1-9][0-9]*|)?\.[0-9]+/g;
分析树
进行文法推导时生成的树:
- 根 : 开始符
 - 内部结点 : 非终结符
 - 叶子结点 : 终结符
 - 层 : 一步推导(优先级影响推导顺序)
 - 叶子结点串: 最终表达式
 - 后序遍历 : 最终结果
 
推导类型
- 最左推导(leftmost)
 - 最右推导(rightmost)(规范推导)
 
句型分析
- 短语: 若 
S -*> Aβ, A -+> α, 则称 α 是句型 αβ 相对于非终结符 A 的短语 - 直接短语: 
S -*> Aβ, A -> α. - 一个右句型的直接短语称为该句型的句柄(用于自下而上的归约分析)
 - 最左归约: 归约最左的句柄, 最右归约: 归约最右的句柄
 
meaning function(多对一)
L(syntax) = semantic: 多个语法对应一个语义(不同形式的表达式对应同一个意思)
二义性文法(一对多)
- 最左推导与最右推导得出的分析树不一致
 - 若给定文法 G, 对于句子 s, 其有 2 种不同的分析树, 则称 G 是二义性文法
 - 若一个上下文无关语言的所有文法都是二义性文法, 则称此语言是先天二义语言
 
文法重写
E -> E + T
  |T
T -> T * F
  |F
F -> num
  |id
消除 + 与
*的二义性, 如 3+4*5
优先级与结合性
声明优先级与结合性可在一定程度上消除文法的二义性
文法规则
- 有害规则: 使文法产生二义性的规则
 - 多余规则: 不可达/不可终止的规则
 - 2 型文法的 ε 规则: 当语言中不含有 ε 符号串, 则一定存在终结符集不含有 ε 的等价文法(代入法消除 ε)
 - 保证非终结符 A 的有效性: 
S -*> αAβ, A -+> t. 
Lexical Analysis
Tokenizer - 词法分析器
- Maximal match
 - Higher priority match
 
转移图算法
token nextToken(void) {
  char c = getChar();
  switch(c) {
    case '<':
      c = getChar();
      switch (c) {
        case '=':
          return LE;
        case '>':
          return NE;
        default:
          rollback();
          return LT;
      }
    case '=':
      return EQ;
    case '>':
      c = getChar();
      switch (c) {
        case '=':
          return GE;
        case '<':
          return NE;
        default:
          rollback();
          return GT;
      }
  }
}
关键字(keyword)处理
- 根据 完美哈希算法(无冲突哈希函数) , 建立所有关键字对应的关键字完美哈希表
 - 读入有效标识符(字符串型)后, 查询关键字哈希表, 检查当前标识符是否为关键字
 
#define KEYWORD_MAX_LEN 10
hash_one(char *str, int len) {
    unsigned int keyValue = 0;
    for (int i = 0; i < len; i++) {
        keyValue += str[i] * ((int)pow(33, len - i));
    }
    keyValue = (keyValue * 3 + 7) % KEYWORD_MAX_LEN;
  return keyValue;
}
#define KEYWORD_HASH_SEED 131
hash_two(char *str, int len) {
  unsigned int keyValue = 0,
           hash = 0;
    for (int i = 0; i < len; i++) {
        hash = hash * KEYWORD_HASH_SEED + str[i];
    }
    keyValue = hash & 0x7fffffff;
    return keyValue;
}
有限状态自动机(Finite Automaton)
确定有限状态自动机(Deterministic Finite Automaton)
- Only a transition for a state with a input
 - No epsilon moves
 
M = (AlphaSet/InputSet, StateSet, currentState, FiniteStateSet, transferFunction)
A = {a, b}, SS = {0, 1, 2}, cS = 0, FS = {2},
transferFunction = {
  (cS0, a) -> cS1, (cS0, b) -> cS0,
  (cS1, a) -> cS2, (cS1, b) -> cS1,
  (cS2, a) -> cS2, (cS2, b) -> cS2,
}
状态转移表实现 DFA
| 状态\字符 | a | b | 
|---|---|---|
| 0 | 1 | 0 | 
| 1 | 2 | 1 | 
| 2 | 2 | 2 | 
非确定有限状态自动机(Nondeterministic Finite Automaton)
transferFunction 中的次态不确定/不唯一(为一个开集合):
- Multiple transitions for a state with a input
 - can epsilon moves
 
(cS0, a) -> {cS1, cS2}
自动词法分析器
RegExp --Thompson 算法--> NFA --子集构造算法--> DFA --Hopcroft 最小化算法--> 词法分析器代码
Thompson 算法
RegExp --> NFA:
- 直接构造基本 RegExp
 - 递归构造复合 RegExp
 - epsilon : i --epsilon--> f
 - RegExp : i --NFA(RegExp)--> f
 - 选择 : i --NFA(RegExp1)--> f, i --NFA(RegExp2)--> f
 - 连接 : i --NFA(RegExp1)--> m --NFA(RegExp2)--> f
 - 闭包 : i --epsilon--> m --epsilon--> f, m --RegExp--> m
 
子集构造算法
NFA --> DFA:
由 Thompson 算法生成的 NFA, 当且仅当输入为 epsilon 时, 次态不唯一
- 将所有可达到次态作为一个集合 s, 视为单一次态 s
 - delta(Sigma) + epsilon-closure(深度/广度优先遍历找寻可达到次态边界)
 
DFA subset_construction(NFA nfa) {
  s0 = eps_closure(n0);
  StateSet += s0;
  enqueue(s0);
  while (work_queue != []) {
    dequeue(s);
    foreach (ch in InputSet) {
      next_state = eps_closure(delta(s, ch));
      Fn[s, ch] = next_state;  // DFA 中的转移函数
      if (next_state not in StateSet) {
        StateSet += next_state;
        enqueue(next_state);
      }
    }
  }
  return DFA(StateSet, Fn);
}
Hopcroft 算法
最小化 DFA(数字逻辑中的最简状态表), 合并等价状态(等价类)
split(StateSet S) {
  foreach (char ch) {
    if (ch can split S) {
      split S into S1, ..., Sk;
    }
  }
}
hopcroft(DFA) {
  split all nodes into InitStateSet and FiniteStateSet (Two State Sets);
  while (set is still changes) {
    split(S);
  }
}
实现
DFA
有向图
转移表
- 行: 现态
 - 列: 输入
 - 值: 次态/ERROR/-1
 
驱动代码: table 用于实现 switch/case, stack 用于实现最长匹配
next_token() {
  state = 0;
  stack = [];
  while (state != ERROR) {
    c = getChar();
    if (state is ACCEPT/FINITE) {
      clear(stack);
    }
    push(state);
    state = table[state][c];
  }
  while (state is not ACCEPT/FINITE) {
    state = pop();
    rollback();
  }
}
Syntax Analysis(语法分析)
Tokens + Grammar --Syntax Analysis--> AST(Abstract Syntax Tree)
自顶向下分析
- 从开始符号出发推导任意句子 t, 与给定句子 s 进行比较分析
 - 利用分析树进行逐叶子匹配, 若匹配失败则进行回溯
 
bool top_down_parsing(tokens[]) {
  i = 0;
  stack = [S];
  while (stack != []) {
    if (stack[top] is a terminal t) {
      t == tokens[i] ? pop(i++) : backtrack();
    } else if (stack[top] is a non_terminal T) {
      pop();
      push(T next expansion); // 自右向左压栈, e.g pop(S), push(N_right), push(V), push(N_left)
    } else {
      throw new SyntaxError();
    }
  }
  return i >= tokens.length && is_empty(stack) ? true : false;
}
避免回溯
利用前看符号避免回溯
Sentence -> Noun Verb Noun
Noun -> sheep
  | tiger
  | grass
  | water
Verb -> eat
  | drink
tiger eat water: 向前看非终结符推导出的所有终结符中匹配 tiger 的终结符; 不向前看,则先推导 N, 再推导 n, 但 n 不一定匹配 tiger, 则需进行回溯; 向前看一个字符, 直接推导 N --> n, 同时直接找寻匹配 tiger 的终结符
S -> N V N
N -> (sheep)tiger
V -> eat
N -> (sheep-tiger-grass)water
递归下降分析算法(Recursive Descent/预测分析算法)
- 分治算法: 每个非终结符构造一个分析函数
 - 前看符号: 用前看符号指导产生式规则的选择(expansion)
 
parse_S(tokens[]) {
  parse_N(tokens[0]);
  parse_V(tokens[1]);
  parse_N(tokens[2]);
}
parse_N(token) {
  if (token == s|t|g|w) {
    return true;
  } else {
    throw new SyntaxError();
  }
}
parse_V(token) {
  if (token == e|d) {
    return true;
  } else {
    throw new SyntaxError();
  }
}
算法实现
- tip one: use save pointer to implement roll back
 - tip two: use logical OR expression to replace nested if-else structure
 
bool term(TOKEN tok) {
    return *next++ == tok;
}
bool E1(void) {
    return T();
}
bool E2(void) {
    return T()
        && term(PLUS)
        && E();
}
bool E(void) {
    // roll back pointer
    TOKEN *save = next;
    return (next = save, E1())
        || (next = save, E2());
}
bool T1(void) {
    return term(INT);
}
bool T2(void) {
    return term(INT)
        && term(TIMES)
        && T();
}
bool T3(void) {
    return term(OPEN)
        && E()
        && term(CLOSE);
}
bool T(void) {
    // roll back pointer
    TOKEN *save = next;
    return (next = save, T1())
        || (next = save, T2())
        || (next = save, T3());
}
// X -> a
//  | XX
//  | aXXX
//  | aXXXXb
parse_X() {
  token = nextToken();
  switch (token) {
    case ...: // i: token == atom_char or parse_XX();
    case ...: // j: token == atom_char, token = nextToken(), parse_XXX();
    // k: token == atom_char, token = nextToken(),
    // parse_XXXX(), token=nextToken(), token == b
    case ...:
    default: throw new SyntaxError();
  }
}
LL(1)分析算法
- 从左(L)向右读入程序(left to right scan)
 - 最左(L)推导: 优先推导最左侧非终结符(leftmost derivation)
 - 一个(1)前看符号(look ahead)
 - 分治算法: 每个非终结符构造一个first set 和一个 follow set, 最后为每个规则构造一个 select set
 - 分析表驱动(由 first sets/follow sets/select sets 推导分析表)
 
bool ll1_parsing(tokens[]) {
  i = 0;
  stack = [S];
  while (stack != []) {
    if (stack[top] is a terminal t) {
      t == tokens[i] ? pop(i++) : throw new SyntaxError();
    } else if (stack[top] is a non_terminal T) {
      pop();
      // push(T correct expansion);
      // 自右向左压栈, e.g pop(S), push(N_right), push(V), push(N_left)
      push(select_table[T][tokens[i]] 对应项(规则编号)所对应规则的右边式子);
    } else {
      throw new SyntaxError();
    }
  }
  return i >= tokens.length && is_empty(stack) ? true : false;
}
nullable sets
- 存在规则: 
X -> epsilon. - 或者: 
X -> Y1Y2...Yn, 且存在规则Y1 -> epsilon, ..., Yn -> epsilon. - 即 : 
X -*> epsilon(epsilon <- first(X)). 
nullable = {};
while (nullable is still changing) {
  foreach (production p: X -> beta) {
    if ((beta == epsilon) || (beta == Y1...Yn
      && Y1 <- nullable && ... && Yn <- nullable)) {
      nullable += X;
    }
  }
}
first sets
first(X) = {t | X -> talpha} U {epsilon | X->epsilon} :
- first(t) = {t}
 - epsilon<-first(X): X -> epsilon or X -> A1...An, epsilon<-first(Ai)
 - first(alpha)<-first(X): X -> A1..Analpha, epsilon<-first(Ai)
 
first sets 不动点算法:
foreach (non_terminal N) {
  first(N) = {};
}
while (some sets is changing) {
  foreach (production p: N->beta1...beta_n) {
    foreach (beta_i from beta1 up to beta_n) {
      if (beta_i == a) {
      // e.g N->abX: first(N) += {a}
        first(N) += {a};
        break;
      } else if (beta_i == M) {
        first(N) += first(M);
        if (M is not in nullable) {
          break;
        } // else continue this loop to add first(beta_next) into first(N)
      }
    }
  }
}
| NonTerminal | First Set | 
|---|---|
| S | {s, t, g, w} | 
| N | {s, t, g, w} | 
| V | {e, d} | 
follow sets
follow(X) = {t | S -*> beta X t epsilon}:
- for 
X -> AB:first(B) <- follow(A),follow(X) <- follow(B).- if 
B -*> epsilon:follow(X) <- follow(A). 
 - for 
A -> alpha X beta:first(beta) - {epsilon} <- follow(X). $ <- follow(S).
follow sets 不动点算法:
foreach (non_terminal N) {
  follow(N) = {};
}
while (some sets is changing) {
  foreach (production p: N->beta1...beta_n) {
        // temp: follow(left) <- follow(right)
    temp = follow(N);
    foreach (beta_i from beta_n down to beta1) {
      if (beta_i == a) {
        temp = {a};
      } else if (beta_i == M) {
        follow(M) += temp
        temp = (M is not nullable) ? (first(M)) : (temp + first(M))
      }
    }
  }
}
select sets
- 当 N -> Y1...Yn 右边 Y 全为 nullable 时, select(p) += follow(N)
 
select sets 不动点算法:
foreach (production p) {
  select(p) = {}
}
calculate_select_set(production p: N->beta1...beta_n) {
  foreach (beta_i from beta1 up to beta_n) {
    if (beta_i == a) {
      select(p) += {a};
      break;
    } else if (beta_i == M) {
      select(p) += first(M);
      if (M is not in nullable) {
        break;
      }
    }
  }
  // all betas are in nullable (当前规则的所有右边符号都是可空集)
  // 故, select(p) 必须包括 follow(M) (当推导出右边符号都为空时, first(p) 即为 follow(M))
  if (i > n) {
    first(N) += follow(N);
  }
}
分析表
- 结合 nullable sets 准确求出 first sets
 - 再利用 first sets 准确求出 follow sets
 - 再利用 first sets, 并结合 follow sets(全空集修正) 准确求出 分析表:
 
0: z -> d
1: | X Y Z
2: Y -> c
3: |
4: X -> Y
5: | a
nullable = {X, Y}
| X | Y | Z | |
|---|---|---|---|
| first | {a, c} | {c} | {a, c, d} | 
| follow | {a, c, d} | {a, c, d} | {} | 
| production | 0 | 1 | 2 | 3 | 4 | 5 | 
|---|---|---|---|---|---|---|
| select | {d} | {a, c, d} | {c} | {a, c, d} | {a, c, d} | {a} | 
|Non\Terminal|a|c|d| |Z|1|1|0, 1| |Y|3|2, 3|3| |X|4, 5|4|4|
数字为规则编号
解决冲突(分析表某项有多个编号)
通过文法重写消除左递归, 使文法适应 L(最左推导):
- 改写成右递归文法
 - 规定优先级与结合性
 - 提取左公因式(Common Prefix)
 
E -> T+E
    |T
E -> TX
X -> +E
    |epsilon
消除直接左递归
S -> Salpha1
    |Salpha2
    ...
    |Salpha_n
    |beta1
    |beta2
    ...
    |beta_m
S -> beta1S'
    |beta2S'
    ...
    |beta_nS'
S'-> alpha1S'
    |alpha2S'
    ...
    |alpha_nS'
    |epsilon
消除间接左递归
- 把文法 G 的所有非终结符按任一顺序排列, e.g A1, A2, …, An
 - 消除 Ai 规则中的直接左递归: 把形如 Ai→Ajγ 的产生式 改写成 Ai→δ1γ /δ2γ /…/δkγ(其中 Aj→δ1 /δ2 /…/δk 是关于的 Aj 全部规则)
 - 去掉多余的规则(不可达规则)
 
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
struct WF {
    string left; //定义产生式的左部
    string right; //定义产生式的右部
};
/*
 * count: number of non-terminal symbols
 */
void Removing(WF *p,char *q,int n,int count) {
    int count1 = n;
    int flag = 0;
  // 判断第一个非终结符是否存在直接左递归 if(p[i].left[0]==q[0])
    for (int i = 0; i < n; i++) {
        if (p[i].left[0] == p[i].right[0]) {
            flag++;
        }
    }
  // 如果存在直接左递归则消除直接左递归
    if (flag != 0)
    {
        for (int i = 0; i < n; i++) {
            if (p[i].left[0] == q[0]) {
                if (p[i].left[0] == p[i].right[0]) {
                  string str;
                    str = p[i].right.substr(1,int (p[i].right.length())); // 取右部第二位开始的字串赋给str
                    // E->E+T => E'->+TE'
                    string temp = p[i].left;
                    string temp1 = "'";
                    p[i].left = temp+temp1;
                    p[i].right = str+p[i].left;
                } else {
                    // E->T => E->TE'
                    string temp=p[i].left;
                    string temp1="'";
                    temp=temp+temp1;
                    p[i].right=p[i].right+temp;
                }
            }
        }
        string str="'";
        p[count1].left=p[0].left[0]+str;
        p[count1].right="ε";
    }
  // 对每一个非终结符迭代
    for ( int i = 0; i <= count; i++) {
      // 对每一个小于 i 的非终结符
        for (int j = 0; j < i; j++) {
          // 对每一个产生式
            for (int g = 0; g < n; g++) {
              // i 非终结符与第 g 产生式左边第一个字母相等
                if (q[i] == p[g].left[0]) {
          // g 产生式右边产生式第一个符号与第 j 个非终结符相等
                    if (p[g].right[0] == q[j]) {
                        for (int h = 0; h < n*n; h++) {
                            if (p[h].left[0] == q[j]
                              && int (p[h].left.length()) == 1) {
                                string str;
                                str = p[g].right.substr(
                                  1,
                                  int (p[g].right.length ()));
                                p[++count1].left = p[g].left;
                                p[count1].right = p[h].right + str;
                            }
                        }
                        p[g].left="";
                        p[g].right="";
                    }
                }
            }
        }
    }
  // 去除间接递归产生式
    for(int i = 0; i <= count; i++) {
        flag = 0;
        for (int j = 0; j < n*n; j++) {
            if (p[j].left[0] == q[i]) {
                if(p[j].left[0] == p[j].right[0]) {
                    flag++;
                }
            }
        }
        if (flag != 0) {
            for (int j = 0; j <= n*n; j++) {
                if (p[j].left[0] == q[i]) {
                    if (p[j].left[0] == p[j].right[0]) {
                        string str;
                        str = p[j].right.substr(1,int (p[j].right.length()));
                        string temp = p[j].left;
                        string temp1 = "'";
                        p[j].left = temp + temp1;
                        p[j].right = str + p[j].left;
                    } else {
                        string temp = p[j].left;
                        string temp1 = "'";
                        temp = temp + temp1;
                        p[j].right = p[j].right + temp;
                    }
                }
            }
            string str = "'";
            p[++count1].left = q[i] + str;
            p[count1].right = "ε";
        }
    }
}
int Delete(WF *p,int n) {
    return 0;
}
int main() {
    ofstream OutFile("result.txt");
    int i,
      j,
      flag = 0,
      count = 1,
      n;
    cout<<"请输入文法产生式个数n:"<<endl;
    cin>>n;
    WF *p=new WF[50];
    cout<<"请输入文法的个产生式:"<<endl;
  // input productions
    for (i = 0; i < n; i++) {
        cin>>p[i].left;
        cout<<"->"<<endl;
        cin>>p[i].right;
        cout<<endl;
    }
    cout<<endl;
    OutFile<<"即输入的文法产生式为:"<<endl;
    // cout<<"即输入的文法产生式为:"<<endl;
    for (i = 0; i < n; i++) {
        // cout<<p[i].left<<"-->"<<p[i].right<<endl;
        OutFile<<p[i].left<<"-->"<<p[i].right<<endl;
    }
    OutFile<<"*********************"<<endl;
    // cout<<"*********************"<<endl;
    char q[20];    // 对产生式的非终结符排序并存取在字符数组q
    q[0] = p[0].left[0]; // 把产生式的第一个非终结符存入q中
  // 对非终结符排序并存取
    for (i = 1; i < n; i++) {
        flag = 0;
        for (j = 0; j < i; j++) {
      // 根据j<i循环避免重复非终结符因此由标志位判断
            if(p[i].left==p[j].left) {
              flag++;
            }
        }
        if(flag==0) {
          // 没有重复加入q数组中
            q[count++]=p[i].left[0];
        }
    }
    count--;
  // 调用消除递归子函数
    Removing(p,q,n,count);
    // 删除无用产生式
    Delete(p,n);
    OutFile<<"消除递归后的文法产生式为:"<<endl;
    // cout<<"消除递归后的文法产生式为:"<<endl;
    for (i = 0; i <= count; i++) {
        for (int j = 0; j <= n*n; j++) {
            if ((p[j].left[0] == q[i]) && int (p[j].left.length ()) == 1) {
                OutFile<<p[j].left<<"-->"<<p[j].right<<endl;
        // cout<<p[j].left<<"-->"<<p[j].right<<endl;
            } else {
              continue;
            }
        }
        for (j = 0; j <= n*n; j++) {
            if((p[j].left[0] == q[i]) && int (p[j].left.length ()) == 2) {
                OutFile<<p[j].left<<"-->"<<p [j].right<<endl;
            // cout<<p[j].left<<"-->"<<p[j].right<<endl;
            } else {
              continue;
            }
        }
    }
    return 0;
}
非 LL(1) 文法/语言
- ambiguous grammar
 - left recursive grammar
 - not left factored grammar(未提取展开式的公因子)
 
自底向上分析
0: S -> E
1: E -> E + T
2: | T
3: T -> T * F
4: | F
5: F -> n
2 + 3 * 4
=> F + 3 * 4
=> T + 3 * 4
=> E + 3 * 4
=> E + T * 4
=> E + T * F
=> E + T
=> E
=> S
最右推导(优先推导最右侧非终结符)逆过程
LR(0) 分析算法
移进-归约 (Reduce) 算法:
- 从左向右读入程序 (left to right scan), 逆向最右推导 (rightmost derivation), 不用前看符号.
 - 添加伪开始符号: 
S' -> . S$,$表示 tokens/file 结束符. - 移进 : 读入记号 
push(token[i]). - 归约 (Reduce): 
pop(right expansion)push(left expansion). 
短语
Handles:
S -*> αXω -> αβω
β 是 αβω 的一个短语 (Handle).
分析表构造
LR(0) 分析表构造算法: (原理同于 Hopcroft 算法)
- E -> A, A -> B, B -> C ... : Recursively, right hand side of C production will be reduced to E finally
 
closure(production_set p) {
  while (p is still changing) {
    foreach (p's item i: A -> b . B ...) {
      p += {B -> . y...}
    }
  }
}
goto(production_set p, token x) {
  temp = {}
  foreach (p's item i: A -> b . x...) {
    temp += {A -> bx . ...}
  }
  return closure(temp)
}
p0 = closure(S'' -> . S $)
(production_with_dot_)set = {p0}
Q = enqueue(p0)
while (Q is not empty) {
  p = dequeue(Q)
  foreach (x <- NonTerminal||Terminal) {
    q = goto(p, x)
    if (x <- Terminal) {
      ACTION[p, x] = q
    } else {
      GOTO[p, x] = q
    }
    if (q not <- set) {
      set += {q}
      enqueue(q)
    }
  }
}
驱动代码
LR(0) 驱动算法:
stack[];
push($)
push(state1)
while (true) {
  token t = nextToken()
  state s = stack[top]
  if (ACTION[s, t] == shift_i) {
    push(t)
    push(state_i)
  } else if (ACTION[s, t] == reduce_j) {
    // X is the left side of production j: X->beta
    // beta is the right side of production j: X->beta
    // pop up right side
    pop(beta && bundle state variables)
    // current state after pop up all bundle state(of beta)
    state s = stack[top]
    // push left side
    push(X)
    // transfer state after reduce
    push(GOTO[s, X])
  } else {
    throw new SyntaxError();
  }
}
解决冲突
SLR, LR(1), LALR, 采取与 first/follow/select sets 以及 前看符号 类似策略:
production_with_dot_set中的 item 修改为X -> [beta1 . beta_n..., a]二元组- closure(production_set p) 中闭包规则从 
X -> [a . Y beta,a]修改为Y -> [.y, b]b <- select(beta a) 
LALR-K
LALR(k)
SLR
Simple LR: improves LR(k) shift/reduce heuristic
New reduce rule:
- state contains item X -> β.
 - next_token <- follow(X)
 
SLR 实现
- stack pair: 
<input, state> - state i: if has item X -> α.aβ , goto[i, a] = j then action[i, a] = shift j(shift then to state j)
 - state i: if has item 
X -> α.,a <- follow(X)thenaction[i, a] = reduce(X -> α) - state i: if has item S' -> S then action[i, $] = accept
 - otherwise: action[i, a] = error
 
抽象语法树
语法制导翻译(Syntax-Directed Translation)
在进行归约(reduce)的同时, 进行语义动作:
- 给每条产生规则附加一个语义动作
 
exp : exp '+' exp { $$ = $1 + $3; }
;
- 在分析栈中压入 symbol, value, state (原本只压入 symbol, state)
 
push(right side symbol);
push(right side value);
push(next state);
抽象语法
- 表达语法结构的内部表示, 作为前端(词法语法分析)和后端(代码生成)的中间件, tokens --语法分析器--> 抽象语法(树) --代码生成器--> 目标代码
 - 抽象语法无需考虑左/右递归, 左公因子提取, 分隔符等
 
// 具体语法
E: E + T
 | T
 ;
T: T * F
 | F
 ;
F: n
 | (E)
 ;
// 抽象语法
E: n
 | E + E
 | E * E
AST 的实现
数据结构
E: n
 | E + E
 | E * E
enum kind {
  E_INT,
  E_ADD,
  E_TIMES
};
struct exp {
  enum kind kind;
};
struct exp_int {
  enum kind kind;
  int value;
};
struct exp_add {
  enum kind kind;
  struct exp *left;
  struct exp *right;
};
struct exp_times {
  enum kind kind;
  struct exp *left;
  struct exp *right;
};
struct exp_int *new_exp_int(int value) {
  struct exp_int *p = (struct exp_int *)malloc(sizeof(struct exp_int));
  if (!p) throw new Error();
  p->kind = E_INT;
  p->value = value;
  return p;
}
struct exp_add *new_exp_add(exp *left, exp *right) {
  struct exp_add *p = (struct exp_add *)malloc(sizeof(struct exp_add));
  if (!p) throw new Error();
  p->kind = E_ADD;
  p->left = left;
  p->right = right;
  return p;
}
struct exp_times *new_exp_times(exp *left, exp *right) {
  struct exp_times *p = (struct exp_times *)malloc(sizeof(struct exp_times));
  if (!p) throw new Error();
  p->kind = E_TIMES;
  p->left = left;
  p->right = right;
  return p;
}
相关算法
int nodes_num(exp *e) {
  switch (e->kind) {
    case E_INT:
      return 1;
    case E_ADD: // fall through
    case E_TIMES:
      return 1 + nodes_num(e->left) + nodes_num(e->right);
    default:
      throw new SyntaxError("compile bug");
  }
}
int pretty_print(exp *e) {
  switch (e->kind) {
    case E_INT:
      printf("%d", e->value);
      return 1;
    case E_ADD:
      printf("(");
      pretty_print(e->left);
      printf(")");
      printf("+");
      printf("(");
      pretty_print(e->right);
      printf(")");
      return 1;
    case E_TIMES:
      printf("(");
      pretty_print(e->left);
      printf(")");
      printf("*");
      printf("(");
      pretty_print(e->right);
      printf(")");
      return 1;
    default:
      throw new SyntaxError();
      break;
  }
}
构造算法
利用语法制导翻译, 在语法动作(action)/语法归约(reduce)中加入生成语法树的代码(自底(叶子)向上(根)构造函数)
E: E + E { $$ = new_exp_add($1, $3); }
 | E * E { $$ = new_exp_times($1, $3); }
 | n     { $$ = new_exp_int($1); }
 ;
Semantic Analysis(语义分析)
- 声明检查(identifiers declaration)
 - 定义检查:
- class 仅可定义一次
 - method 在同一 class 中仅可定义一次
 
 - 类型检查(types)
 - 作用域检查
 - 继承关系(inheritance relationships)
 - 上下文相关分析(检查抽象语法树上下文相关的属性)
 
AST + semantic of programming language --semantic analysis--> intermediate
e.g 变量/函数必须先声明再使用; 每个表达式必须有合适类型(左值/右值); 函数调用与函数定义保持一致(函数签名)
P: D S
 ;
D: T id ';' D
 |
 ;
T: int
 | bool
 ;
S: id = E
 | printi (E)
 | printb (E)
 ;
E: n
 | id
 | true
 | false
 | E + E
 | E && E
 ;
类型系统(type system)
Type Checking
├ e: T meas e 可计算为类型为 T 的值
Type Environments
- Object(identifier) = Type
 OType environments 是一个函数, 将 object identifiers 映射成 typesO ├ e: T表示在 O 函数作用下, 可证明 e 的类型为 T
// input x
// output T
O[T/x](x) = T
O[T/x](y) = O(y)
[Var]
O(x) = T
----------
O ├ x: T
[Let without Init]
O[T0/x] ├ e1: T1
--------------------
O ├ let x: T0 in e1: T1
Typing Methods
- Method(ClassName, functionName) = (Type1, ..., Type_n, Type_n+1)
 - Type_n+1 为返回值的类型, 即方法自身的类型
 
[Dispatch]
O,M ├ e0: T0
O,M ├ e1: T1
...
O,M ├ en: Tn
M(T0, func) = (T1', ..., Tn', Tn+1')
Ti <= Ti'
----------
O,M ├ e0.func(e1, ..., en): Tn+1'
符号表(上下文相关)
用来存储程序中变量的相关信息:
- 类型: 字典结构 (key, type)
 - 作用域:
- 进入作用域, 插入元素(插入哈希表首, 屏蔽外部同名变量); 离开作用域, 删除元素
 - 进入作用域, 压入新符号表; 离开作用域, 弹出栈顶符号表
 
 - 访问控制权
 - 命名空间: 变量, 标签, 形参, 标号 各自拥有一类符号表
 
可将符号表实现为:
- 哈希表: 查找时间复杂度 O(1);
 - 红黑树: 查找时间复杂度 O(lg N);
 
#ifndef XX_SEMANTIC_TABLE_H
#define XX_SEMANTIC_TABLE_H
typedef enum type type_t;
typedef char * key_t;    // typedef int hash_t; typedef hash_t key_t;
typedef struct value {
  type_t type;
  scope_t scope;
} value_t;
typedef ... table_t;// 符号表数据结构
table_t new_table(void);
int table_insert(table_t table, key_t id, value_t info);
value_t table_search(table_t table, key_t id);
#endif
类型检查
- table: 字典结构 (key, type) (Hash Table/Red Black Tree)
 - type environment(Object, Methods, Class) is passed from parent to child(down the tree)
 - types are passed from child to parent(up the tree)
 
TypeCheck(Environment/OMC, e1+e2) = {
    T1 = TypeCheck(OMC, e1);
    T2 = TypeCheck(OMC, e2);
    Check T1 == T2 == Int;
    return Int;
}
TypeCheck(OMC, let x: T <- e0 in e1) = {
    T0 = TypeCheck(OMC, e0);
    T1 = TypeCheck(OMC.add(O(x)=T), e1);
    Check subtype(T0, T1);  // T0 <= T1
    return T1;
}
enum type {INT, BOOL};
table_t table;// symbol table
// dec_t, stm_t, exp_t: AST 中的结点
enum type check_prog(dec_t d, stm_t s) {
  // 生成符号表
  table = check_dec(d);
  // 根据符号表检查语句
  return check_stm(s);
}
// 生成符号表
table_t check_dec(dec_t d){
  foreach(T id <- d) {
    table_insert(table, id, T);
  }
}
enum type check_stm(table_t table, stm_t s) {
  switch (s->kind) {
    case STM_ASSIGN:
      t1 = table_search(table, id);
      t2 = check_exp(table, s->exp);
      if (t1 != t2) {
        throw new SemanticError("type mismatch");
      } else {
        return t1;
      }
    case STM_PRINTI:
      t = check_exp(s->exp);
      if (t != INT) {
        throw new SemanticError("type mismatch");
      } else {
        return INT;
      }
    case STM_PRINTB:
      t = check_exp(s->exp);
      if (t != BOOL) {
        throw new SemanticError("type mismatch");
      } else {
        return BOOL;
      }
  }
}
enum type check_exp(exp_t e) {
  switch (e->kind) {
    case EXP_INT:
      return INT;
    case EXP_ID:
      t = table_search(table, id);// 查询符号表, 得到变量类型
      if (id not exist) {
        throw new SemanticError("id not found");
      } else {
        return t;
      }
    case EXP_TRUE:
      return BOOL;
    case EXP_FALSE:
      return BOOL;
    case EXP_ADD:
      enum type t1 = check_exp_type(e->left);
      enum type t2 = check_exp_type(e->right);
      if (t1 != INT || t2 != INT) {
        throw new SemanticError();
        break;
      } else {
        return INT;
      }
    case EXP_AND:
      enum type t1 = check_exp_type(e->left);
      enum type t2 = check_exp_type(e->right);
      if (t1 != BOOL || t2 != BOOL) {
        throw new SemanticError();
        break;
      } else {
        return BOOL;
      }
    default:
      throw new SemanticError();
      break;
  }
}
作用域检查
table:
- 进入作用域, 插入元素(插入哈希表首, 屏蔽外部同名变量); 离开作用域, 删除元素
 - 进入作用域, 压入新符号表; 离开作用域, 弹出栈顶符号表
 
类型相容性
- 名字不同但结构相同的类型是否相等
 - 面向对象的继承类: is-a 关系 Parent parent = child;
 
错误诊断
- 准确的错误信息: 出错位置等
 - 大量的错误信息
 - 一定的自纠功能
 
Immediate Representation
IR:
- 树与有向无环图(DAG)
 - 三地址码(3-address code)
 - 控制流图(CFG)
 - 静态单赋值形式(SSA)
 - 连续传递风格(CPS)
 
三地址码
- 原子表达式
 - 简单控制流 cjmp/jmp
 - 抽象的机器代码(伪代码)
 
控制流图
Block
- block_t: { label_t; stm_list; jmp_t; }
 - 扫描三地址码, 生成 blocks
 - 图论算法:结点为 blocks, 边为跳转边
 
死基本块删除优化:删除遍历不到的语句块
数据流分析与程序重写
- 根据数据流分析得到的信息, 对三地址码/控制流图进行重写
 - 后端的每一个阶段都可进行数据流分析
 
常量传播优化: 将赋值语句右端变量直接替换为常量, 减少访存
数据分析方法
到达定义分析
分析变量的哪些定义点可以到达变量的使用点处, 若可达定义唯一则可进行常量传播优化:
- in set = prior out set
 - out set = self set + in set - kill set(重复定义点)
 
活性分析
- 寄存器分配优化 活跃区间不相交的变量可共用一个寄存器
 - 并行优化 使用区间并行的计算可并行执行
 
代码优化
组织管理
Activation Record and Frame
AR:
用于管理过程活性(procedure activation)的信息:
- result: 置于记录的顶层, 便于访问此结果
 - argument
 - return address
 - control link: 指向调用者(上级)
 
全局变量
不存于 AR 中, 存于静态数据段
堆区
new/malloc 得到的变量/对象不存于 AR 中, 存于堆区
优化类型
- Local optimizations
 - Global optimizations
 - Inter-procedural optimizations
 
局部优化
- 常量折叠优化: 所有代入常量的地方全部代入常量 
1 + 2 => 3 - 代数化简优化: 
a=1*b => a=b2*a=>a<<1(all tips from CSAPP) - 复制传播(copy propagation)优化: 利用前面计算出来的结果, 直接替换后面所有出现在右边的已计算左式(寄存器)
 
全局优化
Dead Code Elimination
- CFG 中(控制流分析) 死代码块删除优化
 
Constant Propagation
CFG 中(数据流分析-可达定义分析) 常量传播(constant propagation)优化:
- forwards analysis
 - C(stm, x, in) = value of x before stm ; C(stm, x, out) = value of x after stm
 - bottom < c < top => C(stm, x, in) = least_upper_bound{ C(prev_stm_i, x, out) }:
- C(prev_stm, x, out) = top(nondeterministic) => C(stm, x, in) = top
 - C(prev_stm1, x, out) != C(prev_stm2, x, out) => C(stm, x, in) = top
 - C(prev_stm_i, x, out) = c/bottom(dead code) => C(stm, x, in) = c
 
 - C(stm, x, in) = bottom => C(stm, x, out) = bottom
 - C(x := c, x, out) = c
 - C(x := f(), x, out) = top
 - init: set entry to C = top, set anywhere else to C = bottom
 
Liveness Analysis
CFG 中 数据流分析-活性分析(liveness analysis), 可用于复制传播优化与寄存器分配优化:
- backwards analysis
 - L(stm, x, out) = V { L(next_stm, x, in)}
 - L(... := f(x), x, in) = true
 - L(x := e, x, in) = false
 - L(none x, x, in) = L(none x, x, out)
 - init: L(...) = false
 
寄存器分配
Register Allocation and Graph Coloring:
- 当 t1 与 t2 同时具有活性时, 不可共享寄存器; 反之, t1 与 t2 不同时具有活性, 可以共享寄存器
 - 当 t1 与 t2 同时具有活性时, 添加一条边连接 t1 与 t2, 构建 register interference graph(RIG)
 - colors number = registers number, k-colorable problem
 
Code Generation(代码生成)
为数据分配计算资源:
- 数据: 全局变量, 局部变量, 动态分配变量
 - 资源: 寄存器(register), 数据区(.data, .bss), 代码区(.code), 栈区(runtime stack), 堆区(user heap)
 
当前局部变量应该放在寄存器还是内存区?
为代码选择计算指令(等价性):
- 代码: 表达式/语句/函数代码
 - 指令: 算术/比较/跳转/调用/返回指令
 
P: D S
 ;
D: T id ';' D
 |
 ;
T: int
 | bool
 ;
S: id = E
 | printi (E)
 | printb (E)
 ;
E: n
 | id
 | true
 | false
 | E + E
 | E && E
 ;
递归下降代码生成算法
基于栈计算机
Mem + Stack + ALU
JVM(Java Virtual Machine)
s: push NUM
 | load x
 | store x
 | add
 | sub
 | times
 | div
 ;
gen_prog(dec_t d, stm_t s) {
  gen_dec(d);
  gen_stm(s);
}
gen_dec(T id; D) {
  // stack_code(".int id")
  gen_type(T);
  emit(" id");
  gen_dec(D);
}
gen_type(type_t t) {
  switch(t-kind) {
    case INT:// fall through
    case BOOL:
      emit(".int");
      break;
  }
}
gen_stm(stm_t s) {
  switch (s->kind) {
    STM_ASSIGN:
      gen_exp(s->exp);
      emit("store s->id");
      break;
    STM_PRINTI:
      gen_exp(s->exp);
      emit("printi");
      break;
    STM_PRINTB:
      gen_exp(s->exp);
      emit("printb");
      break;
  }
}
gen_exp(exp_t e) {
  switch (e->kind) {
    case EXP_INT:
      emit("push e->value");// n
      break;
    case EXP_ID:
      emit("load e->value");// id
      break;
    case EXP_BOOL:
      emit("push e->value");// 1/0
      break;
    case EXP_ADD:
      gen_exp(e->left);
      gen_exp(e->right);
      emit("add");
      break;
    case EXP_AND:
      gen_exp(e->left);
      gen_exp(e->right);
      emit("and");
      break;
  }
}
基于寄存器计算机 (RISC)
Mem + Reg + ALU
MIPS ISA
// src -> dist
s: mov_n n, r
 | mov r1, r2
 | load [x], r
 | store r, [x]
 | add r1, r2, r3
 | sub r1, r2, r3
 | times r1, r2, r3
 | div r1, r2, r3
void gen_prog(dec_t d, stm_t s) {
  gen_dec(d);
  gen_stm(s);
}
void gen_dec(T id; D) {
  // reg_code(".int id")
  // 为变量分配寄存器
  gen_type(T);
  emit(" id");
  gen_dec(D);
}
void gen_type(type_t t) {
  switch(t-kind) {
    case INT:// fall through
    case BOOL:
      emit(".int");
      break;
  }
}
void gen_stm(stm_t s) {
  switch (s->kind) {
    STM_ASSIGN:
      r = gen_exp(s->exp);
      emit("mov r, e->id");
      break;
    STM_PRINTI:
      r = gen_exp(s->exp);
      emit("printi r");
      break;
    STM_PRINTB:
      r = gen_exp(s->exp);
      emit("printb r");
      break;
  }
}
reg_t gen_exp(exp_t e) {
  switch (e->kind) {
    case EXP_INT:
      r = random_reg();
      emit("mov_n e->value, r");// n
      return r;
    case EXP_ID:
      r = random_reg();
      emit("mov e->value, r");// id
      return r;
    case EXP_BOOL:
      r = random_reg();
      emit("mov_n e->value, r");// 1/0
      return r;
    case EXP_ADD:
      r1 = gen_exp(e->left);
      r2 = gen_exp(e->right);
      r = random_reg();
      emit("add r1, r2, r");
      return r;
    case EXP_AND:
      r1 = gen_exp(e->left);
      r2 = gen_exp(e->right);
      r = random_reg();
      emit("and r1, r2, r");
      return r;
  }
}
Garbage Collection
Mark and Sweep
- mark phase: traces reachable objects (mark_bit |= 1)
 
let todo = {all roots}
while todo != nil do
    pick v <- todo
    todo -= {v}
    if mark(v) == 0 then
        mark(v) |= 1
        let v1, ..., vn be the pointers contained in v
        todo += {v1, ..., vn}
    fi
od
- sweep phase: collects garbage objects (mark_bit == 0)
 
p = bottom of heap
while p < top of heap do
    if mark(p) == 1 then
        mark(p) = 0
    else
        add block p...(p + sizeof(p) - 1)  to freeList
    fi
    p += sizeof(p)
od
Stop and Copy
Copy all reachable objects in old space to new space(reserved for GC):
- Copied objects
 - Scanned objects: pointers have been restored
 
Compilers Exercise
C Declaration Interpreter
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#define MAX_TOKENS 100
#define MAX_TOKEN_LEN 64
enum type_tag {
    IDENTIFIER,
    QUALIFIER,
    TYPE,
};
struct token {
    char type;
    char string[MAX_TOKEN_LEN];
};
int top = -1;
struct token stack[MAX_TOKENS];
struct token ts;
#define pop stack[top--]
#define push(s) stack[++top] = s
enum type_tag classify_string(void) {
    char *s = ts.string;
    if (!strcmp(s, "const")) {
        strcpy(s, "read-only ");
        return QUALIFIER;
    }
    if (!strcmp(s, "volatile")) return QUALIFIER;
    if (!strcmp(s, "void")) return TYPE;
    if (!strcmp(s, "char")) return TYPE;
    if (!strcmp(s, "signed")) return TYPE;
    if (!strcmp(s, "unsigned")) return TYPE;
    if (!strcmp(s, "short")) return TYPE;
    if (!strcmp(s, "int")) return TYPE;
    if (!strcmp(s, "long")) return TYPE;
    if (!strcmp(s, "float")) return TYPE;
    if (!strcmp(s, "double")) return TYPE;
    if (!strcmp(s, "struct")) return TYPE;
    if (!strcmp(s, "union")) return TYPE;
    if (!strcmp(s, "enum")) return TYPE;
    return IDENTIFIER;
}
void get_token(void) {
    char *p = ts.string;
    /* 略过空白字符 */
    while ((*p = getchar()) == ' ');
    if (isalnum(*p)) {
        /* 读入得标识符以a-Z,0-9开头 */
        while (isalnum(*++p = getchar()));
        ungetc(*p, stdin);
        *p = '\0';
        ts.type = classify_string();
        return;
    }
    if (*p == '*') {
        strcpy(ts.string, "pointer to");
        ts.type = '*';
        return;
    }
    ts.string[1] = '\0';
    ts.type = *p;
    return;
}
void read_to_first_identifier(void) {
    get_token();
  // read til identifier
    while (ts.type != IDENTIFIER) {
        push(ts);
        get_token();
    }
    printf("%s is ", ts.string);
    get_token();
}
void deal_with_arrays(void) {
    while (ts.type == '[') {
        printf("array ");
        get_token();
    /* 数字或']' */
        if (isdigit(ts.string[0])) {
            printf("0..%d ", atoi(ts.string) - 1);
            get_token();
        }
        get_token();
        printf("of ");
    }
}
void deal_with_pointers(void) {
    while (stack[top].type == '*')
    {
        printf("%s ", pop.string);
    }
}
void deal_with_function_args(void) {
    while (ts.type != ')') {
        get_token();
    }
    get_token();
    printf("function returning ");
}
void deal_with_declarator(void) {
    /* 处理标识符之后可能存在的数组/函数 */
    switch (ts.type) {
      case '[':
          deal_with_arrays();
          break;
      case '(':
          deal_with_function_args();
          break;
    }
    deal_with_pointers();
    /* 处理在读入到标识符之前压入到堆栈中的符号 */
    while (top >= 0) {
        if (stack[top].type == '(') {
            pop;
            get_token();  //读取')'之后的符号
            deal_with_declarator();
        } else {
            printf("%s", pop.string);
        }
    }
}
int main(void) {
    /* 将标记压入堆栈中, 直到遇见标识符 */
    read_to_first_identifier();
    deal_with_declarator();
    printf("\n");
    system("pause");
    return 0;
}
Cool Language
Classroom Object-Oriented Language:
Parser Implementation
// 返回下一个Token(只测试该Token,不向前移动Token List的offset指针)
Token Peek(void);
// 消费下一个Token
Token Next(void);
// void Expect(expectedToken)
if (Peek() != expectedToken) {
    Error("expect %s, but got %s\n", expectedToken, Peek());
}
// void Try(expectedToken)
if (Peek() == expectedToken) {
    Next(); // 消费之
    return true;
}
return false;