Основне рачунске операције потпуно имплементиране
This commit is contained in:
parent
da13db05d3
commit
4a6944eed4
6
Makefile
6
Makefile
|
@ -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)
|
||||
|
|
|
@ -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
233
eval.c
Normal 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;
|
||||
}
|
17
print.c
17
print.c
|
@ -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
56
read.c
|
@ -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(®Space, "^[[:space:]]*", REG_EXTENDED);
|
||||
|
||||
regcomp(®Number, "^[-+]?[[:digit:]]+", REG_EXTENDED);
|
||||
regcomp(®Symbol, "^[-+/*]", REG_EXTENDED);
|
||||
regcomp(®Symbol, "^[-+/*]+", REG_EXTENDED);
|
||||
/* за сада подржава само симболе -, +, * и / */
|
||||
regcomp(®LParenthesis, "^\\(", REG_EXTENDED);
|
||||
regcomp(®RParenthesis, "^\\)", 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
72
util.c
Normal 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
35
util.h
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue