Потпуно преправљена read функција и додати булеани, карактери и стрингови

This commit is contained in:
kappa 2019-02-03 18:57:49 +01:00
parent 5b5f792f5d
commit 916d3683ff
4 changed files with 536 additions and 375 deletions

91
print.c
View file

@ -10,7 +10,11 @@ char *errors[] =
"Објекат није примењив", "Објекат није примењив",
"Дељење нулом", "Дељење нулом",
"Функцији није прослеђен правилан број аргумената", "Функцији није прослеђен правилан број аргумената",
"Синтаксна грешка" "Пређена је максимална дубина рекурзије",
"Невалидан карактер",
"Невалидна тараба-секвенца",
"Неочекивани крај фајла",
"Неочекивана заграда",
}; };
void printValue(object input); void printValue(object input);
@ -21,7 +25,7 @@ void print(object input)
{ {
fprintf(stderr, "\nГРЕШКА: %s\n\n", errors[ERR(input)]); fprintf(stderr, "\nГРЕШКА: %s\n\n", errors[ERR(input)]);
} }
else else if (TYPE(input) != unspecifiedObject)
{ {
printf("\n"); printf("\n");
printValue(input); printValue(input);
@ -31,40 +35,12 @@ void print(object input)
void printValue(object input) void printValue(object input)
{ {
if (TYPE(input) == nilObject) switch (TYPE(input))
{ {
case nilObject:
printf("()"); printf("()");
} break;
else if (TYPE(input) == numberObject) case consObject:
{
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)
{
printf("("); printf("(");
object *currentCell = &input; object *currentCell = &input;
while (TYPE(*currentCell) == consObject) while (TYPE(*currentCell) == consObject)
@ -82,5 +58,52 @@ void printValue(object input)
printValue(*currentCell); printValue(*currentCell);
} }
printf(")"); 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;
} }
} }

740
read.c
View file

