Added logical operators && || and !
This commit is contained in:
61
functions.c
61
functions.c
@@ -29,6 +29,9 @@ void lenv_add_builtin_funcs(lenv* env) {
|
|||||||
lenv_add_builtin(env, "<=", builtin_comp_le);
|
lenv_add_builtin(env, "<=", builtin_comp_le);
|
||||||
lenv_add_builtin(env, "==", builtin_comp_eq);
|
lenv_add_builtin(env, "==", builtin_comp_eq);
|
||||||
lenv_add_builtin(env, "!=", builtin_comp_neq);
|
lenv_add_builtin(env, "!=", builtin_comp_neq);
|
||||||
|
lenv_add_builtin(env, "&&", builtin_logical_and);
|
||||||
|
lenv_add_builtin(env, "||", builtin_logical_or);
|
||||||
|
lenv_add_builtin(env, "!", builtin_logical_not);
|
||||||
|
|
||||||
//List/Util functions
|
//List/Util functions
|
||||||
lenv_add_builtin(env, "list", builtin_list);
|
lenv_add_builtin(env, "list", builtin_list);
|
||||||
@@ -62,6 +65,10 @@ char* builtin_op_strname(BUILTIN_OP_TYPE op) {
|
|||||||
case BUILTIN_COMP_LE: return "<=";
|
case BUILTIN_COMP_LE: return "<=";
|
||||||
case BUILTIN_COMP_EQ: return "==";
|
case BUILTIN_COMP_EQ: return "==";
|
||||||
case BUILTIN_COMP_NEQ: return "!=";
|
case BUILTIN_COMP_NEQ: return "!=";
|
||||||
|
//Logical Operators
|
||||||
|
case BUILTIN_LOGICAL_AND: return "&&";
|
||||||
|
case BUILTIN_LOGICAL_OR: return "||";
|
||||||
|
case BUILTIN_LOGICAL_NOT: return "!";
|
||||||
default: return "UNKNOWN";
|
default: return "UNKNOWN";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -92,7 +99,7 @@ lval* builtin_op(lenv* env, lval* val, BUILTIN_OP_TYPE op) {
|
|||||||
case BUILTIN_OP_POW: x->data.num = pow(x->data.num,y->data.num); break;
|
case BUILTIN_OP_POW: x->data.num = pow(x->data.num,y->data.num); break;
|
||||||
case BUILTIN_OP_DIV: ;
|
case BUILTIN_OP_DIV: ;
|
||||||
short divZero = 0;
|
short divZero = 0;
|
||||||
if (y->type == LVAL_NUM && fabs(y->data.num) <= DBL_EPSILON) {divZero = 1;}
|
if (y->type == LVAL_NUM && LVAL_IS_FALSE(y)) {divZero = 1;}
|
||||||
|
|
||||||
if (divZero) {
|
if (divZero) {
|
||||||
lval_delete(x);
|
lval_delete(x);
|
||||||
@@ -181,6 +188,54 @@ lval* builtin_comp_eq(lenv* env, lval* val) {
|
|||||||
lval* builtin_comp_neq(lenv* env, lval* val) {
|
lval* builtin_comp_neq(lenv* env, lval* val) {
|
||||||
return builtin_comp_value(env, val, BUILTIN_COMP_NEQ);
|
return builtin_comp_value(env, val, BUILTIN_COMP_NEQ);
|
||||||
}
|
}
|
||||||
|
lval* builtin_logical(lenv* env, lval* val, BUILTIN_OP_TYPE op) {
|
||||||
|
int expectedArgs = op == BUILTIN_LOGICAL_NOT ? 1 : 2;
|
||||||
|
char* opName = builtin_op_strname(op);
|
||||||
|
|
||||||
|
LASSERT_ARG_COUNT(opName, val, val, expectedArgs);
|
||||||
|
LASSERT_TYPE(opName, val, val->cell_list[0], LVAL_NUM);
|
||||||
|
if (expectedArgs == 2) {
|
||||||
|
LASSERT_TYPE(opName, val, val->cell_list[1], LVAL_NUM);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL result = FALSE;
|
||||||
|
|
||||||
|
switch(op) {
|
||||||
|
case BUILTIN_LOGICAL_AND:
|
||||||
|
if (LVAL_IS_TRUE(val->cell_list[0]) && LVAL_IS_TRUE(val->cell_list[1])) {
|
||||||
|
result = TRUE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BUILTIN_LOGICAL_OR:
|
||||||
|
if (LVAL_IS_TRUE(val->cell_list[0]) || LVAL_IS_TRUE(val->cell_list[1])) {
|
||||||
|
result = TRUE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BUILTIN_LOGICAL_NOT:
|
||||||
|
if (LVAL_IS_TRUE(val->cell_list[0])) {
|
||||||
|
result = FALSE;
|
||||||
|
} else {
|
||||||
|
result = TRUE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
lval_delete(val);
|
||||||
|
return lval_err_detail(LERR_BAD_OP, "Expected logical operator, got %s", opName);
|
||||||
|
}
|
||||||
|
|
||||||
|
lval_delete(val);
|
||||||
|
return lval_num((int)result);
|
||||||
|
|
||||||
|
}
|
||||||
|
lval* builtin_logical_and(lenv* env, lval* val) {
|
||||||
|
return builtin_logical(env, val, BUILTIN_LOGICAL_AND);
|
||||||
|
}
|
||||||
|
lval* builtin_logical_or(lenv* env, lval* val) {
|
||||||
|
return builtin_logical(env, val, BUILTIN_LOGICAL_OR);
|
||||||
|
}
|
||||||
|
lval* builtin_logical_not(lenv* env, lval* val) {
|
||||||
|
return builtin_logical(env, val, BUILTIN_LOGICAL_NOT);
|
||||||
|
}
|
||||||
//End Comparison Functions
|
//End Comparison Functions
|
||||||
|
|
||||||
//Start List/Util functions
|
//Start List/Util functions
|
||||||
@@ -239,9 +294,9 @@ lval* builtin_if(lenv* env, lval* val) {
|
|||||||
val->cell_list[1]->type = LVAL_S_EXPR;
|
val->cell_list[1]->type = LVAL_S_EXPR;
|
||||||
val->cell_list[2]->type = LVAL_S_EXPR;
|
val->cell_list[2]->type = LVAL_S_EXPR;
|
||||||
|
|
||||||
if (fabs(val->cell_list[0]->data.num) > DBL_EPSILON) { //Non Zero == True
|
if (LVAL_IS_TRUE(val->cell_list[0])) {
|
||||||
result = eval(env, lval_pop(val, 1));
|
result = eval(env, lval_pop(val, 1));
|
||||||
} else { //Zero == False
|
} else {
|
||||||
result = eval(env, lval_pop(val, 2));
|
result = eval(env, lval_pop(val, 2));
|
||||||
}
|
}
|
||||||
lval_delete(val);
|
lval_delete(val);
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ extern "C" {
|
|||||||
enum BUILTIN_OP_TYPE {
|
enum BUILTIN_OP_TYPE {
|
||||||
BUILTIN_OP_ADD, BUILTIN_OP_SUB, BUILTIN_OP_DIV, BUILTIN_OP_MUL, BUILTIN_OP_POW,
|
BUILTIN_OP_ADD, BUILTIN_OP_SUB, BUILTIN_OP_DIV, BUILTIN_OP_MUL, BUILTIN_OP_POW,
|
||||||
BUILTIN_COMP_GT, BUILTIN_COMP_LT, BUILTIN_COMP_GE, BUILTIN_COMP_LE,
|
BUILTIN_COMP_GT, BUILTIN_COMP_LT, BUILTIN_COMP_GE, BUILTIN_COMP_LE,
|
||||||
BUILTIN_COMP_EQ, BUILTIN_COMP_NEQ
|
BUILTIN_COMP_EQ, BUILTIN_COMP_NEQ,
|
||||||
|
BUILTIN_LOGICAL_OR, BUILTIN_LOGICAL_AND, BUILTIN_LOGICAL_NOT
|
||||||
};
|
};
|
||||||
|
|
||||||
char* builtin_op_strname(BUILTIN_OP_TYPE op);
|
char* builtin_op_strname(BUILTIN_OP_TYPE op);
|
||||||
@@ -45,6 +46,10 @@ extern "C" {
|
|||||||
lval* builtin_comp_value(lenv* env, lval* val, BUILTIN_OP_TYPE op);
|
lval* builtin_comp_value(lenv* env, lval* val, BUILTIN_OP_TYPE op);
|
||||||
lval* builtin_comp_eq(lenv* env, lval* val);
|
lval* builtin_comp_eq(lenv* env, lval* val);
|
||||||
lval* builtin_comp_neq(lenv* env, lval* val);
|
lval* builtin_comp_neq(lenv* env, lval* val);
|
||||||
|
lval* builtin_logical(lenv* env, lval* val, BUILTIN_OP_TYPE op);
|
||||||
|
lval* builtin_logical_and(lenv* env, lval* val);
|
||||||
|
lval* builtin_logical_or(lenv* env, lval* val);
|
||||||
|
lval* builtin_logical_not(lenv* env, lval* val);
|
||||||
|
|
||||||
//List/Util functions
|
//List/Util functions
|
||||||
lval* builtin_list(lenv* env, lval* val);
|
lval* builtin_list(lenv* env, lval* val);
|
||||||
|
|||||||
2
lang.c
2
lang.c
@@ -16,7 +16,7 @@ mpc_ast_t* tokenize(char *input) {
|
|||||||
mpca_lang(MPCA_LANG_DEFAULT,
|
mpca_lang(MPCA_LANG_DEFAULT,
|
||||||
" \
|
" \
|
||||||
number : /-?[0-9]+(\\.[0-9]+)?/ ; \
|
number : /-?[0-9]+(\\.[0-9]+)?/ ; \
|
||||||
symbol : /[a-zA-Z0-9_+\\-*\\/\\\\=<>!&]+/ ; \
|
symbol : /[a-zA-Z0-9_+\\-*\\/\\\\=<>!&\\|]+/ ; \
|
||||||
s_expr : '(' <expr>* ')' ; \
|
s_expr : '(' <expr>* ')' ; \
|
||||||
q_expr : '{' <expr>* '}' ; \
|
q_expr : '{' <expr>* '}' ; \
|
||||||
expr : <number> | <symbol> | <s_expr> | <q_expr> ; \
|
expr : <number> | <symbol> | <s_expr> | <q_expr> ; \
|
||||||
|
|||||||
3
lval.h
3
lval.h
@@ -22,6 +22,9 @@ typedef struct lval_func lval_func;
|
|||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "lenv.h"
|
#include "lenv.h"
|
||||||
|
|
||||||
|
#define LVAL_IS_TRUE(val) (val->type == LVAL_NUM && fabs(val->data.num) > DBL_EPSILON)
|
||||||
|
#define LVAL_IS_FALSE(val) (val->type == LVAL_NUM && fabs(val->data.num) <= DBL_EPSILON)
|
||||||
|
|
||||||
enum VAL_TYPE { LVAL_ERR, LVAL_NUM, LVAL_SYM, LVAL_FUNC, LVAL_S_EXPR, LVAL_Q_EXPR, LVAL_EXIT };
|
enum VAL_TYPE { LVAL_ERR, LVAL_NUM, LVAL_SYM, LVAL_FUNC, LVAL_S_EXPR, LVAL_Q_EXPR, LVAL_EXIT };
|
||||||
enum VAL_ERROR { LERR_DIV_ZERO, LERR_BAD_OP, LERR_BAD_NUM, LERR_BAD_SYM, LERR_OTHER, LERR_SYNTAX };
|
enum VAL_ERROR { LERR_DIV_ZERO, LERR_BAD_OP, LERR_BAD_NUM, LERR_BAD_SYM, LERR_OTHER, LERR_SYNTAX };
|
||||||
typedef enum VAL_TYPE VAL_TYPE;
|
typedef enum VAL_TYPE VAL_TYPE;
|
||||||
|
|||||||
Reference in New Issue
Block a user