Додата подршка за разломачку и плутајућо-тачкасту аритметику
This commit is contained in:
parent
a0f6fa8e3f
commit
6568f1cc57
33
internals.c
33
internals.c
|
@ -26,7 +26,7 @@ object add(object parameters)
|
||||||
}
|
}
|
||||||
else if (listLength(parameters) == 0)
|
else if (listLength(parameters) == 0)
|
||||||
{
|
{
|
||||||
NUM(result) = 0LL;
|
result = longlongToNumber(0LL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -34,7 +34,7 @@ object add(object parameters)
|
||||||
first = CAR(parameters);
|
first = CAR(parameters);
|
||||||
rest = add(CDR(parameters));
|
rest = add(CDR(parameters));
|
||||||
|
|
||||||
NUM(result) = NUM(first) + NUM(rest);
|
result = plusNum(first, rest);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -57,11 +57,12 @@ object subtract(object parameters)
|
||||||
}
|
}
|
||||||
else if (listLength(parameters) == 1)
|
else if (listLength(parameters) == 1)
|
||||||
{
|
{
|
||||||
NUM(result) = -NUM(CAR(parameters));
|
result = minusNum(CAR(parameters));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NUM(result) = NUM(CAR(parameters)) - NUM(add(CDR(parameters)));
|
result = plusNum(CAR(parameters),
|
||||||
|
minusNum(add(CDR(parameters))));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -79,7 +80,7 @@ object multiply(object parameters)
|
||||||
}
|
}
|
||||||
else if (listLength(parameters) == 0)
|
else if (listLength(parameters) == 0)
|
||||||
{
|
{
|
||||||
NUM(result) = 1LL;
|
result = longlongToNumber(1LL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -87,7 +88,7 @@ object multiply(object parameters)
|
||||||
first = CAR(parameters);
|
first = CAR(parameters);
|
||||||
rest = multiply(CDR(parameters));
|
rest = multiply(CDR(parameters));
|
||||||
|
|
||||||
NUM(result) = NUM(first) * NUM(rest);
|
result = timesNum(first,rest);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -110,27 +111,21 @@ object divide(object parameters)
|
||||||
}
|
}
|
||||||
else if (listLength(parameters) == 1)
|
else if (listLength(parameters) == 1)
|
||||||
{
|
{
|
||||||
if (NUM(CAR(parameters)) != 0)
|
result = inverseNum(CAR(parameters));
|
||||||
{
|
|
||||||
NUM(result) = 1/NUM(CAR(parameters));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TYPE(result) = errorObject;
|
|
||||||
ERR(result) = divisionByZeroError;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (NUM(multiply(CDR(parameters))) != 0)
|
object check = inverseNum(multiply(CDR(parameters)));
|
||||||
|
if (TYPE(check) != errorObject)
|
||||||
{
|
{
|
||||||
NUM(result) = NUM(CAR(parameters))/NUM(multiply(CDR(parameters)));
|
result = timesNum(CAR(parameters),
|
||||||
|
inverseNum(multiply(CDR(parameters))));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TYPE(result) = errorObject;
|
result = check;
|
||||||
ERR(result) = divisionByZeroError;
|
|
||||||
}
|
}
|
||||||
|
result = shortenFractionNum(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
15
print.c
15
print.c
|
@ -23,7 +23,7 @@ void print(object input)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf("\n; Value: ");
|
printf("\n");
|
||||||
printValue(input);
|
printValue(input);
|
||||||
printf("\n\n");
|
printf("\n\n");
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,18 @@ void printValue(object input)
|
||||||
}
|
}
|
||||||
else if (input.type == numberObject)
|
else if (input.type == numberObject)
|
||||||
{
|
{
|
||||||
printf("%lld", NUM(input));
|
if (NUM_TYPE(input) == fractionNum)
|
||||||
|
{
|
||||||
|
printf("%lld", NUM_NUMER(input));
|
||||||
|
if (NUM_DENOM(input) != 1)
|
||||||
|
{
|
||||||
|
printf("/%lld", NUM_DENOM(input));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("%LF", NUM_REAL(input));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (input.type == symbolObject)
|
else if (input.type == symbolObject)
|
||||||
{
|
{
|
||||||
|
|
47
read.c
47
read.c
|
@ -11,7 +11,8 @@
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
undefinedToken,
|
undefinedToken,
|
||||||
numberToken,
|
numberFracToken,
|
||||||
|
numberRealToken,
|
||||||
symbolToken,
|
symbolToken,
|
||||||
quoteToken,
|
quoteToken,
|
||||||
lParenthesisToken,
|
lParenthesisToken,
|
||||||
|
@ -131,8 +132,8 @@ void append(token **head, token *tail)
|
||||||
*current = tail;
|
*current = tail;
|
||||||
}
|
}
|
||||||
|
|
||||||
regex_t regNumber, regSymbol, regLParenthesis, regRParenthesis, regSpace,
|
regex_t regNumberFrac, regNumberReal, regLParenthesis, regRParenthesis,
|
||||||
regQuote;
|
regSpace, regSymbol, regQuote;
|
||||||
|
|
||||||
token *lex1Token(char *input, int *i)
|
token *lex1Token(char *input, int *i)
|
||||||
{
|
{
|
||||||
|
@ -141,7 +142,10 @@ token *lex1Token(char *input, int *i)
|
||||||
|
|
||||||
regcomp(®Space, "^[[:space:]]*", REG_EXTENDED);
|
regcomp(®Space, "^[[:space:]]*", REG_EXTENDED);
|
||||||
|
|
||||||
regcomp(®Number, "^[-+]?[[:digit:]]+", REG_EXTENDED);
|
regcomp(®NumberFrac, "^[-+]?[[:digit:]]+(/[[:digit:]]+)?",
|
||||||
|
REG_EXTENDED);
|
||||||
|
regcomp(®NumberReal, "^[-+]?[[:digit:]]*,[[:digit:]]+",
|
||||||
|
REG_EXTENDED);
|
||||||
regcomp(®Symbol, "^[-+/*_\\\\=<>!&?[:alnum:]]+", REG_EXTENDED);
|
regcomp(®Symbol, "^[-+/*_\\\\=<>!&?[:alnum:]]+", REG_EXTENDED);
|
||||||
regcomp(®Quote, "^'", REG_EXTENDED);
|
regcomp(®Quote, "^'", REG_EXTENDED);
|
||||||
regcomp(®LParenthesis, "^\\(", REG_EXTENDED);
|
regcomp(®LParenthesis, "^\\(", REG_EXTENDED);
|
||||||
|
@ -154,16 +158,20 @@ token *lex1Token(char *input, int *i)
|
||||||
*i += a[0].rm_eo;
|
*i += a[0].rm_eo;
|
||||||
/* помера индекс да би се игнорисали почетни "вајт-спејс" карактери */
|
/* помера индекс да би се игнорисали почетни "вајт-спејс" карактери */
|
||||||
|
|
||||||
if (!regexec(®Symbol, input + *i, nmatches, a, 0))
|
if (!regexec(®NumberReal, input + *i, nmatches, a, 0))
|
||||||
|
{
|
||||||
|
result->type = numberRealToken;
|
||||||
|
}
|
||||||
|
else if (!regexec(®Symbol, input + *i, nmatches, a, 0))
|
||||||
{
|
{
|
||||||
int tmp = a[0].rm_eo;
|
int tmp = a[0].rm_eo;
|
||||||
if (!regexec(®Number, input + *i, nmatches, a, 0) &&
|
if (!regexec(®NumberFrac, input + *i, nmatches, a, 0) &&
|
||||||
tmp == a[0].rm_eo)
|
tmp == a[0].rm_eo)
|
||||||
/* симбол може садржати цифре на било којој позицији али не може сам бити број
|
/* симбол може садржати цифре на било којој позицији али не може сам бити број
|
||||||
* не постоји погодан начина да се ово путем regex-a запише стога овај if
|
* не постоји погодан начина да се ово путем regex-a запише стога овај if
|
||||||
* исказ */
|
* исказ */
|
||||||
{
|
{
|
||||||
result->type = numberToken;
|
result->type = numberFracToken;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -173,6 +181,10 @@ token *lex1Token(char *input, int *i)
|
||||||
result->type = symbolToken;
|
result->type = symbolToken;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (!regexec(®NumberFrac, input + *i, nmatches, a, 0))
|
||||||
|
{
|
||||||
|
result->type = numberFracToken;
|
||||||
|
}
|
||||||
else if (!regexec(®Quote, input + *i, nmatches, a, 0))
|
else if (!regexec(®Quote, input + *i, nmatches, a, 0))
|
||||||
{
|
{
|
||||||
result->type = quoteToken;
|
result->type = quoteToken;
|
||||||
|
@ -202,7 +214,8 @@ token *lex1Token(char *input, int *i)
|
||||||
|
|
||||||
skipStringCopy:
|
skipStringCopy:
|
||||||
regfree(®Space);
|
regfree(®Space);
|
||||||
regfree(®Number);
|
regfree(®NumberFrac);
|
||||||
|
regfree(®NumberReal);
|
||||||
regfree(®Symbol);
|
regfree(®Symbol);
|
||||||
regfree(®LParenthesis);
|
regfree(®LParenthesis);
|
||||||
regfree(®RParenthesis);
|
regfree(®RParenthesis);
|
||||||
|
@ -249,11 +262,22 @@ object parseExpression(token **inputList)
|
||||||
/* скида први преостали токен са листе унесених, да би се могао
|
/* скида први преостали токен са листе унесених, да би се могао
|
||||||
* прерадити */
|
* прерадити */
|
||||||
|
|
||||||
if (input.type == numberToken)
|
if (input.type == numberFracToken)
|
||||||
{
|
{
|
||||||
TYPE(result) = numberObject;
|
TYPE(result) = numberObject;
|
||||||
NUM(result) = atoll(input.lexeme);
|
NUM_TYPE(result) = fractionNum;
|
||||||
return result;
|
NUM_NUMER(result) = atoll(input.lexeme);
|
||||||
|
char *tmp;
|
||||||
|
NUM_DENOM(result) = (tmp = strchr(input.lexeme, '/')) == NULL ?
|
||||||
|
1 : atoll(tmp + 1);
|
||||||
|
|
||||||
|
result = shortenFractionNum(result);
|
||||||
|
}
|
||||||
|
else if (input.type == numberRealToken)
|
||||||
|
{
|
||||||
|
TYPE(result) = numberObject;
|
||||||
|
NUM_TYPE(result) = realNum;
|
||||||
|
NUM_REAL(result) = strtold(input.lexeme, NULL);
|
||||||
}
|
}
|
||||||
else if (input.type == symbolToken)
|
else if (input.type == symbolToken)
|
||||||
{
|
{
|
||||||
|
@ -262,7 +286,6 @@ object parseExpression(token **inputList)
|
||||||
* sizeof(char));
|
* sizeof(char));
|
||||||
/* Алокација стринга */
|
/* Алокација стринга */
|
||||||
strcpy(SYM(result), input.lexeme);
|
strcpy(SYM(result), input.lexeme);
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
else if (input.type == quoteToken)
|
else if (input.type == quoteToken)
|
||||||
{
|
{
|
||||||
|
|
175
util.c
175
util.c
|
@ -70,3 +70,178 @@ object copyObject(object input)
|
||||||
|
|
||||||
return result;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
38
util.h
38
util.h
|
@ -5,10 +5,15 @@
|
||||||
#define CONS(x) ((x).value.consCell)
|
#define CONS(x) ((x).value.consCell)
|
||||||
#define CAR(x) (((x).value.consCell)->car)
|
#define CAR(x) (((x).value.consCell)->car)
|
||||||
#define CDR(x) (((x).value.consCell)->cdr)
|
#define CDR(x) (((x).value.consCell)->cdr)
|
||||||
#define NUM(x) ((x).value.number)
|
|
||||||
#define SYM(x) ((x).value.symbol)
|
#define SYM(x) ((x).value.symbol)
|
||||||
#define ERR(x) ((x).value.err)
|
#define ERR(x) ((x).value.err)
|
||||||
|
|
||||||
|
#define NUM(x) ((x).value.num)
|
||||||
|
#define NUM_TYPE(x) ((x).value.num.type)
|
||||||
|
#define NUM_NUMER(x) ((x).value.num.value.fraction.numerator)
|
||||||
|
#define NUM_DENOM(x) ((x).value.num.value.fraction.denominator)
|
||||||
|
#define NUM_REAL(x) ((x).value.num.value.real)
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
nilObject,
|
nilObject,
|
||||||
|
@ -32,6 +37,26 @@ typedef enum
|
||||||
typedef struct object object;
|
typedef struct object object;
|
||||||
typedef struct cons cons;
|
typedef struct cons cons;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
fractionNum,
|
||||||
|
realNum
|
||||||
|
} numType;
|
||||||
|
|
||||||
|
typedef struct number
|
||||||
|
{
|
||||||
|
numType type;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
long double real;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
long long int numerator;
|
||||||
|
long long int denominator;
|
||||||
|
} fraction;
|
||||||
|
} value;
|
||||||
|
} number;
|
||||||
|
|
||||||
struct object
|
struct object
|
||||||
{
|
{
|
||||||
dataType type;
|
dataType type;
|
||||||
|
@ -39,8 +64,8 @@ struct object
|
||||||
{
|
{
|
||||||
error err;
|
error err;
|
||||||
char *symbol;
|
char *symbol;
|
||||||
long long int number;
|
|
||||||
cons *consCell;
|
cons *consCell;
|
||||||
|
number num;
|
||||||
} value;
|
} value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -54,3 +79,12 @@ int properList(object list);
|
||||||
int listLength(object list);
|
int listLength(object list);
|
||||||
void deleteObject(object input);
|
void deleteObject(object input);
|
||||||
object copyObject(object input);
|
object copyObject(object input);
|
||||||
|
|
||||||
|
|
||||||
|
object longlongToNumber(long long int input);
|
||||||
|
object shortenFractionNum(object a);
|
||||||
|
object exactToInexactNum(object a);
|
||||||
|
object plusNum(object a, object b);
|
||||||
|
object minusNum(object a);
|
||||||
|
object timesNum(object a, object b);
|
||||||
|
object inverseNum(object a);
|
||||||
|
|
Loading…
Reference in a new issue