Основне рачунске операције потпуно имплементиране

This commit is contained in:
kappa 2019-01-14 03:16:25 +01:00
parent da13db05d3
commit 4a6944eed4
8 changed files with 387 additions and 48 deletions

View file

@ -13,7 +13,7 @@ LDFLAGS = -lm -lc
CC = cc
SRC = cirilisp.c read.c print.c
SRC = cirilisp.c read.c eval.c print.c util.c
OBJ = $(SRC:.c=.o)
all: cirilisp
@ -21,7 +21,7 @@ all: cirilisp
.c.o:
$(CC) -c $(CFLAGS) $<
$(OBJ): util.h read.h print.h
$(OBJ): util.h read.h eval.h print.h
cirilisp: $(OBJ)
$(CC) -o $@ $(OBJ) $(LDFLAGS)
@ -31,7 +31,7 @@ clean:
dist: clean
mkdir -p cirilisp-$(VERSION)
cp -r Makefile readline.h $(SRC) cirilisp-$(VERSION)
cp -r Makefile util.h read.h eval.h print.h $(SRC) cirilisp-$(VERSION)
tar -cf cirilisp-$(VERSION).tar cirilisp-$(VERSION)
gzip cirilisp-$(VERSION).tar
rm -rf cirilisp-$(VERSION)

View file

@ -4,6 +4,7 @@
#include "util.h"
#include "read.h"
#include "eval.h"
#include "print.h"
int main(int argc, char **argv)
@ -18,9 +19,7 @@ int main(int argc, char **argv)
for (;;)
{
print(read("ШКЉ> "));
/* append(&tokenList, lexLine(readline()));
printTokenList(tokenList); */
print(eval(read("ШКЉ> ")));
}
}

233
eval.c Normal file
View file

@ -0,0 +1,233 @@
#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;
}

3
eval.h Normal file
View file

@ -0,0 +1,3 @@
#pragma once
object eval(object input);

17
print.c
View file

@ -5,32 +5,39 @@
void printValue(object input);
void print(object input)
{
if (input.type == errorObject)
{
fprintf(stderr, "\nГРЕШКА: %s\n\n", ERRMSG(input));
}
else
{
printf("\n; Value: ");
printValue(input);
printf("\n\n");
}
}
void printValue(object input)
{
if (input.type == nilObject)
{
printf("nil");
printf("()");
}
else if (input.type == numberObject)
{
printf("%lld", *((long long *) input.address));
printf("%lld", NUM(input));
}
else if (input.type == symbolObject)
{
printf("%s", (char *) input.address);
printf("%s", SYM(input));
}
else if (input.type == consObject)
{
printf("(");
printValue(((cons *) input.address)->car);
printValue(CAR(input));
printf(" . ");
printValue(((cons *) input.address)->cdr);
printValue(CDR(input));
printf(")");
}
}

56
read.c
View file

