cirilisp/eval.c

234 lines
4.6 KiB
C
Raw Normal View History

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "util.h"
char *improperListError = "Конс објекат мора бити правилна листа да би\
могао бити евалуиран";
char *typeError = "Неправилан тип аргумента прослеђен функцији";
char *unrecognizedSymbolError = "Непознати симбол";
char *notApplicableError = "Објекат није примењив";
char *divisionByZeroError = "Дељење нулом";
char *argumentNumberError = "Функцији није прослеђен правилан број аргумената";
object apply(object function, object parameters);
object eval(object input)
{
object result;
if (TYPE(input) == nilObject || TYPE(input) == numberObject ||
TYPE(input) == errorObject)
result = input;
else if (TYPE(input) == symbolObject)
{
if (!strcmp(SYM(input), "+") || !strcmp(SYM(input), "-") ||
!strcmp(SYM(input), "*") || !strcmp(SYM(input), "/"))
{
result = input;
}
else
{
deleteObject(input);
TYPE(result) = errorObject;
ERRMSG(result) = unrecognizedSymbolError;
}
}
else if (TYPE(input) == consObject)
{
if (!properList(input))
{
deleteObject(input);
TYPE(result) = errorObject;
ERRMSG(result) = improperListError;
}
object *currentCell = &input;
int noErrors = 1;
while (TYPE(*currentCell) != nilObject)
{
CAR(*currentCell) = eval(CAR(*currentCell));
if (TYPE(CAR(*currentCell)) == errorObject)
{
noErrors = 0;
TYPE(result) = errorObject;
ERRMSG(result) = ERRMSG(CAR(*currentCell));
break;
}
currentCell = &CDR(*currentCell);
}
if (noErrors)
{
result = apply(CAR(input), CDR(input));
}
deleteObject(input);
}
return result;
}
object add(object parameters);
object subtract(object parameters);
object multiply(object parameters);
object divide(object parameters);
object apply(object function, object parameters)
{
object result;
if (TYPE(function) != symbolObject)
{
deleteObject(function);
TYPE(result) = errorObject;
ERRMSG(result) = notApplicableError;
}
/* TODO Ово налажење ће се касније извршавати кроз табелу симбола */
else if (!strcmp(SYM(function), "+"))
{
result = add(parameters);
}
else if (!strcmp(SYM(function), "-"))
{
result = subtract(parameters);
}
else if (!strcmp(SYM(function), "*"))
{
result = multiply(parameters);
}
else if (!strcmp(SYM(function), "/"))
{
result = divide(parameters);
}
else
{
deleteObject(function);
TYPE(result) = errorObject;
ERRMSG(result) = improperListError;
}
return result;
}
int allNumbers(object list)
{
object *currentCell = &list;
while (TYPE(*currentCell) != nilObject)
{
if (TYPE(CAR(*currentCell)) != numberObject)
{
return 0;
}
currentCell = &CDR(*currentCell);
}
return 1;
}
object add(object parameters)
{
object result;
TYPE(result) = numberObject;
if (!allNumbers(parameters))
{
TYPE(result) = errorObject;
ERRMSG(result) = typeError;
}
else if (listLength(parameters) == 0)
{
NUM(result) = 0LL;
}
else
{
object first, rest;
first = CAR(parameters);
rest = add(CDR(parameters));
NUM(result) = NUM(first) + NUM(rest);
}
return result;
}
object subtract(object parameters)
{
object result;
TYPE(result) = numberObject;
if (!allNumbers(parameters))
{
TYPE(result) = errorObject;
ERRMSG(result) = typeError;
}
else if (listLength(parameters) == 0)
{
TYPE(result) = errorObject;
ERRMSG(result) = argumentNumberError;
}
else if (listLength(parameters) == 1)
{
NUM(result) = -NUM(CAR(parameters));
}
else
{
NUM(result) = NUM(CAR(parameters)) - NUM(add(CDR(parameters)));
}
return result;
}
object multiply(object parameters)
{
object result;
TYPE(result) = numberObject;
if (!allNumbers(parameters))
{
TYPE(result) = errorObject;
ERRMSG(result) = typeError;
}
else if (listLength(parameters) == 0)
{
NUM(result) = 1LL;
}
else
{
object first, rest;
first = CAR(parameters);
rest = multiply(CDR(parameters));
NUM(result) = NUM(first) * NUM(rest);
}
return result;
}
object divide(object parameters)
{
object result;
TYPE(result) = numberObject;
if (!allNumbers(parameters))
{
TYPE(result) = errorObject;
ERRMSG(result) = typeError;
}
else if (listLength(parameters) == 0)
{
TYPE(result) = errorObject;
ERRMSG(result) = argumentNumberError;
}
else if (listLength(parameters) == 1)
{
NUM(result) = 1/NUM(CAR(parameters));
}
else
{
NUM(result) = NUM(CAR(parameters))/NUM(add(CDR(parameters)));
}
return result;
}