/* * tok.c — token names, keyword lookup, debug printer. * * One table-of-records keyed by kind. The keyword subset is also * scanned linearly during lexing — fewer than 25 entries, a hash * isn't worth it. */ #include "ww.h" #include struct kwent { const char *s; Tkind kind; }; /* keep alphabetised, so kwlookup is easy to read. */ static const struct kwent kwtab[] = { { "as", TK_AS }, { "break", TK_BREAK }, { "case", TK_CASE }, { "chan", TK_CHAN }, { "const", TK_CONST }, { "continue", TK_CONTINUE }, { "def", TK_DEF }, { "defer", TK_DEFER }, { "else", TK_ELSE }, { "enum", TK_ENUM }, { "export", TK_EXPORT }, { "false", TK_FALSE }, { "fn", TK_FN }, { "for", TK_FOR }, { "if", TK_IF }, { "is", TK_IS }, { "let", TK_LET }, { "match", TK_MATCH }, { "nil", TK_NIL }, { "proc", TK_PROC }, { "return", TK_RETURN }, { "static", TK_STATIC }, { "struct", TK_STRUCT }, { "switch", TK_SWITCH }, { "true", TK_TRUE }, { "type", TK_TYPE }, { "use", TK_USE }, { "void", TK_VOID }, { "yield", TK_YIELD } }; Tkind kwlookup(const char *s, u64 n) { /* linear scan: small N, predictable, branchy fall-through is fine. */ for (u64 i = 0; i < nelem(kwtab); i++) { const char *k = kwtab[i].s; if (strlen(k) == n && memcmp(k, s, n) == 0) return kwtab[i].kind; } return TK_NONE; } const char * tokname(Tkind k) { switch (k) { case TK_NONE: return ""; case TK_EOF: return "EOF"; case TK_ERR: return "ERR"; case TK_IDENT: return "IDENT"; case TK_INT: return "INT"; case TK_FLOAT: return "FLOAT"; case TK_RUNE: return "RUNE"; case TK_STR: return "STR"; case TK_FN: return "fn"; case TK_LET: return "let"; case TK_DEF: return "def"; case TK_IF: return "if"; case TK_ELSE: return "else"; case TK_FOR: return "for"; case TK_SWITCH: return "switch"; case TK_CASE: return "case"; case TK_RETURN: return "return"; case TK_USE: return "use"; case TK_TYPE: return "type"; case TK_STRUCT: return "struct"; case TK_DEFER: return "defer"; case TK_BREAK: return "break"; case TK_CONTINUE: return "continue"; case TK_EXPORT: return "export"; case TK_PROC: return "proc"; case TK_CHAN: return "chan"; case TK_NIL: return "nil"; case TK_TRUE: return "true"; case TK_FALSE: return "false"; case TK_AS: return "as"; case TK_IS: return "is"; case TK_VOID: return "void"; case TK_YIELD: return "yield"; case TK_STATIC: return "static"; case TK_MATCH: return "match"; case TK_CONST: return "const"; case TK_UNDER: return "_"; case TK_ENUM: return "enum"; case TK_LPAREN: return "("; case TK_RPAREN: return ")"; case TK_LBRACE: return "{"; case TK_RBRACE: return "}"; case TK_LBRACK: return "["; case TK_RBRACK: return "]"; case TK_COMMA: return ","; case TK_SEMI: return ";"; case TK_COLON: return ":"; case TK_DOT: return "."; case TK_ELLIPSIS: return "..."; case TK_DOTDOT: return ".."; case TK_AT: return "@"; case TK_QUESTION: return "?"; case TK_ASSIGN: return "="; case TK_PLUSEQ: return "+="; case TK_MINUSEQ: return "-="; case TK_STAREQ: return "*="; case TK_SLASHEQ: return "/="; case TK_PERCENTEQ: return "%="; case TK_AMPEQ: return "&="; case TK_PIPEEQ: return "|="; case TK_CARETEQ: return "^="; case TK_LSHIFTEQ: return "<<="; case TK_RSHIFTEQ: return ">>="; case TK_PLUS: return "+"; case TK_MINUS: return "-"; case TK_STAR: return "*"; case TK_SLASH: return "/"; case TK_PERCENT: return "%"; case TK_AMP: return "&"; case TK_PIPE: return "|"; case TK_CARET: return "^"; case TK_TILDE: return "~"; case TK_LSHIFT: return "<<"; case TK_RSHIFT: return ">>"; case TK_EQ: return "=="; case TK_NEQ: return "!="; case TK_LT: return "<"; case TK_LE: return "<="; case TK_GT: return ">"; case TK_GE: return ">="; case TK_AND: return "&&"; case TK_OR: return "||"; case TK_NOT: return "!"; case TK_LARROW: return "<-"; case TK_ARROW: return "->"; case TK_FATARROW: return "=>"; case TK_LAST: return ""; } return ""; } static void fputq(FILE *f, const char *s, u64 n) { fputc('"', f); for (u64 i = 0; i < n; i++) { unsigned char c = (unsigned char)s[i]; switch (c) { case '\\': fputs("\\\\", f); break; case '"': fputs("\\\"", f); break; case '\n': fputs("\\n", f); break; case '\t': fputs("\\t", f); break; case '\r': fputs("\\r", f); break; default: if (c < 0x20 || c == 0x7f) fprintf(f, "\\x%02x", c); else fputc(c, f); } } fputc('"', f); } void tokprint(FILE *f, Tok t) { fprintf(f, "%s:%d:%d %s", t.pos.file ? t.pos.file : "", t.pos.line, t.pos.col, tokname(t.kind)); switch (t.kind) { case TK_IDENT: case TK_STR: case TK_ERR: fputc(' ', f); fputq(f, t.text, t.tlen); break; case TK_INT: case TK_RUNE: fprintf(f, " %llu", (unsigned long long)t.v.uval); break; case TK_FLOAT: fprintf(f, " %g", t.v.fval); break; default: break; } fputc('\n', f); }