// File: /workspace/github_c_makefile_star2_O2/ejunjsh[P]mycc/expr.c
// Function: binexpr
struct ASTnode *binexpr(int ptp) {
  struct ASTnode *left, *right;
  struct ASTnode *ltemp, *rtemp;
  int ASTop;
  int tokentype;

  // 获取树放在left
  // 同时获得下个token
  left = prefix(ptp);

  // 如果遇到下面终结token之一，直接返回这个left节点
  tokentype = Token.token;
  if (tokentype == T_SEMI || tokentype == T_RPAREN ||
      tokentype == T_RBRACKET || tokentype == T_COMMA ||
      tokentype == T_COLON || tokentype == T_RBRACE) {
    left->rvalue = 1;
    return (left);
  }

  // 当前token的优先级大于之前token的优先级(ptp)
  // 或者是右关联同时跟之前token的优先级(ptp)相等
  while ((op_precedence(tokentype) > ptp) ||
	 (rightassoc(tokentype) && op_precedence(tokentype) == ptp)) {
    // 获取下一个token
    scan(&Token);

    // 递归调用binexpr()，其参数就是当前的优先级
    // 创建子树放到right
    right = binexpr(OpPrec[tokentype]);

    // 判断操作符，执行相应操作
    ASTop = binastop(tokentype);

    switch (ASTop) {
    // 三元操作符 aaa?bbb:ccc
    case A_TERNARY:
      // 确认后面跟着的是':'
      match(T_COLON, ":");
      ltemp = binexpr(0);

      // 创建一个语法树节点，然后返回
      // 中间表达式（right）的类型作为该节点类型
      // TODO: 为什么不考虑下第三个表达式（left）的类型呢
      return (mkastnode
	      (A_TERNARY, right->type, right->ctype, left, right, ltemp,
	       NULL, 0));

    case A_ASSIGN:
      // 赋值
      // 令right树为右值
      right->rvalue = 1;

      // 保证right的类型匹配left的
      right = modify_type(right, left->type, left->ctype, 0);
      if (right == NULL)
	      fatal("Incompatible expression in assignment");

      // 交换right和left
      // 这样right表达式生成的汇编会在left表达式前面
      // 例如a=b+1,是不是b+1要先执行呢 
      ltemp = left;
      left = right;
      right = ltemp;
      break;

    default:
      // 如果没有三元或者赋值，那就把left和right树都变成右值
      left->rvalue = 1;
      right->rvalue = 1;

      // TODO: 对于A_ASPLUS等类型加上解引用是有问题等，mark之
      // if(ASTop==A_ASPLUS){
      //   left->rvalue = 0;
      // }

      // 保证这两个类型要兼容，
      // 如果兼容的话，修改其中一个树去匹配另外一个树
      ltemp = modify_type(left, right->type, right->ctype, ASTop);
      rtemp = modify_type(right, left->type, left->ctype, ASTop);
      if (ltemp == NULL && rtemp == NULL)
	      fatal("Incompatible types in binary expression");
      if (ltemp != NULL)
	      left = ltemp;
      if (rtemp != NULL)
	      right = rtemp;
    }

    // left和right合成一个新节点又放回left
    // 新节点的操作是从token类型转换过来的
    left =
      mkastnode(binastop(tokentype), left->type, left->ctype, left, NULL,
		right, NULL, 0);

    // 下面的操作符，都使节点类型变成整型，不管操作数是什么类型
    switch (binastop(tokentype)) {
    case A_LOGOR:
    case A_LOGAND:
    case A_EQ:
    case A_NE:
    case A_LT:
    case A_GT:
    case A_LE:
    case A_GE:
      left->type = P_INT;
    }

    // 获取最新的token类型
    // 如果到了结束token，返回left节点
    tokentype = Token.token;
    if (tokentype == T_SEMI || tokentype == T_RPAREN ||
        tokentype == T_RBRACKET || tokentype == T_COMMA ||
        tokentype == T_COLON || tokentype == T_RBRACE) {
      left->rvalue = 1;
      return (left);
    }
  }

