From f83290449054f3188ffbe2c94b89e4844018a59d Mon Sep 17 00:00:00 2001 From: kappa Date: Sun, 27 Jan 2019 16:31:32 +0100 Subject: [PATCH] =?UTF-8?q?=D0=98=D0=BC=D0=BF=D0=BB=D0=B5=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D1=82=D0=B8=D1=80=D0=B0=D0=BD=20=D1=82=D0=B8=D0=BF=20?= =?UTF-8?q?=D0=BE=D0=B1=D1=98=D0=B5=D0=BA=D1=82=D0=B0:=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D1=86=D0=B5=D0=B4=D1=83=D1=80=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- eval.c | 115 +++++++++++++++++++++++++----------------- init.c | 1 + internals.c | 5 ++ print.c | 15 ++++-- symtable.c | 143 +++++++++++++++++++++++++++++++++------------------- symtable.h | 23 +++------ util.c | 10 +++- util.h | 41 +++++++++++++-- 8 files changed, 229 insertions(+), 124 deletions(-) diff --git a/eval.c b/eval.c index bf25dc3..188bd0d 100644 --- a/eval.c +++ b/eval.c @@ -11,29 +11,9 @@ object eval(object input) { object result; - if (TYPE(input) == nilObject || TYPE(input) == numberObject || - TYPE(input) == errorObject) + if (TYPE(input) == symbolObject) { - result = copyObject(input); - } - else if (TYPE(input) == symbolObject) - { - if (symbolExists(SYM(input))) - { - if (typeOf(SYM(input)) == variableSymbol) - { - result = referVariable(SYM(input)); - } - else - { - result = copyObject(input); - } - } - else - { - TYPE(result) = errorObject; - ERR(result) = unrecognizedSymbolError; - } + result = referVariable(SYM(input)); } else if (TYPE(input) == consObject) { @@ -44,25 +24,33 @@ object eval(object input) } else { + int specialForm = 0; + if (TYPE(CAR(input)) == symbolObject && + isSpecialForm(SYM(CAR(input)))) + { + specialForm = 1; + CAR(input) = eval(CAR(input)); + } + object *currentCell = &input; int noErrors = 1; - while (TYPE(*currentCell) != nilObject) + if (!specialForm) { - if (TYPE(CAR(input)) != symbolObject || - !isSpecialForm(SYM(CAR(input)))) + while (TYPE(*currentCell) != nilObject) { CAR(*currentCell) = eval(CAR(*currentCell)); - } - if (TYPE(CAR(*currentCell)) == errorObject) - { - noErrors = 0; - TYPE(result) = errorObject; - ERR(result) = ERR(CAR(*currentCell)); - break; + if (TYPE(CAR(*currentCell)) == errorObject) + { + noErrors = 0; + TYPE(result) = errorObject; + ERR(result) = + ERR(CAR(*currentCell)); + break; + } + currentCell = &CDR(*currentCell); } - currentCell = &CDR(*currentCell); } if (noErrors) @@ -71,36 +59,71 @@ object eval(object input) } } } + else + { + result = copyObject(input); + } deleteObject(input); return result; } -object apply(object function, object parameters) +object apply(object procedure, object parameters) { object result; - if (TYPE(function) != symbolObject) + if (TYPE(procedure) != procedureObject) { - deleteObject(function); TYPE(result) = errorObject; ERR(result) = notApplicableError; + return result; } - else if (symbolExists(SYM(function))) + + object(*f)() = PROC_BUILTIN(procedure); + if (PROC_TYPE(procedure) == builtinProc) { - object(*f)(); - if ((f = internalFunction(SYM(function))) != NULL) - { - result = f(parameters); - } + result = f(parameters); + return result; } - else + + object args = copyObject(PROC_COMP_ARGS(procedure)); + object body = copyObject(PROC_COMP_BODY(procedure)); + if (listLength(parameters) != listLength(args)) { - deleteObject(function); TYPE(result) = errorObject; - ERR(result) = unrecognizedSymbolError; + ERR(result) = argumentNumberError; + return result; } + if (!createTable()) + { + deleteObject(args); + deleteObject(body); + TYPE(result) = errorObject; + ERR(result) = maxRecursionDepthError; + return result; + } + object *currentArg = &args; + object *currentParam = ¶meters; + while (TYPE(*currentArg) != nilObject) + { + addSymbolVariable(SYM(CAR(*currentArg)), CAR(*currentParam)); + currentArg = &CDR(*currentArg); + currentParam = &CDR(*currentParam); + } + object *currentSubProc = &body; + while (TYPE(*currentSubProc) != nilObject) + { + CAR(*currentSubProc) = eval(CAR(*currentSubProc)); + if (TYPE(CDR(*currentSubProc)) == nilObject) + { + result = CAR(*currentSubProc); + } + currentSubProc = &CDR(*currentSubProc); + } + deleteObject(args); + deleteObject(body); + removeTable(); + return result; } - diff --git a/init.c b/init.c index 6f91274..17bf6d7 100644 --- a/init.c +++ b/init.c @@ -16,6 +16,7 @@ void init() /* Омогућава библиотекама коришћеним у интерпретеру да протумаче српску * ћирилицу */ + createTableStack(1000); addSymbolInternal("+", &add); addSymbolInternal("-", &subtract); addSymbolInternal("*", &multiply); diff --git a/internals.c b/internals.c index e9d2422..7f935ed 100644 --- a/internals.c +++ b/internals.c @@ -206,6 +206,11 @@ object define(object parameters) addSymbolVariable(SYM(result), eval(copyObject(CAR(CDR(parameters))))); } + else + { + TYPE(result) = errorObject; + ERR(result) = typeError; + } return result; } diff --git a/print.c b/print.c index 46a673c..128e3fe 100644 --- a/print.c +++ b/print.c @@ -17,7 +17,7 @@ void printValue(object input); void print(object input) { - if (input.type == errorObject) + if (TYPE(input) == errorObject) { fprintf(stderr, "\nГРЕШКА: %s\n\n", errors[ERR(input)]); } @@ -31,11 +31,11 @@ void print(object input) void printValue(object input) { - if (input.type == nilObject) + if (TYPE(input) == nilObject) { printf("()"); } - else if (input.type == numberObject) + else if (TYPE(input) == numberObject) { if (NUM_TYPE(input) == fractionNum) { @@ -50,11 +50,16 @@ void printValue(object input) printf("%LF", NUM_REAL(input)); } } - else if (input.type == symbolObject) + else if (TYPE(input) == procedureObject) + { + printf("<процедура:%s>", PROC_TYPE(input) == builtinProc ? + "уграђена" : "сложена"); + } + else if (TYPE(input) == symbolObject) { printf("%s", SYM(input)); } - else if (input.type == consObject) + else if (TYPE(input) == consObject) { printf("("); object *currentCell = &input; diff --git a/symtable.c b/symtable.c index 7feee56..ad755d1 100644 --- a/symtable.c +++ b/symtable.c @@ -7,21 +7,25 @@ typedef struct entry { - symbolType type; char *name; - union - { - object (*function)(); - object variable; - } value; + object value; struct entry *left; struct entry *right; } entry; -/* овај тип служи за имплементирање табеле симбола који могу бити дефинисани - * или путем интерне функције написане у интерпретеру, или је дефинисан - * коришћењем самог Ћирилисп интерпретера */ +/* овај тип служи за имплементирање табеле симбола који помажу да се стварају + * променљиве и процедуре у ћирилиспу */ -entry *root = NULL; +entry **tables = NULL; +#define GLOBALTABLE tables[0] +int currentTable = 0; +#define STACKMAX 1000 +/* динамички алоцирани стек табела симбола, где tables[0] означава глобалну + * табелу симбола, а сваки наредни члан означава табелу која постоји у + * контексту друге, већ постојеће. на пример, уколико имамо процедуру "ф" која + * у себи дефиинише и извршава процедуру "г", током извршавања "г", tables[0], + * [1] и [2] ће редом означавати: глобалну табелу, табелу процедуре "ф" и + * табелу процедуре "г", када је "г" евалуирано и ток контроле се пребацује на + * "ф", tables[2] се брише као и сви симболи дефинисани у њој */ entry **findEntry(entry **current, char *symbol) { @@ -51,27 +55,66 @@ entry **findEntry(entry **current, char *symbol) void freeEntry(entry **current) { free((*current)->name); - if ((*current)->type == variableSymbol) + deleteObject((*current)->value); +} + +void createTableStack(int size) +{ + tables = malloc(size * sizeof(entry *)); + tables[0] = NULL; + currentTable = 0; +} + +int createTable() +{ + if (currentTable >= STACKMAX) { - deleteObject((*current)->value.variable); + return 0; + } + else + { + tables[++currentTable] = NULL; + return 1; } } -symbolType typeOf(char *symbol) +void removeTableAux(entry **table) { - entry **e = findEntry(&root, symbol); - - return (*e)->type; + free((*table)->name); + deleteObject((*table)->value); + if ((*table)->left != NULL) + { + removeTableAux(&(*table)->left); + free((*table)->left); + (*table)->left = NULL; + } + if ((*table)->right != NULL) + { + removeTableAux(&(*table)->right); + free((*table)->right); + (*table)->right = NULL; + } } -int addSymbolInternal(char *symbol, object (*function)()) +int removeTable() { - int status = 1; - entry **e = findEntry(&root, symbol); + if (currentTable <= 0) + { + return 0; + } + else + { + removeTableAux(&tables[currentTable--]); + return 1; + } +} + +void addSymbolInternal(char *symbol, object (*function)()) +{ + entry **e = findEntry(&GLOBALTABLE, symbol); if (*e != NULL) { - status = 0; freeEntry(e); } else @@ -79,23 +122,21 @@ int addSymbolInternal(char *symbol, object (*function)()) *e = malloc(sizeof(entry)); } - (*e)->type = internalSymbol; + TYPE((*e)->value) = procedureObject; + PROC((*e)->value) = malloc(sizeof(procedure)); + PROC_TYPE((*e)->value) = builtinProc; + PROC_BUILTIN((*e)->value) = function; (*e)->name = malloc(sizeof(char) * (strlen(symbol) + 1)); strcpy((*e)->name, symbol); - (*e)->value.function = function; (*e)->left = (*e)->right = NULL; - - return status; } -int addSymbolVariable(char *symbol, object variable) +void addSymbolVariable(char *symbol, object variable) { - int status = 1; - entry **e = findEntry(&root, symbol); + entry **e = findEntry(&tables[currentTable], symbol); if (*e != NULL) { - status = 0; freeEntry(e); } else @@ -103,60 +144,58 @@ int addSymbolVariable(char *symbol, object variable) *e = malloc(sizeof(entry)); } - (*e)->type = variableSymbol; + (*e)->value = copyObject(variable); (*e)->name = malloc(sizeof(char) * (strlen(symbol) + 1)); strcpy((*e)->name, symbol); - (*e)->value.variable = copyObject(variable); (*e)->left = (*e)->right = NULL; - - return status; } -int symbolExists(char *symbol) +int symbolExistsAux(int index, char *symbol) { - int status = 1; - entry **e = findEntry(&root, symbol); + entry **e = findEntry(&tables[index], symbol); if (*e == NULL) { + if (index != 0) + { + return symbolExistsAux(index - 1, symbol); + } return 0; } else { return 1; } - - return status; } -object (*internalFunction(char *symbol)) (object) +int symbolExists(char *symbol) { - entry **e = findEntry(&root, symbol); - - if (*e == NULL || (*e)->type != internalSymbol) - { - return NULL; - } - else - { - return ((*e)->value.function); - } + return symbolExistsAux(currentTable, symbol); } -object referVariable(char *symbol) +object referVariableAux(int index, char *symbol) { object result; - entry **e = findEntry(&root, symbol); + entry **e = findEntry(&tables[index], symbol); - if (*e == NULL || (*e)->type != variableSymbol) + if (*e == NULL) { + if (index != 0) + { + return referVariableAux(index - 1, symbol); + } TYPE(result) = errorObject; ERR(result) = unrecognizedSymbolError; } else { - result = (*e)->value.variable; + result = (*e)->value; } return result; } + +object referVariable(char *symbol) +{ + return referVariableAux(currentTable, symbol); +} diff --git a/symtable.h b/symtable.h index 7279eb9..e29c4be 100644 --- a/symtable.h +++ b/symtable.h @@ -2,25 +2,18 @@ #include "util.h" -typedef enum -{ - internalSymbol, - variableSymbol -} symbolType; +void createTableStack(int size); +int createTable(); +int removeTable(); -int addSymbolInternal(char *symbol, object (*function)()); -int addSymbolVariable(char *symbol, object variable); -/* служе за различите методе дефинисања нових симбола у језику - * враћају 1 уколико је нови симбол успешно додат, а 0 уколико није - * (постоји симбол са истим именом) */ +void addSymbolInternal(char *symbol, object (*function)()); +void addSymbolVariable(char *symbol, object variable); +/* функције помоћу којих се дефинишу нове променљиве: addSymbolVariable се + * позива током корисничких дефиниција у програму, док се addSymbolInternal + * користи у init.c да би се дефинисале "уграђене" процедуре */ int symbolExists(char *symbol); /* враћа 1 уколико симбол постоји и 0 у супротном */ -symbolType typeOf(char *symbol); -object (*internalFunction(char *symbol)) (object parameters); -/* враћа показивач на функцију уколико је симбол дефинисан као интерна - * функција, NULL уколико симбол није функција или уколико не постоји - * */ object referVariable(char *symbol); /* враћа вредност на коју се односи име симбола у табели */ diff --git a/util.c b/util.c index ee1f280..c355876 100644 --- a/util.c +++ b/util.c @@ -50,11 +50,19 @@ int listLength(object list) void deleteObject(object input) { - if ((TYPE(input) == symbolObject) && SYM(input) != NULL) + if (TYPE(input) == symbolObject && SYM(input) != NULL) { free(SYM(input)); SYM(input) = NULL; } + else if (TYPE(input) == procedureObject && + PROC_TYPE(input) == compoundProc) + { + deleteObject(PROC_COMP_ARGS(input)); + deleteObject(PROC_COMP_BODY(input)); + free(PROC(input)); + PROC(input) = NULL; + } else if (TYPE(input) == consObject) { deleteObject(CAR(input)); diff --git a/util.h b/util.h index 37bd0b1..c93169b 100644 --- a/util.h +++ b/util.h @@ -8,6 +8,12 @@ #define SYM(x) ((x).value.symbol) #define ERR(x) ((x).value.err) +#define PROC(x) ((x).value.proc) +#define PROC_TYPE(x) ((x).value.proc->type) +#define PROC_BUILTIN(x) ((x).value.proc->value.builtin) +#define PROC_COMP_ARGS(x) ((x).value.proc->value.compound.args) +#define PROC_COMP_BODY(x) ((x).value.proc->value.compound.body) + #define NUM(x) ((x).value.num) #define NUM_TYPE(x) ((x).value.num.type) #define NUM_NUMER(x) ((x).value.num.value.fraction.numerator) @@ -20,6 +26,7 @@ typedef enum consObject, numberObject, symbolObject, + procedureObject, errorObject } dataType; @@ -31,19 +38,28 @@ typedef enum notApplicableError, divisionByZeroError, argumentNumberError, + maxRecursionDepthError, syntaxError } error; -typedef struct object object; -typedef struct cons cons; - typedef enum { fractionNum, realNum } numType; -typedef struct number +typedef enum +{ + builtinProc, + compoundProc +} procType; + +typedef struct number number; +typedef struct object object; +typedef struct cons cons; +typedef struct procedure procedure; + +struct number { numType type; union @@ -55,7 +71,7 @@ typedef struct number long long int denominator; } fraction; } value; -} number; +}; struct object { @@ -66,6 +82,7 @@ struct object char *symbol; cons *consCell; number num; + procedure *proc; } value; }; @@ -75,6 +92,20 @@ struct cons object cdr; }; +struct procedure +{ + procType type; + union + { + object (*builtin)(object); + struct + { + object args; + object body; + } compound; + } value; +}; + int isSpecialForm(char *symbol); int properList(object list); int listLength(object list);