Потпуно преправљена 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);
@ -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;
}
}

740
read.c
View file

@ -1,353 +1,399 @@
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
#include <ctype.h>
#include <string.h>
#include <regex.h>
#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(&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)
{
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);
}
else if (input.type == symbolToken)
{
TYPE(result) = symbolObject;
SYM(result) = malloc((strlen(input.lexeme) + 1)
* sizeof(char));
/* Алокација стринга */
strcpy(SYM(result), input.lexeme);
}
else if (input.type == quoteToken)
{
if ((*inputList)->type != rParenthesisToken)
{
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;
NUM_REAL(result) = strtold(s, NULL);
}
else
{
TYPE(result) = errorObject;
ERR(result) = syntaxError;
TYPE(result) = symbolObject;
SYM(result) = malloc((strlen(s) + 1) * sizeof(char));
strcpy(SYM(result), s);
}
/* уколико "'" оператер директно претходи затвореној загради није могуће
* правилно га претворити у навод оператер стога се он изоставља из било којег
* израза */
return result;
}
else if (input.type == lParenthesisToken)
wchar_t escapedWChar(wchar_t c)
{
object *listCurrent = &result;
switch (c)
{
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;
}
}
while ((*inputList)->type != rParenthesisToken)
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))
{
CHR(result) = c;
}
else
{
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);
}
}
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 (;;)
{
if ((c = scanwc(stdin)) == L'|' &&
(c = scanwc(stdin)) == L'#')
{
break;
}
}
TYPE(result) = unspecifiedObject;
break;
default:
SIGERR(invalidHashSequenceError);
break;
}
return result;
}
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) = parseExpression(inputList);
CAR(*listCurrent) = copyObject(currentObject);
listCurrent = &CDR(*listCurrent);
}
TYPE(*listCurrent) = nilObject;
input = **inputList;
free(*inputList);
*inputList = input.next;
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));
}
}
else if (input.type == rParenthesisToken)
return result;
break;
case L')':
SIGERR(unmatchedParenError);
break;
case L'\'':
case L'`':
expression = read("");
if (TYPE(expression) == errorObject)
{
TYPE(result) = errorObject;
ERR(result) = syntaxError;
return expression;
}
free(input.lexeme);
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;
}
return result;
}

56
util.c
View file

@ -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;

22
util.h
View file

@ -1,14 +1,26 @@
#pragma once
#include <wchar.h>
#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;