Fix operator precedence and introduce auto-deref
This commit is contained in:
parent
07e3604a8c
commit
d46b104d5c
357
src/parse.c
357
src/parse.c
@ -285,32 +285,162 @@ AST *nct_parse_expression(Parser *P, int lOP) {
|
||||
|
||||
expect(P, TOKEN_PAREN_R);
|
||||
}
|
||||
|
||||
while(maybe(P, TOKEN_DOT)) {
|
||||
assert(e->expression.type->type == TYPE_TYPE_RECORD);
|
||||
|
||||
while(maybe(P, TOKEN_DOT) || maybe(P, TOKEN_PAREN_L) || maybe(P, TOKEN_SQUAREN_L)) {
|
||||
Token op = P->tokens[P->i - 1];
|
||||
|
||||
Token fieldTok = expect(P, TOKEN_IDENTIFIER);
|
||||
|
||||
ASTExprDot *d = alloc_node(P, sizeof(*d));
|
||||
d->nodeKind = AST_EXPR_DOT;
|
||||
d->a = (AST*) e;
|
||||
|
||||
bool foundField = false;
|
||||
|
||||
for(size_t f = 0; f < e->expression.type->record.fieldCount; f++) {
|
||||
char *fieldName = e->expression.type->record.fieldNames[f];
|
||||
if(!strcmp(fieldName, fieldTok.content)) {
|
||||
foundField = true;
|
||||
d->type = e->expression.type->record.fieldTypes[f];
|
||||
d->b = strdup(fieldName);
|
||||
if(op.type == TOKEN_DOT) {
|
||||
while(type_is_any_pointer(e->expression.type)) {
|
||||
AST *deref = alloc_node(P, sizeof(ASTExprUnaryOp));
|
||||
deref->nodeKind = AST_EXPR_UNARY_OP;
|
||||
deref->exprUnOp.operator = UNOP_DEREF;
|
||||
deref->exprUnOp.operand = (AST*) e;
|
||||
deref->exprUnOp.type = type_dereference(e->expression.type);
|
||||
|
||||
e = (AST*) deref;
|
||||
}
|
||||
}
|
||||
|
||||
if(!foundField) {
|
||||
stahp(fieldTok.row, fieldTok.column, "Field %s does not exist.", fieldTok.content);
|
||||
}
|
||||
|
||||
e = (AST*) d;
|
||||
|
||||
assert(e->expression.type->type == TYPE_TYPE_RECORD);
|
||||
|
||||
Token fieldTok = expect(P, TOKEN_IDENTIFIER);
|
||||
|
||||
ASTExprDot *d = alloc_node(P, sizeof(*d));
|
||||
d->nodeKind = AST_EXPR_DOT;
|
||||
d->a = (AST*) e;
|
||||
|
||||
bool foundField = false;
|
||||
|
||||
for(size_t f = 0; f < e->expression.type->record.fieldCount; f++) {
|
||||
char *fieldName = e->expression.type->record.fieldNames[f];
|
||||
if(!strcmp(fieldName, fieldTok.content)) {
|
||||
foundField = true;
|
||||
d->type = e->expression.type->record.fieldTypes[f];
|
||||
d->b = strdup(fieldName);
|
||||
}
|
||||
}
|
||||
|
||||
if(!foundField) {
|
||||
stahp(fieldTok.row, fieldTok.column, "Field %s does not exist.", fieldTok.content);
|
||||
}
|
||||
|
||||
e = (AST*) d;
|
||||
} else if(op.type == TOKEN_PAREN_L) {
|
||||
// Convert a call like foo() to (&foo)()
|
||||
if(e->expression.type->type == TYPE_TYPE_FUNCTION) {
|
||||
ASTExprUnaryOp *ref = alloc_node(P, sizeof(*ref));
|
||||
ref->nodeKind = AST_EXPR_UNARY_OP;
|
||||
ref->type = type_pointer_wrap(e->expression.type);
|
||||
ref->operator = UNOP_REF;
|
||||
ref->operand = e;
|
||||
e = (AST*) ref;
|
||||
}
|
||||
|
||||
if(e->expression.type->type != TYPE_TYPE_POINTER || e->expression.type->pointer.of->type != TYPE_TYPE_FUNCTION) {
|
||||
stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Only function types or function pointers may be called.");
|
||||
}
|
||||
|
||||
Type *ftype = e->expression.type->pointer.of;
|
||||
|
||||
ASTExprCall *call = alloc_node(P, sizeof(*call));
|
||||
call->nodeKind = AST_EXPR_CALL;
|
||||
call->type = ftype->function.ret;
|
||||
call->what = e;
|
||||
call->args = NULL;
|
||||
|
||||
int argCount = 0;
|
||||
|
||||
if(!maybe(P, TOKEN_PAREN_R)) {
|
||||
while(peek(P, 0).type != TOKEN_PAREN_R && peek(P, 0).type != TOKEN_COMMA) {
|
||||
call->args = realloc(call->args, (argCount + 1) * sizeof(AST*));
|
||||
call->args[argCount] = ast_cast_expr(nct_parse_expression(P, 0), ftype->function.args[argCount]);
|
||||
|
||||
argCount++;
|
||||
|
||||
if(maybe(P, TOKEN_PAREN_R)) {
|
||||
break;
|
||||
} else expect(P, TOKEN_COMMA);
|
||||
}
|
||||
}
|
||||
|
||||
if(argCount != ftype->function.argCount) {
|
||||
stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Mismatched number of arguments");
|
||||
}
|
||||
|
||||
e = (AST*) call;
|
||||
} else if(op.type == TOKEN_SQUAREN_L) {
|
||||
P->scope = scope_new(P->scope);
|
||||
|
||||
P->i--;
|
||||
|
||||
if(parse_parametrization(P)) {
|
||||
// Generic type parametrization
|
||||
|
||||
// Generic functions are not first-class
|
||||
assert(e->nodeKind == AST_EXPR_VAR);
|
||||
assert(e->exprVar.thing != NULL);
|
||||
assert(e->exprVar.thing->kind == SCOPEITEM_SYMBOL);
|
||||
|
||||
char *cname = parametrize_function_name(e->expression.type, e->exprVar.thing->data.symbol.name, P->scope);
|
||||
|
||||
ScopeItem *cvte = scope_find(P->scope, cname);
|
||||
|
||||
if(!cvte) {
|
||||
stahp_token(&P->tokens[P->i], "Parametrization %s not found.", cname);
|
||||
}
|
||||
|
||||
e = exprvar(P, cvte);
|
||||
} else {
|
||||
// Array access
|
||||
|
||||
expect(P, TOKEN_SQUAREN_L);
|
||||
|
||||
ASTExprUnaryOp *ref = alloc_node(P, sizeof(*ref));
|
||||
ref->nodeKind = AST_EXPR_UNARY_OP;
|
||||
ref->operator = UNOP_REF;
|
||||
ref->operand = e;
|
||||
ref->type = type_pointer_wrap(e->expression.type->array.of);
|
||||
|
||||
ASTExprBinaryOp *child = alloc_node(P, sizeof(*child));
|
||||
child->nodeKind = AST_EXPR_BINARY_OP;
|
||||
child->operands[0] = (AST*) ref;
|
||||
child->operands[1] = nct_parse_expression(P, 0);
|
||||
child->operator = BINOP_ADD;
|
||||
child->type = ref->type;
|
||||
|
||||
if(e->expression.type->type != TYPE_TYPE_ARRAY) {
|
||||
stahp_token(&P->tokens[P->i], "Attempt to index a non-array type");
|
||||
}
|
||||
|
||||
int typesize = type_size(e->expression.type->array.of);
|
||||
if(typesize != 1) {
|
||||
ASTExprPrimitive *scale = alloc_node(P, sizeof(*scale));
|
||||
scale->nodeKind = AST_EXPR_PRIMITIVE;
|
||||
scale->type = type_u(8 * arch_gpr_size());
|
||||
scale->val = typesize;
|
||||
|
||||
ASTExprBinaryOp *mul = alloc_node(P, sizeof(*mul));
|
||||
mul->nodeKind = AST_EXPR_BINARY_OP;
|
||||
mul->type = child->operands[1]->expression.type;
|
||||
mul->operator = BINOP_MUL;
|
||||
mul->operands[0] = (AST*) scale;
|
||||
mul->operands[1] = child->operands[1];
|
||||
|
||||
child->operands[1] = (AST*) mul;
|
||||
}
|
||||
|
||||
ASTExprUnaryOp *unop = alloc_node(P, sizeof(*unop));
|
||||
unop->nodeKind = AST_EXPR_UNARY_OP;
|
||||
unop->type = e->expression.type->array.of;
|
||||
unop->operator = UNOP_DEREF;
|
||||
unop->operand = (AST*) child;
|
||||
|
||||
expect(P, TOKEN_SQUAREN_R);
|
||||
|
||||
e = (AST*) unop;
|
||||
}
|
||||
|
||||
P->scope = P->scope->parent;
|
||||
} else abort();
|
||||
}
|
||||
|
||||
return e;
|
||||
@ -369,128 +499,7 @@ AST *nct_parse_expression(Parser *P, int lOP) {
|
||||
}
|
||||
} else return nct_parse_expression(P, lOP + 1);
|
||||
} 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) {
|
||||
if(maybe(P, TOKEN_PAREN_L)) {
|
||||
if(ret->expression.type->type == TYPE_TYPE_FUNCTION) {
|
||||
ASTExprUnaryOp *ref = alloc_node(P, sizeof(*ref));
|
||||
ref->nodeKind = AST_EXPR_UNARY_OP;
|
||||
ref->type = type_pointer_wrap(ret->expression.type);
|
||||
ref->operator = UNOP_REF;
|
||||
ref->operand = ret;
|
||||
ret = (AST*) ref;
|
||||
}
|
||||
|
||||
if(ret->expression.type->type != TYPE_TYPE_POINTER || ret->expression.type->pointer.of->type != TYPE_TYPE_FUNCTION) {
|
||||
stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Only function types or function pointers may be called.");
|
||||
}
|
||||
|
||||
Type *ftype = ret->expression.type->pointer.of;
|
||||
|
||||
ASTExprCall *call = alloc_node(P, sizeof(*call));
|
||||
call->nodeKind = AST_EXPR_CALL;
|
||||
call->type = ftype->function.ret;
|
||||
call->what = ret;
|
||||
call->args = NULL;
|
||||
|
||||
int argCount = 0;
|
||||
|
||||
if(!maybe(P, TOKEN_PAREN_R)) {
|
||||
while(peek(P, 0).type != TOKEN_PAREN_R && peek(P, 0).type != TOKEN_COMMA) {
|
||||
call->args = realloc(call->args, (argCount + 1) * sizeof(AST*));
|
||||
call->args[argCount] = ast_cast_expr(nct_parse_expression(P, 0), ftype->function.args[argCount]);
|
||||
|
||||
argCount++;
|
||||
|
||||
if(maybe(P, TOKEN_PAREN_R)) {
|
||||
break;
|
||||
} else expect(P, TOKEN_COMMA);
|
||||
}
|
||||
}
|
||||
|
||||
if(argCount != ftype->function.argCount) {
|
||||
stahp(P->tokens[P->i].row, P->tokens[P->i].column, "Mismatched number of arguments");
|
||||
}
|
||||
|
||||
ret = (AST*) call;
|
||||
} else if(peek(P, 0).type == TOKEN_SQUAREN_L) {
|
||||
|
||||
P->scope = scope_new(P->scope);
|
||||
|
||||
if(parse_parametrization(P)) {
|
||||
// Generic type parametrization
|
||||
|
||||
// Generic functions are not first-class
|
||||
assert(ret->nodeKind == AST_EXPR_VAR);
|
||||
assert(ret->exprVar.thing != NULL);
|
||||
assert(ret->exprVar.thing->kind == SCOPEITEM_SYMBOL);
|
||||
|
||||
char *cname = parametrize_function_name(ret->expression.type, ret->exprVar.thing->data.symbol.name, P->scope);
|
||||
|
||||
ScopeItem *cvte = scope_find(P->scope, cname);
|
||||
|
||||
if(!cvte) {
|
||||
stahp_token(&P->tokens[P->i], "Parametrization %s not found.", cname);
|
||||
}
|
||||
|
||||
ret = exprvar(P, cvte);
|
||||
} else {
|
||||
// Array access
|
||||
|
||||
expect(P, TOKEN_SQUAREN_L);
|
||||
|
||||
ASTExprUnaryOp *ref = alloc_node(P, sizeof(*ref));
|
||||
ref->nodeKind = AST_EXPR_UNARY_OP;
|
||||
ref->operator = UNOP_REF;
|
||||
ref->operand = ret;
|
||||
ref->type = type_pointer_wrap(ret->expression.type->array.of);
|
||||
|
||||
ASTExprBinaryOp *child = alloc_node(P, sizeof(*child));
|
||||
child->nodeKind = AST_EXPR_BINARY_OP;
|
||||
child->operands[0] = (AST*) ref;
|
||||
child->operands[1] = nct_parse_expression(P, 0);
|
||||
child->operator = BINOP_ADD;
|
||||
child->type = ref->type;
|
||||
|
||||
if(ret->expression.type->type != TYPE_TYPE_ARRAY) {
|
||||
stahp_token(&P->tokens[P->i], "Attempt to index a non-array type");
|
||||
}
|
||||
|
||||
int typesize = type_size(ret->expression.type->array.of);
|
||||
if(typesize != 1) {
|
||||
ASTExprPrimitive *scale = alloc_node(P, sizeof(*scale));
|
||||
scale->nodeKind = AST_EXPR_PRIMITIVE;
|
||||
scale->type = type_u(8 * arch_gpr_size());
|
||||
scale->val = typesize;
|
||||
|
||||
ASTExprBinaryOp *mul = alloc_node(P, sizeof(*mul));
|
||||
mul->nodeKind = AST_EXPR_BINARY_OP;
|
||||
mul->type = child->operands[1]->expression.type;
|
||||
mul->operator = BINOP_MUL;
|
||||
mul->operands[0] = (AST*) scale;
|
||||
mul->operands[1] = child->operands[1];
|
||||
|
||||
child->operands[1] = (AST*) mul;
|
||||
}
|
||||
|
||||
ASTExprUnaryOp *unop = alloc_node(P, sizeof(*unop));
|
||||
unop->nodeKind = AST_EXPR_UNARY_OP;
|
||||
unop->type = ret->expression.type->array.of;
|
||||
unop->operator = UNOP_DEREF;
|
||||
unop->operand = (AST*) child;
|
||||
|
||||
expect(P, TOKEN_SQUAREN_R);
|
||||
|
||||
ret = (AST*) unop;
|
||||
}
|
||||
|
||||
P->scope = P->scope->parent;
|
||||
|
||||
} else abort();
|
||||
}
|
||||
|
||||
return ret;
|
||||
return nct_parse_expression(P, lOP + 1);
|
||||
} else if(lOP == 4) {
|
||||
AST *ret = nct_parse_expression(P, lOP + 1);
|
||||
|
||||
@ -582,35 +591,6 @@ AST *nct_parse_expression(Parser *P, int lOP) {
|
||||
} 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);
|
||||
|
||||
if(peek(P, 0).type == TOKEN_DOUBLE_EQUALS || peek(P, 0).type == TOKEN_EXCLAMATION_EQUALS || peek(P, 0).type == TOKEN_LESS || peek(P, 0).type == TOKEN_GREATER || peek(P, 0).type == TOKEN_LEQUAL || peek(P, 0).type == TOKEN_GEQUAL) {
|
||||
while(1) {
|
||||
BinaryOp op;
|
||||
@ -622,6 +602,33 @@ AST *nct_parse_expression(Parser *P, int lOP) {
|
||||
else if(maybe(P, TOKEN_GEQUAL)) op = BINOP_GEQUAL;
|
||||
else break;
|
||||
|
||||
ASTExprBinaryOp *astop = alloc_node(P, sizeof(*astop));
|
||||
astop->nodeKind = AST_EXPR_BINARY_OP;
|
||||
astop->type = type_u(1);
|
||||
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.");
|
||||
}
|
||||
|
||||
ret = (AST*) astop;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
} else if(lOP == 0) {
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user