diff --git a/src/ast/ast.h b/src/ast/ast.h index 7c1cbec..061d3dd 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -73,6 +73,9 @@ typedef enum ENUMPAK { BINOP_LEQUAL = 13, BINOP_GEQUAL = 14, + BINOP_LOGICAL_AND = 15, + BINOP_LOGICAL_OR = 16, + BINOP_WTF = 999, } BinaryOp; diff --git a/src/ast/dump.c b/src/ast/dump.c index bae8a8b..4bcd268 100644 --- a/src/ast/dump.c +++ b/src/ast/dump.c @@ -129,6 +129,12 @@ static char *ast_dumpe(AST *tlc, AST *e) { case BINOP_MULHI: op = "*^"; break; + case BINOP_LOGICAL_AND: + op = "&&"; + break; + case BINOP_LOGICAL_OR: + op = "||"; + break; default: abort(); } diff --git a/src/lexer.c b/src/lexer.c index f0a7392..a41771f 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -143,9 +143,17 @@ Token nct_tokenize(FILE *f) { return tok; } else if(c == '&') { tok.type = TOKEN_AMPERSAND; + int c = nextc(f); + if(c == '&') { + tok.type = TOKEN_DOUBLE_AMPERSAND; + } else ungetc(c, f); return tok; } else if(c == '|') { tok.type = TOKEN_VERTICAL_BAR; + int c = nextc(f); + if(c == '|') { + tok.type = TOKEN_DOUBLE_VERTICAL_BAR; + } else ungetc(c, f); return tok; } else if(c == '^') { tok.type = TOKEN_CARET; diff --git a/src/lexer.h b/src/lexer.h index 4ab589d..4ce0266 100644 --- a/src/lexer.h +++ b/src/lexer.h @@ -27,7 +27,9 @@ typedef enum { TOKEN_BREAK, TOKEN_COMMA, TOKEN_AMPERSAND, + TOKEN_DOUBLE_AMPERSAND, TOKEN_VERTICAL_BAR, + TOKEN_DOUBLE_VERTICAL_BAR, TOKEN_CARET, TOKEN_TILDE, TOKEN_DOUBLE_EQUALS, diff --git a/src/parse.c b/src/parse.c index 5ffc7f2..20aa7d1 100644 --- a/src/parse.c +++ b/src/parse.c @@ -250,7 +250,7 @@ AST *nct_parse_expression(Parser *P, int lOP) { } } - if(lOP == 6) { + if(lOP == 7) { AST *e = NULL; if(peek(P, 0).type == TOKEN_NUMBER) { @@ -347,7 +347,7 @@ AST *nct_parse_expression(Parser *P, int lOP) { } return e; - } else if(lOP == 5) { + } else if(lOP == 6) { if(maybe(P, TOKEN_STAR)) { ASTExprUnaryOp *astop = alloc_node(P, sizeof(*astop)); astop->nodeKind = AST_EXPR_UNARY_OP; @@ -401,7 +401,7 @@ AST *nct_parse_expression(Parser *P, int lOP) { return (AST *) astop; } } else return nct_parse_expression(P, lOP + 1); - } else if(lOP == 4) { + } else if(lOP == 5) { AST *ret = nct_parse_expression(P, lOP + 1); while(peek(P, 0).type == TOKEN_PAREN_L || peek(P, 0).type == TOKEN_SQUAREN_L) { @@ -524,7 +524,7 @@ AST *nct_parse_expression(Parser *P, int lOP) { } return ret; - } else if(lOP == 3) { + } else if(lOP == 4) { AST *ret = nct_parse_expression(P, lOP + 1); if(peek(P, 0).type == TOKEN_STAR || peek(P, 0).type == TOKEN_SLASH || peek(P, 0).type == TOKEN_STAR_CARET) { @@ -564,7 +564,7 @@ AST *nct_parse_expression(Parser *P, int lOP) { } return ret; - } else if(lOP == 2) { + } else if(lOP == 3) { AST *ret = nct_parse_expression(P, lOP + 1); if( @@ -603,7 +603,7 @@ AST *nct_parse_expression(Parser *P, int lOP) { } return ret; - } else if(lOP == 1) { + } else if(lOP == 2) { AST *ret = nct_parse_expression(P, lOP + 1); while(maybe(P, TOKEN_AS)) { @@ -611,6 +611,35 @@ AST *nct_parse_expression(Parser *P, int lOP) { ret = ast_cast_expr(ret, castTo); } + return ret; + } else if(lOP == 1) { + AST *ret = nct_parse_expression(P, lOP + 1); + + if(peek(P, 0).type == TOKEN_DOUBLE_AMPERSAND || peek(P, 0).type == TOKEN_DOUBLE_VERTICAL_BAR) { + while(1) { + BinaryOp op; + if(maybe(P, TOKEN_DOUBLE_AMPERSAND)) op = BINOP_LOGICAL_AND; + else if(maybe(P, TOKEN_DOUBLE_VERTICAL_BAR)) op = BINOP_LOGICAL_OR; + else break; + + ASTExprBinaryOp *astop = alloc_node(P, sizeof(*astop)); + astop->nodeKind = AST_EXPR_BINARY_OP; + astop->type = NULL; + astop->operator = op; + astop->operands[0] = ret; + + ASTExpr *operand = &(astop->operands[1] = nct_parse_expression(P, lOP + 1))->expression; + + if(operand->type->type != TYPE_TYPE_PRIMITIVE) { + stahp_token(&P->tokens[P->i], "Invalid combination of operator and operand types."); + } + + binop_implicit_cast(astop); + + ret = (AST*) astop; + } + } + return ret; } else if(lOP == 0) { AST *ret = nct_parse_expression(P, lOP + 1); @@ -644,8 +673,6 @@ AST *nct_parse_expression(Parser *P, int lOP) { } } - //ret = ast_expression_optimize(ret); - return ret; } #ifdef DEBUG diff --git a/src/x86/dumberdowner.c b/src/x86/dumberdowner.c index a7e7a2c..5557b5d 100644 --- a/src/x86/dumberdowner.c +++ b/src/x86/dumberdowner.c @@ -116,10 +116,107 @@ static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST * e->exprBinOp.operands[1] = varify(tlc, chu, stmtPrev, s, e->exprBinOp.operands[1]); this->effective = 1; } + + } else if(e->nodeKind == AST_EXPR_UNARY_OP && e->exprUnOp.operator == UNOP_NOT && e->exprUnOp.operand->nodeKind == AST_EXPR_BINARY_OP && (e->exprUnOp.operand->exprBinOp.operator == BINOP_LOGICAL_AND || e->exprUnOp.operand->exprBinOp.operator == BINOP_LOGICAL_OR)) { + + AST *binop = e->exprUnOp.operand; + + e->exprUnOp.operand = binop->exprBinOp.operands[0]; + binop->exprBinOp.operands[0] = e; + + AST *unop2 = calloc(1, sizeof(ASTExprUnaryOp)); + unop2->nodeKind = AST_EXPR_UNARY_OP; + unop2->expression.type = binop->exprBinOp.operands[1]->expression.type; + unop2->exprUnOp.operator = UNOP_NOT; + unop2->exprUnOp.operand = binop->exprBinOp.operands[1]; + binop->exprBinOp.operands[1] = unop2; + + binop->exprBinOp.operator = binop->exprBinOp.operator == BINOP_LOGICAL_AND ? BINOP_LOGICAL_OR : BINOP_LOGICAL_AND; + + s->stmtJump.condition = binop; + + ast_denoop(tlc, &s->stmtJump.condition); + + this->effective = 1; + + } else if(e->nodeKind == AST_EXPR_BINARY_OP && e->exprBinOp.operator == BINOP_LOGICAL_OR) { + + AST *cond0 = e->exprBinOp.operands[0]; + AST *cond1 = e->exprBinOp.operands[1]; + + s->stmtJump.condition = cond0; + + AST *jump2 = calloc(1, sizeof(ASTStmtJump)); + jump2->nodeKind = AST_STMT_JUMP; + jump2->stmtJump.condition = cond1; + jump2->stmtJump.label = strdup(s->stmtJump.label); + jump2->statement.next = s->statement.next; + s->statement.next = jump2; + + this->effective = 1; + + } else if(e->nodeKind == AST_EXPR_BINARY_OP && e->exprBinOp.operator == BINOP_LOGICAL_AND) { + + static size_t idx = 0; + + AST *cond0 = e->exprBinOp.operands[0]; + AST *cond1 = e->exprBinOp.operands[1]; + + AST *lbl = calloc(1, sizeof(ASTStmtLabel)); + lbl->nodeKind = AST_STMT_LABEL; + lbl->stmtLabel.name = malp("$dla%lu", idx++); + lbl->statement.next = s->statement.next; + + AST *unop = calloc(1, sizeof(ASTExprUnaryOp)); + unop->nodeKind = AST_EXPR_UNARY_OP; + unop->expression.type = cond0->expression.type; + unop->exprUnOp.operator = UNOP_NOT; + unop->exprUnOp.operand = cond0; + s->stmtJump.condition = unop; + + AST *jump2 = calloc(1, sizeof(ASTStmtJump)); + jump2->nodeKind = AST_STMT_JUMP; + jump2->stmtJump.condition = cond1; + jump2->stmtJump.label = strdup(s->stmtJump.label); + jump2->statement.next = lbl; + + s->stmtJump.label = strdup(lbl->stmtLabel.name); + + s->statement.next = jump2; + + ast_denoop(tlc, &s->stmtJump.condition); + + this->effective = 1; } else { - s->stmtJump.condition = varify(tlc, chu, stmtPrev, s, e); + AST *v = e; + + bool not = v->nodeKind == AST_EXPR_UNARY_OP && v->exprUnOp.operator == UNOP_NOT; + if(not) { + v = v->exprUnOp.operand; + } + + if(v->nodeKind != AST_EXPR_VAR) { + v = varify(tlc, chu, stmtPrev, s, e); + } + + AST *zero = calloc(1, sizeof(ASTExprPrimitive)); + zero->nodeKind = AST_EXPR_PRIMITIVE; + zero->expression.type = v->expression.type; + zero->exprPrim.val = 0; + + AST *binop = calloc(1, sizeof(ASTExprBinaryOp)); + binop->nodeKind = AST_EXPR_BINARY_OP; + binop->expression.type = v->expression.type; + binop->exprBinOp.operator = not ? BINOP_EQUAL : BINOP_NEQUAL; + binop->exprBinOp.operands[0] = v; + binop->exprBinOp.operands[1] = zero; + + s->stmtJump.condition = binop; + + ast_denoop(tlc, &s->stmtJump.condition); + this->effective = 1; } @@ -507,13 +604,19 @@ static void denoop_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST *nptr = n->exprBinOp.operands[0]; *success = true; - } else if(n->nodeKind == AST_EXPR_UNARY_OP && n->exprUnOp.operator == UNOP_NOT && n->exprUnOp.operand->nodeKind == AST_EXPR_BINARY_OP) { + } else if(n->nodeKind == AST_EXPR_UNARY_OP && n->exprUnOp.operator == UNOP_NOT && n->exprUnOp.operand->nodeKind == AST_EXPR_BINARY_OP && binop_comp_opposite(n->exprUnOp.operand->exprBinOp.operator) != BINOP_WTF) { // Turn `!(a op b)` to `(a !op b)` n->exprUnOp.operand->exprBinOp.operator = binop_comp_opposite(n->exprUnOp.operand->exprBinOp.operator); *nptr = n->exprUnOp.operand; + *success = true; + } else if(n->nodeKind == AST_EXPR_UNARY_OP && n->exprUnOp.operator == UNOP_NOT && n->exprUnOp.operand->nodeKind == AST_EXPR_UNARY_OP && n->exprUnOp.operand->exprUnOp.operator == UNOP_NOT) { + // Turn `!!x` to `x` + + *nptr = n->exprUnOp.operand->exprUnOp.operand; + *success = true; } else if(n->nodeKind == AST_EXPR_CAST && n->exprCast.what->expression.type->type == TYPE_TYPE_POINTER && n->exprCast.to->type == TYPE_TYPE_POINTER) { // Turn (x as A*) into x, since all pointer types are identical in Nectar's AST @@ -540,6 +643,18 @@ static void denoop_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chunk, AST } } +void ast_denoop(AST *tlc, AST **node) { + if(!node) { + node = &tlc; + } + + struct DenoopState state = {.targetTLC = tlc}; + do { + state.success = false; + generic_visitor(node, NULL, NULL, tlc, tlc, &state, denoop_visitor, NULL); + } while(state.success); +} + void dumben_pre(AST *tlc) { generic_visitor(&tlc, NULL, NULL, tlc, tlc, tlc, pre_dumb_visitor, NULL); generic_visitor(&tlc, NULL, NULL, tlc, tlc, tlc, decompose_symbol_record_field_access, NULL); @@ -552,25 +667,9 @@ void dumben_pre(AST *tlc) { } } - if(ntc_get_int("pdbg")) { - char *astdump = ast_dump(tlc); - fprintf(stderr, "### BEFORE DENOOP ###\n%s\n", astdump); - free(astdump); - } - - struct DenoopState state = {.targetTLC = tlc}; - do { - state.success = false; - generic_visitor(&tlc, NULL, NULL, tlc, tlc, &state, denoop_visitor, NULL); - } while(state.success); + ast_denoop(tlc, NULL); ast_commutativity_pass(tlc); - - if(ntc_get_int("pdbg")) { - char *astdump = ast_dump(tlc); - fprintf(stderr, "### AFTER DENOOP ###\n%s\n", astdump); - free(astdump); - } } void dumben_go(AST* tlc) {