includes := include/lang2 | includes := include/lang2 | ||||
files := lib cmd | files := lib cmd | ||||
warnings := all extra no-unused-parameter pedantic | |||||
cflags := -g | cflags := -g |
// X macro: Define a macro named X, then include this file, then undef X. | // X macro: Define a macro named X, then include this file, then undef X. | ||||
#ifdef X | #ifdef X | ||||
X("+", l2_builtin_add); | |||||
X("-", l2_builtin_sub); | |||||
X("*", l2_builtin_mul); | |||||
X("/", l2_builtin_div); | |||||
X("print", l2_builtin_print); | |||||
X("len", l2_builtin_len); | |||||
X("+", l2_builtin_add) | |||||
X("-", l2_builtin_sub) | |||||
X("*", l2_builtin_mul) | |||||
X("/", l2_builtin_div) | |||||
X("print", l2_builtin_print) | |||||
X("len", l2_builtin_len) | |||||
#endif | #endif |
if (n < 0) { | if (n < 0) { | ||||
va_end(va); | va_end(va); | ||||
return n; | return n; | ||||
} else if (n + 1 < sizeof(buf)) { | |||||
} else if ((size_t)n + 1 < sizeof(buf)) { | |||||
w->write(w, buf, n); | w->write(w, buf, n); | ||||
va_end(va); | va_end(va); | ||||
return n; | return n; | ||||
len = r->len - r->idx; | len = r->len - r->idx; | ||||
} | } | ||||
memcpy(buf, r->mem + r->idx, len); | |||||
memcpy(buf, (char *)r->mem + r->idx, len); | |||||
r->idx += len; | r->idx += len; | ||||
return len; | return len; | ||||
} | } |
va_end(va); | va_end(va); | ||||
l2_trace("Parse error: %s", err->message); | l2_trace("Parse error: %s", err->message); | ||||
return; | return; | ||||
} else if (n + 1 < sizeof(buf)) { | |||||
} else if ((size_t)n + 1 < sizeof(buf)) { | |||||
err->message = malloc(n + 1); | err->message = malloc(n + 1); | ||||
strcpy(err->message, buf); | strcpy(err->message, buf); | ||||
va_end(va); | va_end(va); |
case L2_TOK_ERROR: | case L2_TOK_ERROR: | ||||
return "error"; | return "error"; | ||||
} | } | ||||
return "(unknown)"; | |||||
} | } | ||||
void l2_token_free(struct l2_token *tok) { | void l2_token_free(struct l2_token *tok) { | ||||
static int read_integer(struct l2_lexer *lexer) { | static int read_integer(struct l2_lexer *lexer) { | ||||
char buffer[16]; // Should be enough | char buffer[16]; // Should be enough | ||||
int len = 0; | |||||
size_t len = 0; | |||||
while (len < sizeof(buffer) - 1 && is_numeric(peek_ch(lexer))) { | while (len < sizeof(buffer) - 1 && is_numeric(peek_ch(lexer))) { | ||||
buffer[len++] = read_ch(lexer); | buffer[len++] = read_ch(lexer); |
} | } | ||||
#endif | #endif | ||||
// ISO C forbids an empty translation unit | |||||
// (and GCC warns on usude variables, but __attribute__((unused)) isn't ISO C) | |||||
#ifdef __GNUC__ | |||||
__attribute__((unused)) static int make_compiler_happy; | |||||
#else | |||||
static int make_compiler_happy; | |||||
#endif |
#include <stdio.h> | #include <stdio.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <stdint.h> | |||||
void l2_vm_print_val(struct l2_vm_value *val) { | void l2_vm_print_val(struct l2_vm_value *val) { | ||||
break; | break; | ||||
case L2_VAL_TYPE_CFUNCTION: | case L2_VAL_TYPE_CFUNCTION: | ||||
printf("C FUNCTION, %p\n", val->cfunc); | |||||
// ISO C doesn't let you cast a function pointer to void*. | |||||
printf("C FUNCTION, %jx\n", (uintmax_t)val->cfunc); | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
static void print_op_num(l2_word *ops, size_t opcount, size_t ptr) { | |||||
if (ptr >= opcount) { | |||||
printf("<EOF>"); | |||||
} else { | |||||
printf("%i", ops[ptr]); | |||||
} | |||||
} | |||||
void l2_vm_print_op(l2_word *ops, size_t opcount, size_t *ptr) { | void l2_vm_print_op(l2_word *ops, size_t opcount, size_t *ptr) { | ||||
enum l2_opcode opcode = (enum l2_opcode)ops[(*ptr)++]; | enum l2_opcode opcode = (enum l2_opcode)ops[(*ptr)++]; | ||||
return (l2_word)id; | return (l2_word)id; | ||||
} | } | ||||
static float u32_to_float(uint32_t num) { | |||||
float f; | |||||
memcpy(&f, &num, sizeof(num)); | |||||
return f; | |||||
} | |||||
static double u32s_to_double(uint32_t high, uint32_t low) { | static double u32s_to_double(uint32_t high, uint32_t low) { | ||||
double d; | double d; | ||||
uint64_t num = (uint64_t)high << 32 | (uint64_t)low; | uint64_t num = (uint64_t)high << 32 | (uint64_t)low; | ||||
break; | break; | ||||
case L2_OP_RJMP: | case L2_OP_RJMP: | ||||
vm->iptr += vm->ops[vm->iptr++]; | |||||
vm->iptr += vm->ops[vm->iptr] + 1; | |||||
break; | break; | ||||
case L2_OP_STACK_FRAME_LOOKUP: | case L2_OP_STACK_FRAME_LOOKUP: |
return -1; | return -1; | ||||
} | } | ||||
l2_vm_init(&vm, (l2_word *)w.mem, w.len / sizeof(l2_word)); | |||||
l2_vm_init(&vm, w.mem, w.len / sizeof(l2_word)); | |||||
l2_vm_run(&vm); | l2_vm_run(&vm); | ||||
free(w.mem); | free(w.mem); |
}; | }; | ||||
struct l2_vm vm; | struct l2_vm vm; | ||||
l2_vm_init(&vm, (l2_word *)bytecode.mem, bytecode.len / sizeof(l2_word)); | |||||
l2_vm_init(&vm, bytecode.mem, bytecode.len / sizeof(l2_word)); | |||||
vm.std_output = &output.w; | vm.std_output = &output.w; | ||||
// Run a GC after every instruction to uncover potential GC issues | // Run a GC after every instruction to uncover potential GC issues |