Add && and ||

This commit is contained in:
Mid 2025-09-13 11:17:11 +03:00
parent b4272a67d1
commit 13333c971a
6 changed files with 172 additions and 27 deletions

View File

@ -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;

View File

@ -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();
}

View File

@ -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;

View File

@ -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,

View File

@ -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

View File

@ -117,9 +117,106 @@ static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *
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) {