// File: /workspace/github_c_makefile_star2_O3/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 $0x18, %rsp
movl %edi, %r14d
callq 0x4fc1
movq %rax, %rbx
leaq 0xa644(%rip), %rax      # 0xf3a0
movl (%rax), %r15d
leal -0x35(%r15), %eax
cmpl $0xb, %eax
ja 0x4d76
movl $0x9a9, %ecx            # imm = 0x9A9
btl %eax, %ecx
jb 0x4f66
movl %r15d, %edi
callq 0x5643
cmpl %r14d, %eax
jg 0x4da1
leal -0x6(%r15), %eax
cmpl $-0x5, %eax
jb 0x4f66
movl %r15d, %edi
callq 0x5643
cmpl %r14d, %eax
jne 0x4f66
movl %r14d, -0x2c(%rbp)
leaq 0xa5f4(%rip), %r12      # 0xf3a0
movq %r12, %rdi
callq 0x6b20
movslq %r15d, %r14
leaq 0x6032(%rip), %rax      # 0xadf0
movl (%rax,%r14,4), %edi
callq 0x4d39
movq %rax, %r13
leal -0x1(%r15), %eax
cmpl $0x19, %eax
movq %r14, -0x38(%rbp)
jae 0x4df2
cmpl $0x1, %r15d
je 0x4f14
movl %eax, -0x30(%rbp)
movl %r15d, %r12d
cmpl $0x7, %r15d
jne 0x4e0f
jmp 0x4f7f
movl %eax, -0x30(%rbp)
leaq 0xa304(%rip), %rax      # 0xf100
movq (%rax,%r14,8), %rsi
leaq 0x639e(%rip), %rdi      # 0xb1a5
callq 0x683f
xorl %r12d, %r12d
movl $0x1, %eax
movl %eax, 0x18(%rbx)
movl %eax, 0x18(%r13)
movl 0x8(%r13), %esi
movq 0x10(%r13), %rdx
movq %rbx, %rdi
movl %r12d, %ecx
callq 0x8eba
movq %rax, %r14
movl 0x8(%rbx), %esi
movq 0x10(%rbx), %rdx
movq %r13, %rdi
movl %r12d, %ecx
callq 0x8eba
movq %rax, %r12
movq %r14, %rax
orq %r12, %rax
jne 0x4e5a
leaq 0x6005(%rip), %rdi      # 0xae5a
callq 0x6937
testq %r14, %r14
cmovneq %r14, %rbx
testq %r12, %r12
cmovneq %r12, %r13
cmpl $0x19, -0x30(%rbp)
jae 0x4ebb
movl 0x8(%rbx), %esi
movq 0x10(%rbx), %rdx
movl %r15d, %edi
movq %rbx, %rcx
xorl %r8d, %r8d
movq %r13, %r9
pushq $0x0
pushq $0x0
callq 0x8828
addq $0x10, %rsp
movq %rax, %rbx
leal -0xd(%r15), %eax
cmpl $0x6, %eax
leaq 0xa501(%rip), %r12      # 0xf3a0
jb 0x4eaf
addl $-0x8, %r15d
cmpl $0x1, %r15d
ja 0x4f59
movl $0x30, 0x8(%rbx)
jmp 0x4f59
leaq 0xa23e(%rip), %r15      # 0xf100
movq -0x38(%rbp), %r12
movq (%r15,%r12,8), %rsi
leaq 0x62d4(%rip), %r14      # 0xb1a5
movq %r14, %rdi
callq 0x683f
movl 0x8(%rbx), %esi
movq 0x10(%rbx), %rdx
xorl %edi, %edi
movq %rbx, %rcx
xorl %r8d, %r8d
movq %r13, %r9
pushq $0x0
pushq $0x0
callq 0x8828
addq $0x10, %rsp
movq %rax, %rbx
movq (%r15,%r12,8), %rsi
movq %r14, %rdi
callq 0x683f
movl -0x2c(%rbp), %r14d
leaq 0xa48e(%rip), %r12      # 0xf3a0
jmp 0x4f5d
movl $0x1, 0x18(%r13)
movl 0x8(%rbx), %esi
movq 0x10(%rbx), %rdx
movq %r13, %rdi
xorl %ecx, %ecx
callq 0x8eba
testq %rax, %rax
je 0x4fbc
movl 0x8(%rax), %esi
movq 0x10(%rax), %rdx
movl %r15d, %edi
movq %rax, %rcx
xorl %r8d, %r8d
movq %rbx, %r9
pushq $0x0
pushq $0x0
callq 0x8828
addq $0x10, %rsp
movq %rax, %rbx
movl -0x2c(%rbp), %r14d
movl (%r12), %r15d
jmp 0x4d5f
movl $0x1, 0x18(%rbx)
movq %rbx, %rax
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x55ff(%rip), %rsi      # 0xa585
movl $0x40, %edi
callq 0x6818
xorl %edi, %edi
callq 0x4d39
movl 0x8(%r13), %esi
movq 0x10(%r13), %rdx
movl $0x7, %edi
movq %rbx, %rcx
movq %r13, %r8
movq %rax, %r9
pushq $0x0
pushq $0x0
callq 0x8828
addq $0x28, %rsp
jmp 0x4f74
callq 0x21c0