Потпуно преправљена read функција и додати булеани, карактери и стрингови
This commit is contained in:
parent
5b5f792f5d
commit
916d3683ff
91
print.c
91
print.c
|
@ -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
740
read.c
|
@ -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(®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)
|
|
||||||
{
|
|
||||||
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
56
util.c
|
@ -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
22
util.h
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue