diff --git a/ir.c b/ir.c index 3d32a1f..9afbbfc 100644 --- a/ir.c +++ b/ir.c @@ -84,6 +84,9 @@ static void print_val(const Value *v) { case TypeBool: printf("%s", v->Bool ? "true" : "false"); break; + case TypeChar: + printf("'%c'", v->Char); + break; default: printf("(unknown type)"); break; diff --git a/lex.c b/lex.c index 68aa3a5..bc42e3c 100644 --- a/lex.c +++ b/lex.c @@ -11,6 +11,7 @@ static void consume(Pos *p, char c); static void emit(TokList *toks, const Pos *p, Tok t); static void mark(Pos *p); static void mark_err(const Pos *p); +static char get_esc_char(char c); static void consume(Pos *p, char c) { if (c == '\n') { @@ -36,6 +37,23 @@ static void mark_err(const Pos *p) { err_col = p->m_col; } +static char get_esc_char(char c) { + switch(c) { + case 'a': return '\a'; + case 'b': return '\b'; + case 'e': return '\033'; + case 'f': return '\f'; + case 'n': return '\n'; + case 'r': return '\r'; + case 't': return '\t'; + case 'v': return '\v'; + case '\\': return '\\'; + case '\'': return '\''; + case '"': return '\"'; + default: return 0; + } +} + TokList lex(const char *s) { TokList toks; toklist_init(&toks); @@ -248,6 +266,25 @@ TokList lex(const char *s) { }); } continue; + case '\'': { + consume(&pos, *(s++)); + char c = s[0]; + if (c == '\\') { + consume(&pos, *(s++)); + c = get_esc_char(s[0]); + if (!c) { + set_err("Unrecognized escape sequence: '\\%c'", c); + return toks; + } + } + consume(&pos, *(s++)); + if (s[0] != '\'') { + set_err("Unclosed char literal"); + return toks; + } + emit(&toks, &pos, (Tok){ .kind = TokVal, .Val = { .type = { .kind = TypeChar, }, .Char = c, }, }); + break; + } default: set_err("Unrecognized character: '%c'", s[0]); return toks; diff --git a/main.c b/main.c index 9aa265a..e80bddd 100644 --- a/main.c +++ b/main.c @@ -33,18 +33,25 @@ static void die(const char *fmt, ...) { exit(1); } -static Value fn_print(Value *args) { +static Value fn_put(Value *args) { switch (args[0].type.kind) { - case TypeVoid: printf("(void)\n"); break; - case TypeFloat: printf("%f\n", args[0].Float); break; - case TypeInt: printf("%zd\n", args[0].Int); break; - case TypeBool: printf("%s\n", args[0].Bool ? "true" : "false"); break; + case TypeVoid: printf("(void)"); break; + case TypeFloat: printf("%f", args[0].Float); break; + case TypeInt: printf("%zd", args[0].Int); break; + case TypeBool: printf("%s", args[0].Bool ? "true" : "false"); break; + case TypeChar: printf("%c", args[0].Char); break; default: ASSERT_UNREACHED(); } return (Value){0}; } +static Value fn_print(Value *args) { + fn_put(args); + printf("\n"); + return (Value){0}; +} + static Value fn_int(Value *args) { Value ret = { .type.kind = TypeInt, @@ -141,6 +148,7 @@ int main(int argc, const char **argv) { print_toks(&tokens); /* parse tokens into IR code */ BuiltinFunc funcs[] = { + { .name = "put", .side_effects = true, .n_args = 1, .func = fn_put, }, { .name = "print", .side_effects = true, .n_args = 1, .func = fn_print, }, { .name = "int", .side_effects = false, .n_args = 1, .func = fn_int, }, { .name = "float", .side_effects = false, .n_args = 1, .func = fn_float, }, diff --git a/tok.c b/tok.c index 4d324e2..4f51026 100644 --- a/tok.c +++ b/tok.c @@ -115,6 +115,9 @@ void print_toks(TokList *l) { case TypeBool: printf(": " C_ICYAN "%s" C_RESET, i->tok.Val.Bool ? "true" : "false"); break; + case TypeChar: + printf(": " C_ICYAN "'%c'" C_RESET, i->tok.Val.Char); + break; default: printf(" " C_ICYAN "(unknown type)" C_RESET); break; diff --git a/tok.h b/tok.h index 3a8e1f3..34fd371 100644 --- a/tok.h +++ b/tok.h @@ -12,6 +12,7 @@ typedef struct Type { TypeFloat, TypeInt, TypeBool, + TypeChar, } kind; /*union { @@ -25,6 +26,7 @@ typedef struct Value { double Float; ssize_t Int; bool Bool; + char Char; }; } Value;