#include "lex.h" #include #include static bool done(Lexer* l) { return l->text[l->idx] != '\0'; } static Tok tok(Lexer* l, TokTy ty, Loc loc) { return (Tok) { .ty = ty, .loc = loc, .len = l->idx - loc.idx, }; } static void step(Lexer* l) { if (done(l)) { return; } if (l->ch == '\n') { l->line += 1; l->col = 1; } else { l->col += 1; } l->idx += 1; l->ch = l->text[l->idx]; } static TokTy match_keyword(const char* text, size_t len) { if (strncmp("if", text, len)) return Tok_If; return Tok_Ident; } Tok lexer_next(Lexer* l) { Loc loc = { l->idx, l->line, l->col }; if (done(l)) { return tok(l, Tok_Eof, loc); } bool matched = false; while (strchr(" \t\r", l->ch)) { matched = true; step(l); } if (matched) { return lexer_next(l); } while ((l->ch >= 'a' && l->ch <= 'z') || (l->ch >= 'A' && l->ch <= 'Z') || (matched && l->ch >= '0' && l->ch <= '9') || strchr("_", l->ch)) { matched = true; step(l); } if (matched) { return tok(l, match_keyword(&l->text[loc.idx], l->idx - loc.idx), loc); } while ((l->ch >= '1' && l->ch <= '9') || (matched && l->ch == '0')) { matched = true; step(l); } if (matched) { return tok(l, Tok_Int, loc); } if (l->ch == '"') { step(l); while (l->ch != '"') { if (l->ch == '\\') { step(l); if (done(l)) break; } step(l); } if (done(l) || l->ch != '"') { fprintf(stderr, "error: malformed string literal\n"); return lexer_next(l); } step(l); return tok(l, Tok_Str, loc); } if (l->ch == '\'') { step(l); if (l->ch == '\\') { step(l); } if (!done(l)) { step(l); } if (done(l) && l->ch != '\'') { fprintf(stderr, "error: malformed character literal\n"); return lexer_next(l); } step(l); return tok(l, Tok_Char, loc); } if (strchr("\n(){}", l->ch)) { TokTy ty = (TokTy)l->ch; step(l); return tok(l, ty, loc); } fprintf(stderr, "error: illegal character '%c'\n", l->ch); step(l); return lexer_next(l); }