From 916d3683ff8ae48d6ae0a740db462f511e303b62 Mon Sep 17 00:00:00 2001 From: kappa Date: Sun, 3 Feb 2019 18:57:49 +0100 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=BE=D1=82=D0=BF=D1=83=D0=BD=D0=BE=20?= =?UTF-8?q?=D0=BF=D1=80=D0=B5=D0=BF=D1=80=D0=B0=D0=B2=D1=99=D0=B5=D0=BD?= =?UTF-8?q?=D0=B0=20read=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D1=98?= =?UTF-8?q?=D0=B0=20=D0=B8=20=D0=B4=D0=BE=D0=B4=D0=B0=D1=82=D0=B8=20=D0=B1?= =?UTF-8?q?=D1=83=D0=BB=D0=B5=D0=B0=D0=BD=D0=B8,=20=D0=BA=D0=B0=D1=80?= =?UTF-8?q?=D0=B0=D0=BA=D1=82=D0=B5=D1=80=D0=B8=20=D0=B8=20=D1=81=D1=82?= =?UTF-8?q?=D1=80=D0=B8=D0=BD=D0=B3=D0=BE=D0=B2=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- print.c | 91 ++++--- read.c | 742 ++++++++++++++++++++++++++++++++------------------------ util.c | 56 +++-- util.h | 22 +- 4 files changed, 536 insertions(+), 375 deletions(-) diff --git a/print.c b/print.c index 8facbfb..90391c7 100644 --- a/print.c +++ b/print.c @@ -10,7 +10,11 @@ char *errors[] = "Објекат није примењив", "Дељење нулом", "Функцији није прослеђен правилан број аргумената", - "Синтаксна грешка" + "Пређена је максимална дубина рекурзије", + "Невалидан карактер", + "Невалидна тараба-секвенца", + "Неочекивани крај фајла", + "Неочекивана заграда", }; void printValue(object input); @@ -21,7 +25,7 @@ void print(object input) { fprintf(stderr, "\nГРЕШКА: %s\n\n", errors[ERR(input)]); } - else + else if (TYPE(input) != unspecifiedObject) { printf("\n"); printValue(input); @@ -31,40 +35,12 @@ void print(object input) void printValue(object input) { - if (TYPE(input) == nilObject) + switch (TYPE(input)) { + case nilObject: printf("()"); - } - else if (TYPE(input) == numberObject) - { - if (NUM_TYPE(input) == fractionNum) - { - printf("%lld", NUM_NUMER(input)); - if (NUM_DENOM(input) != 1) - { - printf("/%lld", NUM_DENOM(input)); - } - } - else - { - printf("%LF", NUM_REAL(input)); - } - } - else if (TYPE(input) == procedureObject) - { - printf("<процедура:%s>", PROC_TYPE(input) == builtinProc ? - "уграђена" : "сложена"); - } - else if (TYPE(input) == symbolObject) - { - printf("%s", SYM(input)); - } - else if (TYPE(input) == boolObject) - { - printf("#%s", BOOL(input) ? "истинито" : "лажно"); - } - else if (TYPE(input) == consObject) - { + break; + case consObject: printf("("); object *currentCell = &input; while (TYPE(*currentCell) == consObject) @@ -82,5 +58,52 @@ void printValue(object input) printValue(*currentCell); } printf(")"); + break; + case numberObject: + if (NUM_TYPE(input) == fractionNum) + { + printf("%lld", NUM_NUMER(input)); + if (NUM_DENOM(input) != 1) + { + printf("/%lld", NUM_DENOM(input)); + } + } + else + { + printf("%LF", NUM_REAL(input)); + } + break; + case symbolObject: + printf("%s", SYM(input)); + break; + case procedureObject: + printf("<процедура:%s>", PROC_TYPE(input) == builtinProc ? + "уграђена" : "сложена"); + break; + case boolObject: + printf("#%s", BOOL(input) ? "и" : "л"); + break; + case stringObject: + printf("\"%s\"", STR(input)); + break; + case charObject: + printf("#\\"); + switch (CHR(input)) + { + case L' ': + printf("размак"); + break; + case L'\n': + printf("новиред"); + break; + case L'\t': + printf("табулар"); + break; + default: + printf("%lc", CHR(input)); + } + break; + default: + break; } } diff --git a/read.c b/read.c index cb61ead..1ecdca6 100644 --- a/read.c +++ b/read.c @@ -1,353 +1,399 @@ #include #include +#include +#include +#include #include -#include #include "util.h" #include "read.h" -#include "print.h" -typedef enum -{ - undefinedToken, - numberFracToken, - numberRealToken, - symbolToken, - boolToken, - quoteToken, - lParenthesisToken, - rParenthesisToken -} tokenType; +int isSerbAlpha(wchar_t c); +int isConstituent(wchar_t c); +int isMacroC(wchar_t c); +int isEscape(wchar_t c); -typedef struct _Token -{ - tokenType type; - char *lexeme; - struct _Token *next; -} token; - -int completeExpression(token **tokenQueue); -char *readline(); -void append(token **head, token *appendix); -token *lexLine(char *input); -object parseExpression(token **inputList); - -token *tokenQueue = NULL; +wchar_t scanwc(FILE *stream); +#define unscanwc(c,stream) ungetwc(c,stream); +object getToken(); +object macroFunction(wchar_t m); object read(char *prompt) { printf("%s", prompt); - while (!completeExpression(&tokenQueue)) - { - char *input = readline(); - if (input == NULL) /* унесен је EOF */ - { - printf("\nКрај улазног стрима.\nВоЗдра и дођите нам\ - опет!\n"); - exit(0); - } - append(&tokenQueue, lexLine(input)); - } - - return parseExpression(&tokenQueue); -} - -int completeExpression(token **tokenQueue) -{ - int result = 0, indentLevel = 0; - token *current = *tokenQueue; - - while (current != NULL) - { - if (current->type == lParenthesisToken) - { - ++indentLevel; - } - else if (current->type == rParenthesisToken) - { - if (indentLevel == 0) - { - token **deleteParen = tokenQueue; - while (*deleteParen != current) - { - deleteParen = &(*deleteParen)->next; - } - *deleteParen = current->next; - free(current); - current = *deleteParen; - continue; - } - else - { - if (indentLevel == 1) - { - result = 1; - } - --indentLevel; - } - } - else - { - if (indentLevel == 0 && current->type != quoteToken) - { - result = 1; - } - } - current = current->next; - } - return result; -} - -ssize_t bytesRead; -size_t nbytes = 2048; -char *buffer = NULL; - -char *readline() -{ - if (buffer == NULL) - { - buffer = (char *) malloc(nbytes + 1); - } - bytesRead = getline(&buffer, &nbytes, stdin); - if (bytesRead == -1) - { - return NULL; - } - - buffer[strlen(buffer)-1] = '\0'; - /* Уклања завршни њу-лајн или ЕОФ у стрингу - * и копира стринг на ново место */ - - return buffer; -} - -void append(token **head, token *tail) -{ - token **current = head; - - while (*current != NULL) - { - current = &(*current)->next; - } - *current = tail; -} - - - -void deleteTokenList(token *root) -{ - if (root->lexeme != NULL) - { - free(root->lexeme); - } - - if (root->next != NULL) - { - deleteTokenList(root->next); - } - - free(root); -} - -token *lexLine(char *input) -{ - regex_t regSpace, regTokenGeneral, regNumberFrac, regNumberReal, - regLParenthesis, regRParenthesis, regSymbol, regQuote, regDot, - regBool; - - regcomp(®Space, "^[[:space:]]*", REG_EXTENDED); - regcomp(®TokenGeneral,"^(\\(|\\)|'|[-,.+/*_\\\\=<>!&?[:alnum:]]+|\ -\\|[[:print:]]+\\||\"[[:print:]]+\")", REG_EXTENDED); - - const int nmatches = 1; - regmatch_t a[nmatches]; - - token *root = NULL, **new; - new = &root; - - int i = 0, n; - n = strlen(input); - regexec(®Space, input + i, nmatches, a, 0); - i += a[0].rm_eo; -/* помера индекс да би се игнорисали почетни "вајт-спејс" карактери */ - while (i < n) - { - *new = malloc(sizeof(token)); - (*new)->next = NULL; - - if (!regexec(®TokenGeneral, input + i, nmatches, a, 0)) - { - (*new)->lexeme = malloc((a[0].rm_eo + 1) * - sizeof(char)); - strncpy((*new)->lexeme, input + i, a[0].rm_eo); - (*new)->lexeme[a[0].rm_eo] = '\0'; - i += a[0].rm_eo; - } - else - { -/* уколико се у реду нађе карактер који се не може прихватити, штампа се место - * тог каракетера у реду и бришу се сви токени тог реда, функција враћа NULL*/ - fprintf(stderr, "Невалидан карактер на месту %d\n", i); - (*new)->lexeme = NULL; - deleteTokenList(root); - return NULL; - } - regexec(®Space, input + i, nmatches, a, 0); - i += a[0].rm_eo; - new = &((*new)->next); - } -/* у овој петљи су нађени сви токени у реду и њихови лексеми су копирани у - * листу, међутим још није одређен њихов тип, нити чак то да су валидни */ - - regcomp(®NumberFrac, "^[-+]?[[:digit:]]+(/[[:digit:]]+)?$", - REG_EXTENDED); - regcomp(®NumberReal, "^[-+]?[[:digit:]]*,[[:digit:]]+$", - REG_EXTENDED); - regcomp(®Symbol, "^([-+/*_\\\\=<>!&?[:alnum:]]+|\ -\\|[[:print:]]+\\|)$", REG_EXTENDED); - regcomp(®Quote, "^'$", REG_EXTENDED); - regcomp(®LParenthesis, "^\\($", REG_EXTENDED); - regcomp(®RParenthesis, "^\\)$", REG_EXTENDED); - regcomp(®Dot, "^\\.$", REG_EXTENDED); - regcomp(®Bool, "^(истинито|лажно)$", REG_EXTENDED); - - new = &root; - while ((*new) != NULL) - { - if (!regexec(®NumberFrac, (*new)->lexeme, nmatches, a, 0)) - { - (*new)->type = numberFracToken; - } - else if (!regexec(®NumberReal, (*new)->lexeme, nmatches, a, - 0)) - { - (*new)->type = numberRealToken; - } - else if (!regexec(®Bool, (*new)->lexeme, nmatches, a, 0)) - { - (*new)->type = boolToken; - } - else if (!regexec(®Symbol, (*new)->lexeme, nmatches, a, 0)) - { - (*new)->type = symbolToken; - } - else if (!regexec(®Quote, (*new)->lexeme, nmatches, a, 0)) - { - (*new)->type = quoteToken; - } - else if (!regexec(®LParenthesis, (*new)->lexeme, nmatches, - a, 0)) - { - (*new)->type = lParenthesisToken; - } - else if (!regexec(®RParenthesis, (*new)->lexeme, nmatches, - a, 0)) - { - (*new)->type = rParenthesisToken; - } - else - { -/* уколико се неки токен не може класификовати, штампа се лексем тог токена, - * бришу се сви нађени токени у реду, и враћа се NULL */ - fprintf(stderr, "Невалидан токен:\"%s\"\n", - (*new)->lexeme); - deleteTokenList(root); - return NULL; - } - new = &((*new)->next); - } - - return root; -} - -object parseExpression(token **inputList) -{ + wint_t c; object result; - token input = **inputList; - free(*inputList); - *inputList = input.next; - /* скида први преостали токен са листе унесених, да би се могао - * прерадити */ + while (iswspace(c = scanwc(stdin))) + ; + if (isMacroC(c)) + { + result = macroFunction(c); + } + else if (isEscape(c) || isConstituent(c)) + { + unscanwc(c, stdin); + result = getToken(); + } + else + { + SIGERR(invalidCharacterError); + } - if (input.type == numberFracToken) + if (TYPE(result) == unspecifiedObject) + { + return read(""); +/* уколико улаз функције није прави објекат (на пример уколико је учитан + * коментар) покушавамо прочитати опет */ + } + else + { + return result; + } +} + +int isSerbAlpha(wchar_t c) +{ + return ((c) == L'Ђ') || (((c) >= L'Ј') && ((c) <= L'Ћ')) || + (((c) >= L'Џ') && ((c) <= L'И')) || (((c) >= L'К') && + ((c) <= L'Ш')) || (((c) >= L'а') && ((c) <= L'и')) || + (((c) >= L'к') && ((c) <= L'ш')) || ((c) == L'ђ') || + ((c >= L'ј') && (c <= L'ћ')) || (c == L'џ'); +} + +int isConstituent(wchar_t c) +{ + return isSerbAlpha(c) || iswdigit(c) || ((c) == L'!') || ((c) == L'$') + || ((c) == L'&') || ((c) == L'*') || ((c) == L'+') || + (((c) >= L'-') && ((c) <= L'/')) || (((c) >= L'<') && + ((c) <= L'@')) || ((c) == L'^') || ((c) == L'\\') || + ((c) == L'_') || ((c) == L'~') || ((c) == L','); +} + +int isMacroC(wchar_t c) +{ + return ((c) == L'"') || ((c) == L'#') || ((c) == L'\'') || + ((c) == L'(') || ((c) == L')') || ((c) == L';') || + ((c) == L'`'); +} + +int isEscape(wchar_t c) +{ + return (c) == L'|'; +} + +int bufferSize = 1024; +wchar_t *globalBuffer = NULL; + +wchar_t *getBuffer() +{ + if (globalBuffer == NULL) + { + globalBuffer = malloc(bufferSize * sizeof(wchar_t)); + } + + return globalBuffer; +} + +wchar_t *increaseBuffer() +{ + bufferSize += 1024; + return realloc(globalBuffer, bufferSize); +} + +wchar_t scanwc(FILE *stream) +{ + wint_t c; + + if ((c = fgetwc(stream)) == WEOF) + { + printf("\nКрај улазног стрима.\nВоЗдра и дођите нам опет!\n"); + exit(0); + } + else + { + return c; + } +} + +int lengthDigitArray(char *s) +{ + int i; + for (i = 0; isdigit(s[i]); ++i) + ; + return i; +} + +int isFracNumToken(char *s) +{ + int digitNum1 = lengthDigitArray(s); + + if (digitNum1 == 0) + { + return 0; + } + else if (s[digitNum1] == '\0') + { + return 1; + } + else if (s[digitNum1] == '/') + { + int digitNum2 = lengthDigitArray(s + digitNum1 + 1); + + if (digitNum2 == 0) + { + return 0; + } + else if (s[digitNum1 + 1 + digitNum2] == '\0') + { + return 1; + } + else + { + return 0; + } + } + else + { + return 0; + } +} + +int isRealNumToken(char *s) +{ + int digitNum1 = lengthDigitArray(s); + + if (digitNum1 == 0) + { + return 0; + } + else if (s[digitNum1] == '\0') + { + return 1; + } + else if (s[digitNum1] == ',') + { + int digitNum2 = lengthDigitArray(s + digitNum1 + 1); + + if (digitNum2 == 0) + { + return 0; + } + else if (s[digitNum1 + 1 + digitNum2] == '\0') + { + return 1; + } + else + { + return 0; + } + } + else + { + return 0; + } +} + +object getToken() +{ + object result; + wchar_t *buffer = getBuffer(); + wint_t c; + int i = 0; + buffer[0] = c = scanwc(stdin); + if (isEscape(c)) + { + while (!isEscape(c = scanwc(stdin))) + { + if (i + 2 >= bufferSize) + { + increaseBuffer(); + } + buffer[++i] = c; + } + + buffer[++i] = c; + buffer[++i] = L'\0'; + } + else + { + while (isConstituent(c = scanwc(stdin))) + { + if (i + 1 >= bufferSize) + { + increaseBuffer(); + } + buffer[++i] = towlower(c); + } + unscanwc(c, stdin); + buffer[++i] = L'\0'; + } + + int n = wcstombs(NULL, buffer, 0) + 1; + char *s = malloc(n * sizeof(char)); + wcstombs(s, buffer, n); + + if (isFracNumToken(s)) { TYPE(result) = numberObject; NUM_TYPE(result) = fractionNum; - NUM_NUMER(result) = atoll(input.lexeme); + NUM_NUMER(result) = atoll(s); char *tmp; - NUM_DENOM(result) = (tmp = strchr(input.lexeme, '/')) == NULL ? + NUM_DENOM(result) = (tmp = strchr(s, '/')) == NULL ? 1 : atoll(tmp + 1); - result = shortenFractionNum(result); } - else if (input.type == boolToken) - { - TYPE(result) = boolObject; - BOOL(result) = !strcmp("истинито", input.lexeme) ? 1 : 0; - } - else if (input.type == numberRealToken) + else if (isRealNumToken(s)) { TYPE(result) = numberObject; NUM_TYPE(result) = realNum; - NUM_REAL(result) = strtold(input.lexeme, NULL); + NUM_REAL(result) = strtold(s, NULL); } - else if (input.type == symbolToken) + else { TYPE(result) = symbolObject; - SYM(result) = malloc((strlen(input.lexeme) + 1) - * sizeof(char)); - /* Алокација стринга */ - strcpy(SYM(result), input.lexeme); + SYM(result) = malloc((strlen(s) + 1) * sizeof(char)); + strcpy(SYM(result), s); } - else if (input.type == quoteToken) + + return result; +} + +wchar_t escapedWChar(wchar_t c) +{ + switch (c) { - if ((*inputList)->type != rParenthesisToken) + case L'n': + return L'\n'; + break; + case L't': + return L'\t'; + break; + case L'\\': + return L'\\'; + break; + case L'"': + return L'"'; + break; + default: + return c; + break; + } +} + +object dispatchedChar(wchar_t c) +{ + object result; + + switch (c) + { + case L'\\': + TYPE(result) = charObject; + + wchar_t *buffer = getBuffer(); + int i = 0, n; + + c = scanwc(stdin); + if (!isConstituent(c)) { - TYPE(result) = consObject; - CONS(result) = malloc(sizeof(cons)); - TYPE(CAR(result)) = symbolObject; - SYM(CAR(result)) = malloc((strlen("навод") + 1) - * sizeof(char)); - strcpy(SYM(CAR(result)), "навод"); - - TYPE(CDR(result)) = consObject; - CONS(CDR(result)) = malloc(sizeof(cons)); - CAR(CDR(result)) = parseExpression(inputList); - - TYPE(CDR(CDR(result))) = nilObject; + CHR(result) = c; } else { - TYPE(result) = errorObject; - ERR(result) = syntaxError; + unscanwc(c, stdin); + while (!iswspace(c = scanwc(stdin))) + { + if (i + 1 >= bufferSize) + { + increaseBuffer(); + } + buffer[i++] = c; + } + buffer[i] = L'\0'; + n = wcslen(buffer); + if (n == 1) + { + CHR(result) = buffer[0]; + } + else if (!wcscmp(buffer, L"размак")) + { + CHR(result) = L' '; + } + else if (!wcscmp(buffer, L"новиред")) + { + CHR(result) = L'\n'; + } + else if (!wcscmp(buffer, L"табулар")) + { + CHR(result) = L'\t'; + } + else + { + SIGERR(invalidHashSequenceError); + } } - -/* уколико "'" оператер директно претходи затвореној загради није могуће - * правилно га претворити у навод оператер стога се он изоставља из било којег - * израза */ - } - else if (input.type == lParenthesisToken) - { - object *listCurrent = &result; - - while ((*inputList)->type != rParenthesisToken) + break; + case L'И': + case L'и': + TYPE(result) = boolObject; + BOOL(result) = 1; + break; + case L'Л': + case L'л': + TYPE(result) = boolObject; + BOOL(result) = 0; + break; + case L'|': + for (;;) { - TYPE(*listCurrent) = consObject; - CONS(*listCurrent) = malloc(sizeof(cons)); - /* Алокација конс ћелије */ - - CAR(*listCurrent) = parseExpression(inputList); - - listCurrent = &CDR(*listCurrent); + + if ((c = scanwc(stdin)) == L'|' && + (c = scanwc(stdin)) == L'#') + { + break; + } } + TYPE(result) = unspecifiedObject; + break; + default: + SIGERR(invalidHashSequenceError); + break; + } - TYPE(*listCurrent) = nilObject; + return result; +} - input = **inputList; - free(*inputList); - *inputList = input.next; +object macroFunction(wchar_t m) +{ + object result; + object *listCurrent; + object expression; + wchar_t *buffer; + + switch (m) + { + case L'(': + listCurrent = &result; + for (;;) + { + object currentObject = read(""); + if (TYPE(currentObject) == errorObject && + ERR(currentObject) == unmatchedParenError) + { + TYPE(*listCurrent) = nilObject; + break; + } + else + { + TYPE(*listCurrent) = consObject; + CONS(*listCurrent) = malloc(sizeof(cons)); + CAR(*listCurrent) = copyObject(currentObject); + + listCurrent = &CDR(*listCurrent); + } + deleteObject(currentObject); + } int noErrors = 1; listCurrent = &result; @@ -357,21 +403,81 @@ object parseExpression(token **inputList) if (TYPE(CAR(*listCurrent)) == errorObject) { noErrors = 0; + break; } listCurrent = &CDR(*listCurrent); } if (!noErrors) { + object error = copyObject(CAR(*listCurrent)); deleteObject(result); - TYPE(result) = errorObject; - ERR(result) = syntaxError; + SIGERR(ERR(error)); } + + return result; + break; + case L')': + SIGERR(unmatchedParenError); + break; + case L'\'': + case L'`': + expression = read(""); + if (TYPE(expression) == errorObject) + { + return expression; + } + + TYPE(result) = consObject; + CONS(result) = malloc(sizeof(cons)); + TYPE(CAR(result)) = symbolObject; + SYM(CAR(result)) = malloc((strlen("навод") + 1) * + sizeof(char)); + strcpy(SYM(CAR(result)), "навод"); + + TYPE(CDR(result)) = consObject; + CONS(CDR(result)) = malloc(sizeof(cons)); + CAR(CDR(result)) = expression; + + TYPE(CDR(CDR(result))) = nilObject; + break; + case L';': + TYPE(result) = unspecifiedObject; + while (scanwc(stdin) != L'\n') + ; + break; + case L'"': + buffer = getBuffer(); + wchar_t c; + int i = 0; + + while ((c = scanwc(stdin)) != L'"') + { + if (i + 2 >= bufferSize) + { + increaseBuffer(); + } + if (c == L'\\') + { + c = scanwc(stdin); + buffer[i++] = escapedWChar(c); + } + else + { + buffer[i++] = c; + } + } + buffer[i] = L'\0'; + + int n = wcstombs(NULL, buffer, 0) + 1; + char *s = malloc(n * sizeof(char)); + wcstombs(s, buffer, n); + TYPE(result) = stringObject; + STR(result) = s; + break; + case L'#': + result = dispatchedChar(scanwc(stdin)); + break; } - else if (input.type == rParenthesisToken) - { - TYPE(result) = errorObject; - ERR(result) = syntaxError; - } - free(input.lexeme); + return result; } diff --git a/util.c b/util.c index 073648f..33eab3e 100644 --- a/util.c +++ b/util.c @@ -56,6 +56,11 @@ void deleteObject(object input) free(SYM(input)); SYM(input) = NULL; } + else if (TYPE(input) == stringObject && STR(input) != NULL) + { + free(STR(input)); + STR(input) = NULL; + } else if (TYPE(input) == procedureObject && PROC_TYPE(input) == compoundProc) { @@ -79,32 +84,22 @@ object copyObject(object input) { object result; TYPE(result) = TYPE(input); - if (TYPE(input) == errorObject) - { - ERR(result) = ERR(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) + switch (TYPE(input)) { + case consObject: CONS(result) = malloc(sizeof(cons)); CAR(result) = copyObject(CAR(input)); CDR(result) = copyObject(CDR(input)); - } - else if (TYPE(input) == boolObject) - { - BOOL(result) = BOOL(input); - } - else if (TYPE(input) == procedureObject) - { + break; + case numberObject: + NUM(result) = NUM(input); + break; + case symbolObject: + SYM(result) = + malloc(sizeof(char) * (strlen(SYM(input)) + 1)); + strcpy(SYM(result), SYM(input)); + break; + case procedureObject: PROC(result) = malloc(sizeof(procedure)); PROC_TYPE(result) = PROC_TYPE(input); if (PROC_TYPE(result) == builtinProc) @@ -118,6 +113,23 @@ object copyObject(object input) PROC_COMP_BODY(result) = copyObject(PROC_COMP_BODY(input)); } + break; + case boolObject: + BOOL(result) = BOOL(input); + break; + case stringObject: + STR(result) = + malloc(sizeof(char) * (strlen(STR(input)) + 1)); + strcpy(STR(result), STR(input)); + break; + case charObject: + CHR(result) = CHR(input); + break; + case errorObject: + ERR(result) = ERR(input); + break; + default: + break; } return result; diff --git a/util.h b/util.h index 4a2711c..50d3402 100644 --- a/util.h +++ b/util.h @@ -1,14 +1,26 @@ #pragma once +#include + #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 SYM(x) ((x).value.symbol) +#define STR(x) ((x).value.string) +#define CHR(x) ((x).value.character) #define BOOL(x) ((x).value.boolean) #define ERR(x) ((x).value.err) +#define SIGERR(error) \ +{\ + object result;\ + TYPE(result) = errorObject;\ + ERR(result) = error;\ + return result;\ +} + #define PROC(x) ((x).value.proc) #define PROC_TYPE(x) ((x).value.proc->type) #define PROC_BUILTIN(x) ((x).value.proc->value.builtin) @@ -24,11 +36,14 @@ typedef enum { nilObject, + unspecifiedObject, consObject, numberObject, symbolObject, procedureObject, boolObject, + stringObject, + charObject, errorObject } dataType; @@ -41,7 +56,10 @@ typedef enum divisionByZeroError, argumentNumberError, maxRecursionDepthError, - syntaxError + invalidCharacterError, + invalidHashSequenceError, + unexpectedEOFError, + unmatchedParenError, } error; typedef enum @@ -82,6 +100,8 @@ struct object { error err; char *symbol; + char *string; + wchar_t character; cons *consCell; number num; procedure *proc;