  // 如果优先级一样或者更加低，直接返回
  left->rvalue = 1;
  return (left);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x28, %rsp
movl %edi, %r14d
callq 0x4bae
movq %rax, %r12
leaq 0x99c8(%rip), %rax      # 0xe3a0
movl (%rax), %r15d
leal -0x35(%r15), %eax
cmpl $0xb, %eax
ja 0x49f2
movl $0x9a9, %ecx            # imm = 0x9A9
btl %eax, %ecx
jb 0x4b58
movl %r15d, %edi
callq 0x5227
cmpl %r14d, %eax
jg 0x4a1d
leal -0x6(%r15), %eax
cmpl $-0x5, %eax
jb 0x4b58
movl %r15d, %edi
callq 0x5227
cmpl %r14d, %eax
jne 0x4b58
leaq 0x997c(%rip), %rdi      # 0xe3a0
callq 0x66f4
movslq %r15d, %rax
leaq 0x53bd(%rip), %rcx      # 0x9df0
movl (%rcx,%rax,4), %edi
callq 0x49b5
movq %rax, %r13
movl %r15d, %edi
callq 0x527f
cmpl $0x1, %eax
je 0x4ac8
movl %eax, %ebx
cmpl $0x7, %eax
je 0x4b73
movl %r14d, -0x2c(%rbp)
pushq $0x1
popq %rax
movl %eax, 0x18(%r12)
movl %eax, 0x18(%r13)
movl 0x8(%r13), %esi
movq 0x10(%r13), %rdx
movq %r12, %rdi
movl %ebx, %ecx
callq 0x87ba
movq %rax, -0x38(%rbp)
movl 0x8(%r12), %esi
movq 0x10(%r12), %rdx
movq %r13, %rdi
movl %ebx, %ecx
callq 0x87ba
movq %rax, %r14
movq -0x38(%rbp), %rax
movq %rax, %rbx
orq %r14, %rax
jne 0x4aab
leaq 0x53b4(%rip), %rdi      # 0x9e5a
callq 0x6515
movq %rbx, %rax
testq %rbx, %rbx
movq %r12, %rbx
cmovneq %rax, %rbx
testq %r14, %r14
cmovneq %r14, %r13
movq %r13, %r12
movl -0x2c(%rbp), %r14d
jmp 0x4afc
movl $0x1, 0x18(%r13)
movl 0x8(%r12), %esi
movq 0x10(%r12), %rdx
movq %r13, %rdi
xorl %ecx, %ecx
callq 0x87ba
testq %rax, %rax
je 0x4aee
movq %rax, %rbx
jmp 0x4afc
leaq 0x5275(%rip), %rdi      # 0x9d6a
callq 0x6515
xorl %ebx, %ebx
leaq 0x989d(%rip), %r13      # 0xe3a0
movl %r15d, %edi
callq 0x527f
movl 0x8(%rbx), %esi
movq 0x10(%rbx), %rdx
andl $0x0, 0x8(%rsp)
andq $0x0, (%rsp)
movl %eax, %edi
movq %rbx, %rcx
xorl %r8d, %r8d
movq %r12, %r9
callq 0x8108
movq %rax, %r12
movl %r15d, %edi
callq 0x527f
cmpl $0x12, %eax
ja 0x4b4f
movl $0x7e300, %ecx          # imm = 0x7E300
btl %eax, %ecx
jae 0x4b4f
movl $0x30, 0x8(%r12)
movl (%r13), %r15d
jmp 0x49db
movl $0x1, 0x18(%r12)
movq %r12, %rax
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x4a0b(%rip), %rsi      # 0x9585
pushq $0x40
popq %rdi
callq 0x63f8
xorl %edi, %edi
callq 0x49b5
movl 0x8(%r13), %esi
movq 0x10(%r13), %rdx
andl $0x0, 0x8(%rsp)
andq $0x0, (%rsp)
pushq $0x7
popq %rdi
movq %r12, %rcx
movq %r13, %r8
movq %rax, %r9
callq 0x8108
jmp 0x4b64