Compare commits

...

4 Commits

Author SHA1 Message Date
r4 ca232fbf6a add mandelbrot example 2021-12-23 21:44:59 +01:00
r4 6bdc4e3210 add logical or and logical and 2021-12-23 21:42:09 +01:00
r4 d67008cfbf add char literals 2021-12-23 21:26:53 +01:00
r4 a0842424ec print not in IR 2021-12-23 21:08:01 +01:00
10 changed files with 199 additions and 14 deletions

8
ir.c
View File

@ -14,6 +14,8 @@ const char *irinstr_str[IRInstrEnumSize] = {
[IRLt] = "lt",
[IRLe] = "le",
[IRNot] = "not",
[IRAnd] = "and",
[IROr] = "or",
[IRJmp] = "jmp",
[IRJnz] = "jnz",
[IRCallInternal] = "calli",
@ -84,6 +86,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;
@ -105,6 +110,7 @@ void print_ir(IRToks *v, const BuiltinFunc *builtin_funcs) {
switch (v->toks[i].instr) {
case IRSet:
case IRNeg:
case IRNot:
printf(" %%%zx ", v->toks[i].Unary.addr);
print_irparam(&v->toks[i].Unary.val);
break;
@ -115,6 +121,8 @@ void print_ir(IRToks *v, const BuiltinFunc *builtin_funcs) {
case IREq:
case IRLt:
case IRLe:
case IRAnd:
case IROr:
printf(" %%%zx ", v->toks[i].Binary.addr);
print_irparam(&v->toks[i].Binary.lhs);
printf(" ");

2
ir.h
View File

@ -22,6 +22,8 @@ enum IRInstr {
IRLt,
IRLe,
IRNot,
IRAnd,
IROr,
IRJmp,
IRJnz,
IRCallInternal,

51
lex.c
View File

@ -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);
@ -200,6 +218,20 @@ TokList lex(const char *s) {
continue;
}
break;
case '&':
consume(&pos, *(s++));
if (s[0] == '&') {
emit(&toks, &pos, (Tok){ .kind = TokOp, .Op = OpAnd });
} else
continue;
break;
case '|':
consume(&pos, *(s++));
if (s[0] == '|') {
emit(&toks, &pos, (Tok){ .kind = TokOp, .Op = OpOr });
} else
continue;
break;
case '{':
case '}':
case '(':
@ -248,6 +280,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;

18
main.c
View File

@ -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, },

87
mandelbrot.script Normal file
View File

@ -0,0 +1,87 @@
width := 280
height := 100
iterations := 100
xmin := -2.0
xmax := 0.5
ymin := -1.0
ymax := 1.0
// Some further coordinates:
/*iterations := 1000
xmin := -0.9072945999
xmax := -0.8984310833
ymin := 0.2304178999
ymax := 0.2370858666*/
/*iterations := 100
xmin := -0.193596288
xmax := -0.119260320
ymin := 1.006960992
ymax := 1.062687264*/
/*iterations := 800
xmin := -0.1675326254
xmax := -0.1675148625
ymin := 1.0413005672
ymax := 1.0413138086*/
/*iterations := 918
xmin := -0.7506201104
xmax := -0.7503409687
ymin := 0.0170447020
ymax := 0.0172540583*/
/*iterations := 400
xmin := -0.7548484315
xmax := -0.7540548595
ymin := 0.0530077004
ymax := 0.0536039518*/
y := 0
while y < height {
c_im := (float(height - y) / float(height)) * (ymax - ymin) + ymin
x := 0
while x < width {
c_re := (float(x) / float(width)) * (xmax - xmin) + xmin
z_re := 0.0
z_im := 0.0
it := 0
loop := true
while it < iterations && loop {
/* z = z*z + c */
/* (a + bi)^2 = a^2 + 2abi - b^2 */
z_re_tmp := z_re * z_re - z_im * z_im + c_re
z_im = 2.0 * z_re * z_im + c_im
z_re = z_re_tmp
/* Break if the number shoots off to infinity. */
if z_re * z_re + z_im * z_im > 4.0 {
loop = false
}
it = it + 1
}
if it <= iterations / 5 {
put(' ')
} else if it <= iterations / 5 * 2 {
put('.')
} else if it <= iterations / 5 * 3 {
put(',')
} else if it <= iterations / 5 * 4 {
put('*')
} else if it < iterations {
put('+')
} else if it == iterations {
put('#')
}
x = x + 1
}
put('\n')
y = y + 1
}

View File

@ -56,6 +56,8 @@ static void set_irtok_dest_addr(IRTok *t, size_t addr) {
case IREq:
case IRLt:
case IRLe:
case IRAnd:
case IROr:
t->Binary.addr = addr;
break;
case IRCallInternal:
@ -446,6 +448,8 @@ static ExprRet expr(IRToks *out_ir, TokList *toks, Map *funcs, Scope *parent_sc,
case OpLe: instr = IRLe; break;
case OpGt: instr = IRLt; swap_operands = true; break;
case OpGe: instr = IRLe; swap_operands = true; break;
case OpAnd: instr = IRAnd; break;
case OpOr: instr = IROr; break;
default:
mark_err(l_op);
set_err("Unknown operation: '%s'", op_str[l_op->Op]);

View File

@ -65,6 +65,18 @@ Value eval_binary(IRInstr instr, const Value *lhs, const Value *rhs) {
.type.kind = TypeBool,
.Bool = res,
};
case IRAnd:
return (Value){
.type.kind = TypeBool,
.Bool = is_nonzero(lhs) && is_nonzero(rhs),
};
break;
case IROr:
return (Value){
.type.kind = TypeBool,
.Bool = is_nonzero(lhs) || is_nonzero(rhs),
};
break;
default:
ASSERT_UNREACHED();
}

25
tok.c
View File

@ -11,15 +11,17 @@ int8_t op_prec[OperatorEnumSize] = {
[OpLCurl] = PREC_DELIM,
[OpRParen] = PREC_DELIM,
[OpComma] = PREC_DELIM,
[OpEq] = 0,
[OpLt] = 0,
[OpGt] = 0,
[OpLe] = 0,
[OpGe] = 0,
[OpAdd] = 1,
[OpSub] = 1,
[OpMul] = 2,
[OpDiv] = 2,
[OpAnd] = 0,
[OpOr] = 0,
[OpEq] = 1,
[OpLt] = 1,
[OpGt] = 1,
[OpLe] = 1,
[OpGe] = 1,
[OpAdd] = 2,
[OpSub] = 2,
[OpMul] = 3,
[OpDiv] = 3,
};
const char *op_str[OperatorEnumSize] = {
@ -40,6 +42,8 @@ const char *op_str[OperatorEnumSize] = {
[OpGt] = ">",
[OpLe] = "<=",
[OpGe] = ">=",
[OpAnd] = "&&",
[OpOr] = "||",
};
const char *tok_str[TokKindEnumSize] = {
@ -115,6 +119,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;

4
tok.h
View File

@ -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;
@ -45,6 +47,8 @@ enum Operator {
OpGt,
OpLe,
OpGe,
OpAnd,
OpOr,
OpNewLn,
OpEOF,
OperatorEnumSize,

2
vm.c
View File

@ -67,6 +67,8 @@ void run(const IRToks *ir, const BuiltinFunc *builtin_funcs) {
case IREq:
case IRLt:
case IRLe:
case IRAnd:
case IROr:
stack_fit(&s, instr->Binary.addr);
TRY_ELSE(s.mem[instr->Binary.addr] = eval_binary(instr->instr,
irparam_to_val(&s, &instr->Binary.lhs),