// File: /workspace/github_c_makefile_star2_O1/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 0x4f1b
movq %rax, %r12
leaq 0xa6b8(%rip), %rax      # 0xf3a0
movl (%rax), %r15d
leal -0x35(%r15), %eax
cmpl $0xb, %eax
ja 0x4d02
movl $0x9a9, %ecx            # imm = 0x9A9
btl %eax, %ecx
jb 0x4ec3
movl %r15d, %edi
callq 0x5599
cmpl %r14d, %eax
jg 0x4d2d
leal -0x6(%r15), %eax
cmpl $-0x5, %eax
jb 0x4ec3
movl %r15d, %edi
callq 0x5599
cmpl %r14d, %eax
jne 0x4ec3
leaq 0xa66c(%rip), %rdi      # 0xf3a0
callq 0x6a78
movslq %r15d, %rcx
leaq 0x60ad(%rip), %rax      # 0xadf0
movq %rcx, -0x38(%rbp)
movl (%rax,%rcx,4), %edi
callq 0x4cc5
movq %rax, %r13
leal -0x1(%r15), %eax
movl %r15d, %ebx
movl %eax, -0x2c(%rbp)
cmpl $0x19, %eax
jb 0x4d7e
leaq 0xa398(%rip), %rax      # 0xf100
movq -0x38(%rbp), %rcx
movq (%rax,%rcx,8), %rsi
leaq 0x642e(%rip), %rdi      # 0xb1a5
callq 0x6797
xorl %ebx, %ebx
cmpl $0x1, %ebx
je 0x4dfd
cmpl $0x7, %ebx
je 0x4ede
movl %r14d, -0x3c(%rbp)
movl $0x1, %eax
movl %eax, 0x18(%r12)
movl %eax, 0x18(%r13)
movl 0x8(%r13), %esi
movq 0x10(%r13), %rdx
movq %r12, %rdi
movl %ebx, %ecx
callq 0x8e42
movq %rax, %r14
movl 0x8(%r12), %esi
movq %r12, -0x48(%rbp)
movq 0x10(%r12), %rdx
movq %r13, %rdi
movl %ebx, %ecx
callq 0x8e42
movq %rax, %r12
movq %r14, %rax
orq %r12, %rax
jne 0x4de2
leaq 0x607d(%rip), %rdi      # 0xae5a
callq 0x688f
testq %r14, %r14
movq -0x48(%rbp), %rbx
cmovneq %r14, %rbx
testq %r12, %r12
cmovneq %r12, %r13
movq %r13, %r12
movl -0x3c(%rbp), %r14d
jmp 0x4e2d
movl $0x1, 0x18(%r13)
movl 0x8(%r12), %esi
movq 0x10(%r12), %rdx
movq %r13, %rdi
xorl %ecx, %ecx
callq 0x8e42
movq %rax, %rbx
testq %rax, %rax
jne 0x4e2d
leaq 0x5f42(%rip), %rdi      # 0xad6a
callq 0x688f
leaq 0xa56c(%rip), %r13      # 0xf3a0
movl %r15d, %edi
cmpl $0x19, -0x2c(%rbp)
jb 0x4e5a
leaq 0xa2bc(%rip), %rax      # 0xf100
movq -0x38(%rbp), %rcx
movq (%rax,%rcx,8), %rsi
leaq 0x6352(%rip), %rdi      # 0xb1a5
callq 0x6797
xorl %edi, %edi
movl 0x8(%rbx), %esi
movq 0x10(%rbx), %rdx
movq %rbx, %rcx
xorl %r8d, %r8d
movq %r12, %r9
pushq $0x0
pushq $0x0
callq 0x87b0
addq $0x10, %rsp
movq %rax, %r12
cmpl $0x19, -0x2c(%rbp)
jb 0x4e9e
leaq 0xa279(%rip), %rax      # 0xf100
movq -0x38(%rbp), %rcx
movq (%rax,%rcx,8), %rsi
leaq 0x630f(%rip), %rdi      # 0xb1a5
callq 0x6797
xorl %r15d, %r15d
leal -0xd(%r15), %eax
cmpl $0x6, %eax
jb 0x4eb1
addl $-0x8, %r15d
cmpl $0x1, %r15d
ja 0x4eba
movl $0x30, 0x8(%r12)
movl (%r13), %r15d
jmp 0x4ceb
movl $0x1, 0x18(%r12)
movq %r12, %rax
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x56a0(%rip), %rsi      # 0xa585
movl $0x40, %edi
callq 0x6770
xorl %edi, %edi
callq 0x4cc5
movl 0x8(%r13), %esi
movq 0x10(%r13), %rdx
movl $0x7, %edi
movq %r12, %rcx
movq %r13, %r8
movq %rax, %r9
pushq $0x0
pushq $0x0
callq 0x87b0
addq $0x38, %rsp
jmp 0x4ed3