@ -1,353 +1,399 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
#include <ctype.h>
#include <string.h> #include <string.h>
#include <regex.h>
#include "util.h" #include "util.h"
#include "read.h" #include "read.h"
#include "print.h"
typedef enum int isSerbAlpha(wchar_t c);
{ int isConstituent(wchar_t c);
undefinedToken, int isMacroC(wchar_t c);
numberFracToken, int isEscape(wchar_t c);
numberRealToken,
symbolToken,
boolToken,
quoteToken,
lParenthesisToken,
rParenthesisToken
} tokenType;
typedef struct _Token wchar_t scanwc(FILE *stream);
{ #define unscanwc(c,stream) ungetwc(c,stream);
tokenType type; object getToken();
char *lexeme; object macroFunction(wchar_t m);
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;
object read(char *prompt) object read(char *prompt)
{ {
printf("%s", prompt); printf("%s", prompt);
while (!completeExpression(&tokenQueue)) wint_t c;
{
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(&regSpace, "^[[:space:]]*", REG_EXTENDED);
regcomp(&regTokenGeneral,"^(\\(|\\)|'|[-,.+/*_\\\\=<>!&?[: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(&regSpace, input + i, nmatches, a, 0);
i += a[0].rm_eo;
/* помера индекс да би се игнорисали почетни "вајт-спејс" карактери */
while (i < n)
{
*new = malloc(sizeof(token));
(*new)->next = NULL;
if (!regexec(&regTokenGeneral, 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(&regSpace, input + i, nmatches, a, 0);
i += a[0].rm_eo;
new = &((*new)->next);
}
/* у овој петљи су нађени сви токени у реду и њихови лексеми су копирани у
* листу, међутим још није одређен њихов тип, нити чак то да су валидни */
regcomp(&regNumberFrac, "^[-+]?[[:digit:]]+(/[[:digit:]]+)?$",
REG_EXTENDED);
regcomp(&regNumberReal, "^[-+]?[[:digit:]]*,[[:digit:]]+$",
REG_EXTENDED);
regcomp(&regSymbol, "^([-+/*_\\\\=<>!&?[:alnum:]]+|\
\\|[[:print:]]+\\|)$", REG_EXTENDED);
regcomp(&regQuote, "^'$", REG_EXTENDED);
regcomp(&regLParenthesis, "^\\($", REG_EXTENDED);
regcomp(&regRParenthesis, "^\\)$", REG_EXTENDED);
regcomp(&regDot, "^\\.$", REG_EXTENDED);
regcomp(&regBool, "^(истинито|лажно)$", REG_EXTENDED);
new = &root;
while ((*new) != NULL)
{
if (!regexec(&regNumberFrac, (*new)->lexeme, nmatches, a, 0))
{
(*new)->type = numberFracToken;
}
else if (!regexec(&regNumberReal, (*new)->lexeme, nmatches, a,
0))
{
(*new)->type = numberRealToken;
}
else if (!regexec(&regBool, (*new)->lexeme, nmatches, a, 0))
{
(*new)->type = boolToken;
}
else if (!regexec(&regSymbol, (*new)->lexeme, nmatches, a, 0))
{
(*new)->type = symbolToken;
}
else if (!regexec(&regQuote, (*new)->lexeme, nmatches, a, 0))
{
(*new)->type = quoteToken;
}
else if (!regexec(&regLParenthesis, (*new)->lexeme, nmatches,
a, 0))
{
(*new)->type = lParenthesisToken;
}
else if (!regexec(&regRParenthesis, (*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)
{
object result; object result;
token input = **inputList; while (iswspace(c = scanwc(stdin)))
free(*inputList); ;
*inputList = input.next; 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; TYPE(result) = numberObject;
NUM_TYPE(result) = fractionNum; NUM_TYPE(result) = fractionNum;
NUM_NUMER(result) = atoll(input.lexeme); NUM_NUMER(result) = atoll(s);
char *tmp; char *tmp;
NUM_DENOM(result) = (tmp = strchr(input.lexeme, '/')) == NULL ? NUM_DENOM(result) = (tmp = strchr(s, '/')) == NULL ?
1 : atoll(tmp + 1); 1 : atoll(tmp + 1);
result = shortenFractionNum(result); result = shortenFractionNum(result);
} }
else if (input.type == boolToken) else if (isRealNumToken(s))
{
TYPE(result) = boolObject;
BOOL(result) = !strcmp("истинито", input.lexeme) ? 1 : 0;
}
else if (input.type == numberRealToken)
{ {
TYPE(result) = numberObject; TYPE(result) = numberObject;
NUM_TYPE(result) = realNum; 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; TYPE(result) = symbolObject;
SYM(result) = malloc((strlen(input.lexeme) + 1) SYM(result) = malloc((strlen(s) + 1) * sizeof(char));
* sizeof(char)); strcpy(SYM(result), s);
/* Алокација стринга */
strcpy(SYM(result), input.lexeme);
} }
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; CHR(result) = c;
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;
} }
else else
{ {
TYPE(result) = errorObject; unscanwc(c, stdin);
ERR(result) = syntaxError; 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);
}
} }
break;
/* уколико "'" оператер директно претходи затвореној загради није могуће case L'И':
* правилно га претворити у навод оператер стога се он изоставља из било којег case L'и':
* израза */ TYPE(result) = boolObject;
} BOOL(result) = 1;
else if (input.type == lParenthesisToken) break;
{ case L'Л':
object *listCurrent = &result; case L'л':
TYPE(result) = boolObject;
while ((*inputList)->type != rParenthesisToken) BOOL(result) = 0;
break;
case L'|':
for (;;)
{ {
TYPE(*listCurrent) = consObject;
CONS(*listCurrent) = malloc(sizeof(cons));
/* Алокација конс ћелије */
CAR(*listCurrent) = parseExpression(inputList); if ((c = scanwc(stdin)) == L'|' &&
(c = scanwc(stdin)) == L'#')
listCurrent = &CDR(*listCurrent); {
break;
}
} }
TYPE(result) = unspecifiedObject;
break;
default:
SIGERR(invalidHashSequenceError);
break;
}
TYPE(*listCurrent) = nilObject; return result;
}
input = **inputList; object macroFunction(wchar_t m)
free(*inputList); {
*inputList = input.next; 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; int noErrors = 1;
listCurrent = &result; listCurrent = &result;
@ -357,21 +403,81 @@ object parseExpression(token **inputList)
if (TYPE(CAR(*listCurrent)) == errorObject) if (TYPE(CAR(*listCurrent)) == errorObject)
{ {
noErrors = 0; noErrors = 0;
break;
} }
listCurrent = &CDR(*listCurrent); listCurrent = &CDR(*listCurrent);
} }
if (!noErrors) if (!noErrors)
{ {
object error = copyObject(CAR(*listCurrent));
deleteObject(result); deleteObject(result);
TYPE(result) = errorObject; SIGERR(ERR(error));
ERR(result) = syntaxError;
} }
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; return result;
} }

