unify printing + add basic strings
This commit is contained in:
parent
92c4c5c991
commit
f02dae603d
23
ir.c
23
ir.c
@ -72,32 +72,11 @@ void irtoks_eat_irtoks(IRToks *v, IRToks *other, size_t jmp_offset) {
|
|||||||
free(other->toks);
|
free(other->toks);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_val(const Value *v);
|
|
||||||
static void print_irparam(const IRParam *p);
|
static void print_irparam(const IRParam *p);
|
||||||
|
|
||||||
static void print_val(const Value *v) {
|
|
||||||
switch (v->type.kind) {
|
|
||||||
case TypeFloat:
|
|
||||||
printf("%f", v->Float);
|
|
||||||
break;
|
|
||||||
case TypeInt:
|
|
||||||
printf("%zd", v->Int);
|
|
||||||
break;
|
|
||||||
case TypeBool:
|
|
||||||
printf("%s", v->Bool ? "true" : "false");
|
|
||||||
break;
|
|
||||||
case TypeChar:
|
|
||||||
printf("'%c'", v->Char);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printf("(unknown type)");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_irparam(const IRParam *p) {
|
static void print_irparam(const IRParam *p) {
|
||||||
if (p->kind == IRParamLiteral) {
|
if (p->kind == IRParamLiteral) {
|
||||||
print_val(&p->Literal);
|
print_value(&p->Literal, false);
|
||||||
} else if (p->kind == IRParamAddr) {
|
} else if (p->kind == IRParamAddr) {
|
||||||
printf("%%%zd", p->Addr);
|
printf("%%%zd", p->Addr);
|
||||||
}
|
}
|
||||||
|
48
lex.c
48
lex.c
@ -54,7 +54,7 @@ static char get_esc_char(char c) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TokList lex(const char *s) {
|
TokList lex(const char *s, Pool *static_vars) {
|
||||||
TokList toks;
|
TokList toks;
|
||||||
toklist_init(&toks);
|
toklist_init(&toks);
|
||||||
Pos pos = { .ln = 1, .col = 1 };
|
Pos pos = { .ln = 1, .col = 1 };
|
||||||
@ -299,6 +299,52 @@ TokList lex(const char *s) {
|
|||||||
emit(&toks, &pos, (Tok){ .kind = TokVal, .Val = { .type = { .kind = TypeChar, }, .Char = c, }, });
|
emit(&toks, &pos, (Tok){ .kind = TokVal, .Val = { .type = { .kind = TypeChar, }, .Char = c, }, });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case '"': {
|
||||||
|
consume(&pos, *(s++));
|
||||||
|
const char *start = s;
|
||||||
|
Pos start_pos = pos;
|
||||||
|
size_t size = 0;
|
||||||
|
|
||||||
|
/* count the string size before allocating */
|
||||||
|
while (s[0] != '"') {
|
||||||
|
if (!s[0]) {
|
||||||
|
set_err("Unexpected EOF in string literal");
|
||||||
|
return toks;
|
||||||
|
} else if (s[0] == '\\')
|
||||||
|
consume(&pos, *(s++));
|
||||||
|
consume(&pos, *(s++));
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* go through the actual string */
|
||||||
|
s = start;
|
||||||
|
pos = start_pos;
|
||||||
|
char *str = pool_alloc(static_vars, type_size[TypeChar] * size);
|
||||||
|
for (size_t i = 0; i < size; i++) {
|
||||||
|
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++));
|
||||||
|
str[i] = c;
|
||||||
|
}
|
||||||
|
emit(&toks, &pos, (Tok){ .kind = TokVal, .Val = {
|
||||||
|
.type.kind = TypeArr,
|
||||||
|
.Arr = {
|
||||||
|
.is_string = true,
|
||||||
|
.type.kind = TypeChar,
|
||||||
|
.vals = str,
|
||||||
|
.len = size,
|
||||||
|
.cap = size,
|
||||||
|
},
|
||||||
|
},});
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
set_err("Unrecognized character: '%c'", s[0]);
|
set_err("Unrecognized character: '%c'", s[0]);
|
||||||
return toks;
|
return toks;
|
||||||
|
2
lex.h
2
lex.h
@ -3,6 +3,6 @@
|
|||||||
|
|
||||||
#include "tok.h"
|
#include "tok.h"
|
||||||
|
|
||||||
TokList lex(const char *s);
|
TokList lex(const char *s, Pool *static_vars);
|
||||||
|
|
||||||
#endif /* LEX_H */
|
#endif /* LEX_H */
|
||||||
|
17
main.c
17
main.c
@ -34,15 +34,7 @@ static void die(const char *fmt, ...) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Value fn_put(Value *args) {
|
static Value fn_put(Value *args) {
|
||||||
switch (args[0].type.kind) {
|
print_value(&args[0], true);
|
||||||
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};
|
return (Value){0};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,9 +128,11 @@ int main(int argc, const char **argv) {
|
|||||||
}
|
}
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
/* lex source file */
|
/* lex source file */
|
||||||
TokList tokens = lex(file);
|
Pool *static_vars = pool_new(4096);
|
||||||
|
TokList tokens = lex(file, static_vars);
|
||||||
if (err) {
|
if (err) {
|
||||||
toklist_term(&tokens);
|
toklist_term(&tokens);
|
||||||
|
pool_term(static_vars);
|
||||||
free(file);
|
free(file);
|
||||||
fprintf(stderr, C_IRED "Lexer error" C_RESET " in " C_CYAN "%s" C_RESET ":%zu:%zu: %s\n", filename, err_ln, err_col, errbuf);
|
fprintf(stderr, C_IRED "Lexer error" C_RESET " in " C_CYAN "%s" C_RESET ":%zu:%zu: %s\n", filename, err_ln, err_col, errbuf);
|
||||||
return 1;
|
return 1;
|
||||||
@ -158,6 +152,7 @@ int main(int argc, const char **argv) {
|
|||||||
if (err) {
|
if (err) {
|
||||||
irtoks_term(&ir);
|
irtoks_term(&ir);
|
||||||
toklist_term(&tokens);
|
toklist_term(&tokens);
|
||||||
|
pool_term(static_vars);
|
||||||
fprintf(stderr, C_IRED "Parser error" C_RESET " in " C_CYAN "%s" C_RESET ":%zu:%zu: %s\n", filename, err_ln, err_col, errbuf);
|
fprintf(stderr, C_IRED "Parser error" C_RESET " in " C_CYAN "%s" C_RESET ":%zu:%zu: %s\n", filename, err_ln, err_col, errbuf);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -169,9 +164,11 @@ int main(int argc, const char **argv) {
|
|||||||
run(&ir, funcs);
|
run(&ir, funcs);
|
||||||
if (err) {
|
if (err) {
|
||||||
irtoks_term(&ir);
|
irtoks_term(&ir);
|
||||||
|
pool_term(static_vars);
|
||||||
fprintf(stderr, C_IRED "Runtime error" C_RESET " in " C_CYAN "%s" C_RESET ":%zu:%zu: %s\n", filename, err_ln, err_col, errbuf);
|
fprintf(stderr, C_IRED "Runtime error" C_RESET " in " C_CYAN "%s" C_RESET ":%zu:%zu: %s\n", filename, err_ln, err_col, errbuf);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
irtoks_term(&ir);
|
irtoks_term(&ir);
|
||||||
|
pool_term(static_vars);
|
||||||
}
|
}
|
||||||
|
90
tok.c
90
tok.c
@ -5,6 +5,75 @@
|
|||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
size_t type_size[TypeEnumSize] = {
|
||||||
|
[TypeVoid] = 0,
|
||||||
|
[TypeFloat] = sizeof(((Value*)NULL)->Float),
|
||||||
|
[TypeInt] = sizeof(((Value*)NULL)->Int),
|
||||||
|
[TypeBool] = sizeof(((Value*)NULL)->Bool),
|
||||||
|
[TypeChar] = sizeof(((Value*)NULL)->Char),
|
||||||
|
[TypeArr] = sizeof(((Value*)NULL)->Arr),
|
||||||
|
};
|
||||||
|
|
||||||
|
void print_value(const Value *v, bool raw) {
|
||||||
|
switch (v->type.kind) {
|
||||||
|
case TypeVoid:
|
||||||
|
printf("(void)");
|
||||||
|
break;
|
||||||
|
case TypeFloat:
|
||||||
|
printf("%f", v->Float);
|
||||||
|
break;
|
||||||
|
case TypeInt:
|
||||||
|
printf("%zd", v->Int);
|
||||||
|
break;
|
||||||
|
case TypeBool:
|
||||||
|
printf("%s", v->Bool ? "true" : "false");
|
||||||
|
break;
|
||||||
|
case TypeChar:
|
||||||
|
if (raw)
|
||||||
|
printf("%c", v->Char);
|
||||||
|
else {
|
||||||
|
const char *esc = unescape_char(v->Char);
|
||||||
|
if (esc) printf("'%s'", esc);
|
||||||
|
else printf("'%c'", v->Char);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TypeArr:
|
||||||
|
if (v->Arr.is_string) {
|
||||||
|
if (v->Arr.type.kind != TypeChar)
|
||||||
|
ASSERT_UNREACHED();
|
||||||
|
char *str = v->Arr.vals;
|
||||||
|
if (!raw)
|
||||||
|
printf("\"");
|
||||||
|
for (size_t i = 0; i < v->Arr.len; i++) {
|
||||||
|
char c = str[i];
|
||||||
|
if (raw)
|
||||||
|
printf("%c", c);
|
||||||
|
else {
|
||||||
|
const char *esc = unescape_char(c);
|
||||||
|
if (esc) printf("%s", esc);
|
||||||
|
else printf("%c", c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!raw)
|
||||||
|
printf("\"");
|
||||||
|
} else {
|
||||||
|
printf("[");
|
||||||
|
for (size_t i = 0;; i++) {
|
||||||
|
size_t ty_sz = type_size[v->Arr.type.kind];
|
||||||
|
Value ty_val = { .type = v->Arr.type };
|
||||||
|
memcpy(&ty_val.Void, (uint8_t*)v->Arr.vals + ty_sz * i, ty_sz);
|
||||||
|
print_value(&ty_val, false);
|
||||||
|
if (i == v->Arr.len-1) break;
|
||||||
|
printf(", ");
|
||||||
|
}
|
||||||
|
printf("]");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ASSERT_UNREACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int8_t op_prec[OperatorEnumSize] = {
|
int8_t op_prec[OperatorEnumSize] = {
|
||||||
[OpEOF] = PREC_DELIM,
|
[OpEOF] = PREC_DELIM,
|
||||||
[OpNewLn] = PREC_DELIM,
|
[OpNewLn] = PREC_DELIM,
|
||||||
@ -108,24 +177,9 @@ void print_toks(TokList *l) {
|
|||||||
printf(": " C_ICYAN "%s" C_RESET, op_str[i->tok.Op]);
|
printf(": " C_ICYAN "%s" C_RESET, op_str[i->tok.Op]);
|
||||||
break;
|
break;
|
||||||
case TokVal:
|
case TokVal:
|
||||||
printf(C_IYELLOW "Val" C_RESET);
|
printf(C_IYELLOW "Val" C_RESET ": " C_ICYAN);
|
||||||
switch (i->tok.Val.type.kind) {
|
print_value(&i->tok.Val, false);
|
||||||
case TypeFloat:
|
printf(C_RESET);
|
||||||
printf(": " C_ICYAN "%f" C_RESET, i->tok.Val.Float);
|
|
||||||
break;
|
|
||||||
case TypeInt:
|
|
||||||
printf(": " C_ICYAN "%zd" C_RESET, i->tok.Val.Int);
|
|
||||||
break;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case TokIdent:
|
case TokIdent:
|
||||||
printf(C_IYELLOW "Ident" C_RESET);
|
printf(C_IYELLOW "Ident" C_RESET);
|
||||||
|
13
tok.h
13
tok.h
@ -13,23 +13,36 @@ typedef struct Type {
|
|||||||
TypeInt,
|
TypeInt,
|
||||||
TypeBool,
|
TypeBool,
|
||||||
TypeChar,
|
TypeChar,
|
||||||
|
TypeArr,
|
||||||
|
TypeEnumSize,
|
||||||
} kind;
|
} kind;
|
||||||
|
|
||||||
/*union {
|
/*union {
|
||||||
};*/
|
};*/
|
||||||
} Type;
|
} Type;
|
||||||
|
|
||||||
|
extern size_t type_size[TypeEnumSize];
|
||||||
|
|
||||||
typedef struct Value {
|
typedef struct Value {
|
||||||
Type type;
|
Type type;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
pseudo_void Void;
|
||||||
double Float;
|
double Float;
|
||||||
ssize_t Int;
|
ssize_t Int;
|
||||||
bool Bool;
|
bool Bool;
|
||||||
char Char;
|
char Char;
|
||||||
|
struct {
|
||||||
|
bool is_string : 1;
|
||||||
|
Type type;
|
||||||
|
void *vals;
|
||||||
|
size_t len, cap;
|
||||||
|
} Arr;
|
||||||
};
|
};
|
||||||
} Value;
|
} Value;
|
||||||
|
|
||||||
|
void print_value(const Value *v, bool raw);
|
||||||
|
|
||||||
enum Operator {
|
enum Operator {
|
||||||
OpLCurl = '{',
|
OpLCurl = '{',
|
||||||
OpRCurl = '}',
|
OpRCurl = '}',
|
||||||
|
17
util.c
17
util.c
@ -168,6 +168,23 @@ double stod(const char *s, size_t n, ssize_t *endpos) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *unescape_char(char c) {
|
||||||
|
switch (c) {
|
||||||
|
case '\a': return "\\a";
|
||||||
|
case '\b': return "\\b";
|
||||||
|
case '\033': return "\\e";
|
||||||
|
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 NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
char *mreadfile(FILE *fp) {
|
char *mreadfile(FILE *fp) {
|
||||||
if (fseek(fp, 0l, SEEK_END) == -1)
|
if (fseek(fp, 0l, SEEK_END) == -1)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
4
util.h
4
util.h
@ -8,6 +8,8 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
typedef uint8_t pseudo_void;
|
||||||
|
|
||||||
/* some ANSI color codes */
|
/* some ANSI color codes */
|
||||||
#define C_RED "\x1b[31m"
|
#define C_RED "\x1b[31m"
|
||||||
#define C_GREEN "\x1b[32m"
|
#define C_GREEN "\x1b[32m"
|
||||||
@ -67,6 +69,8 @@ char *psndup(Pool *p, const char *s, size_t n);
|
|||||||
intmax_t stoimax(const char *s, size_t n, size_t base, ssize_t *endpos /* -1 on success */);
|
intmax_t stoimax(const char *s, size_t n, size_t base, ssize_t *endpos /* -1 on success */);
|
||||||
/* convert a non-null-terminated string to a double */
|
/* convert a non-null-terminated string to a double */
|
||||||
double stod(const char *s, size_t n, ssize_t *endpos /* -1 on success */);
|
double stod(const char *s, size_t n, ssize_t *endpos /* -1 on success */);
|
||||||
|
/* return the escape sequence for a given character; return NULL if there is none */
|
||||||
|
const char *unescape_char(char c);
|
||||||
|
|
||||||
/* sets errno on failure */
|
/* sets errno on failure */
|
||||||
char *mreadfile(FILE *fp);
|
char *mreadfile(FILE *fp);
|
||||||
|
Loading…
Reference in New Issue
Block a user