Files
ww/cmd/wcc/tok.c

203 lines
4.8 KiB
C

/*
* 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 <string.h>
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 },
{ "export", TK_EXPORT },
{ "false", TK_FALSE },
{ "fn", TK_FN },
{ "for", TK_FOR },
{ "if", TK_IF },
{ "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 }
};
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 "<none>";
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_STATIC: return "static";
case TK_MATCH: return "match";
case TK_CONST: return "const";
case TK_UNDER: return "_";
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 "<last>";
}
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 : "<none>", 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);
}