evalExpr.c 2.69 KB
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#include <expValue.h>
#include <tepal.h>
#include <tepal_pars.h>
#include <evalExpr.h>


/*
 * static function (internal only)
 */
static
inline
	s_expVal *
stringPlus(s_expVal * _op1, s_expVal * _op2)
{
	s_expVal * ret;
	char     * op1 = expValueString (_op1);
	char     * op2 = expValueString (_op2);
	char     * retVal =
		(char *)malloc(sizeof(char) * (strlen(op1) + strlen(op2) + 1));

	strcpy(retVal, op1);
	strcat(retVal, op2);
	ret = expValueStringNew(retVal);

	free(retVal);
	free(op2);
	free(op1);

	return ret;
}

static
inline
	s_expVal *
stringNeg(s_expVal * _op)
{
	s_expVal * ret;
	int        i;

	char * op  = expValueString(_op);
	int    len = strlen(op) - 1;

	for (i=0; i<=(len/2); i++) {
		char tmp = op[i];
		op[i] = op[len-i];
		op[len-i] = tmp;
	}

	ret = expValueStringNew(op);
	free(op);
	return ret;
}

static
inline
	s_expVal *
evalIntExp(int op, s_expVal * _op1, s_expVal * _op2)
{
	long op1 = expValueInt(_op1);
	long op2 = (_op2 != NULL) ? expValueInt(_op2) : 0;

	if (op == NEG) return expValueIntNew(- op1);

	switch (expValueGetType(_op2)) {
		case EXP_TYP_INT:
		case EXP_TYP_FLOAT:
			switch (op) {
				case PLUS: return expValueIntNew(op1 + op2);
				case MINUS: return expValueIntNew(op1 - op2);
				case TIMES: return expValueIntNew(op1 * op2);
				case OVER: return expValueIntNew(op1 / op2);
				case MODULO: return expValueIntNew(op1 % op2);
			}
		case EXP_TYP_STRING:
			if (op == PLUS) return stringPlus(_op1, _op2);
			exitError(ERR_STRING_OPERATOR, op);
	}
}

static
inline
	s_expVal *
evalFloatExp(int op, s_expVal * _op1, s_expVal * _op2)
{
	double op1 = expValueFloat (_op1);
	double op2 = (_op2 != NULL) ? expValueFloat(_op2) : 0.0;

	if (op == NEG) return expValueFloatNew(- op1);

	switch (expValueGetType(_op2)) {
		case EXP_TYP_INT:
		case EXP_TYP_FLOAT:
			switch (op) {
				case MODULO: exitError(ERR_FLOAT_OPERATOR, op);
				case PLUS: return expValueFloatNew(op1 + op2);
				case MINUS: return expValueFloatNew(op1 - op2);
				case TIMES: return expValueFloatNew(op1 * op2);
				case OVER: return expValueFloatNew(op1 / op2);
			}
		case EXP_TYP_STRING:
			if (op == PLUS) return stringPlus(_op1, _op2);
			exitError(ERR_STRING_OPERATOR, op);
	}
}



/*
 * public functions (interface)
 */
	s_expVal *
evalExpr(int op, s_expVal * op1, s_expVal * op2)
{
	switch (expValueGetType(op1)) {
		case EXP_TYP_INT:
			return evalIntExp(op, op1, op2);
		case EXP_TYP_FLOAT:
			if (op != MODULO) return evalFloatExp(op, op1, op2);
			exitError (ERR_FLOAT_OPERATOR, op);
		case EXP_TYP_STRING:
			if (op == PLUS) return stringPlus(op1, op2);
			if (op == NEG) return stringNeg(op1);
			exitError(ERR_STRING_OPERATOR, op);
	}
}