diff --git a/Makefile b/Makefile index d5d7f41..efbe299 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ LDFLAGS = -lm -lc CC = cc -SRC = cirilisp.c read.c eval.c print.c util.c +SRC = cirilisp.c read.c eval.c print.c util.c symtable.c internals.c init.c OBJ = $(SRC:.c=.o) all: cirilisp @@ -21,7 +21,7 @@ all: cirilisp .c.o: $(CC) -c $(CFLAGS) $< -$(OBJ): util.h read.h eval.h print.h +$(OBJ): util.h read.h eval.h print.h symtable.h internals.h init.h cirilisp: $(OBJ) $(CC) -o $@ $(OBJ) $(LDFLAGS) diff --git a/cirilisp.c b/cirilisp.c index 9c444fe..7f81872 100644 --- a/cirilisp.c +++ b/cirilisp.c @@ -1,25 +1,13 @@ -#include -#include -#include - -#include "util.h" +#include "init.h" #include "read.h" #include "eval.h" #include "print.h" int main(int argc, char **argv) { -/* Омогућава библиотекама коришћеним у интерпретеру да протумаче српску ћирилицу */ - if (setlocale(LC_ALL, "sr_RS.utf8") == NULL) - { - fprintf(stderr, "locale couldn't be set to \"sr_RS.utf8\",\ - check if you've enabled it on your system\n"); - exit(0); - } - + init(); for (;;) { print(eval(read("ШКЉ> "))); } } - diff --git a/eval.c b/eval.c index 71599a7..8f17980 100644 --- a/eval.c +++ b/eval.c @@ -3,6 +3,7 @@ #include #include "util.h" +#include "symtable.h" object apply(object function, object parameters); @@ -12,11 +13,12 @@ object eval(object input) 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), "/")) + if (symbolExists(SYM(input))) { result = input; } @@ -62,11 +64,6 @@ object eval(object 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; @@ -77,165 +74,21 @@ object apply(object function, object parameters) TYPE(result) = errorObject; ERR(result) = notApplicableError; } - /* TODO Ово налажење ће се касније извршавати кроз табелу симбола */ - else if (!strcmp(SYM(function), "+")) + else if (symbolExists(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); + object(*f)(); + if ((f = internalFunction(SYM(function))) != NULL) + { + result = f(parameters); + } } else { deleteObject(function); TYPE(result) = errorObject; - ERR(result) = improperListError; + ERR(result) = unrecognizedSymbolError; } 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; - ERR(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; - ERR(result) = typeError; - } - else if (listLength(parameters) == 0) - { - TYPE(result) = errorObject; - ERR(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; - ERR(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; - ERR(result) = typeError; - } - else if (listLength(parameters) == 0) - { - TYPE(result) = errorObject; - ERR(result) = argumentNumberError; - } - else if (listLength(parameters) == 1) - { - if (NUM(CAR(parameters)) != 0) - { - NUM(result) = 1/NUM(CAR(parameters)); - } - else - { - TYPE(result) = errorObject; - ERR(result) = divisionByZeroError; - } - } - else - { - if (NUM(add(CDR(parameters))) != 0) - { - NUM(result) = NUM(CAR(parameters))/NUM(add(CDR(parameters))); - } - else - { - TYPE(result) = errorObject; - ERR(result) = divisionByZeroError; - } - } - - return result; -} diff --git a/init.c b/init.c new file mode 100644 index 0000000..8fa1f17 --- /dev/null +++ b/init.c @@ -0,0 +1,23 @@ +#include +#include +#include + +#include "symtable.h" +#include "internals.h" + +void init() +{ + if (setlocale(LC_ALL, "sr_RS.utf8") == NULL) + { + fprintf(stderr, "lokal se nije mogao podesiti na\ +\"sr_RS.utf8\", proverite da li ste ga osposobili na vasem sistemu\n"); + exit(0); + } +/* Омогућава библиотекама коришћеним у интерпретеру да протумаче српску + * ћирилицу */ + + addSymbolInternal("+", &add); + addSymbolInternal("-", &subtract); + addSymbolInternal("*", &multiply); + addSymbolInternal("/", ÷); +} diff --git a/init.h b/init.h new file mode 100644 index 0000000..c6d8ff4 --- /dev/null +++ b/init.h @@ -0,0 +1,3 @@ +#pragma once + +void init(void); diff --git a/internals.c b/internals.c new file mode 100644 index 0000000..eb36f51 --- /dev/null +++ b/internals.c @@ -0,0 +1,137 @@ +#include "util.h" + +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; + ERR(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; + ERR(result) = typeError; + } + else if (listLength(parameters) == 0) + { + TYPE(result) = errorObject; + ERR(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; + ERR(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; + ERR(result) = typeError; + } + else if (listLength(parameters) == 0) + { + TYPE(result) = errorObject; + ERR(result) = argumentNumberError; + } + else if (listLength(parameters) == 1) + { + if (NUM(CAR(parameters)) != 0) + { + NUM(result) = 1/NUM(CAR(parameters)); + } + else + { + TYPE(result) = errorObject; + ERR(result) = divisionByZeroError; + } + } + else + { + if (NUM(add(CDR(parameters))) != 0) + { + NUM(result) = NUM(CAR(parameters))/NUM(add(CDR(parameters))); + } + else + { + TYPE(result) = errorObject; + ERR(result) = divisionByZeroError; + } + } + + return result; +} diff --git a/internals.h b/internals.h new file mode 100644 index 0000000..0895f28 --- /dev/null +++ b/internals.h @@ -0,0 +1,6 @@ +#pragma once + +object add(object parameters); +object subtract(object parameters); +object multiply(object parameters); +object divide(object parameters); diff --git a/read.h b/read.h index 14fdef7..ccff389 100644 --- a/read.h +++ b/read.h @@ -1,3 +1,5 @@ #pragma once +#include "util.h" + object read(char *prompt); diff --git a/symtable.c b/symtable.c new file mode 100644 index 0000000..f7f3cbc --- /dev/null +++ b/symtable.c @@ -0,0 +1,130 @@ +#include +#include +#include + +#include "util.h" +#include "symtable.h" + +typedef enum +{ + internalSymbol, + objectSymbol +} symbolType; + +typedef struct entry +{ + symbolType type; + char *name; + union + { + object (*function)(); + object definition; + } value; + struct entry *left; + struct entry *right; +} entry; +/* овај тип служи за имплементирање табеле симбола који могу бити дефинисани + * или путем интерне функције написане у интерпретеру, или је дефинисан + * коришћењем самог Ћирилисп интерпретера */ + +entry *root = NULL; + +entry **findEntry(entry **current, char *symbol) +{ + int cond; + + if (*current == NULL) + { + return current; + } + else if ((cond = strcmp(symbol, (*current)->name)) < 0) + { + return findEntry(&(*current)->left, symbol); + } + else if (cond > 0) + { + return findEntry(&(*current)->right, symbol); + } + else + { + return current; + } + /* случај у којем тражени симбол не постоји у табели, и случај у којем + * је он нађен враћају вредност на исти начин, али су гране тока + * одвојене ради читљивости */ +} + +int addSymbolInternal(char *symbol, object (*function)()) +{ + int status = 1; + entry **e = findEntry(&root, symbol); + + if (*e == NULL) + { + *e = malloc(sizeof(entry)); + (*e)->type = internalSymbol; + (*e)->name = malloc(sizeof(char) * (strlen(symbol) + 1)); + strcpy((*e)->name, symbol); + (*e)->value.function = function; + (*e)->left = (*e)->right = NULL; + } + else + { + status = 0; + } + + return status; +} + +int addSymbolDefinition(char *symbol, object definition) +{ + int status = 1; + entry **e = findEntry(&root, symbol); + + if (*e == NULL) + { + *e = malloc(sizeof(entry)); + (*e)->type = objectSymbol; + (*e)->name = malloc(sizeof(char) * (strlen(symbol) + 1)); + strcpy((*e)->name, symbol); + (*e)->value.definition = copyObject(definition); + (*e)->left = (*e)->right = NULL; + } + else + { + status = 0; + } + + return status; +} + +int symbolExists(char *symbol) +{ + int status = 1; + entry **e = findEntry(&root, symbol); + + if (*e == NULL) + { + return 0; + } + else + { + return 1; + } + + return status; +} + +object (*internalFunction(char *symbol)) (object) +{ + entry **e = findEntry(&root, symbol); + + if (*e == NULL || (*e)->type != internalSymbol) + { + return NULL; + } + else + { + return ((*e)->value.function); + } +} diff --git a/symtable.h b/symtable.h new file mode 100644 index 0000000..5736008 --- /dev/null +++ b/symtable.h @@ -0,0 +1,17 @@ +#pragma once + +#include "util.h" + +int addSymbolInternal(char *symbol, object (*function)()); +int addSymbolDefinition(char *symbol, object definition); +/* служе за различите методе дефинисања нових симбола у језику + * враћају 1 уколико је нови симбол успешно додат, а 0 уколико није + * (постоји симбол са истим именом) */ + +int symbolExists(char *symbol); +/* враћа 1 уколико симбол постоји и 0 у супротном */ + +object (*internalFunction(char *symbol)) (object parameters); +/* враћа показивач на функцију уколико је симбол дефинисан као интерна + * функција, NULL уколико симбол није функција или уколико не постоји + * */