Имплементирана табела симбола и иницијална функција
This commit is contained in:
parent
b28b911ac3
commit
508e5fc9e1
4
Makefile
4
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)
|
||||
|
|
16
cirilisp.c
16
cirilisp.c
|
@ -1,25 +1,13 @@
|
|||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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("ШКЉ> ")));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
169
eval.c
169
eval.c
|
@ -3,6 +3,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
|
23
init.c
Normal file
23
init.c
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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("/", ÷);
|
||||
}
|
137
internals.c
Normal file
137
internals.c
Normal file
|
@ -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;
|
||||
}
|
6
internals.h
Normal file
6
internals.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
object add(object parameters);
|
||||
object subtract(object parameters);
|
||||
object multiply(object parameters);
|
||||
object divide(object parameters);
|
130
symtable.c
Normal file
130
symtable.c
Normal file
|
@ -0,0 +1,130 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
17
symtable.h
Normal file
17
symtable.h
Normal file
|
@ -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 уколико симбол није функција или уколико не постоји
|
||||
* */
|
Loading…
Reference in a new issue