// File: /workspace/github_c_makefile_star2_O0/ejunjsh[P]mycc/gen.c
// Function: genAST
int genAST(struct ASTnode *n, int iflabel, int looptoplabel,
	   int loopendlabel, int parentASTop) {
  int leftreg = NOREG, rightreg = NOREG;

  // 空树，什么都不做
  if (n == NULL)
    return (NOREG);

  // 在输出中更新行号
  update_line(n);

  // 上面我们定义了一些语法树节点处理的函数，所以，如果遇到某些操作，就直接扔给相关函数处理即可
  switch (n->op) {
  case A_IF:
    return (genIF(n, looptoplabel, loopendlabel));
  case A_WHILE:
    return (genWHILE(n));
  case A_SWITCH:
    return (genSWITCH(n));
  case A_FUNCCALL:
    return (gen_funccall(n));
  case A_TERNARY:
    return (gen_ternary(n));
  case A_LOGOR:
    return (gen_logandor(n));
  case A_LOGAND:
    return (gen_logandor(n));
  case A_GLUE:
    // 执行每个子语句，然后释放所有寄存器
    if (n->left != NULL)
      genAST(n->left, iflabel, looptoplabel, loopendlabel, n->op);
    genfreeregs(NOREG);
    if (n->right != NULL)
      genAST(n->right, iflabel, looptoplabel, loopendlabel, n->op);
    genfreeregs(NOREG);
    return (NOREG);
  case A_FUNCTION:
    // 生成函数的前置汇编，然会再到子树的汇编
    cgfuncpreamble(n->sym);
    genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);
    cgfuncpostamble(n->sym);
    return (NOREG);
  }

  // 下面是通用语法树处理

  // 获得左树和右数的值
  if (n->left)
    leftreg = genAST(n->left, NOLABEL, NOLABEL, NOLABEL, n->op);
  if (n->right)
    rightreg = genAST(n->right, NOLABEL, NOLABEL, NOLABEL, n->op);

  switch (n->op) {
  case A_ADD:
    return (cgadd(leftreg, rightreg));
  case A_SUBTRACT:
    return (cgsub(leftreg, rightreg));
  case A_MULTIPLY:
    return (cgmul(leftreg, rightreg));
  case A_DIVIDE:
    return (cgdivmod(leftreg, rightreg, A_DIVIDE));
  case A_MOD:
    return (cgdivmod(leftreg, rightreg, A_MOD));
  case A_AND:
    return (cgand(leftreg, rightreg));
  case A_OR:
    return (cgor(leftreg, rightreg));
  case A_XOR:
    return (cgxor(leftreg, rightreg));
  case A_LSHIFT:
    return (cgshl(leftreg, rightreg));
  case A_RSHIFT:
    return (cgshr(leftreg, rightreg));
  case A_EQ:
  case A_NE:
  case A_LT:
  case A_GT:
  case A_LE:
  case A_GE:
    // 如果父节点是A_IF, A_WHILE 或者 A_TERNARY，
    // 生成比较和跳转的代码，否则比较寄存器，然后根据比较结果设置其中一个寄存器的值为1或0
    if (parentASTop == A_IF || parentASTop == A_WHILE || parentASTop == A_TERNARY)
      return (cgcompare_and_jump(n->op, leftreg, rightreg, iflabel, n->left->type));
    else
      return (cgcompare_and_set(n->op, leftreg, rightreg, n->left->type));
  case A_INTLIT:
    return (cgloadint(n->atu.a_intvalue, n->type));
  case A_STRLIT:
    return (cgloadglobstr(n->atu.a_intvalue));
  case A_IDENT:
    // 如果是右值或者是解引用，则加载值
    if (n->rvalue || parentASTop == A_DEREF) {
      return (cgloadvar(n->sym, n->op));
    } else
      return (NOREG);
  case A_ASPLUS:
  case A_ASMINUS:
  case A_ASSTAR:
  case A_ASSLASH:
  case A_ASMOD:
  case A_ASSIGN:

    // 对于'+='和相关操作，生成合适的汇编代码，同时获取结果寄存器
    // 然后令右节点等于左节点，这样就变成赋值操作了
    switch (n->op) {
    case A_ASPLUS:
      leftreg = cgadd(leftreg, rightreg);
      n->right = n->left;
      break;
    case A_ASMINUS:
      leftreg = cgsub(leftreg, rightreg);
      n->right = n->left;
      break;
    case A_ASSTAR:
      leftreg = cgmul(leftreg, rightreg);
      n->right = n->left;
      break;
    case A_ASSLASH:
      leftreg = cgdivmod(leftreg, rightreg, A_DIVIDE);
      n->right = n->left;
      break;
    case A_ASMOD:
      leftreg = cgdivmod(leftreg, rightreg, A_MOD);
      n->right = n->left;
      break;
    }

    // 赋值代码
    switch (n->right->op) {
    case A_IDENT:
      if (n->right->sym->class == C_GLOBAL ||
        n->right->sym->class == C_EXTERN ||
        n->right->sym->class == C_STATIC)
	      return (cgstorglob(leftreg, n->right->sym));
      else
	      return (cgstorlocal(leftreg, n->right->sym));
    case A_DEREF:
      return (cgstorderef(leftreg, rightreg, n->right->type));
    default:
      fatald("Can't A_ASSIGN in genAST(), op", n->op);
    }
  case A_WIDEN:
    // 加宽子节点的类型到父节点的类型
    return (cgwiden(leftreg, n->left->type, n->type));
  case A_RETURN:
    cgreturn(leftreg, Functionid);
    return (NOREG);
  case A_ADDR:
    // 如果有符号，直接获取它的地址，否则左寄存器已经有地址，因为这是个成员访问
    if (n->sym != NULL)
      return (cgaddress(n->sym));
    else
      return (leftreg);
  case A_DEREF:
    // 如果是右值，解引用来获得值
    // 否则直接返回，留给A_ASSIGN来处理
    if (n->rvalue)
      return (cgderef(leftreg, n->left->type));
    else
      return (leftreg);
  case A_SCALE:
    // 小优化：如果大小是2的幂次方，就使用位移来处理
    switch (n->atu.a_size) {
    case 2:
      return (cgshlconst(leftreg, 1));
    case 4:
      return (cgshlconst(leftreg, 2));
    case 8:
      return (cgshlconst(leftreg, 3));
    default:
      // 加载大小到寄存器，然后用左寄存器相乘
      rightreg = cgloadint(n->atu.a_size, P_INT);
      return (cgmul(leftreg, rightreg));
    }
  case A_POSTINC:
  case A_POSTDEC:
    // 例如：i++
    // 先返回i，再++
    return (cgloadvar(n->sym, n->op));
  case A_PREINC:
  case A_PREDEC:
    // 例如：++i
    // 先++，再返回i
    return (cgloadvar(n->left->sym, n->op));
  case A_NEGATE:
    return (cgnegate(leftreg));
  case A_INVERT:
    return (cginvert(leftreg));
  case A_LOGNOT:
    return (cglognot(leftreg));
  case A_TOBOOL:
    // 如果父节点是A_IF, A_WHILE，
    // 生成比较和跳转的代码，否则根据是零还是非零来设置寄存器的值为0或1
    return (cgboolean(leftreg, parentASTop, iflabel));
  case A_BREAK:
    cgjump(loopendlabel);
    return (NOREG);
  case A_CONTINUE:
    cgjump(looptoplabel);
    return (NOREG);
  case A_CAST:
    return (leftreg);		// 什么都不用做
  default:
    fatald("Unknown AST operator", n->op);
  }
  return (NOREG);	
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x50, %rsp
movq %rdi, -0x10(%rbp)
movl %esi, -0x14(%rbp)
movl %edx, -0x18(%rbp)
movl %ecx, -0x1c(%rbp)
movl %r8d, -0x20(%rbp)
movl $0xffffffff, -0x24(%rbp) # imm = 0xFFFFFFFF
movl $0xffffffff, -0x28(%rbp) # imm = 0xFFFFFFFF
cmpq $0x0, -0x10(%rbp)
jne 0x688a
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0x6f71
movq -0x10(%rbp), %rdi
callq 0x6f80
movq -0x10(%rbp), %rax
movl 0x4(%rax), %eax
addl $-0x7, %eax
movl %eax, %ecx
movq %rcx, -0x30(%rbp)
subl $0x2a, %eax
ja 0x69f0
movq -0x30(%rbp), %rax
leaq 0x6959(%rip), %rcx      # 0xd210
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq -0x10(%rbp), %rdi
movl -0x18(%rbp), %esi
movl -0x1c(%rbp), %edx
callq 0x6fd0
movl %eax, -0x4(%rbp)
jmp 0x6f71
movq -0x10(%rbp), %rdi
callq 0x70b0
movl %eax, -0x4(%rbp)
jmp 0x6f71
movq -0x10(%rbp), %rdi
callq 0x7140
movl %eax, -0x4(%rbp)
jmp 0x6f71
movq -0x10(%rbp), %rdi
callq 0x72c0
movl %eax, -0x4(%rbp)
jmp 0x6f71
movq -0x10(%rbp), %rdi
callq 0x7350
movl %eax, -0x4(%rbp)
jmp 0x6f71
movq -0x10(%rbp), %rdi
callq 0x7420
movl %eax, -0x4(%rbp)
jmp 0x6f71
movq -0x10(%rbp), %rdi
callq 0x7420
movl %eax, -0x4(%rbp)
jmp 0x6f71
movq -0x10(%rbp), %rax
cmpq $0x0, 0x20(%rax)
je 0x6966
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rdi
movl -0x14(%rbp), %esi
movl -0x18(%rbp), %edx
movl -0x1c(%rbp), %ecx
movq -0x10(%rbp), %rax
movl 0x4(%rax), %r8d
callq 0x6850
movl $0xffffffff, %edi       # imm = 0xFFFFFFFF
callq 0x7520
movq -0x10(%rbp), %rax
cmpq $0x0, 0x30(%rax)
je 0x6999
movq -0x10(%rbp), %rax
movq 0x30(%rax), %rdi
movl -0x14(%rbp), %esi
movl -0x18(%rbp), %edx
movl -0x1c(%rbp), %ecx
movq -0x10(%rbp), %rax
movl 0x4(%rax), %r8d
callq 0x6850
movl $0xffffffff, %edi       # imm = 0xFFFFFFFF
callq 0x7520
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0x6f71
movq -0x10(%rbp), %rax
movq 0x38(%rax), %rdi
callq 0x2670
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rdi
movq -0x10(%rbp), %rax
movl 0x4(%rax), %r8d
xorl %ecx, %ecx
movl %ecx, %esi
movl %ecx, %edx
callq 0x6850
movq -0x10(%rbp), %rax
movq 0x38(%rax), %rdi
callq 0x2900
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0x6f71
movq -0x10(%rbp), %rax
cmpq $0x0, 0x20(%rax)
je 0x6a19
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rdi
movq -0x10(%rbp), %rax
movl 0x4(%rax), %r8d
xorl %ecx, %ecx
movl %ecx, %esi
movl %ecx, %edx
callq 0x6850
movl %eax, -0x24(%rbp)
movq -0x10(%rbp), %rax
cmpq $0x0, 0x30(%rax)
je 0x6a42
movq -0x10(%rbp), %rax
movq 0x30(%rax), %rdi
movq -0x10(%rbp), %rax
movl 0x4(%rax), %r8d
xorl %ecx, %ecx
movl %ecx, %esi
movl %ecx, %edx
callq 0x6850
movl %eax, -0x28(%rbp)
movq -0x10(%rbp), %rax
movl 0x4(%rax), %eax
decl %eax
movl %eax, %ecx
movq %rcx, -0x38(%rbp)
subl $0x33, %eax
ja 0x6f57
movq -0x38(%rbp), %rax
leaq 0x6857(%rip), %rcx      # 0xd2bc
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movl -0x24(%rbp), %edi
movl -0x28(%rbp), %esi
callq 0x2e90
movl %eax, -0x4(%rbp)
jmp 0x6f71
movl -0x24(%rbp), %edi
movl -0x28(%rbp), %esi
callq 0x2ef0
movl %eax, -0x4(%rbp)
jmp 0x6f71
movl -0x24(%rbp), %edi
movl -0x28(%rbp), %esi
callq 0x2f50
movl %eax, -0x4(%rbp)
jmp 0x6f71
movl -0x24(%rbp), %edi
movl -0x28(%rbp), %esi
movl $0x18, %edx
callq 0x2fb0
movl %eax, -0x4(%rbp)
jmp 0x6f71
movl -0x24(%rbp), %edi
movl -0x28(%rbp), %esi
movl $0x19, %edx
callq 0x2fb0
movl %eax, -0x4(%rbp)
jmp 0x6f71
movl -0x24(%rbp), %edi
movl -0x28(%rbp), %esi
callq 0x3090
movl %eax, -0x4(%rbp)
jmp 0x6f71
movl -0x24(%rbp), %edi
movl -0x28(%rbp), %esi
callq 0x30f0
movl %eax, -0x4(%rbp)
jmp 0x6f71
movl -0x24(%rbp), %edi
movl -0x28(%rbp), %esi
callq 0x3150
movl %eax, -0x4(%rbp)
jmp 0x6f71
movl -0x24(%rbp), %edi
movl -0x28(%rbp), %esi
callq 0x31b0
movl %eax, -0x4(%rbp)
jmp 0x6f71
movl -0x24(%rbp), %edi
movl -0x28(%rbp), %esi
callq 0x3220
movl %eax, -0x4(%rbp)
jmp 0x6f71
cmpl $0x1e, -0x20(%rbp)
je 0x6b48
cmpl $0x1f, -0x20(%rbp)
je 0x6b48
cmpl $0x7, -0x20(%rbp)
jne 0x6b71
movq -0x10(%rbp), %rax
movl 0x4(%rax), %edi
movl -0x24(%rbp), %esi
movl -0x28(%rbp), %edx
movl -0x14(%rbp), %ecx
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rax
movl 0x8(%rax), %r8d
callq 0x3bf0
movl %eax, -0x4(%rbp)
jmp 0x6f71
movq -0x10(%rbp), %rax
movl 0x4(%rax), %edi
movl -0x24(%rbp), %esi
movl -0x28(%rbp), %edx
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rax
movl 0x8(%rax), %ecx
callq 0x3a40
movl %eax, -0x4(%rbp)
jmp 0x6f71
movq -0x10(%rbp), %rax
movl (%rax), %edi
movq -0x10(%rbp), %rax
movl 0x8(%rax), %esi
callq 0x2990
movl %eax, -0x4(%rbp)
jmp 0x6f71
movq -0x10(%rbp), %rax
movl (%rax), %edi
callq 0x2e40
movl %eax, -0x4(%rbp)
jmp 0x6f71
movq -0x10(%rbp), %rax
cmpl $0x0, 0x18(%rax)
jne 0x6bd3
cmpl $0x24, -0x20(%rbp)
jne 0x6bef
movq -0x10(%rbp), %rax
movq 0x38(%rax), %rdi
movq -0x10(%rbp), %rax
movl 0x4(%rax), %esi
callq 0x29e0
movl %eax, -0x4(%rbp)
jmp 0x6f71
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0x6f71
movq -0x10(%rbp), %rax
movl 0x4(%rax), %eax
addl $-0x2, %eax
movl %eax, %ecx
movq %rcx, -0x40(%rbp)
subl $0x4, %eax
ja 0x6cd3
movq -0x40(%rbp), %rax
leaq 0x676d(%rip), %rcx      # 0xd38c
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movl -0x24(%rbp), %edi
movl -0x28(%rbp), %esi
callq 0x2e90
movl %eax, -0x24(%rbp)
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rcx
movq -0x10(%rbp), %rax
movq %rcx, 0x30(%rax)
jmp 0x6cd3
movl -0x24(%rbp), %edi
movl -0x28(%rbp), %esi
callq 0x2ef0
movl %eax, -0x24(%rbp)
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rcx
movq -0x10(%rbp), %rax
movq %rcx, 0x30(%rax)
jmp 0x6cd3
movl -0x24(%rbp), %edi
movl -0x28(%rbp), %esi
callq 0x2f50
movl %eax, -0x24(%rbp)
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rcx
movq -0x10(%rbp), %rax
movq %rcx, 0x30(%rax)
jmp 0x6cd3
movl -0x24(%rbp), %edi
movl -0x28(%rbp), %esi
movl $0x18, %edx
callq 0x2fb0
movl %eax, -0x24(%rbp)
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rcx
movq -0x10(%rbp), %rax
movq %rcx, 0x30(%rax)
jmp 0x6cd3
movl -0x24(%rbp), %edi
movl -0x28(%rbp), %esi
movl $0x19, %edx
callq 0x2fb0
movl %eax, -0x24(%rbp)
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rcx
movq -0x10(%rbp), %rax
movq %rcx, 0x30(%rax)
movq -0x10(%rbp), %rax
movq 0x30(%rax), %rax
movl 0x4(%rax), %eax
movl %eax, -0x44(%rbp)
subl $0x1c, %eax
je 0x6cf5
jmp 0x6ce8
movl -0x44(%rbp), %eax
subl $0x24, %eax
je 0x6d63
jmp 0x6d81
movq -0x10(%rbp), %rax
movq 0x30(%rax), %rax
movq 0x38(%rax), %rax
cmpl $0x1, 0x24(%rax)
je 0x6d2b
movq -0x10(%rbp), %rax
movq 0x30(%rax), %rax
movq 0x38(%rax), %rax
cmpl $0x4, 0x24(%rax)
je 0x6d2b
movq -0x10(%rbp), %rax
movq 0x30(%rax), %rax
movq 0x38(%rax), %rax
cmpl $0x5, 0x24(%rax)
jne 0x6d47
movl -0x24(%rbp), %edi
movq -0x10(%rbp), %rax
movq 0x30(%rax), %rax
movq 0x38(%rax), %rsi
callq 0x36b0
movl %eax, -0x4(%rbp)
jmp 0x6f71
movl -0x24(%rbp), %edi
movq -0x10(%rbp), %rax
movq 0x30(%rax), %rax
movq 0x38(%rax), %rsi
callq 0x2810
movl %eax, -0x4(%rbp)
jmp 0x6f71
movl -0x24(%rbp), %edi
movl -0x28(%rbp), %esi
movq -0x10(%rbp), %rax
movq 0x30(%rax), %rax
movl 0x8(%rax), %edx
callq 0x4030
movl %eax, -0x4(%rbp)
jmp 0x6f71
movq -0x10(%rbp), %rax
movl 0x4(%rax), %esi
leaq 0x6611(%rip), %rdi      # 0xd3a0
callq 0x8180
jmp 0x6d96
movl -0x24(%rbp), %edi
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rax
movl 0x8(%rax), %esi
movq -0x10(%rbp), %rax
movl 0x8(%rax), %edx
callq 0x3d40
movl %eax, -0x4(%rbp)
jmp 0x6f71
movl -0x24(%rbp), %edi
leaq 0xb746(%rip), %rax      # 0x12508
movq (%rax), %rsi
callq 0x3d60
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0x6f71
movq -0x10(%rbp), %rax
cmpq $0x0, 0x38(%rax)
je 0x6df6
movq -0x10(%rbp), %rax
movq 0x38(%rax), %rdi
callq 0x3e80
movl %eax, -0x4(%rbp)
jmp 0x6f71
movl -0x24(%rbp), %eax
movl %eax, -0x4(%rbp)
jmp 0x6f71
movq -0x10(%rbp), %rax
cmpl $0x0, 0x18(%rax)
je 0x6e26
movl -0x24(%rbp), %edi
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rax
movl 0x8(%rax), %esi
callq 0x3f20
movl %eax, -0x4(%rbp)
jmp 0x6f71
movl -0x24(%rbp), %eax
movl %eax, -0x4(%rbp)
jmp 0x6f71
movq -0x10(%rbp), %rax
movl (%rax), %eax
movl %eax, -0x48(%rbp)
subl $0x2, %eax
je 0x6e55
jmp 0x6e41
movl -0x48(%rbp), %eax
subl $0x4, %eax
je 0x6e6a
jmp 0x6e4b
movl -0x48(%rbp), %eax
subl $0x8, %eax
je 0x6e7f
jmp 0x6e94
movl -0x24(%rbp), %edi
movl $0x1, %esi
callq 0x3660
movl %eax, -0x4(%rbp)
jmp 0x6f71
movl -0x24(%rbp), %edi
movl $0x2, %esi
callq 0x3660
movl %eax, -0x4(%rbp)
jmp 0x6f71
movl -0x24(%rbp), %edi
movl $0x3, %esi
callq 0x3660
movl %eax, -0x4(%rbp)
jmp 0x6f71
movq -0x10(%rbp), %rax
movl (%rax), %edi
movl $0x30, %esi
callq 0x2990
movl %eax, -0x28(%rbp)
movl -0x24(%rbp), %edi
movl -0x28(%rbp), %esi
callq 0x2f50
movl %eax, -0x4(%rbp)
jmp 0x6f71
movq -0x10(%rbp), %rax
movq 0x38(%rax), %rdi
movq -0x10(%rbp), %rax
movl 0x4(%rax), %esi
callq 0x29e0
movl %eax, -0x4(%rbp)
jmp 0x6f71
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rax
movq 0x38(%rax), %rdi
movq -0x10(%rbp), %rax
movl 0x4(%rax), %esi
callq 0x29e0
movl %eax, -0x4(%rbp)
jmp 0x6f71
movl -0x24(%rbp), %edi
callq 0x3290
movl %eax, -0x4(%rbp)
jmp 0x6f71
movl -0x24(%rbp), %edi
callq 0x32d0
movl %eax, -0x4(%rbp)
jmp 0x6f71
movl -0x24(%rbp), %edi
callq 0x3310
movl %eax, -0x4(%rbp)
jmp 0x6f71
movl -0x24(%rbp), %edi
movl -0x20(%rbp), %esi
movl -0x14(%rbp), %edx
callq 0x3400
movl %eax, -0x4(%rbp)
jmp 0x6f71
movl -0x1c(%rbp), %edi
callq 0x3bc0
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0x6f71
movl -0x18(%rbp), %edi
callq 0x3bc0
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
jmp 0x6f71
movl -0x24(%rbp), %eax
movl %eax, -0x4(%rbp)
jmp 0x6f71
movq -0x10(%rbp), %rax
movl 0x4(%rax), %esi
leaq 0x645a(%rip), %rdi      # 0xd3bf
callq 0x8180
movl $0xffffffff, -0x4(%rbp) # imm = 0xFFFFFFFF
movl -0x4(%rbp), %eax
addq $0x50, %rsp
popq %rbp
retq
nopw (%rax,%rax)