@ -24,36 +24,36 @@ typedef struct _Token
struct _Token *next;
} token;
int completeSExpr(token **tokenList);
int completeExpression(token **tokenQueue);
char *readline();
void append(token **head, token *appendix);
token *lexLine(char *input);
object parseObject(token **inputList);
object parseExpression(token **inputList);
token *tokenList = NULL;
token *tokenQueue = NULL;
object read(char *prompt)
{
printf("%s", prompt);
while (!completeSExpr(&tokenList))
while (!completeExpression(&tokenQueue))
{
char *input = readline();
if (input == NULL) /* унесен је EOF сигнал */
if (input == NULL) /* унесен је EOF */
{
printf("\nКрај улазног стрима.\n");
exit(0);
}
append(&tokenList, lexLine(input));
append(&tokenQueue, lexLine(input));
}
return parseObject(&tokenList);
return parseExpression(&tokenQueue);
}
int completeSExpr(token **tokenList)
int completeExpression(token **tokenQueue)
{
int result = 0, indentLevel = 0;
token *current = *tokenList;
token *current = *tokenQueue;
while (current != NULL)
{
@ -65,7 +65,7 @@ int completeSExpr(token **tokenList)
{
if (indentLevel == 0)
{
token **deleteParen = tokenList;
token **deleteParen = tokenQueue;
while (*deleteParen != current)
{
deleteParen = &(*deleteParen)->next;
@ -115,7 +115,8 @@ char *readline()
char *cpy = malloc(strlen(buffer)+1);
strcpy(cpy, buffer);
cpy[strlen(cpy)-1] = '\0';
// Уклања завршни њу-лајн или ЕОФ у стрингу и копира га на ново место
/* Уклања завршни њу-лајн или ЕОФ у стрингу
* и копира стринг на ново место */
return cpy;
}
@ -141,7 +142,7 @@ token *lex1Token(char *input, int *i)
regcomp(&regSpace, "^[[:space:]]*", REG_EXTENDED);
regcomp(&regNumber, "^[-+]?[[:digit:]]+", REG_EXTENDED);
regcomp(&regSymbol, "^[-+/*]", REG_EXTENDED);
regcomp(&regSymbol, "^[-+/*]+", REG_EXTENDED);
/* за сада подржава само симболе -, +, * и / */
regcomp(&regLParenthesis, "^\\(", REG_EXTENDED);
regcomp(&regRParenthesis, "^\\)", REG_EXTENDED);
@ -206,7 +207,7 @@ token *lexLine(char *input)
if ((*new)->type == undefinedToken)
{
/* уколико се у реду нађе токен који је лексички погрешан, штампа се место тог
токена у реду и бришу се сви токени нађени у реду, функција враћа NULL*/
* токена у реду и бришу се сви токени нађени у реду, функција враћа NULL*/
fprintf(stderr, "Невалидан токен на месту %d\n", i);
new = &root;
while (*new != NULL)
@ -223,27 +224,29 @@ token *lexLine(char *input)
return root;
}
object parseObject(token **inputList)
object parseExpression(token **inputList)
{
object result;
token input = **inputList;
free(*inputList);
*inputList = input.next;
/* скида први преостали токен са листе унесених, да би се могао
* прерадити */
if (input.type == numberToken)
{
result.type = numberObject;
result.address = malloc(sizeof(long long int));
*((long long *) result.address) = atoll(input.lexeme);
TYPE(result) = numberObject;
NUM(result) = atoll(input.lexeme);
return result;
}
else if (input.type == symbolToken)
{
result.type = symbolObject;
result.address = malloc((strlen(input.lexeme) + 1)
TYPE(result) = symbolObject;
SYM(result) = malloc((strlen(input.lexeme) + 1)
* sizeof(char));
strcpy((char *) result.address, input.lexeme);
/* Алокација стринга */
strcpy(SYM(result), input.lexeme);
return result;
}
else if (input.type == lParenthesisToken)
@ -252,17 +255,16 @@ object parseObject(token **inputList)
while ((*inputList)->type != rParenthesisToken)
{
listCurrent->type = consObject;
listCurrent->address = malloc(sizeof(cons));
TYPE(*listCurrent) = consObject;
CONS(*listCurrent) = malloc(sizeof(cons));
/* Алокација конс ћелије */
((cons *) listCurrent->address)->car =
parseObject(inputList);
CAR(*listCurrent) = parseExpression(inputList);
listCurrent = &(((cons *) listCurrent->address)->cdr);
listCurrent = &CDR(*listCurrent);
}
(*listCurrent).type = nilObject;
(*listCurrent).address = NULL;
TYPE(*listCurrent) = nilObject;
input = **inputList;
free(*inputList);

72
util.c Normal file
View file

@ -0,0 +1,72 @@
#include <stdlib.h>
#include <string.h>
#include "util.h"
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) == 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)
{
ERRMSG(result) = ERRMSG(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));
}
return result;
}

35
util.h
View file

@ -1,22 +1,45 @@
#pragma once
#define TYPE(x) ((x).type)
#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 ERRMSG(x) ((x).value.errmsg)
typedef struct object object;
typedef struct cons cons;
typedef enum
{
nilObject,
consObject,
numberObject,
symbolObject
symbolObject,
errorObject
} dataType;
typedef struct _Object
struct object
{
dataType type;
void *address;
} object;
union
{
char *errmsg;
char *symbol;
long long int number;
cons *consCell;
} value;
};
typedef struct _Cons
struct cons
{
object car;
object cdr;
} cons;
};
int properList(object list);
int listLength(object list);
void deleteObject(object input);
object copyObject(object input);