aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMustafa Quraish <[email protected]>2022-02-06 21:18:04 -0500
committerMustafa Quraish <[email protected]>2022-02-06 21:19:45 -0500
commit0dd893225bebffd9a25f1345ec49922aa961b882 (patch)
treee843cef529e0e1d6cdba85c2268742e3aed68749
parentAdd some information to the README (diff)
downloadcup-0dd893225bebffd9a25f1345ec49922aa961b882.tar.xz
cup-0dd893225bebffd9a25f1345ec49922aa961b882.zip
[C]: Add `here` keyword that evaluates to a string with it's location
It's not really a keyword like the other ones, but just handled completely at the lexer level since it already knows the location of the token, so it injects a string literal instead. We also use this in the self-hosted compiler now for better error reporting for where the error happened internally.
-rw-r--r--compiler/lexer.cup2
-rw-r--r--compiler/parser.cup25
-rw-r--r--compiler/tokens.cup8
-rw-r--r--compiler/types.cup2
-rw-r--r--src/lexer.c9
5 files changed, 28 insertions, 18 deletions
diff --git a/compiler/lexer.cup b/compiler/lexer.cup
index c0062a2..a7fd032 100644
--- a/compiler/lexer.cup
+++ b/compiler/lexer.cup
@@ -217,7 +217,7 @@ fn lexer_next(lexer: Lexer*, token: Token*) {
lexer_loc(lexer, &loc);
if (pos == lexer.len)
- die_loc(&loc, "EOF while parsing string literal");
+ die_loc(here, &loc, "EOF while parsing string literal");
// Careful with indexing here, because we want to skip opening and closing quotes
let str_len = pos - lexer.pos - 1;
diff --git a/compiler/parser.cup b/compiler/parser.cup
index 9093f84..208f49c 100644
--- a/compiler/parser.cup
+++ b/compiler/parser.cup
@@ -155,7 +155,7 @@ fn parse_literal(lexer: Lexer*): Node* {
node.d.literal.as_char = token.value.as_char;
node.etyp = type_new(TYPE_CHAR);
} else {
- die_loc2(&token.loc, "Unexpected token in parse_literal: ", token_type_to_string(token.typ));
+ die_loc2(here, &token.loc, "Unexpected token in parse_literal: ", token_type_to_string(token.typ));
}
return node;
}
@@ -177,7 +177,7 @@ fn parse_type(lexer: Lexer*): Type* {
lexer_next_assert(lexer, &token, TOKEN_IDENTIFIER);
typ = find_compound_type(&token);
if (!typ)
- die_loc2(&token.loc, "Unknown token in parse_type: ", token.value.as_string);
+ die_loc2(here, &token.loc, "Unknown token in parse_type: ", token.value.as_string);
}
let running = true;
@@ -199,12 +199,12 @@ fn parse_type(lexer: Lexer*): Type* {
} else if (token.typ == TOKEN_IDENTIFIER) {
let constant = find_constant(&token);
if (!constant)
- die_loc2(&token.loc, "Could not find constant: ", token.value.as_string);
+ die_loc2(here, &token.loc, "Could not find constant: ", token.value.as_string);
// FIXME: This is a complete mess.
let value = constant.d.constant.value;
arr.array_size = value.d.literal.as_int;
} else {
- die_loc(&token.loc, "Expected a constant expression for array size");
+ die_loc(here, &token.loc, "Expected a constant expression for array size");
}
lexer_next_assert(lexer, &token, TOKEN_CLOSE_BRACKET);
typ = arr;
@@ -243,7 +243,7 @@ fn parse_function_call_args(lexer: Lexer*, func: Node*): Node* {
lexer_next_assert(lexer, &token, TOKEN_CLOSE_PAREN);
if (node.d.call.args.size != func.d.func.args.size)
- die_loc2(&token.loc, "Function call argument count mismatch: ", func.d.func.name);
+ die_loc2(here, &token.loc, "Function call argument count mismatch: ", func.d.func.name);
return node;
}
@@ -285,7 +285,7 @@ fn parse_identifier(lexer: Lexer*): Node* {
return constant.d.constant.value;
}
- die_loc2(&token.loc, "Unknown identifier in parse_identifier: ", token.value.as_string);
+ die_loc2(here, &token.loc, "Unknown identifier in parse_identifier: ", token.value.as_string);
return null;
}
@@ -309,7 +309,7 @@ fn parse_factor(lexer: Lexer*): Node* {
expr = node_new(AST_ASSIGN);
expr.d.assign.lhs = parse_factor(lexer);
if (!is_lvalue(expr.d.assign.lhs.typ))
- die_loc(&token.loc, "Cannot increment non-lvalue");
+ die_loc(here, &token.loc, "Cannot increment non-lvalue");
let plus = node_new(AST_PLUS);
plus.d.binary.lhs = expr.d.assign.lhs;
@@ -322,7 +322,7 @@ fn parse_factor(lexer: Lexer*): Node* {
expr = node_new(AST_ASSIGN);
expr.d.assign.lhs = parse_factor(lexer);
if (!is_lvalue(expr.d.assign.lhs.typ))
- die_loc(&token.loc, "Cannot decrement non-lvalue");
+ die_loc(here, &token.loc, "Cannot decrement non-lvalue");
let minus = node_new(AST_MINUS);
minus.d.binary.lhs = expr.d.assign.lhs;
@@ -360,7 +360,7 @@ fn parse_factor(lexer: Lexer*): Node* {
die("TOKEN_STAR not implemented in parse_factor");
} else {
- die_loc2(&token.loc, ": Unexpected token found in parse_factor: ", token_type_to_string(token.typ));
+ die_loc2(here, &token.loc, ": Unexpected token found in parse_factor: ", token_type_to_string(token.typ));
}
// TODO: Handle postfix operators here.
@@ -601,7 +601,6 @@ fn parse_var_declaration(lexer: Lexer*): Node* {
decl.var.name = token.value.as_string;
lexer_peek(lexer, &token);
- let has_type = false;
// TODO: implicit types when type system is better
lexer_next_assert(lexer, &token, TOKEN_COLON);
decl.var.typ = parse_type(lexer);
@@ -635,7 +634,7 @@ fn parse_function_params(lexer: Lexer*, func: Node*) {
let name = token.value.as_string;
if (identifier_exists(&token))
- die_loc2(&token.loc, "Identifier already defined: ", name);
+ die_loc2(here, &token.loc, "Identifier already defined: ", name);
lexer_next_assert(lexer, &token, TOKEN_COLON);
let typ = parse_type(lexer);
@@ -839,8 +838,10 @@ fn parse_program(lexer: Lexer*): Node* {
block_add_child(node, parse_var_declaration(lexer));
} else if (token.typ == TOKEN_SEMICOLON) {
lexer_next(lexer, &token);
+ } else if (token.typ == TOKEN_CONST) {
+ parse_constant_declaration(lexer);
} else {
- die_loc2(&token.loc, "unexpected token in parse_program", token_type_to_string(token.typ));
+ die_loc2(here, &token.loc, "unexpected token in parse_program", token_type_to_string(token.typ));
}
lexer_peek(lexer, &token);
diff --git a/compiler/tokens.cup b/compiler/tokens.cup
index cf1b011..9c00a8a 100644
--- a/compiler/tokens.cup
+++ b/compiler/tokens.cup
@@ -185,16 +185,18 @@ fn location_print(loc: Location *) {
putu(loc.col + 1);
}
-fn die_loc2(loc: Location*, msg1: char *, msg2: char *) {
+fn die_loc2(eloc: char*, loc: Location*, msg1: char *, msg2: char *) {
location_print(loc);
puts(": ");
puts(msg1);
putsln(msg2);
+ puts("Note: Error happened here: ");
+ putsln(eloc);
exit(1);
}
-fn die_loc(loc: Location*, msg: char *) {
- die_loc2(loc, msg, "");
+fn die_loc(eloc: char*, loc: Location*, msg: char *) {
+ die_loc2(eloc, loc, msg, "");
}
fn token_from_type(token: Token*, typ: int, loc: Location *) {
diff --git a/compiler/types.cup b/compiler/types.cup
index c2afdec..e6cb233 100644
--- a/compiler/types.cup
+++ b/compiler/types.cup
@@ -62,8 +62,6 @@ fn type_new(typ: int): Type* {
if (typ == TYPE_VOID) return _type_void;
if (typ == TYPE_ANY) return _type_any;
- putsln("Allocating Type*");
-
let t: Type* = malloc(sizeof(Type));
t.typ = typ;
t.size = size_for_base_type(typ);
diff --git a/src/lexer.c b/src/lexer.c
index 0d34eea..7bf426a 100644
--- a/src/lexer.c
+++ b/src/lexer.c
@@ -200,6 +200,15 @@ Token Lexer_next(Lexer *lexer)
default: {
+ // Hack to support getting source locations
+ if (Lexer_starts_with(lexer, "here")) {
+ char *loc_string = calloc(sizeof(char), 100);
+ sprintf(loc_string, "%s:%lld:%lld", lexer->filename, lexer->line+1, lexer->col+1);
+ Token token = Token_from_string(loc_string, Lexer_loc(lexer));
+ advance(lexer, 4);
+ return token;
+ }
+
// Handle keywords explicitly
#define LEX_KEYWORD(token_type, str) if (Lexer_starts_with(lexer, str)) return Lexer_make_token(lexer, token_type, strlen(str));
ENUM_KEYWORDS(LEX_KEYWORD)