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