56
util.c
View file

@ -56,6 +56,11 @@ void deleteObject(object input)
free(SYM(input)); free(SYM(input));
SYM(input) = NULL; SYM(input) = NULL;
} }
else if (TYPE(input) == stringObject && STR(input) != NULL)
{
free(STR(input));
STR(input) = NULL;
}
else if (TYPE(input) == procedureObject && else if (TYPE(input) == procedureObject &&
PROC_TYPE(input) == compoundProc) PROC_TYPE(input) == compoundProc)
{ {
@ -79,32 +84,22 @@ object copyObject(object input)
{ {
object result; object result;
TYPE(result) = TYPE(input); TYPE(result) = TYPE(input);
if (TYPE(input) == errorObject) switch (TYPE(input))
{
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)
{ {
case consObject:
CONS(result) = malloc(sizeof(cons)); CONS(result) = malloc(sizeof(cons));
CAR(result) = copyObject(CAR(input)); CAR(result) = copyObject(CAR(input));
CDR(result) = copyObject(CDR(input)); CDR(result) = copyObject(CDR(input));
} break;
else if (TYPE(input) == boolObject) case numberObject:
{ NUM(result) = NUM(input);
BOOL(result) = BOOL(input); break;
} case symbolObject:
else if (TYPE(input) == procedureObject) SYM(result) =
{ malloc(sizeof(char) * (strlen(SYM(input)) + 1));
strcpy(SYM(result), SYM(input));
break;
case procedureObject:
PROC(result) = malloc(sizeof(procedure)); PROC(result) = malloc(sizeof(procedure));
PROC_TYPE(result) = PROC_TYPE(input); PROC_TYPE(result) = PROC_TYPE(input);
if (PROC_TYPE(result) == builtinProc) if (PROC_TYPE(result) == builtinProc)
@ -118,6 +113,23 @@ object copyObject(object input)
PROC_COMP_BODY(result) = PROC_COMP_BODY(result) =
copyObject(PROC_COMP_BODY(input)); 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; return result;

22
util.h
View file

@ -1,14 +1,26 @@
#pragma once #pragma once
#include <wchar.h>
#define TYPE(x) ((x).type) #define TYPE(x) ((x).type)
#define CONS(x) ((x).value.consCell) #define CONS(x) ((x).value.consCell)
#define CAR(x) (((x).value.consCell)->car) #define CAR(x) (((x).value.consCell)->car)
#define CDR(x) (((x).value.consCell)->cdr) #define CDR(x) (((x).value.consCell)->cdr)
#define SYM(x) ((x).value.symbol) #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 BOOL(x) ((x).value.boolean)
#define ERR(x) ((x).value.err) #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(x) ((x).value.proc)
#define PROC_TYPE(x) ((x).value.proc->type) #define PROC_TYPE(x) ((x).value.proc->type)
#define PROC_BUILTIN(x) ((x).value.proc->value.builtin) #define PROC_BUILTIN(x) ((x).value.proc->value.builtin)
@ -24,11 +36,14 @@
typedef enum typedef enum
{ {
nilObject, nilObject,
unspecifiedObject,
consObject, consObject,
numberObject, numberObject,
symbolObject, symbolObject,
procedureObject, procedureObject,
boolObject, boolObject,
stringObject,
charObject,
errorObject errorObject
} dataType; } dataType;
@ -41,7 +56,10 @@ typedef enum
divisionByZeroError, divisionByZeroError,
argumentNumberError, argumentNumberError,
maxRecursionDepthError, maxRecursionDepthError,
syntaxError invalidCharacterError,
invalidHashSequenceError,
unexpectedEOFError,
unmatchedParenError,
} error; } error;
typedef enum typedef enum
@ -82,6 +100,8 @@ struct object
{ {
error err; error err;
char *symbol; char *symbol;
char *string;
wchar_t character;
cons *consCell; cons *consCell;
number num; number num;
procedure *proc; procedure *proc;