diff options
| author | Mustafa Quraish <[email protected]> | 2022-02-06 21:18:04 -0500 |
|---|---|---|
| committer | Mustafa Quraish <[email protected]> | 2022-02-06 21:19:45 -0500 |
| commit | 0dd893225bebffd9a25f1345ec49922aa961b882 (patch) | |
| tree | e843cef529e0e1d6cdba85c2268742e3aed68749 | |
| parent | Add some information to the README (diff) | |
| download | cup-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.cup | 2 | ||||
| -rw-r--r-- | compiler/parser.cup | 25 | ||||
| -rw-r--r-- | compiler/tokens.cup | 8 | ||||
| -rw-r--r-- | compiler/types.cup | 2 | ||||
| -rw-r--r-- | src/lexer.c | 9 |
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) |