Compare commits
8 Commits
7569420fe0
...
b21ce51435
Author | SHA1 | Date | |
---|---|---|---|
![]() |
b21ce51435 | ||
![]() |
2f67a6f109 | ||
![]() |
1177462bda | ||
![]() |
246f7a3b71 | ||
![]() |
2188448b19 | ||
![]() |
d46b104d5c | ||
![]() |
07e3604a8c | ||
![]() |
fb75434cba |
@ -11,7 +11,7 @@ record ListDLU[T, S; growth] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ListDLU_remove: [T, S; growth]u0(ListDLU[T, S; growth]* this, S index) -> {
|
ListDLU_remove: [T, S; growth]u0(ListDLU[T, S; growth]* this, S index) -> {
|
||||||
T* data0 = &((*((*this).data))[index]);
|
T* data0 = &(*(*this).data)[index];
|
||||||
T* data1 = data0 + @sizeof T;
|
T* data1 = data0 + @sizeof T;
|
||||||
S sz = (*this).size;
|
S sz = (*this).size;
|
||||||
(*this).size = (*this).size - 1;
|
(*this).size = (*this).size - 1;
|
||||||
@ -33,7 +33,7 @@ ListDLU_add: [T, S; growth]u0(ListDLU[T, S; growth]* this, Alloc *alloc, T value
|
|||||||
if((*this).size == (*this).capacity) {
|
if((*this).size == (*this).capacity) {
|
||||||
u32 newcap = (*this).capacity + growth;
|
u32 newcap = (*this).capacity + growth;
|
||||||
(*this).capacity = newcap;
|
(*this).capacity = newcap;
|
||||||
(*this).data = ((*alloc).realloc)((*alloc).userdata, (*this).data, newcap * @sizeof T);
|
(*this).data = (*alloc).realloc((*alloc).userdata, (*this).data, newcap * @sizeof T);
|
||||||
}
|
}
|
||||||
|
|
||||||
(*((*this).data))[(*this).size] = value;
|
(*((*this).data))[(*this).size] = value;
|
||||||
|
@ -1,31 +1,77 @@
|
|||||||
/*
|
/*
|
||||||
* SOaLDhS: Statically-allocated, Open-addressing, Linear probing, Dynamic hash, sentinels
|
* SIOaLpDhFt: Statically-allocated, Interleaved KV values, Open-addressing, Linear probing, Dynamic hash, Flag tombstones
|
||||||
*/
|
*/
|
||||||
|
|
||||||
record KVPair[K, V] {
|
record KVPair[K, V] {
|
||||||
K key;
|
K key;
|
||||||
V value;
|
V value;
|
||||||
}
|
}
|
||||||
|
|
||||||
record MapSOaLDhS[K, V, S; capacity, sentinel] {
|
record MapSIOaLpDhFt[K, V, S; capacity] {
|
||||||
S(K*) hash;
|
S(K*)* hash;
|
||||||
KVPair[capacity] data;
|
KVPair[capacity] data;
|
||||||
|
u8[capacity] occupied;
|
||||||
}
|
}
|
||||||
|
|
||||||
MapSOaLDhS_add: [K, V, S; capacity, sentinel]u1(MapSOaLDhS[K, V, S; capacity, sentinel]* this, K* key, V* value) -> {
|
MapSIOaLpDhFt_add: [K, V, S; capacity]u1(MapSIOaLpDhFt[K, V, S; capacity]* this, K* key, V* value) -> {
|
||||||
S index = ((*this).hash)(value);
|
S start = this.hash(key);
|
||||||
index = index & (capacity - 1);
|
start = start & (capacity - 1);
|
||||||
|
|
||||||
|
S index = start;
|
||||||
loop {
|
loop {
|
||||||
KVPair[K, V]* pair = &((*this).data[index]);
|
KVPair[K, V]* pair = &this.data[index];
|
||||||
if(((*pair).key == *key) || ((*pair).value == sentinel)) {
|
if(pair.key == *key || this.occupied[index] == 0) {
|
||||||
(*pair).key = *key;
|
pair.key = *key;
|
||||||
(*pair).value = *value;
|
pair.value = *value;
|
||||||
}
|
this.occupied[index] = 1;
|
||||||
index = index + 1;
|
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
index = (index + 1) & (capacity - 1);
|
||||||
|
if(index == start) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@instantiate MapSOaLDhS_add[ugpr, ugpr, ugpr; 128, 0];
|
MapSIOaLpDhFt_get: [K, V, S; capacity]V*(MapSIOaLpDhFt[K, V, S; capacity]* this, K* key) -> {
|
||||||
|
S start = this.hash(key);
|
||||||
|
start = start & (capacity - 1);
|
||||||
|
|
||||||
MapSOaLDhS[ugpr, ugpr, ugpr; 128, 0] map;
|
S index = start;
|
||||||
|
loop {
|
||||||
|
KVPair[K, V]* pair = &this.data[index];
|
||||||
|
if(pair.key == *key) {
|
||||||
|
if(this.occupied[index] == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return &pair.value;
|
||||||
|
}
|
||||||
|
index = (index + 1) & (capacity - 1);
|
||||||
|
if(index == start) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
zero_hash: ugpr(ugpr* val) -> {
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
@instantiate MapSIOaLpDhFt_add[ugpr, ugpr, ugpr; 32];
|
||||||
|
@instantiate MapSIOaLpDhFt_get[ugpr, ugpr, ugpr; 32];
|
||||||
|
|
||||||
|
main: u0() -> {
|
||||||
|
map.hash = &zero_hash;
|
||||||
|
|
||||||
|
MapSIOaLpDhFt_get[ugpr, ugpr, ugpr; 32](&map, &test_key);
|
||||||
|
MapSIOaLpDhFt_add[ugpr, ugpr, ugpr; 32](&map, &test_key, &test_value);
|
||||||
|
MapSIOaLpDhFt_get[ugpr, ugpr, ugpr; 32](&map, &test_key);
|
||||||
|
};
|
||||||
|
|
||||||
|
loop {}
|
||||||
|
|
||||||
|
@section(".data");
|
||||||
|
MapSIOaLpDhFt[ugpr, ugpr, ugpr; 32] map:;
|
||||||
|
|
||||||
|
ugpr test_value: 10;
|
||||||
|
ugpr test_key: 5;
|
@ -242,12 +242,19 @@ AST *ast_cast_expr(AST *what, Type *to) {
|
|||||||
} else abort();
|
} else abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool copy = false;
|
||||||
|
|
||||||
// Make sure an unparametrized generic int parameter hasn't sneaked its way in
|
// Make sure an unparametrized generic int parameter hasn't sneaked its way in
|
||||||
while(what->nodeKind == AST_EXPR_VAR && what->exprVar.thing->kind == SCOPEITEM_CEXPR && what->exprVar.thing->data.cexpr.concrete) {
|
while(what->nodeKind == AST_EXPR_VAR && what->exprVar.thing->kind == SCOPEITEM_CEXPR && what->exprVar.thing->data.cexpr.concrete) {
|
||||||
what = what->exprVar.thing->data.cexpr.concrete;
|
what = what->exprVar.thing->data.cexpr.concrete;
|
||||||
|
copy = true;
|
||||||
}
|
}
|
||||||
assert(!(what->nodeKind == AST_EXPR_VAR && what->exprVar.thing->kind == SCOPEITEM_CEXPR));
|
assert(!(what->nodeKind == AST_EXPR_VAR && what->exprVar.thing->kind == SCOPEITEM_CEXPR));
|
||||||
|
|
||||||
|
if(copy) {
|
||||||
|
what = ast_deep_copy(what);
|
||||||
|
}
|
||||||
|
|
||||||
if(type_equal(what->expression.type, to)) return what;
|
if(type_equal(what->expression.type, to)) return what;
|
||||||
|
|
||||||
if(!type_is_castable(what->expression.type, to)) {
|
if(!type_is_castable(what->expression.type, to)) {
|
||||||
|
316
src/parse.c
316
src/parse.c
@ -202,7 +202,6 @@ AST *nct_parse_expression(Parser *P, int lOP) {
|
|||||||
P->isInFunction++;
|
P->isInFunction++;
|
||||||
|
|
||||||
e->chunk = (AST*) nct_parse_chunk(P, 1, 0, scope_new(P->scope), ft);
|
e->chunk = (AST*) nct_parse_chunk(P, 1, 0, scope_new(P->scope), ft);
|
||||||
e->chunk->chunk.functionType = ft;
|
|
||||||
|
|
||||||
P->isInFunction--;
|
P->isInFunction--;
|
||||||
|
|
||||||
@ -287,7 +286,20 @@ 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)) {
|
||||||
|
Token op = P->tokens[P->i - 1];
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
assert(e->expression.type->type == TYPE_TYPE_RECORD);
|
assert(e->expression.type->type == TYPE_TYPE_RECORD);
|
||||||
|
|
||||||
Token fieldTok = expect(P, TOKEN_IDENTIFIER);
|
Token fieldTok = expect(P, TOKEN_IDENTIFIER);
|
||||||
@ -312,6 +324,123 @@ AST *nct_parse_expression(Parser *P, int lOP) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
e = (AST*) d;
|
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;
|
||||||
@ -370,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);
|
||||||
|
|
||||||
@ -583,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;
|
||||||
@ -623,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;
|
||||||
@ -1160,7 +1166,7 @@ static void nct_parse_statement(Parser *P) {
|
|||||||
ret->next = NULL;
|
ret->next = NULL;
|
||||||
|
|
||||||
if(!maybe(P, TOKEN_SEMICOLON)) {
|
if(!maybe(P, TOKEN_SEMICOLON)) {
|
||||||
ret->val = nct_parse_expression(P, 0);
|
ret->val = ast_cast_expr(nct_parse_expression(P, 0), P->topLevel->functionType->function.ret);
|
||||||
|
|
||||||
expect(P, TOKEN_SEMICOLON);
|
expect(P, TOKEN_SEMICOLON);
|
||||||
}
|
}
|
||||||
@ -1642,6 +1648,8 @@ ASTChunk *nct_parse_chunk(Parser *P, int isTopLevel, int varPrioritize, Scope *t
|
|||||||
|
|
||||||
/* Arguments */
|
/* Arguments */
|
||||||
if(ft && isTopLevel) {
|
if(ft && isTopLevel) {
|
||||||
|
P->topLevel->functionType = ft;
|
||||||
|
|
||||||
ScopeItem **vtes = alloca(sizeof(*vtes) * ft->function.argCount);
|
ScopeItem **vtes = alloca(sizeof(*vtes) * ft->function.argCount);
|
||||||
|
|
||||||
// First arguments in a function TLC is the arguments
|
// First arguments in a function TLC is the arguments
|
||||||
|
17
src/types.h
17
src/types.h
@ -6,6 +6,8 @@
|
|||||||
#include<stdbool.h>
|
#include<stdbool.h>
|
||||||
#include<string.h>
|
#include<string.h>
|
||||||
#include<stdio.h>
|
#include<stdio.h>
|
||||||
|
#include<assert.h>
|
||||||
|
#include<stdlib.h>
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
TYPE_TYPE_PRIMITIVE, TYPE_TYPE_RECORD, TYPE_TYPE_POINTER, TYPE_TYPE_FUNCTION, TYPE_TYPE_ARRAY, TYPE_TYPE_GENERIC, TYPE_TYPE_ERROR
|
TYPE_TYPE_PRIMITIVE, TYPE_TYPE_RECORD, TYPE_TYPE_POINTER, TYPE_TYPE_FUNCTION, TYPE_TYPE_ARRAY, TYPE_TYPE_GENERIC, TYPE_TYPE_ERROR
|
||||||
@ -117,6 +119,21 @@ static inline bool type_is_segmented_pointer(Type *type) {
|
|||||||
return type->type == TYPE_TYPE_RECORD && !!strstr(type->record.name, " @far*");
|
return type->type == TYPE_TYPE_RECORD && !!strstr(type->record.name, " @far*");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool type_is_any_pointer(Type *type) {
|
||||||
|
return type->type == TYPE_TYPE_POINTER || type_is_segmented_pointer(type);
|
||||||
|
}
|
||||||
|
static inline Type *type_dereference(Type *type) {
|
||||||
|
assert(type_is_any_pointer(type));
|
||||||
|
|
||||||
|
if(type->type == TYPE_TYPE_POINTER) {
|
||||||
|
return type->pointer.of;
|
||||||
|
} else if(type_is_segmented_pointer(type)) {
|
||||||
|
return type->record.fieldTypes[1]->pointer.of;
|
||||||
|
}
|
||||||
|
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
static inline Type *type_u(size_t bits) {
|
static inline Type *type_u(size_t bits) {
|
||||||
char buf[32];
|
char buf[32];
|
||||||
snprintf(buf, sizeof(buf), "u%lu", bits);
|
snprintf(buf, sizeof(buf), "u%lu", bits);
|
||||||
|
@ -142,7 +142,7 @@ static AST *is_field_access(AST *e) {
|
|||||||
* */
|
* */
|
||||||
static const char *xop_sz(AST *tlc, AST *e, int sz) {
|
static const char *xop_sz(AST *tlc, AST *e, int sz) {
|
||||||
#define XOPBUFS 16
|
#define XOPBUFS 16
|
||||||
#define XOPBUFSZ 32
|
#define XOPBUFSZ 64
|
||||||
static char bufs[XOPBUFS][XOPBUFSZ];
|
static char bufs[XOPBUFS][XOPBUFSZ];
|
||||||
static int bufidx = 0;
|
static int bufidx = 0;
|
||||||
|
|
||||||
|
@ -109,6 +109,10 @@ static void mark_d(ScopeItem *si) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RULE ONE OF DUMBING: NEVER xopify NOR varify MORE THAN ONCE IN A SINGLE CALL TO VISITOR!!!
|
||||||
|
* IF YOU DO THIS, stmtPrev WILL FUCK UP AND STATEMENTS WILL BE LOST
|
||||||
|
*/
|
||||||
struct DumbenState {
|
struct DumbenState {
|
||||||
AST *targetTLC;
|
AST *targetTLC;
|
||||||
int effective;
|
int effective;
|
||||||
@ -129,14 +133,10 @@ static void dumben_visitor(AST **nptr, AST *stmt, AST *stmtPrev, AST *chu, AST *
|
|||||||
if(is_xop(e->exprBinOp.operands[0]) == XOP_NOT_XOP) {
|
if(is_xop(e->exprBinOp.operands[0]) == XOP_NOT_XOP) {
|
||||||
e->exprBinOp.operands[0] = xopify(tlc, chu, stmtPrev, s, e->exprBinOp.operands[0]);
|
e->exprBinOp.operands[0] = xopify(tlc, chu, stmtPrev, s, e->exprBinOp.operands[0]);
|
||||||
this->effective = 1;
|
this->effective = 1;
|
||||||
}
|
} else if(is_xop(e->exprBinOp.operands[1]) == XOP_NOT_XOP) {
|
||||||
|
|
||||||
if(is_xop(e->exprBinOp.operands[1]) == XOP_NOT_XOP) {
|
|
||||||
e->exprBinOp.operands[1] = xopify(tlc, chu, stmtPrev, s, e->exprBinOp.operands[1]);
|
e->exprBinOp.operands[1] = xopify(tlc, chu, stmtPrev, s, e->exprBinOp.operands[1]);
|
||||||
this->effective = 1;
|
this->effective = 1;
|
||||||
}
|
} else if(is_xop(e->exprBinOp.operands[0]) == XOP_MEM && is_xop(e->exprBinOp.operands[1]) == XOP_MEM) {
|
||||||
|
|
||||||
if(is_xop(e->exprBinOp.operands[0]) == XOP_MEM && is_xop(e->exprBinOp.operands[1]) == XOP_MEM) {
|
|
||||||
// Can't have two mems; put one in var
|
// Can't have two mems; put one in var
|
||||||
|
|
||||||
e->exprBinOp.operands[1] = varify(tlc, chu, stmtPrev, s, e->exprBinOp.operands[1]);
|
e->exprBinOp.operands[1] = varify(tlc, chu, stmtPrev, s, e->exprBinOp.operands[1]);
|
||||||
|
Loading…
Reference in New Issue
Block a user