Додата подршка за разломачку и плутајућо-тачкасту аритметику

This commit is contained in:
kappa 2019-01-20 23:48:12 +01:00
parent a0f6fa8e3f
commit 6568f1cc57
5 changed files with 273 additions and 35 deletions

View file

@ -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));
result = inverseNum(CAR(parameters));
}
else
{
TYPE(result) = errorObject;
ERR(result) = divisionByZeroError;
}
object check = inverseNum(multiply(CDR(parameters)));
if (TYPE(check) != errorObject)
{
result = timesNum(CAR(parameters),
inverseNum(multiply(CDR(parameters))));
}
else
{
if (NUM(multiply(CDR(parameters))) != 0)
{
NUM(result) = NUM(CAR(parameters))/NUM(multiply(CDR(parameters)));
}
else
{
TYPE(result) = errorObject;
ERR(result) = divisionByZeroError;
result = check;
}
result = shortenFractionNum(result);
}
return result;

15
print.c
View file

@ -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
View file

@ -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(&regSpace, "^[[:space:]]*", REG_EXTENDED);
regcomp(&regNumber, "^[-+]?[[:digit:]]+", REG_EXTENDED);
regcomp(&regNumberFrac, "^[-+]?[[:digit:]]+(/[[:digit:]]+)?",
REG_EXTENDED);
regcomp(&regNumberReal, "^[-+]?[[:digit:]]*,[[:digit:]]+",
REG_EXTENDED);
regcomp(&regSymbol, "^[-+/*_\\\\=<>!&?[:alnum:]]+", REG_EXTENDED);
regcomp(&regQuote, "^'", REG_EXTENDED);
regcomp(&regLParenthesis, "^\\(", REG_EXTENDED);
@ -154,16 +158,20 @@ token *lex1Token(char *input, int *i)
*i += a[0].rm_eo;
/* помера индекс да би се игнорисали почетни "вајт-спејс" карактери */
if (!regexec(&regSymbol, input + *i, nmatches, a, 0))
if (!regexec(&regNumberReal, input + *i, nmatches, a, 0))
{
result->type = numberRealToken;
}
else if (!regexec(&regSymbol, input + *i, nmatches, a, 0))
{
int tmp = a[0].rm_eo;
if (!regexec(&regNumber, input + *i, nmatches, a, 0) &&
if (!regexec(&regNumberFrac, 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(&regNumberFrac, input + *i, nmatches, a, 0))
{
result->type = numberFracToken;
}
else if (!regexec(&regQuote, input + *i, nmatches, a, 0))
{
result->type = quoteToken;
@ -202,7 +214,8 @@ token *lex1Token(char *input, int *i)
skipStringCopy:
regfree(&regSpace);
regfree(&regNumber);
regfree(&regNumberFrac);
regfree(&regNumberReal);
regfree(&regSymbol);
regfree(&regLParenthesis);
regfree(&regRParenthesis);
@ -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
View file

@ -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
View file

@ -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);