Skip to content

Commit f4d122d

Browse files
Use static tokens for single-char lexemes (closes #229)
1 parent 5260898 commit f4d122d

2 files changed

Lines changed: 44 additions & 7 deletions

File tree

src/lexer.c

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ void lexer_init(Lexer *lexer, const char *source, const char *filename) {
9090
lexer->column = 1;
9191
lexer->pending_token.type = TOKEN_EOF;
9292
lexer->pending_token.literal = NULL;
93+
lexer->pending_token.literal_kind = TOKEN_LITERAL_NULL;
9394
lexer->pending_token.line = 0;
9495
lexer->pending_token.column = 0;
9596
lexer->has_pending = false;
@@ -175,15 +176,31 @@ static Token make_token(Lexer *lexer, PTokenType type, const char *start, size_t
175176
Token token;
176177
token.type = type;
177178
token.line = lexer->line;
178-
token.column = lexer->column - (int)length; // Approximate start column
179+
token.column = lexer->column - (int)length;
179180
if (length == 0 && start != NULL) {
180181
token.literal = safe_strdup(start);
182+
token.literal_kind = TOKEN_LITERAL_HEAP;
183+
} else if (length == 1 && start != NULL) {
184+
static char pool[256][2];
185+
static bool pool_ready = false;
186+
if (!pool_ready) {
187+
for (int i = 0; i < 256; i++) {
188+
pool[i][0] = (char)i;
189+
pool[i][1] = '\0';
190+
}
191+
pool_ready = true;
192+
}
193+
unsigned char uc = (unsigned char)start[0];
194+
token.literal = pool[uc];
195+
token.literal_kind = TOKEN_LITERAL_STATIC;
181196
} else if (start != NULL) {
182197
token.literal = (char *)safe_malloc(length + 1);
183198
memcpy(token.literal, start, length);
184199
token.literal[length] = '\0';
200+
token.literal_kind = TOKEN_LITERAL_HEAP;
185201
} else {
186202
token.literal = NULL;
203+
token.literal_kind = TOKEN_LITERAL_NULL;
187204
}
188205
return token;
189206
}
@@ -194,6 +211,7 @@ static Token error_token(Lexer *lexer, const char *message) {
194211
token.line = lexer->line;
195212
token.column = lexer->column;
196213
token.literal = safe_strdup(message);
214+
token.literal_kind = TOKEN_LITERAL_HEAP;
197215
return token;
198216
}
199217

@@ -246,6 +264,7 @@ static Token flush_fmt_buffer(Lexer *lexer) {
246264
t.line = lexer->line;
247265
t.column = lexer->column - (int)lexer->fmt_buffer_len;
248266
t.literal = safe_strdup(lexer->fmt_buffer ? lexer->fmt_buffer : "");
267+
t.literal_kind = TOKEN_LITERAL_HEAP;
249268
lexer->fmt_buffer_len = 0;
250269
if (lexer->fmt_buffer) {
251270
lexer->fmt_buffer[0] = '\0';
@@ -433,7 +452,8 @@ static Token scan_fmt_string_text(Lexer *lexer, char quote_char) {
433452
lexer->pending_token.type = TOKEN_FMT_OPEN;
434453
lexer->pending_token.line = lexer->line;
435454
lexer->pending_token.column = lexer->column;
436-
lexer->pending_token.literal = safe_strdup("{");
455+
lexer->pending_token.literal = "{";
456+
lexer->pending_token.literal_kind = TOKEN_LITERAL_STATIC;
437457
return t;
438458
}
439459

@@ -529,12 +549,12 @@ Token lexer_next_token(Lexer *lexer) {
529549
}
530550
if (c == '\n') {
531551
advance(lexer);
532-
Token t = {TOKEN_NEWLINE, safe_strdup("\n"), lexer->line - 1, lexer->column};
552+
Token t = {TOKEN_NEWLINE, "\n", TOKEN_LITERAL_STATIC, lexer->line - 1, lexer->column};
533553
return t;
534554
}
535555
if (c == ';') {
536556
advance(lexer);
537-
Token t = {TOKEN_NEWLINE, safe_strdup("\n"), lexer->line, lexer->column};
557+
Token t = {TOKEN_NEWLINE, "\n", TOKEN_LITERAL_STATIC, lexer->line, lexer->column};
538558
return t;
539559
}
540560
if (c == '!') {
@@ -674,7 +694,7 @@ Token lexer_next_token(Lexer *lexer) {
674694
return error_token(lexer, err_msg);
675695
}
676696

677-
Token t = {TOKEN_EOF, NULL, lexer->line, lexer->column};
697+
Token t = {TOKEN_EOF, NULL, TOKEN_LITERAL_NULL, lexer->line, lexer->column};
678698
return t;
679699
}
680700

@@ -736,6 +756,7 @@ static Token identifier_token(Lexer *lexer) {
736756
Token t;
737757
t.type = type;
738758
t.literal = value;
759+
t.literal_kind = TOKEN_LITERAL_HEAP;
739760
t.line = start_line;
740761
t.column = start_col;
741762
return t;
@@ -861,6 +882,17 @@ static Token number_token(Lexer *lexer, bool is_negative_start) {
861882
}
862883

863884
value[len_val] = '\0';
864-
Token t = {(int)has_dot ? TOKEN_FLOAT : TOKEN_NUMBER, value, start_line, start_col};
885+
Token t = {(int)has_dot ? TOKEN_FLOAT : TOKEN_NUMBER, value, TOKEN_LITERAL_HEAP, start_line, start_col};
865886
return t;
866887
}
888+
889+
void token_free(Token *token) {
890+
if (!token) {
891+
return;
892+
}
893+
if (token->literal_kind == TOKEN_LITERAL_HEAP && token->literal != NULL) {
894+
free(token->literal);
895+
}
896+
token->literal = NULL;
897+
token->literal_kind = TOKEN_LITERAL_NULL;
898+
}

src/token.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,16 @@ typedef enum {
5959

6060
} PTokenType;
6161

62+
typedef enum { TOKEN_LITERAL_NULL = 0, TOKEN_LITERAL_STATIC, TOKEN_LITERAL_HEAP } TokenLiteralKind;
63+
6264
typedef struct {
6365
PTokenType type;
64-
char *literal; // For IDENT, NUMBER, FLOAT, STRING, etc.
66+
char *literal;
67+
TokenLiteralKind literal_kind;
6568
int line;
6669
int column;
6770
} Token;
6871

72+
void token_free(Token *token);
73+
6974
#endif // TOKEN_H

0 commit comments

Comments
 (0)