refactoring of the instruction table; removed unused instructions PUSHTYPTYP and ERROR; new modulo operator %; new examples fibonacci.noja and isprime.noja
This commit is contained in:
+1
-1
@@ -11,4 +11,4 @@ vgcore.*
|
||||
*.gcov
|
||||
lib*.a
|
||||
|
||||
*.noja
|
||||
./*.noja
|
||||
@@ -0,0 +1,17 @@
|
||||
|
||||
fun fibonacci(n: int) {
|
||||
|
||||
if n < 0:
|
||||
error("Only non-negative integers allowed");
|
||||
|
||||
if n == 0 or n == 1:
|
||||
return 1;
|
||||
|
||||
if n == 2:
|
||||
return 2;
|
||||
|
||||
return fibonacci(n-1)
|
||||
+ fibonacci(n-2);
|
||||
}
|
||||
|
||||
print(fibonacci(10), "\n");
|
||||
@@ -0,0 +1,50 @@
|
||||
|
||||
fun isPrime(n: int) {
|
||||
prime = true; # First assumption
|
||||
if n < 3: {
|
||||
if n == 2:
|
||||
prime = true;
|
||||
else
|
||||
prime = false;
|
||||
} else {
|
||||
i = 2;
|
||||
sqrt = math.sqrt(n/1.0);
|
||||
do {
|
||||
if n % i == 0: {
|
||||
prime = false;
|
||||
break;
|
||||
}
|
||||
i = i+1;
|
||||
} while i <= sqrt;
|
||||
}
|
||||
return prime;
|
||||
}
|
||||
|
||||
numbers = [
|
||||
[-1, false],
|
||||
[ 0, false],
|
||||
[ 1, false],
|
||||
[ 2, true],
|
||||
[ 3, true],
|
||||
[ 4, false],
|
||||
[ 5, true],
|
||||
[ 6, false],
|
||||
[ 7, true],
|
||||
[ 9, false],
|
||||
[10, false],
|
||||
[11, true],
|
||||
[12, false],
|
||||
[13, true],
|
||||
[14, false],
|
||||
[15, false]
|
||||
];
|
||||
|
||||
i = 0;
|
||||
while i < count(numbers): {
|
||||
num = numbers[i][0];
|
||||
exp = numbers[i][1];
|
||||
res = isPrime(numbers[i][0]);
|
||||
print("isPrime(", num, ") == ", res, "\n");
|
||||
assert(res == exp);
|
||||
i = i+1;
|
||||
}
|
||||
-11352
File diff suppressed because one or more lines are too long
+80
-60
@@ -37,6 +37,7 @@
|
||||
#include "executable.h"
|
||||
|
||||
#define MAX_OPS 3
|
||||
#define MAX_OPCODE_NAME_SIZE 127
|
||||
|
||||
typedef struct {
|
||||
Opcode opcode;
|
||||
@@ -62,84 +63,104 @@ struct xExeBuilder {
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
Opcode opcode;
|
||||
const char *name;
|
||||
int opcount;
|
||||
int opcount;
|
||||
OperandType *optypes;
|
||||
} InstrInfo;
|
||||
|
||||
#define INSTR(name, ...) \
|
||||
{ \
|
||||
OPCODE_##name, \
|
||||
#name, \
|
||||
sizeof((OperandType[]) { __VA_ARGS__ }) / sizeof(OperandType), \
|
||||
(OperandType[]) { __VA_ARGS__ }, \
|
||||
},
|
||||
|
||||
static const InstrInfo instr_table[] = {
|
||||
[OPCODE_NOPE] = {"NOPE", 0, NULL},
|
||||
[OPCODE_POS] = {"POS", 0, NULL},
|
||||
[OPCODE_NEG] = {"NEG", 0, NULL},
|
||||
[OPCODE_NOT] = {"NOT", 0, NULL},
|
||||
[OPCODE_ADD] = {"ADD", 0, NULL},
|
||||
[OPCODE_SUB] = {"SUB", 0, NULL},
|
||||
[OPCODE_MUL] = {"MUL", 0, NULL},
|
||||
[OPCODE_DIV] = {"DIV", 0, NULL},
|
||||
[OPCODE_EQL] = {"EQL", 0, NULL},
|
||||
[OPCODE_NQL] = {"NQL", 0, NULL},
|
||||
[OPCODE_LSS] = {"LSS", 0, NULL},
|
||||
[OPCODE_GRT] = {"GRT", 0, NULL},
|
||||
[OPCODE_LEQ] = {"LEQ", 0, NULL},
|
||||
[OPCODE_GEQ] = {"GEQ", 0, NULL},
|
||||
[OPCODE_NLB] = {"NLB", 0, NULL},
|
||||
[OPCODE_STP] = {"STP", 0, NULL},
|
||||
[OPCODE_ASS] = {"ASS", 1, (OperandType[]) {OPTP_STRING}},
|
||||
[OPCODE_POP] = {"POP", 1, (OperandType[]) {OPTP_INT}},
|
||||
[OPCODE_CHECKTYPE] = {"CHECKTYPE", 2, (OperandType[]) {OPTP_INT, OPTP_STRING}},
|
||||
[OPCODE_CALL] = {"CALL", 2, (OperandType[]) {OPTP_INT, OPTP_INT}},
|
||||
[OPCODE_SELECT] = {"SELECT", 0, NULL},
|
||||
[OPCODE_INSERT] = {"INSERT", 0, NULL},
|
||||
[OPCODE_INSERT2] = {"INSERT2", 0, NULL},
|
||||
[OPCODE_PUSHINT] = {"PUSHINT", 1, (OperandType[]) {OPTP_INT}},
|
||||
[OPCODE_PUSHFLT] = {"PUSHFLT", 1, (OperandType[]) {OPTP_FLOAT}},
|
||||
[OPCODE_PUSHSTR] = {"PUSHSTR", 1, (OperandType[]) {OPTP_STRING}},
|
||||
[OPCODE_PUSHVAR] = {"PUSHVAR", 1, (OperandType[]) {OPTP_STRING}},
|
||||
[OPCODE_PUSHTRU] = {"PUSHTRU", 0, NULL},
|
||||
[OPCODE_PUSHFLS] = {"PUSHFLS", 0, NULL},
|
||||
[OPCODE_PUSHNNE] = {"PUSHNNE", 0, NULL},
|
||||
[OPCODE_PUSHFUN] = {"PUSHFUN", 2, (OperandType[]) {OPTP_IDX, OPTP_INT}},
|
||||
[OPCODE_PUSHLST] = {"PUSHLST", 1, (OperandType[]) {OPTP_INT}},
|
||||
[OPCODE_PUSHMAP] = {"PUSHMAP", 1, (OperandType[]) {OPTP_INT}},
|
||||
[OPCODE_PUSHTYP] = {"PUSHTYP", 0, NULL},
|
||||
[OPCODE_PUSHTYPTYP] = {"PUSHTYPTYP", 0, NULL},
|
||||
[OPCODE_PUSHNNETYP] = {"PUSHNNETYP", 0, NULL},
|
||||
[OPCODE_RETURN] = {"RETURN", 1, (OperandType[]) {OPTP_INT}},
|
||||
[OPCODE_ERROR] = {"ERROR", 1, (OperandType[]) {OPTP_STRING}},
|
||||
[OPCODE_EXIT] = {"EXIT", 0, NULL},
|
||||
[OPCODE_JUMPIFNOTANDPOP] = {"JUMPIFNOTANDPOP", 1, (OperandType[]) {OPTP_IDX}},
|
||||
[OPCODE_JUMPIFANDPOP] = {"JUMPIFANDPOP", 1, (OperandType[]) {OPTP_IDX}},
|
||||
[OPCODE_JUMP] = {"JUMP", 1, (OperandType[]) {OPTP_IDX}},
|
||||
INSTR(NOPE)
|
||||
INSTR(POS)
|
||||
INSTR(NEG)
|
||||
INSTR(NOT)
|
||||
INSTR(ADD)
|
||||
INSTR(SUB)
|
||||
INSTR(MUL)
|
||||
INSTR(DIV)
|
||||
INSTR(EQL)
|
||||
INSTR(NQL)
|
||||
INSTR(LSS)
|
||||
INSTR(GRT)
|
||||
INSTR(LEQ)
|
||||
INSTR(GEQ)
|
||||
INSTR(NLB)
|
||||
INSTR(STP)
|
||||
INSTR(ASS, OPTP_STRING)
|
||||
INSTR(POP, OPTP_INT)
|
||||
INSTR(CHECKTYPE, OPTP_INT, OPTP_STRING)
|
||||
INSTR(CALL, OPTP_INT, OPTP_INT)
|
||||
INSTR(SELECT)
|
||||
INSTR(INSERT)
|
||||
INSTR(INSERT2)
|
||||
INSTR(PUSHINT, OPTP_INT)
|
||||
INSTR(PUSHFLT, OPTP_FLOAT)
|
||||
INSTR(PUSHSTR, OPTP_STRING)
|
||||
INSTR(PUSHVAR, OPTP_STRING)
|
||||
INSTR(PUSHTRU)
|
||||
INSTR(PUSHFLS)
|
||||
INSTR(PUSHNNE)
|
||||
INSTR(PUSHFUN, OPTP_IDX, OPTP_INT)
|
||||
INSTR(PUSHLST, OPTP_INT)
|
||||
INSTR(PUSHMAP, OPTP_INT)
|
||||
INSTR(PUSHTYP)
|
||||
INSTR(PUSHNNETYP)
|
||||
INSTR(RETURN, OPTP_INT)
|
||||
INSTR(EXIT)
|
||||
INSTR(JUMPIFNOTANDPOP, OPTP_IDX)
|
||||
INSTR(JUMPIFANDPOP, OPTP_IDX)
|
||||
INSTR(JUMP, OPTP_IDX)
|
||||
};
|
||||
|
||||
_Bool Executable_GetOpcodeBinaryFromName(const char *name, size_t name_len, Opcode *opcode)
|
||||
static const size_t instr_count = sizeof(instr_table)/sizeof(instr_table[0]);
|
||||
|
||||
_Bool Executable_GetOpcodeBinaryFromName(const char *name, size_t len, Opcode *opcode)
|
||||
{
|
||||
// The input name is assumed not zero-terminated,
|
||||
// so to simplify things we duplicate it to add
|
||||
// an extra null byte.
|
||||
char buff[128]; // No opcode should have a name this big.
|
||||
ASSERT(name_len < sizeof(buff)); // If this is triggered, [buff] should be made bigger.
|
||||
|
||||
memcpy(buff, name, name_len);
|
||||
buff[name_len] = '\0';
|
||||
|
||||
char buff[MAX_OPCODE_NAME_SIZE+1]; // No opcode should have a name this big.
|
||||
if (len >= sizeof(buff))
|
||||
return false;
|
||||
memcpy(buff, name, len);
|
||||
buff[len] = '\0';
|
||||
name = buff;
|
||||
|
||||
// Now name is zero terminated.
|
||||
ASSERT(name[name_len] == '\0');
|
||||
ASSERT(name[len] == '\0');
|
||||
|
||||
for(size_t i = 0; i < sizeof(instr_table)/sizeof(instr_table[0]); i += 1) {
|
||||
for(size_t i = 0; i < instr_count; i += 1) {
|
||||
if(!strcmp(name, instr_table[i].name)) {
|
||||
*opcode = i; // Is this safe?
|
||||
if (opcode != NULL)
|
||||
*opcode = instr_table[i].opcode;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const InstrInfo *Executable_GetInstrByOpcode(Opcode opcode)
|
||||
{
|
||||
for (size_t i = 0; i < instr_count; i++)
|
||||
if (instr_table[i].opcode == opcode)
|
||||
return instr_table + i;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *Executable_GetOpcodeName(Opcode opcode)
|
||||
{
|
||||
return instr_table[opcode].name;
|
||||
const InstrInfo *instr = Executable_GetInstrByOpcode(opcode);
|
||||
if (instr == NULL)
|
||||
return NULL;
|
||||
return instr->name;
|
||||
}
|
||||
|
||||
Executable *Executable_Copy(Executable *exe)
|
||||
@@ -172,8 +193,8 @@ void Executable_Dump(Executable *exe)
|
||||
int opc = MAX_OPS;
|
||||
|
||||
(void) Executable_Fetch(exe, i, &opcode, ops, &opc);
|
||||
|
||||
const InstrInfo *info = instr_table + exe->body[i].opcode;
|
||||
|
||||
const InstrInfo *info = Executable_GetInstrByOpcode(opcode);
|
||||
|
||||
fprintf(stderr, "%d: %s ", i, info->name);
|
||||
|
||||
@@ -250,7 +271,7 @@ _Bool Executable_Fetch(Executable *exe, int index, Opcode *opcode, Operand *ops,
|
||||
return 0;
|
||||
|
||||
const Instruction *instr = exe->body + index;
|
||||
const InstrInfo *info = instr_table + instr->opcode;
|
||||
const InstrInfo *info = Executable_GetInstrByOpcode(instr->opcode);
|
||||
|
||||
if(opcode)
|
||||
*opcode = instr->opcode;
|
||||
@@ -497,7 +518,7 @@ _Bool ExeBuilder_Append(ExeBuilder *exeb, Error *error, Opcode opcode, Operand *
|
||||
[OPTP_STRING] = membersizeof(Operand, as_string),
|
||||
};
|
||||
|
||||
const InstrInfo *info = instr_table + opcode;
|
||||
const InstrInfo *info = Executable_GetInstrByOpcode(opcode);
|
||||
|
||||
if(opc != info->opcount)
|
||||
{
|
||||
@@ -633,5 +654,4 @@ int ExeBuilder_InstrCount(ExeBuilder *exeb)
|
||||
ASSERT(raw_size % sizeof(Instruction) == 0);
|
||||
|
||||
return raw_size / sizeof(Instruction);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -61,6 +61,7 @@ typedef enum {
|
||||
OPCODE_SUB,
|
||||
OPCODE_MUL,
|
||||
OPCODE_DIV,
|
||||
OPCODE_MOD,
|
||||
OPCODE_EQL,
|
||||
OPCODE_NQL,
|
||||
OPCODE_LSS,
|
||||
@@ -86,10 +87,8 @@ typedef enum {
|
||||
OPCODE_PUSHLST,
|
||||
OPCODE_PUSHMAP,
|
||||
OPCODE_PUSHTYP,
|
||||
OPCODE_PUSHTYPTYP,
|
||||
OPCODE_PUSHNNETYP,
|
||||
OPCODE_RETURN,
|
||||
OPCODE_ERROR,
|
||||
OPCODE_EXIT,
|
||||
OPCODE_JUMPIFANDPOP,
|
||||
OPCODE_JUMPIFNOTANDPOP,
|
||||
|
||||
@@ -52,6 +52,7 @@ typedef enum {
|
||||
EXPR_SUB,
|
||||
EXPR_MUL,
|
||||
EXPR_DIV,
|
||||
EXPR_MOD,
|
||||
|
||||
EXPR_EQL,
|
||||
EXPR_NQL,
|
||||
|
||||
@@ -135,14 +135,6 @@ static void emitInstr_EQL(CodegenContext *ctx, int off, int len)
|
||||
CodegenContext_EmitInstr(ctx, OPCODE_EQL, NULL, 0, off, len);
|
||||
}
|
||||
|
||||
static void emitInstr_ERROR(CodegenContext *ctx, const char *msg, int off, int len)
|
||||
{
|
||||
Operand opv[1] = {
|
||||
{ .type = OPTP_STRING, .as_string = msg },
|
||||
};
|
||||
CodegenContext_EmitInstr(ctx, OPCODE_ERROR, opv, 1, off, len);
|
||||
}
|
||||
|
||||
static void emitInstr_CHECKTYPE(CodegenContext *ctx, int arg_index, const char *arg_name, int off, int len)
|
||||
{
|
||||
Operand opv[2] = {
|
||||
@@ -167,11 +159,6 @@ static void emitInstr_PUSHTYP(CodegenContext *ctx, int off, int len)
|
||||
CodegenContext_EmitInstr(ctx, OPCODE_PUSHTYP, NULL, 0, off, len);
|
||||
}
|
||||
|
||||
static void emitInstr_PUSHTYPTYP(CodegenContext *ctx, int off, int len)
|
||||
{
|
||||
CodegenContext_EmitInstr(ctx, OPCODE_PUSHTYPTYP, NULL, 0, off, len);
|
||||
}
|
||||
|
||||
static void emitInstr_PUSHNNETYP(CodegenContext *ctx, int off, int len)
|
||||
{
|
||||
CodegenContext_EmitInstr(ctx, OPCODE_PUSHNNETYP, NULL, 0, off, len);
|
||||
@@ -192,6 +179,7 @@ static Opcode exprkind_to_opcode(ExprKind kind)
|
||||
case EXPR_SUB: return OPCODE_SUB;
|
||||
case EXPR_MUL: return OPCODE_MUL;
|
||||
case EXPR_DIV: return OPCODE_DIV;
|
||||
case EXPR_MOD: return OPCODE_MOD;
|
||||
case EXPR_EQL: return OPCODE_EQL;
|
||||
case EXPR_NQL: return OPCODE_NQL;
|
||||
case EXPR_LSS: return OPCODE_LSS;
|
||||
@@ -391,7 +379,7 @@ static void emitInstrForExprNode(CodegenContext *ctx, ExprNode *expr,
|
||||
|
||||
case EXPR_NULLABLETYPE:
|
||||
case EXPR_SUMTYPE:
|
||||
case EXPR_NOT:
|
||||
case EXPR_NOT: case EXPR_MOD:
|
||||
case EXPR_POS: case EXPR_NEG:
|
||||
case EXPR_ADD: case EXPR_SUB:
|
||||
case EXPR_MUL: case EXPR_DIV:
|
||||
|
||||
@@ -71,6 +71,7 @@ typedef enum {
|
||||
TSUB = '-',
|
||||
TMUL = '*',
|
||||
TDIV = '/',
|
||||
TMOD = '%',
|
||||
|
||||
TLSS = '<',
|
||||
TGRT = '>',
|
||||
@@ -145,7 +146,8 @@ static inline _Bool isoper(char c)
|
||||
c == '*' || c == '/' ||
|
||||
c == '<' || c == '>' ||
|
||||
c == '!' || c == '=' ||
|
||||
c == ',' || c == '|';
|
||||
c == ',' || c == '|' ||
|
||||
c == '%';
|
||||
}
|
||||
|
||||
/* Symbol: tokenize
|
||||
@@ -328,6 +330,7 @@ static Token *tokenize(Source *src, BPAlloc *alloc, Error *error)
|
||||
{ TASS, 1, "=" },
|
||||
{ TCOMMA, 1, "," },
|
||||
{ TSMT, 1, "|" },
|
||||
{ TMOD, 1, "%" },
|
||||
};
|
||||
|
||||
_Bool found = 0;
|
||||
@@ -1603,7 +1606,7 @@ static inline _Bool isbinop(Token *tok)
|
||||
tok->kind == TEQL || tok->kind == TNQL ||
|
||||
tok->kind == TKWAND || tok->kind == TKWOR ||
|
||||
tok->kind == '=' || tok->kind == ',' ||
|
||||
tok->kind == '|';
|
||||
tok->kind == '|' || tok->kind == '%';
|
||||
}
|
||||
|
||||
static inline _Bool isrightassoc(Token *tok)
|
||||
@@ -1645,6 +1648,7 @@ static inline int precedenceof(Token *tok)
|
||||
|
||||
case '*':
|
||||
case '/':
|
||||
case '%':
|
||||
return 6;
|
||||
|
||||
case ',':
|
||||
@@ -1707,6 +1711,7 @@ static Node *parse_expression_2(Context *ctx, Node *left_expr, int min_prec, _Bo
|
||||
case '-': temp->base.kind = EXPR_SUB; break;
|
||||
case '*': temp->base.kind = EXPR_MUL; break;
|
||||
case '/': temp->base.kind = EXPR_DIV; break;
|
||||
case '%': temp->base.kind = EXPR_MOD; break;
|
||||
case '<': temp->base.kind = EXPR_LSS; break;
|
||||
case '>': temp->base.kind = EXPR_GRT; break;
|
||||
case TLEQ: temp->base.kind = EXPR_LEQ; break;
|
||||
|
||||
+34
-21
@@ -739,6 +739,40 @@ static _Bool step(Runtime *runtime, Error *error)
|
||||
return 1;
|
||||
}
|
||||
|
||||
case OPCODE_MOD:
|
||||
{
|
||||
ASSERT(opc == 0);
|
||||
|
||||
Object *rop = Stack_Top(runtime->stack, 0);
|
||||
Object *lop = Stack_Top(runtime->stack, -1);
|
||||
|
||||
if(!Runtime_Pop(runtime, error, 2))
|
||||
return 0;
|
||||
|
||||
// We managed to pop rop and lop,
|
||||
// so we know they're not NULL.
|
||||
ASSERT(rop != NULL);
|
||||
ASSERT(lop != NULL);
|
||||
|
||||
if (!Object_IsInt(rop) || !Object_IsInt(lop)) {
|
||||
Error_Report(error, 0, "Arithmetic operation on a non-numeric object");
|
||||
return 0;
|
||||
}
|
||||
|
||||
long long int x, y, z;
|
||||
y = Object_GetInt(rop);
|
||||
x = Object_GetInt(lop);
|
||||
z = x % y;
|
||||
|
||||
Object *res = Object_FromInt(z, runtime->heap, error);
|
||||
if(res == NULL)
|
||||
return 0;
|
||||
|
||||
if(!Runtime_Push(runtime, error, res))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
case OPCODE_EQL:
|
||||
case OPCODE_NQL:
|
||||
{
|
||||
@@ -1213,18 +1247,6 @@ static _Bool step(Runtime *runtime, Error *error)
|
||||
return 1;
|
||||
}
|
||||
|
||||
case OPCODE_PUSHTYPTYP:
|
||||
{
|
||||
ASSERT(opc == 0);
|
||||
|
||||
Object *obj = (Object*) Object_GetTypeType();
|
||||
ASSERT(obj != NULL);
|
||||
|
||||
if(!Runtime_Push(runtime, error, obj))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
case OPCODE_PUSHNNETYP:
|
||||
{
|
||||
ASSERT(opc == 0);
|
||||
@@ -1282,15 +1304,6 @@ static _Bool step(Runtime *runtime, Error *error)
|
||||
return 0;
|
||||
}
|
||||
|
||||
case OPCODE_ERROR:
|
||||
{
|
||||
ASSERT(opc == 1);
|
||||
ASSERT(ops[0].type == OPTP_STRING);
|
||||
const char *msg = ops[0].as_string;
|
||||
Error_Report(error, 0, "%s", msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
case OPCODE_JUMP:
|
||||
ASSERT(opc == 1);
|
||||
ASSERT(ops[0].type == OPTP_IDX);
|
||||
|
||||
Binary file not shown.
@@ -15,7 +15,7 @@
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.noja",
|
||||
"match": "(\\+|-|\\*|\\/|=|==|!=|\\>|\\<|\\>=|\\<=|\\|)"
|
||||
"match": "(\\+|-|\\*|\\/|%|=|==|!=|\\>|\\<|\\>=|\\<=|\\|)"
|
||||
},
|
||||
{
|
||||
"name": "keyword.operator.logical.noja",
|
||||
|
||||
Reference in New Issue
Block a user