Fix operator precedence and introduce auto-deref
This commit is contained in:
parent
07e3604a8c
commit
d46b104d5c
349
src/parse.c
349
src/parse.c
@ -286,31 +286,161 @@ AST *nct_parse_expression(Parser *P, int lOP) {
|
|||||||
expect(P, TOKEN_PAREN_R);
|
expect(P, TOKEN_PAREN_R);
|
||||||
}
|
}
|
||||||
|
|
||||||
while(maybe(P, TOKEN_DOT)) {
|
while(maybe(P, TOKEN_DOT) || maybe(P, TOKEN_PAREN_L) || maybe(P, TOKEN_SQUAREN_L)) {
|
||||||
assert(e->expression.type->type == TYPE_TYPE_RECORD);
|
Token op = P->tokens[P->i - 1];
|
||||||
|
|
||||||
Token fieldTok = expect(P, TOKEN_IDENTIFIER);
|
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);
|
||||||
|
|
||||||
ASTExprDot *d = alloc_node(P, sizeof(*d));
|
e = (AST*) deref;
|
||||||
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) {
|
assert(e->expression.type->type == TYPE_TYPE_RECORD);
|
||||||
stahp(fieldTok.row, fieldTok.column, "Field %s does not exist.", fieldTok.content);
|
|
||||||
}
|
|
||||||
|
|
||||||
e = (AST*) d;
|
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;
|
return e;
|
||||||
@ -369,128 +499,7 @@ AST *nct_parse_expression(Parser *P, int lOP) {
|
|||||||
}
|
}
|
||||||
} else return nct_parse_expression(P, lOP + 1);
|
} else return nct_parse_expression(P, lOP + 1);
|
||||||
} else if(lOP == 5) {
|
} else if(lOP == 5) {
|
||||||
AST *ret = nct_parse_expression(P, lOP + 1);
|
return 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;
|
|
||||||
} else if(lOP == 4) {
|
} else if(lOP == 4) {
|
||||||
AST *ret = nct_parse_expression(P, lOP + 1);
|
AST *ret = nct_parse_expression(P, lOP + 1);
|
||||||
|
|
||||||
@ -582,35 +591,6 @@ AST *nct_parse_expression(Parser *P, int lOP) {
|
|||||||
} else if(lOP == 1) {
|
} else if(lOP == 1) {
|
||||||
AST *ret = nct_parse_expression(P, 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) {
|
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) {
|
while(1) {
|
||||||
BinaryOp op;
|
BinaryOp op;
|
||||||
@ -622,6 +602,33 @@ AST *nct_parse_expression(Parser *P, int lOP) {
|
|||||||
else if(maybe(P, TOKEN_GEQUAL)) op = BINOP_GEQUAL;
|
else if(maybe(P, TOKEN_GEQUAL)) op = BINOP_GEQUAL;
|
||||||
else break;
|
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));
|
ASTExprBinaryOp *astop = alloc_node(P, sizeof(*astop));
|
||||||
astop->nodeKind = AST_EXPR_BINARY_OP;
|
astop->nodeKind = AST_EXPR_BINARY_OP;
|
||||||
astop->type = NULL;
|
astop->type = NULL;
|
||||||
|
Loading…
Reference in New Issue
Block a user