#include "parse.h" #include #include #include #include // phases: // https://en.cppreference.com/c/language/translation_phases // phase 1 - source chars void source_char_iter_init(SourceCharIter* r, const char* text) { *r = (SourceCharIter) { .text = text, .i = 0, .line = 1, .col = 1, }; } SourceChar source_iter_next(SourceCharIter* r) { char ch = r->text[r->i]; int line = r->line; int col = r->col; if (r->text[r->i] != '\0') { if (ch == '\n') { r->line += 1; r->col = 1; } else { r->col += 1; } r->i += 1; } return (SourceChar) { ch, line, col }; } // phase 2 - logical source lines void lsl_iter_init(LslCharIter* r, SourceCharIter* source_char_iter) { SourceChar curr = source_iter_next(source_char_iter); *r = (LslCharIter) { .source_char_iter = source_char_iter, .curr = curr, }; } LslChar lsl_iter_next(LslCharIter* r) { SourceChar next = source_iter_next(r->source_char_iter); if (r->curr.ch == '\\' && next.ch == '\n') { r->curr = source_iter_next(r->source_char_iter); return lsl_iter_next(r); } LslChar lsl_char = { r->curr.ch, r->curr.line, r->curr.col }; r->curr = next; return lsl_char; } // phase 3 - preprocessor tokens void lexer_init(Lexer* r, LslCharIter* lsl_char_iter) { LslChar curr = lsl_iter_next(lsl_char_iter); *r = (Lexer) { .lsl_char_iter = lsl_char_iter, .curr = curr, }; } static Tok tok(TokTy ty, const char* text, int line, int col) { return (Tok) { ty, strdup(text), line, col }; } static bool l_done(Lexer* l) { return l->curr.ch == '\0'; } constexpr size_t max_token_text_len = 64; static void l_step(Lexer* l, char text[], size_t* text_len) { assert(*text_len < max_token_text_len); text[*text_len] = l->curr.ch; *text_len += 1; l->curr = lsl_iter_next(l->lsl_char_iter); } Tok lexer_next(Lexer* l) { int line = l->curr.line; int col = l->curr.col; char text[max_token_text_len] = ""; size_t text_len = 0; if (l_done(l)) { return tok(Tok_Eof, text, line, col); } bool matched = false; while (strchr(" \t\r", l->curr.ch)) { matched = true; l_step(l, text, &text_len); } if (matched) { return lexer_next(l); } while ((l->curr.ch >= 'a' && l->curr.ch <= 'z') || (l->curr.ch >= 'A' && l->curr.ch <= 'Z') || (matched && l->curr.ch >= '0' && l->curr.ch <= '9') || strchr("_", l->curr.ch)) { matched = true; l_step(l, text, &text_len); } if (matched) { return tok(Tok_Ident, text, line, col); } while ((l->curr.ch >= '1' && l->curr.ch <= '9') || (matched && l->curr.ch == '0')) { matched = true; l_step(l, text, &text_len); } if (matched) { return tok(Tok_Int, text, line, col); } if (l->curr.ch == '"') { l_step(l, text, &text_len); while (l->curr.ch != '"') { if (l->curr.ch == '\\') { l_step(l, text, &text_len); if (l_done(l)) break; } l_step(l, text, &text_len); } if (l_done(l) || l->curr.ch != '"') { fprintf(stderr, "error: malformed string literal\n"); return lexer_next(l); } l_step(l, text, &text_len); return tok(Tok_Str, text, line, col); } if (l->curr.ch == '\'') { l_step(l, text, &text_len); if (l->curr.ch == '\\') { l_step(l, text, &text_len); } if (!l_done(l)) { l_step(l, text, &text_len); } if (l_done(l) && l->curr.ch != '\'') { fprintf(stderr, "error: malformed character literal\n"); return lexer_next(l); } l_step(l, text, &text_len); return tok(Tok_Char, text, line, col); } if (strchr("\n;(){}", l->curr.ch)) { TokTy ty = (TokTy)l->curr.ch; l_step(l, text, &text_len); return tok(ty, text, line, col); } fprintf(stderr, "error: illegal character '%c'\n", l->curr.ch); l_step(l, text, &text_len); return lexer_next(l); }