112 lines
2.4 KiB
C
112 lines
2.4 KiB
C
#include "lex.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
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);
|
|
}
|