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

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 CC = cc
SRC = cirilisp.c read.c print.c SRC = cirilisp.c read.c eval.c print.c util.c
OBJ = $(SRC:.c=.o) OBJ = $(SRC:.c=.o)
all: cirilisp all: cirilisp
@ -21,7 +21,7 @@ all: cirilisp
.c.o: .c.o:
$(CC) -c $(CFLAGS) $< $(CC) -c $(CFLAGS) $<
$(OBJ): util.h read.h print.h $(OBJ): util.h read.h eval.h print.h
cirilisp: $(OBJ) cirilisp: $(OBJ)
$(CC) -o $@ $(OBJ) $(LDFLAGS) $(CC) -o $@ $(OBJ) $(LDFLAGS)
@ -31,7 +31,7 @@ clean:
dist: clean dist: clean
mkdir -p cirilisp-$(VERSION) 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) tar -cf cirilisp-$(VERSION).tar cirilisp-$(VERSION)
gzip cirilisp-$(VERSION).tar gzip cirilisp-$(VERSION).tar
rm -rf cirilisp-$(VERSION) rm -rf cirilisp-$(VERSION)

View file

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

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

23
print.c
View file

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

58
read.c
View file

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