add char literals
This commit is contained in:
parent
a0842424ec
commit
d67008cfbf
3
ir.c
3
ir.c
@ -84,6 +84,9 @@ static void print_val(const Value *v) {
|
|||||||
case TypeBool:
|
case TypeBool:
|
||||||
printf("%s", v->Bool ? "true" : "false");
|
printf("%s", v->Bool ? "true" : "false");
|
||||||
break;
|
break;
|
||||||
|
case TypeChar:
|
||||||
|
printf("'%c'", v->Char);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
printf("(unknown type)");
|
printf("(unknown type)");
|
||||||
break;
|
break;
|
||||||
|
37
lex.c
37
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 emit(TokList *toks, const Pos *p, Tok t);
|
||||||
static void mark(Pos *p);
|
static void mark(Pos *p);
|
||||||
static void mark_err(const Pos *p);
|
static void mark_err(const Pos *p);
|
||||||
|
static char get_esc_char(char c);
|
||||||
|
|
||||||
static void consume(Pos *p, char c) {
|
static void consume(Pos *p, char c) {
|
||||||
if (c == '\n') {
|
if (c == '\n') {
|
||||||
@ -36,6 +37,23 @@ static void mark_err(const Pos *p) {
|
|||||||
err_col = p->m_col;
|
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 lex(const char *s) {
|
||||||
TokList toks;
|
TokList toks;
|
||||||
toklist_init(&toks);
|
toklist_init(&toks);
|
||||||
@ -248,6 +266,25 @@ TokList lex(const char *s) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
continue;
|
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:
|
default:
|
||||||
set_err("Unrecognized character: '%c'", s[0]);
|
set_err("Unrecognized character: '%c'", s[0]);
|
||||||
return toks;
|
return toks;
|
||||||
|
18
main.c
18
main.c
@ -33,18 +33,25 @@ static void die(const char *fmt, ...) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Value fn_print(Value *args) {
|
static Value fn_put(Value *args) {
|
||||||
switch (args[0].type.kind) {
|
switch (args[0].type.kind) {
|
||||||
case TypeVoid: printf("(void)\n"); break;
|
case TypeVoid: printf("(void)"); break;
|
||||||
case TypeFloat: printf("%f\n", args[0].Float); break;
|
case TypeFloat: printf("%f", args[0].Float); break;
|
||||||
case TypeInt: printf("%zd\n", args[0].Int); break;
|
case TypeInt: printf("%zd", args[0].Int); break;
|
||||||
case TypeBool: printf("%s\n", args[0].Bool ? "true" : "false"); break;
|
case TypeBool: printf("%s", args[0].Bool ? "true" : "false"); break;
|
||||||
|
case TypeChar: printf("%c", args[0].Char); break;
|
||||||
default:
|
default:
|
||||||
ASSERT_UNREACHED();
|
ASSERT_UNREACHED();
|
||||||
}
|
}
|
||||||
return (Value){0};
|
return (Value){0};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Value fn_print(Value *args) {
|
||||||
|
fn_put(args);
|
||||||
|
printf("\n");
|
||||||
|
return (Value){0};
|
||||||
|
}
|
||||||
|
|
||||||
static Value fn_int(Value *args) {
|
static Value fn_int(Value *args) {
|
||||||
Value ret = {
|
Value ret = {
|
||||||
.type.kind = TypeInt,
|
.type.kind = TypeInt,
|
||||||
@ -141,6 +148,7 @@ int main(int argc, const char **argv) {
|
|||||||
print_toks(&tokens);
|
print_toks(&tokens);
|
||||||
/* parse tokens into IR code */
|
/* parse tokens into IR code */
|
||||||
BuiltinFunc funcs[] = {
|
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 = "print", .side_effects = true, .n_args = 1, .func = fn_print, },
|
||||||
{ .name = "int", .side_effects = false, .n_args = 1, .func = fn_int, },
|
{ .name = "int", .side_effects = false, .n_args = 1, .func = fn_int, },
|
||||||
{ .name = "float", .side_effects = false, .n_args = 1, .func = fn_float, },
|
{ .name = "float", .side_effects = false, .n_args = 1, .func = fn_float, },
|
||||||
|
3
tok.c
3
tok.c
@ -115,6 +115,9 @@ void print_toks(TokList *l) {
|
|||||||
case TypeBool:
|
case TypeBool:
|
||||||
printf(": " C_ICYAN "%s" C_RESET, i->tok.Val.Bool ? "true" : "false");
|
printf(": " C_ICYAN "%s" C_RESET, i->tok.Val.Bool ? "true" : "false");
|
||||||
break;
|
break;
|
||||||
|
case TypeChar:
|
||||||
|
printf(": " C_ICYAN "'%c'" C_RESET, i->tok.Val.Char);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
printf(" " C_ICYAN "(unknown type)" C_RESET);
|
printf(" " C_ICYAN "(unknown type)" C_RESET);
|
||||||
break;
|
break;
|
||||||
|
2
tok.h
2
tok.h
@ -12,6 +12,7 @@ typedef struct Type {
|
|||||||
TypeFloat,
|
TypeFloat,
|
||||||
TypeInt,
|
TypeInt,
|
||||||
TypeBool,
|
TypeBool,
|
||||||
|
TypeChar,
|
||||||
} kind;
|
} kind;
|
||||||
|
|
||||||
/*union {
|
/*union {
|
||||||
@ -25,6 +26,7 @@ typedef struct Value {
|
|||||||
double Float;
|
double Float;
|
||||||
ssize_t Int;
|
ssize_t Int;
|
||||||
bool Bool;
|
bool Bool;
|
||||||
|
char Char;
|
||||||
};
|
};
|
||||||
} Value;
|
} Value;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user