cirilisp/util.c
2019-01-29 23:54:32 +01:00

329 lines
6.3 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <math.h>
#include "util.h"
#define SPECIALFORMSNUM 3
int isSpecialForm(char *symbol)
{
int result = 0;
char *specialForms[] =
{
"навод",
"дефиниши",
"ламбда"
};
for (int i = 0; i < SPECIALFORMSNUM; ++i)
{
if (!strcmp(symbol, specialForms[i]))
{
result = 1;
}
}
return result;
}
int properList(object list)
{
object *current = &list;
while (TYPE(*current) == consObject)
{
current = &CDR(*current);
}
return TYPE(*current) == nilObject;
}
int listLength(object list)
{
object *current = &list;
int i = 0;
while (TYPE(*current) != nilObject)
{
current = &CDR(*current);
++i;
}
return i;
}
void deleteObject(object input)
{
if (TYPE(input) == symbolObject && SYM(input) != NULL)
{
free(SYM(input));
SYM(input) = NULL;
}
else if (TYPE(input) == procedureObject &&
PROC_TYPE(input) == compoundProc)
{
deleteObject(PROC_COMP_ARGS(input));
deleteObject(PROC_COMP_BODY(input));
free(PROC(input));
PROC(input) = NULL;
}
else if (TYPE(input) == consObject)
{
deleteObject(CAR(input));
deleteObject(CDR(input));
free(CONS(input));
CONS(input) = NULL;
}
TYPE(input) = nilObject;
}
object copyObject(object input)
{
object result;
TYPE(result) = TYPE(input);
if (TYPE(input) == errorObject)
{
ERR(result) = ERR(input);
}
else if (TYPE(input) == numberObject)
{
NUM(result) = NUM(input);
}
else if (TYPE(input) == symbolObject)
{
SYM(result) =
malloc(sizeof(char) * (strlen(SYM(input)) + 1));
strcpy(SYM(result), SYM(input));
}
else if (TYPE(input) == consObject)
{
CONS(result) = malloc(sizeof(cons));
CAR(result) = copyObject(CAR(input));
CDR(result) = copyObject(CDR(input));
}
else if (TYPE(input) == boolObject)
{
BOOL(result) = BOOL(input);
}
else if (TYPE(input) == procedureObject)
{
PROC(result) = malloc(sizeof(procedure));
PROC_TYPE(result) = PROC_TYPE(input);
if (PROC_TYPE(result) == builtinProc)
{
PROC_BUILTIN(result) = PROC_BUILTIN(input);
}
else
{
PROC_COMP_ARGS(result) =
copyObject(PROC_COMP_ARGS(input));
PROC_COMP_BODY(result) =
copyObject(PROC_COMP_BODY(input));
}
}
return result;
}
object longlongToNumber(long long int input)
{
object result;
TYPE(result) = numberObject;
NUM_TYPE(result) = fractionNum;
NUM_NUMER(result) = input;
NUM_DENOM(result) = 1LL;
return result;
}
object exactToInexactNum(object a)
{
object result = copyObject(a);
if (TYPE(result) == numberObject && NUM_TYPE(result) == fractionNum)
{
NUM_TYPE(result) = realNum;
NUM_REAL(result) = (long double) NUM_NUMER(result) /
(long double) NUM_DENOM(result);
}
return result;
}
object inexactToExactNum(object a)
{
object result = copyObject(a);
if (TYPE(result) == numberObject && NUM_TYPE(result) == realNum)
{
long long int divisor = 1;
while (NUM_REAL(result) != floorl(NUM_REAL(result)) &&
divisor <= INT_MAX)
{
NUM_REAL(result) *= 10.0L;
divisor *= 10LL;
}
NUM_TYPE(result) = fractionNum;
NUM_NUMER(result) = (long long int) floorl(NUM_REAL(result));
NUM_DENOM(result) = divisor;
result = shortenFractionNum(result);
}
return result;
}
long long int gcd(long long int a, long long int b)
/* највећи заједнички делилац */
{
if (b == 0LL)
{
return a;
}
else
{
return gcd(b, a - b * (a / b));
}
}
long long int lcm(long long int a, long long int b)
/* најмањи заједнички садржалац */
{
if (a == 0LL && b == 0LL)
{
return 0L;
}
else
{
return llabs(a * b) / gcd(a, b);
}
}
object shortenFractionNum(object a)
/* скраћује разломак, враћа грешку ако је неправилан разломак, уколико улаз
* заиста јесте дат као разломак */
{
object result = copyObject(a);
if (TYPE(result) == numberObject && NUM_TYPE(result) == fractionNum)
{
if (NUM_DENOM(result) == 0)
{
deleteObject(result);
TYPE(result) = errorObject;
ERR(result) = divisionByZeroError;
}
else if (NUM_NUMER(result) == 0)
{
NUM_DENOM(result) = 1;
}
else
{
long long int divisor =
gcd(NUM_NUMER(result), NUM_DENOM(result));
NUM_NUMER(result) /= divisor;
NUM_DENOM(result) /= divisor;
}
}
return result;
}
object plusNum(object a, object b)
{
object result;
TYPE(result) = numberObject;
if (NUM_TYPE(a) == fractionNum && NUM_TYPE(b) == fractionNum)
{
NUM_TYPE(result) = fractionNum;
NUM_NUMER(result) = NUM_NUMER(a) * NUM_DENOM(b) + NUM_NUMER(b) * NUM_DENOM(a);
NUM_DENOM(result) = NUM_DENOM(a) * NUM_DENOM(b);
/*
* TODO: имплементирати оптималнији начин множења разломака
long long int denominator = lcm(NUM_DENOM(a), NUM_DENOM(b));
NUM_NUMER(result) =
NUM_NUMER(a) * (denominator / NUM_DENOM(a)) +
NUM_NUMER(b) * (denominator / NUM_DENOM(b));
*/
result = shortenFractionNum(result);
}
else
{
NUM_TYPE(result) = realNum;
NUM_REAL(result) = NUM_REAL(exactToInexactNum(a))
+ NUM_REAL(exactToInexactNum(b));
}
return result;
}
object minusNum(object a)
{
object result;
result = copyObject(a);
if (NUM_TYPE(result) == fractionNum)
{
NUM_NUMER(result) = -NUM_NUMER(result);
}
else if (NUM_TYPE(result) == realNum)
{
NUM_REAL(result) = -NUM_REAL(result);
}
return result;
}
object timesNum(object a, object b)
{
object result;
TYPE(result) = numberObject;
if (NUM_TYPE(a) == fractionNum && NUM_TYPE(b) == fractionNum)
{
NUM_TYPE(result) = fractionNum;
NUM_NUMER(result) = NUM_NUMER(a) * NUM_NUMER(b);
NUM_DENOM(result) = NUM_DENOM(a) * NUM_DENOM(b);
result = shortenFractionNum(result);
}
else
{
NUM_TYPE(result) = realNum;
NUM_REAL(result) = NUM_REAL(exactToInexactNum(a)) *
NUM_REAL(exactToInexactNum(b));
}
return result;
}
object inverseNum(object a)
{
object result;
result = copyObject(a);
if (NUM_TYPE(result) == fractionNum)
{
if (NUM_NUMER(result) == 0)
{
deleteObject(result);
TYPE(result) = errorObject;
ERR(result) = divisionByZeroError;
}
else
{
NUM_NUMER(result) = NUM_DENOM(a);
NUM_DENOM(result) = NUM_NUMER(a);
}
}
else if (NUM_TYPE(result) == realNum)
{
NUM_REAL(result) = 1.0L/NUM_REAL(result);
}
return result;
}
procedure *createProcedure()
{
return malloc(sizeof(procedure));
}