From 84f78956841214437e2be94fd6225895e66dce0e Mon Sep 17 00:00:00 2001 From: CPunch Date: Fri, 1 Jan 2021 00:47:15 -0600 Subject: [PATCH] Added modulo operator '%' - added OP_MOD, which performs a modulo operation on the 2 values on the stack. Pops the 2 values and pushes the result. - also added TOKEN_PERCENT to the lexer, and extended binary() in cparse.c to support it. --- Makefile | 2 +- src/cdebug.c | 2 ++ src/clex.c | 1 + src/clex.h | 1 + src/coperators.h | 1 + src/cparse.c | 2 ++ src/cvm.c | 14 ++++++++++++++ 7 files changed, 22 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7a995df..90f9d79 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ CC=clang CFLAGS=-fPIE -Wall -O3 -std=c11 -LDFLAGS=#-fsanitize=address +LDFLAGS=-lm #-fsanitize=address OUT=bin/cosmo CHDR=\ diff --git a/src/cdebug.c b/src/cdebug.c index 37bc680..97cc066 100644 --- a/src/cdebug.c +++ b/src/cdebug.c @@ -144,6 +144,8 @@ int disasmInstr(CChunk *chunk, int offset, int indent) { return simpleInstruction("OP_MULT", offset); case OP_DIV: return simpleInstruction("OP_DIV", offset); + case OP_MOD: + return simpleInstruction("OP_MOD", offset); case OP_TRUE: return simpleInstruction("OP_TRUE", offset); case OP_FALSE: diff --git a/src/clex.c b/src/clex.c index fdaaa33..ad063b8 100644 --- a/src/clex.c +++ b/src/clex.c @@ -308,6 +308,7 @@ CToken cosmoL_scanToken(CLexState *state) { case ',': return makeToken(state, TOKEN_COMMA); case ':': return makeToken(state, TOKEN_COLON); case '*': return makeToken(state, TOKEN_STAR); + case '%': return makeToken(state, TOKEN_PERCENT); case '#': return makeToken(state, TOKEN_POUND); case '/': return makeToken(state, TOKEN_SLASH); // two character tokens diff --git a/src/clex.h b/src/clex.h index 7f020a6..67fe084 100644 --- a/src/clex.h +++ b/src/clex.h @@ -23,6 +23,7 @@ typedef enum { TOKEN_SLASH, TOKEN_STAR, TOKEN_POUND, + TOKEN_PERCENT, TOKEN_EOS, // end of statement // equality operators diff --git a/src/coperators.h b/src/coperators.h index 2280549..a1f0603 100644 --- a/src/coperators.h +++ b/src/coperators.h @@ -37,6 +37,7 @@ typedef enum { OP_SUB, OP_MULT, OP_DIV, + OP_MOD, OP_NOT, OP_NEGATE, OP_COUNT, diff --git a/src/cparse.c b/src/cparse.c index 512797a..f6163d6 100644 --- a/src/cparse.c +++ b/src/cparse.c @@ -430,6 +430,7 @@ static void binary(CParseState *pstate, bool canAssign) { case TOKEN_MINUS: writeu8Chunk(pstate->state, getChunk(pstate), OP_SUB, cachedLine); break; case TOKEN_STAR: writeu8Chunk(pstate->state, getChunk(pstate), OP_MULT, cachedLine); break; case TOKEN_SLASH: writeu8Chunk(pstate->state, getChunk(pstate), OP_DIV, cachedLine); break; + case TOKEN_PERCENT: writeu8Chunk(pstate->state, getChunk(pstate), OP_MOD, cachedLine); break; // EQUALITY case TOKEN_EQUAL_EQUAL: writeu8Chunk(pstate->state, getChunk(pstate), OP_EQUAL, cachedLine); break; case TOKEN_GREATER: writeu8Chunk(pstate->state, getChunk(pstate), OP_GREATER, cachedLine); break; @@ -730,6 +731,7 @@ ParseRule ruleTable[] = { [TOKEN_PLUS_PLUS] = {preincrement, NULL, PREC_TERM}, [TOKEN_SLASH] = {NULL, binary, PREC_FACTOR}, [TOKEN_STAR] = {NULL, binary, PREC_FACTOR}, + [TOKEN_PERCENT] = {NULL, binary, PREC_FACTOR}, [TOKEN_POUND] = {unary, NULL, PREC_NONE}, [TOKEN_EOS] = {NULL, NULL, PREC_NONE}, [TOKEN_BANG] = {unary, NULL, PREC_NONE}, diff --git a/src/cvm.c b/src/cvm.c index 3fad491..915dc61 100644 --- a/src/cvm.c +++ b/src/cvm.c @@ -6,6 +6,8 @@ #include #include +#include + COSMO_API void cosmoV_pushFString(CState *state, const char *format, ...) { va_list args; va_start(args, format); @@ -802,6 +804,18 @@ int cosmoV_execute(CState *state) { NUMBEROP(cosmoV_newNumber, /) break; } + case OP_MOD: { + StkPtr valA = cosmoV_getTop(state, 1); + StkPtr valB = cosmoV_getTop(state, 0); + if (IS_NUMBER(*valA) && IS_NUMBER(*valB)) { + cosmoV_setTop(state, 2); /* pop the 2 values */ + cosmoV_pushValue(state, cosmoV_newNumber(fmod(cosmoV_readNumber(*valA), cosmoV_readNumber(*valB)))); + } else { \ + cosmoV_error(state, "Expected numbers, got %s and %s!", cosmoV_typeStr(*valA), cosmoV_typeStr(*valB)); + return -1; \ + } \ + break; + } case OP_NOT: { cosmoV_pushBoolean(state, isFalsey(cosmoV_pop(state))); break;