Merged SRS and de-linted code
This commit is contained in:
parent
233aa9481d
commit
78456aabfd
6
Makefile
6
Makefile
|
@ -5,6 +5,7 @@ SRCS = lexer.c tokenizer.c parser.c interpreter.c unicode.c main.c
|
|||
HDRS = lexer.h tokenizer.h parser.h interpreter.h unicode.h
|
||||
INSTALL = /usr/local/bin/install -c
|
||||
CPPFLAGS = -O3
|
||||
LINT = splint -nullret -temptrans -compdestroy -usereleased -compdef -compmempass -mustfreefresh -boolops -predboolint -nullpass -nullderef +boolint -predboolothers -uniondef -unqualifiedtrans -nullstate -bufferoverflowhigh -branchstate -mustfreeonly -nullassign -shiftimplementation -exportlocal
|
||||
|
||||
prefix = /usr/local
|
||||
bindir = $(prefix)/bin
|
||||
|
@ -16,7 +17,10 @@ $(TARGET): $(OBJS) $(LIBS)
|
|||
$(CC) $(CPPFLAGS) -o $(TARGET) $(OBJS) $(LIBS)
|
||||
|
||||
pedantic: $(OBJS) $(LIBS)
|
||||
$(CC) -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wundef -W -Wall -ansi -pedantic -g -o $(TARGET) $(OBJS) $(LIBS)
|
||||
$(CC) -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wundef -Wall -ansi -pedantic -g -o $(TARGET) $(SRCS) $(HDRS) $(LIBS)
|
||||
|
||||
lint: all
|
||||
$(LINT) $(SRCS)
|
||||
|
||||
check: all
|
||||
@cd $(testdir) && ./testDir.sh -q ../$(TARGET) 1.3-Tests/
|
||||
|
|
329
interpreter.c
329
interpreter.c
|
@ -230,9 +230,68 @@ void deleteReturnObject(ReturnObject *object) /**< [in,out] The ReturnObject str
|
|||
free(object);
|
||||
}
|
||||
|
||||
/** Translates an identifier into a string naming a variable.
|
||||
*
|
||||
* \pre \a id was created by createIdentifierNode(IdentifierType, void *, const char *, unsigned int).
|
||||
* \pre \a scope was created by createScopeObject(ScopeObject *) and contains
|
||||
* contents added by createScopeValue(ScopeObject *, IdentifierNode *) and
|
||||
* contents updated by updateScopeValue(ScopeObject *, IdentifierNode *, ValueObject *).
|
||||
*
|
||||
* \return A newly-allocated array of characters representing the name of the
|
||||
* identifier.
|
||||
*
|
||||
* \retval NULL malloc was unable to allocate memory. */
|
||||
char *resolveIdentifierName(IdentifierNode *id, /**< [in] A pointer to the IdentifierNode structure to translate. */
|
||||
ScopeObject *scope) /**< [in] A pointer to the ScopeObject structure to translate \a id under. */
|
||||
{
|
||||
ValueObject *val = NULL;
|
||||
ValueObject *str = NULL;
|
||||
char *ret = NULL;
|
||||
|
||||
if (!id) goto resolveIdentifierNameAbort;
|
||||
|
||||
if (id->type == IT_DIRECT) {
|
||||
/* Just return a copy of the character array */
|
||||
const char *temp = (char *)(id->id);
|
||||
ret = malloc(sizeof(char) * (strlen(temp) + 1));
|
||||
strcpy(ret, temp);
|
||||
}
|
||||
else if (id->type == IT_INDIRECT) {
|
||||
ExprNode *expr = (ExprNode *)(id->id);
|
||||
|
||||
/* Interpret the identifier expression */
|
||||
val = interpretExprNode(expr, scope);
|
||||
if (!val) goto resolveIdentifierNameAbort;
|
||||
|
||||
/* Then cast it to a string */
|
||||
str = castStringExplicit(val, scope);
|
||||
if (!str) goto resolveIdentifierNameAbort;
|
||||
deleteValueObject(val);
|
||||
|
||||
/* Copy the evaluated string */
|
||||
ret = createString(getString(str));
|
||||
if (!ret) goto resolveIdentifierNameAbort;
|
||||
deleteValueObject(str);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "%s:%u: invalid identifier type\n", id->fname, id->line);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
resolveIdentifierNameAbort: /* Exception handline */
|
||||
|
||||
/* Clean up any allocated structures */
|
||||
if (ret) free(ret);
|
||||
if (str) deleteValueObject(str);
|
||||
if (val) deleteValueObject(val);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Creates a ScopeObject structure.
|
||||
*
|
||||
* \pre \a scope was created by createScopeObject(ScopeObject *) and contains
|
||||
* \pre \a parent was created by createScopeObject(ScopeObject *) and contains
|
||||
* contents added by createScopeValue(ScopeObject *, IdentifierNode *) and
|
||||
* contents updated by updateScopeValue(ScopeObject *, IdentifierNode *, ValueObject *)
|
||||
* or is \c NULL if creating the root parent.
|
||||
|
@ -242,7 +301,7 @@ void deleteReturnObject(ReturnObject *object) /**< [in,out] The ReturnObject str
|
|||
* \retval NULL malloc was unable to allocate memory.
|
||||
*
|
||||
* \see deleteScopeObject(ScopeObject *) */
|
||||
ScopeObject *createScopeObject(ScopeObject *parent) /**< [in] A pointer to the parent ScopeObject. */
|
||||
ScopeObject *createScopeObject(ScopeObject *parent) /**< [in] A pointer to the parent ScopeObject structure. */
|
||||
{
|
||||
ScopeObject *p = malloc(sizeof(ScopeObject));
|
||||
if (!p) {
|
||||
|
@ -276,8 +335,7 @@ void deleteScopeObject(ScopeObject *scope) /**< [in,out] The ScopeObject structu
|
|||
unsigned int n;
|
||||
if (!scope) return;
|
||||
for (n = 0; n < scope->numvals; n++) {
|
||||
/* The individual names are pointers to existing IdentifierNode
|
||||
* structures, so don't free them here. */
|
||||
free(scope->names[n]);
|
||||
deleteValueObject(scope->values[n]);
|
||||
}
|
||||
free(scope->names);
|
||||
|
@ -306,15 +364,24 @@ ValueObject *getScopeValue(ScopeObject *scope, /**< [in] The ScopeObject str
|
|||
IdentifierNode *target) /**< [in] The name of the value to find. */
|
||||
{
|
||||
ScopeObject *current = scope;
|
||||
char *name = NULL;
|
||||
|
||||
/* Look up the identifier name */
|
||||
name = resolveIdentifierName(target, scope);
|
||||
if (!name) return NULL;
|
||||
|
||||
/* Traverse upwards through scopes */
|
||||
do {
|
||||
unsigned int n;
|
||||
/* Check for value in current scope */
|
||||
for (n = 0; n < current->numvals; n++) {
|
||||
if (!strcmp(current->names[n]->image, target->image))
|
||||
if (!strcmp(current->names[n], name)) {
|
||||
free(name);
|
||||
return current->values[n];
|
||||
}
|
||||
}
|
||||
} while ((current = current->parent));
|
||||
free(name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -338,11 +405,20 @@ ValueObject *getLocalScopeValue(ScopeObject *scope, /**< [in] The ScopeObjec
|
|||
IdentifierNode *target) /**< [in] The name of the value to find. */
|
||||
{
|
||||
unsigned int n;
|
||||
char *name = NULL;
|
||||
|
||||
/* Look up the identifier name */
|
||||
name = resolveIdentifierName(target, scope);
|
||||
if (!name) return NULL;
|
||||
|
||||
/* Check for value in current scope */
|
||||
for (n = 0; n < scope->numvals; n++) {
|
||||
if (!strcmp(scope->names[n]->image, target->image))
|
||||
if (!strcmp(scope->names[n], name)) {
|
||||
free(name);
|
||||
return scope->values[n];
|
||||
}
|
||||
}
|
||||
free(name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -367,20 +443,28 @@ ValueObject *createScopeValue(ScopeObject *scope, /**< [in,out] The ScopeObj
|
|||
{
|
||||
unsigned int newnumvals = scope->numvals + 1;
|
||||
void *mem1 = NULL, *mem2 = NULL;
|
||||
char *name = NULL;
|
||||
|
||||
/* Look up the identifier name */
|
||||
name = resolveIdentifierName(target, scope);
|
||||
if (!name) return NULL;
|
||||
|
||||
/* Add value to local scope */
|
||||
mem1 = realloc(scope->names, sizeof(IdentifierNode *) * newnumvals);
|
||||
if (!mem1) {
|
||||
perror("realloc");
|
||||
free(name);
|
||||
return NULL;
|
||||
}
|
||||
mem2 = realloc(scope->values, sizeof(ValueObject *) * newnumvals);
|
||||
if (!mem2) {
|
||||
perror("realloc");
|
||||
free(name);
|
||||
return NULL;
|
||||
}
|
||||
scope->names = mem1;
|
||||
scope->values = mem2;
|
||||
scope->names[scope->numvals] = target;
|
||||
scope->names[scope->numvals] = name;
|
||||
scope->values[scope->numvals] = createNilValueObject();
|
||||
if (!scope->values[scope->numvals])
|
||||
return NULL;
|
||||
|
@ -414,12 +498,19 @@ ValueObject *updateScopeValue(ScopeObject *scope, /**< [in,out] A pointer to
|
|||
ValueObject *value) /**< [in] A pointer to the ValueObject structure containing the value to copy for the update. */
|
||||
{
|
||||
ScopeObject *current = scope;
|
||||
char *name = NULL;
|
||||
|
||||
/* Look up the identifier name */
|
||||
name = resolveIdentifierName(target, scope);
|
||||
if (!name) return NULL;
|
||||
|
||||
/* Traverse upwards through scopes */
|
||||
do {
|
||||
unsigned int n;
|
||||
/* Check for existing value in current scope */
|
||||
for (n = 0; n < current->numvals; n++) {
|
||||
if (!strcmp(current->names[n]->image, target->image)) {
|
||||
if (!strcmp(current->names[n], name)) {
|
||||
free(name);
|
||||
/* Wipe out the old value */
|
||||
deleteValueObject(current->values[n]);
|
||||
/* Assign the new value */
|
||||
|
@ -431,7 +522,8 @@ ValueObject *updateScopeValue(ScopeObject *scope, /**< [in,out] A pointer to
|
|||
}
|
||||
}
|
||||
} while ((current = current->parent));
|
||||
fprintf(stderr, "%s:%d: unable to store variable at: %s\n", target->fname, target->line, target->image);
|
||||
fprintf(stderr, "%s:%u: unable to store variable at: %s\n", target->fname, target->line, name);
|
||||
free(name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -451,15 +543,22 @@ void deleteScopeValue(ScopeObject *scope, /**< [in,out] A pointer to the Sco
|
|||
IdentifierNode *target) /**< [in] A pointer to the IdentifierNode structure containing the name of the value to delete. */
|
||||
{
|
||||
ScopeObject *current = scope;
|
||||
char *name = NULL;
|
||||
|
||||
/* Look up the identifier name */
|
||||
name = resolveIdentifierName(target, scope);
|
||||
if (!name) return;
|
||||
|
||||
/* Traverse upwards through scopes */
|
||||
do {
|
||||
unsigned int n;
|
||||
/* Check for existing value in current scope */
|
||||
for (n = 0; n < current->numvals; n++) {
|
||||
if (!strcmp(current->names[n]->image, target->image)) {
|
||||
if (!strcmp(current->names[n], name)) {
|
||||
unsigned int i;
|
||||
unsigned int newnumvals = scope->numvals - 1;
|
||||
void *mem1 = NULL, *mem2 = NULL;
|
||||
free(name);
|
||||
/* Don't delete anything in the names table
|
||||
* because it's just pointers to IdentifierNode
|
||||
* structures in the parse tree. */
|
||||
|
@ -488,6 +587,7 @@ void deleteScopeValue(ScopeObject *scope, /**< [in,out] A pointer to the Sco
|
|||
}
|
||||
}
|
||||
} while ((current = current->parent));
|
||||
free(name);
|
||||
}
|
||||
|
||||
/** Checks if a string of characters follows the format for a number.
|
||||
|
@ -496,8 +596,8 @@ void deleteScopeValue(ScopeObject *scope, /**< [in,out] A pointer to the Sco
|
|||
* \retval 1 The string of characters is a number. */
|
||||
unsigned int isNumString(const char *stringdata) /**< [in] The array of characters to check the format of. */
|
||||
{
|
||||
unsigned int n;
|
||||
unsigned int len = strlen(stringdata);
|
||||
size_t n;
|
||||
size_t len = strlen(stringdata);
|
||||
/* Check for empty string */
|
||||
if (len == 0) return 0;
|
||||
/* Check for non-digit, non-hyphen, and non-period characters */
|
||||
|
@ -517,8 +617,8 @@ unsigned int isNumString(const char *stringdata) /**< [in] The array of characte
|
|||
* \retval 1 The string of characters is a hexadecimal number. */
|
||||
unsigned int isHexString(const char *stringdata) /**< [in] The array of characters to check the format of. */
|
||||
{
|
||||
unsigned int n;
|
||||
unsigned int len = strlen(stringdata);
|
||||
size_t n;
|
||||
size_t len = strlen(stringdata);
|
||||
/* Check for empty string */
|
||||
if (len == 0) return 0;
|
||||
/* Check for non-digit and non-A-through-F characters */
|
||||
|
@ -687,7 +787,7 @@ ValueObject *castBooleanExplicit(ValueObject *node, /**< [in] The ValueObject s
|
|||
case VT_INTEGER:
|
||||
return createBooleanValueObject(getInteger(node) != 0);
|
||||
case VT_FLOAT:
|
||||
return createBooleanValueObject(getFloat(node) != 0.0);
|
||||
return createBooleanValueObject(fabs(getFloat(node) - 0.0) > FLT_EPSILON);
|
||||
case VT_STRING:
|
||||
if (strstr(getString(node), ":{")) {
|
||||
/* Perform interpolation */
|
||||
|
@ -700,9 +800,13 @@ ValueObject *castBooleanExplicit(ValueObject *node, /**< [in] The ValueObject s
|
|||
}
|
||||
else
|
||||
return createBooleanValueObject(getString(node)[0] != '\0');
|
||||
case VT_FUNC:
|
||||
fprintf(stderr, "Cannot cast functions to booleans\n");
|
||||
return NULL;
|
||||
default:
|
||||
fprintf(stderr, "Unknown value type encountered during boolean cast\n");
|
||||
return NULL;
|
||||
}
|
||||
fprintf(stderr, "Unknown value type encountered during boolean cast\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Casts the contents of a ValueObject structure to integer type in an
|
||||
|
@ -734,7 +838,7 @@ ValueObject *castIntegerExplicit(ValueObject *node, /**< [in] The ValueObject s
|
|||
case VT_INTEGER:
|
||||
return createIntegerValueObject(getInteger(node));
|
||||
case VT_FLOAT:
|
||||
return createIntegerValueObject(getFloat(node));
|
||||
return createIntegerValueObject((int)getFloat(node));
|
||||
case VT_STRING:
|
||||
if (strstr(getString(node), ":{")) {
|
||||
/* Perform interpolation */
|
||||
|
@ -747,7 +851,11 @@ ValueObject *castIntegerExplicit(ValueObject *node, /**< [in] The ValueObject s
|
|||
deleteValueObject(interp);
|
||||
return NULL;
|
||||
}
|
||||
sscanf(getString(interp), "%i", &value);
|
||||
if (sscanf(getString(interp), "%i", &value) != 1) {
|
||||
fprintf(stderr, "Expected integer value\n");
|
||||
deleteValueObject(interp);
|
||||
return NULL;
|
||||
}
|
||||
ret = createIntegerValueObject(value);
|
||||
deleteValueObject(interp);
|
||||
return ret;
|
||||
|
@ -758,12 +866,19 @@ ValueObject *castIntegerExplicit(ValueObject *node, /**< [in] The ValueObject s
|
|||
fprintf(stderr, "Unable to cast value\n");
|
||||
return NULL;
|
||||
}
|
||||
sscanf(getString(node), "%i", &value);
|
||||
if (sscanf(getString(node), "%i", &value) != 1) {
|
||||
fprintf(stderr, "Expected integer value\n");
|
||||
return NULL;
|
||||
}
|
||||
return createIntegerValueObject(value);
|
||||
}
|
||||
case VT_FUNC:
|
||||
fprintf(stderr, "Cannot cast functions to integers\n");
|
||||
return NULL;
|
||||
default:
|
||||
fprintf(stderr, "Unknown value type encountered during integer cast\n");
|
||||
return NULL;
|
||||
}
|
||||
fprintf(stderr, "Unknown value type encountered during integer cast\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Casts the contents of a ValueObject structure to floating point decimal
|
||||
|
@ -793,7 +908,7 @@ ValueObject *castFloatExplicit(ValueObject *node, /**< [in] The ValueObject str
|
|||
return createFloatValueObject(0.0);
|
||||
case VT_BOOLEAN:
|
||||
case VT_INTEGER:
|
||||
return createFloatValueObject(getInteger(node));
|
||||
return createFloatValueObject((float)getInteger(node));
|
||||
case VT_FLOAT:
|
||||
return createFloatValueObject(getFloat(node));
|
||||
case VT_STRING:
|
||||
|
@ -808,7 +923,11 @@ ValueObject *castFloatExplicit(ValueObject *node, /**< [in] The ValueObject str
|
|||
deleteValueObject(interp);
|
||||
return NULL;
|
||||
}
|
||||
sscanf(getString(interp), "%f", &value);
|
||||
if (sscanf(getString(interp), "%f", &value) != 1) {
|
||||
fprintf(stderr, "Expected floating point decimal value\n");
|
||||
deleteValueObject(interp);
|
||||
return NULL;
|
||||
}
|
||||
ret = createFloatValueObject(value);
|
||||
deleteValueObject(interp);
|
||||
return ret;
|
||||
|
@ -819,12 +938,19 @@ ValueObject *castFloatExplicit(ValueObject *node, /**< [in] The ValueObject str
|
|||
fprintf(stderr, "Unable to cast value\n");
|
||||
return NULL;
|
||||
}
|
||||
sscanf(getString(node), "%f", &value);
|
||||
if (sscanf(getString(node), "%f", &value) != 1) {
|
||||
fprintf(stderr, "Expected floating point decimal value\n");
|
||||
return NULL;
|
||||
}
|
||||
return createFloatValueObject(value);
|
||||
}
|
||||
case VT_FUNC:
|
||||
fprintf(stderr, "Cannot cast functions to floats\n");
|
||||
return NULL;
|
||||
default:
|
||||
fprintf(stderr, "Unknown value type encountered during floating point decimal cast\n");
|
||||
return NULL;
|
||||
}
|
||||
fprintf(stderr, "Unknown value type encountered during floating point decimal cast\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Casts the contents of a ValueObject structure to string type in an explicit
|
||||
|
@ -892,7 +1018,8 @@ ValueObject *castStringExplicit(ValueObject *node, /**< [in] The ValueObject st
|
|||
char *temp = NULL;
|
||||
char *data = NULL;
|
||||
char *str = getString(node);
|
||||
unsigned int a, b, size;
|
||||
unsigned int a, b;
|
||||
size_t size;
|
||||
/* Perform interpolation */
|
||||
size = strlen(getString(node)) + 1;
|
||||
temp = malloc(sizeof(char) * size);
|
||||
|
@ -920,12 +1047,19 @@ ValueObject *castStringExplicit(ValueObject *node, /**< [in] The ValueObject st
|
|||
else if (!strncmp(str + b, ":(", 2)) {
|
||||
const char *start = str + b + 2;
|
||||
const char *end = strchr(start, ')');
|
||||
unsigned short len = end - start;
|
||||
char *image = malloc(sizeof(char) * (len + 1));
|
||||
size_t len;
|
||||
char *image = NULL;
|
||||
long codepoint;
|
||||
char out[3];
|
||||
unsigned short num;
|
||||
size_t num;
|
||||
void *mem = NULL;
|
||||
if (end < start) {
|
||||
fprintf(stderr, "Expected closing parenthesis after :(\n");
|
||||
free(temp);
|
||||
return NULL;
|
||||
}
|
||||
len = (size_t)(end - start);
|
||||
image = malloc(sizeof(char) * (len + 1));
|
||||
strncpy(image, start, len);
|
||||
image[len] = '\0';
|
||||
if (!isHexString(image)) {
|
||||
|
@ -936,7 +1070,12 @@ ValueObject *castStringExplicit(ValueObject *node, /**< [in] The ValueObject st
|
|||
}
|
||||
codepoint = strtol(image, NULL, 16);
|
||||
free(image);
|
||||
num = convertCodePointToUTF8(codepoint, out);
|
||||
if (codepoint < 0) {
|
||||
fprintf(stderr, "Code point is supposed to be positive\n");
|
||||
free(temp);
|
||||
return NULL;
|
||||
}
|
||||
num = convertCodePointToUTF8((unsigned int)codepoint, out);
|
||||
if (num == 0) {
|
||||
free(temp);
|
||||
return NULL;
|
||||
|
@ -955,22 +1094,30 @@ ValueObject *castStringExplicit(ValueObject *node, /**< [in] The ValueObject st
|
|||
else if (!strncmp(str + b, ":[", 2)) {
|
||||
const char *start = str + b + 2;
|
||||
const char *end = strchr(start, ']');
|
||||
unsigned short len = end - start;
|
||||
char *image = malloc(sizeof(char) * (len + 1));
|
||||
size_t len;
|
||||
char *image = NULL;
|
||||
long codepoint;
|
||||
char out[3];
|
||||
unsigned short num;
|
||||
size_t num;
|
||||
void *mem = NULL;
|
||||
if (end < start) {
|
||||
fprintf(stderr, "Expected closing square bracket after :[\n");
|
||||
free(temp);
|
||||
return NULL;
|
||||
}
|
||||
len = (size_t)(end - start);
|
||||
image = malloc(sizeof(char) * (len + 1));
|
||||
strncpy(image, start, len);
|
||||
strncpy(image, start, len);
|
||||
image[len] = '\0';
|
||||
codepoint = convertNormativeNameToCodePoint(image);
|
||||
free(image);
|
||||
if (codepoint < 0) {
|
||||
fprintf(stderr, "Code point is supposed to be positive\n");
|
||||
free(temp);
|
||||
return NULL;
|
||||
}
|
||||
num = convertCodePointToUTF8(codepoint, out);
|
||||
num = convertCodePointToUTF8((unsigned int)codepoint, out);
|
||||
size += num;
|
||||
mem = realloc(temp, size);
|
||||
if (!mem) {
|
||||
|
@ -988,9 +1135,16 @@ ValueObject *castStringExplicit(ValueObject *node, /**< [in] The ValueObject st
|
|||
/* Copy the variable name into image */
|
||||
const char *start = str + b + 2;
|
||||
const char *end = strchr(start, '}');
|
||||
unsigned short len = end - start;
|
||||
char *image = malloc(sizeof(char) * (len + 1));
|
||||
size_t len;
|
||||
char *image = NULL;
|
||||
void *mem = NULL;
|
||||
if (end < start) {
|
||||
fprintf(stderr, "Expected closing curly brace after :{\n");
|
||||
free(temp);
|
||||
return NULL;
|
||||
}
|
||||
len = (size_t)(end - start);
|
||||
image = malloc(sizeof(char) * (len + 1));
|
||||
strncpy(image, start, len);
|
||||
image[len] = '\0';
|
||||
if (!strcmp(image, "IT"))
|
||||
|
@ -1000,7 +1154,7 @@ ValueObject *castStringExplicit(ValueObject *node, /**< [in] The ValueObject st
|
|||
/* Create a new IdentifierNode
|
||||
* structure and lookup its
|
||||
* value */
|
||||
target = createIdentifierNode(image, NULL, 0);
|
||||
target = createIdentifierNode(IT_DIRECT, image, NULL, 0);
|
||||
if (!target) {
|
||||
free(temp);
|
||||
return NULL;
|
||||
|
@ -1043,9 +1197,14 @@ ValueObject *castStringExplicit(ValueObject *node, /**< [in] The ValueObject st
|
|||
free(temp);
|
||||
return createStringValueObject(data);
|
||||
}
|
||||
case VT_FUNC: {
|
||||
fprintf(stderr, "Cannot cast functions to strings\n");
|
||||
return NULL;
|
||||
}
|
||||
default:
|
||||
fprintf(stderr, "Unknown value type encountered during string cast\n");
|
||||
return NULL;
|
||||
}
|
||||
fprintf(stderr, "Unknown value type encountered during string cast\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Interprets an implicit variable expression.
|
||||
|
@ -1157,14 +1316,22 @@ ValueObject *interpretFuncCallExprNode(ExprNode *node, /**< [in] A pointer t
|
|||
def = getScopeValue(scope, expr->name);
|
||||
if (!def || def->type != VT_FUNC) {
|
||||
IdentifierNode *id = (IdentifierNode *)(expr->name);
|
||||
fprintf(stderr, "%s:%d: undefined function at: %s\n", id->fname, id->line, id->image);
|
||||
char *name = resolveIdentifierName(id, scope);
|
||||
if (name) {
|
||||
fprintf(stderr, "%s:%u: undefined function at: %s\n", id->fname, id->line, name);
|
||||
free(name);
|
||||
}
|
||||
deleteScopeObject(outer);
|
||||
return NULL;
|
||||
}
|
||||
/* Check for correct supplied arity */
|
||||
if (getFunction(def)->args->num != expr->args->num) {
|
||||
IdentifierNode *id = (IdentifierNode *)(expr->name);
|
||||
fprintf(stderr, "%s:%d: incorrect number of arguments supplied to: %s\n", id->fname, id->line, id->image);
|
||||
char *name = resolveIdentifierName(id, scope);
|
||||
if (name) {
|
||||
fprintf(stderr, "%s:%u: incorrect number of arguments supplied to: %s\n", id->fname, id->line, name);
|
||||
free(name);
|
||||
}
|
||||
deleteScopeObject(outer);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1243,7 +1410,11 @@ ValueObject *interpretIdentifierExprNode(ExprNode *node, /**< [in] A pointer
|
|||
ValueObject *val = getScopeValue(scope, node->expr);
|
||||
if (!val) {
|
||||
IdentifierNode *id = (IdentifierNode *)(node->expr);
|
||||
fprintf(stderr, "%s:%d: variable does not exist at: %s\n", id->fname, id->line, id->image);
|
||||
char *name = resolveIdentifierName(id, scope);
|
||||
if (name) {
|
||||
fprintf(stderr, "%s:%u: variable does not exist at: %s\n", id->fname, id->line, name);
|
||||
free(name);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
return copyValueObject(val);
|
||||
|
@ -1502,7 +1673,7 @@ ValueObject *opModIntegerInteger(ValueObject *a, /**< [in] The dividend. */
|
|||
ValueObject *opAddIntegerFloat(ValueObject *a, /**< [in] The first term to add. */
|
||||
ValueObject *b) /**< [in] The second term to add. */
|
||||
{
|
||||
return createFloatValueObject(getInteger(a) + getFloat(b));
|
||||
return createFloatValueObject((float)(getInteger(a) + getFloat(b)));
|
||||
}
|
||||
|
||||
/** Subtracts an integer and a float.
|
||||
|
@ -1522,7 +1693,7 @@ ValueObject *opAddIntegerFloat(ValueObject *a, /**< [in] The first term to add.
|
|||
ValueObject *opSubIntegerFloat(ValueObject *a, /**< [in] The minuend. */
|
||||
ValueObject *b) /**< [in] The subtrahend. */
|
||||
{
|
||||
return createFloatValueObject(getInteger(a) - getFloat(b));
|
||||
return createFloatValueObject((float)(getInteger(a) - getFloat(b)));
|
||||
}
|
||||
|
||||
/** Multiplies an integer and a float.
|
||||
|
@ -1542,7 +1713,7 @@ ValueObject *opSubIntegerFloat(ValueObject *a, /**< [in] The minuend. */
|
|||
ValueObject *opMultIntegerFloat(ValueObject *a, /**< [in] The first factor to multiply. */
|
||||
ValueObject *b) /**< [in] The second factor to multiply. */
|
||||
{
|
||||
return createFloatValueObject(getInteger(a) * getFloat(b));
|
||||
return createFloatValueObject((float)(getInteger(a) * getFloat(b)));
|
||||
}
|
||||
|
||||
/** Divides an integer and a float.
|
||||
|
@ -1564,11 +1735,11 @@ ValueObject *opMultIntegerFloat(ValueObject *a, /**< [in] The first factor to mu
|
|||
ValueObject *opDivIntegerFloat(ValueObject *a, /**< [in] The dividend. */
|
||||
ValueObject *b) /**< [in] The divisor. */
|
||||
{
|
||||
if (getFloat(b) == 0.0) {
|
||||
if (fabs(getFloat(b) - 0.0) < FLT_EPSILON) {
|
||||
fprintf(stderr, "Division by zero undefined\n");
|
||||
return NULL;
|
||||
}
|
||||
return createFloatValueObject(getInteger(a) / getFloat(b));
|
||||
return createFloatValueObject((float)(getInteger(a) / getFloat(b)));
|
||||
}
|
||||
|
||||
/** Finds the maximum of an integer and a float.
|
||||
|
@ -1588,7 +1759,7 @@ ValueObject *opDivIntegerFloat(ValueObject *a, /**< [in] The dividend. */
|
|||
ValueObject *opMaxIntegerFloat(ValueObject *a, /**< [in] The first number to compare. */
|
||||
ValueObject *b) /**< [in] The second number to compare. */
|
||||
{
|
||||
return createFloatValueObject(getInteger(a) > getFloat(b) ? getInteger(a) : getFloat(b));
|
||||
return createFloatValueObject((float)(getInteger(a)) > getFloat(b) ? (float)(getInteger(a)) : getFloat(b));
|
||||
}
|
||||
|
||||
/** Finds the minimum of an integer and a float.
|
||||
|
@ -1608,7 +1779,7 @@ ValueObject *opMaxIntegerFloat(ValueObject *a, /**< [in] The first number to com
|
|||
ValueObject *opMinIntegerFloat(ValueObject *a, /**< [in] The first number to compare. */
|
||||
ValueObject *b) /**< [in] The second number to compare. */
|
||||
{
|
||||
return createFloatValueObject(getInteger(a) < getFloat(b) ? getInteger(a) : getFloat(b));
|
||||
return createFloatValueObject((float)(getInteger(a)) < getFloat(b) ? (float)(getInteger(a)) : getFloat(b));
|
||||
}
|
||||
|
||||
/** Calculates the modulus of an integer and a float.
|
||||
|
@ -1628,11 +1799,11 @@ ValueObject *opMinIntegerFloat(ValueObject *a, /**< [in] The first number to com
|
|||
ValueObject *opModIntegerFloat(ValueObject *a, /**< [in] The dividend. */
|
||||
ValueObject *b) /**< [in] The divisor. */
|
||||
{
|
||||
if (getFloat(b) == 0.0) {
|
||||
if (fabs(getFloat(b) - 0.0) < FLT_EPSILON) {
|
||||
fprintf(stderr, "Division by zero undefined\n");
|
||||
return NULL;
|
||||
}
|
||||
return createFloatValueObject(fmod(getInteger(a), getFloat(b)));
|
||||
return createFloatValueObject((float)(fmod((double)(getInteger(a)), getFloat(b))));
|
||||
}
|
||||
|
||||
/** Adds a float and an integer.
|
||||
|
@ -1737,7 +1908,7 @@ ValueObject *opDivFloatInteger(ValueObject *a, /**< [in] The dividend. */
|
|||
ValueObject *opMaxFloatInteger(ValueObject *a, /**< [in] The first number to compare. */
|
||||
ValueObject *b) /**< [in] The second number to compare. */
|
||||
{
|
||||
return createFloatValueObject(getFloat(a) > getInteger(b) ? getFloat(a) : getInteger(b));
|
||||
return createFloatValueObject(getFloat(a) > (float)(getInteger(b)) ? getFloat(a) : (float)(getInteger(b)));
|
||||
}
|
||||
|
||||
/** Finds the minimum of a float and an integer.
|
||||
|
@ -1757,7 +1928,7 @@ ValueObject *opMaxFloatInteger(ValueObject *a, /**< [in] The first number to com
|
|||
ValueObject *opMinFloatInteger(ValueObject *a, /**< [in] The first number to compare. */
|
||||
ValueObject *b) /**< [in] The second number to compare. */
|
||||
{
|
||||
return createFloatValueObject(getFloat(a) < getInteger(b) ? getFloat(a) : getInteger(b));
|
||||
return createFloatValueObject(getFloat(a) < (float)(getInteger(b)) ? getFloat(a) : (float)(getInteger(b)));
|
||||
}
|
||||
|
||||
/** Calculates the modulus of a float and an integer.
|
||||
|
@ -1781,7 +1952,7 @@ ValueObject *opModFloatInteger(ValueObject *a, /**< [in] The dividend. */
|
|||
fprintf(stderr, "Division by zero undefined\n");
|
||||
return NULL;
|
||||
}
|
||||
return createFloatValueObject(fmod(getFloat(a), getInteger(b)));
|
||||
return createFloatValueObject((float)(fmod(getFloat(a), (double)(getInteger(b)))));
|
||||
}
|
||||
|
||||
/** Adds two floats.
|
||||
|
@ -1859,7 +2030,7 @@ ValueObject *opMultFloatFloat(ValueObject *a, /**< [in] The first factor to mult
|
|||
ValueObject *opDivFloatFloat(ValueObject *a, /**< [in] The dividend. */
|
||||
ValueObject *b) /**< [in] The divisor. */
|
||||
{
|
||||
if (getFloat(b) == 0.0) {
|
||||
if (fabs(getFloat(b) - 0.0) < FLT_EPSILON) {
|
||||
fprintf(stderr, "Division by zero undefined\n");
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1920,11 +2091,11 @@ ValueObject *opMinFloatFloat(ValueObject *a, /**< [in] The first number to compa
|
|||
ValueObject *opModFloatFloat(ValueObject *a, /**< [in] The dividend. */
|
||||
ValueObject *b) /**< [in] The divisor. */
|
||||
{
|
||||
if (getFloat(b) == 0.0) {
|
||||
if (fabs(getFloat(b) - 0.0) < FLT_EPSILON) {
|
||||
fprintf(stderr, "Division by zero undefined\n");
|
||||
return NULL;
|
||||
}
|
||||
return createFloatValueObject(fmod(getFloat(a), getFloat(b)));
|
||||
return createFloatValueObject((float)(fmod(getFloat(a), getFloat(b))));
|
||||
}
|
||||
|
||||
/* A jump table for arithmetic operations. The first index determines the
|
||||
|
@ -2096,7 +2267,7 @@ ValueObject *interpretBoolOpExprNode(OpExprNode *expr, /**< [in] A pointer to
|
|||
for (n = 0; n < expr->args->num; n++) {
|
||||
ValueObject *val = interpretExprNode(expr->args->exprs[n], scope);
|
||||
ValueObject *use = val;
|
||||
unsigned int temp;
|
||||
int temp;
|
||||
unsigned int cast = 0;
|
||||
if (!val) return NULL;
|
||||
if (val->type != VT_BOOLEAN && val->type != VT_INTEGER) {
|
||||
|
@ -2175,7 +2346,7 @@ ValueObject *opNeqIntegerInteger(ValueObject *a, /**< [in] The first value to te
|
|||
ValueObject *opEqIntegerFloat(ValueObject *a, /**< [in] The first value to test. */
|
||||
ValueObject *b) /**< [in] The second value to test. */
|
||||
{
|
||||
return createBooleanValueObject(getInteger(a) == getFloat(b));
|
||||
return createBooleanValueObject(fabs((float)(getInteger(a)) - getFloat(b)) < FLT_EPSILON);
|
||||
}
|
||||
|
||||
/** Tests if an integer and a float are not equal.
|
||||
|
@ -2190,7 +2361,7 @@ ValueObject *opEqIntegerFloat(ValueObject *a, /**< [in] The first value to test.
|
|||
ValueObject *opNeqIntegerFloat(ValueObject *a, /**< [in] The first value to test. */
|
||||
ValueObject *b) /**< [in] The second value to test. */
|
||||
{
|
||||
return createBooleanValueObject(getInteger(a) != getFloat(b));
|
||||
return createBooleanValueObject(fabs((float)(getInteger(a)) - getFloat(b)) > FLT_EPSILON);
|
||||
}
|
||||
|
||||
/** Tests if a float and an integer are equal.
|
||||
|
@ -2205,7 +2376,7 @@ ValueObject *opNeqIntegerFloat(ValueObject *a, /**< [in] The first value to test
|
|||
ValueObject *opEqFloatInteger(ValueObject *a, /**< [in] The first value to test. */
|
||||
ValueObject *b) /**< [in] The second value to test. */
|
||||
{
|
||||
return createBooleanValueObject(getFloat(a) == getInteger(b));
|
||||
return createBooleanValueObject(fabs(getFloat(a) - (float)(getInteger(b))) < FLT_EPSILON);
|
||||
}
|
||||
|
||||
/** Tests if a float and an integer are not equal.
|
||||
|
@ -2220,7 +2391,7 @@ ValueObject *opEqFloatInteger(ValueObject *a, /**< [in] The first value to test.
|
|||
ValueObject *opNeqFloatInteger(ValueObject *a, /**< [in] The first value to test. */
|
||||
ValueObject *b) /**< [in] The second value to test. */
|
||||
{
|
||||
return createBooleanValueObject(getFloat(a) != getInteger(b));
|
||||
return createBooleanValueObject(fabs(getFloat(a) - (float)(getInteger(b))) > FLT_EPSILON);
|
||||
}
|
||||
|
||||
/** Tests if two floats are equal.
|
||||
|
@ -2234,7 +2405,7 @@ ValueObject *opNeqFloatInteger(ValueObject *a, /**< [in] The first value to test
|
|||
ValueObject *opEqFloatFloat(ValueObject *a, /**< [in] The first value to test. */
|
||||
ValueObject *b) /**< [in] The second value to test. */
|
||||
{
|
||||
return createBooleanValueObject(getFloat(a) == getFloat(b));
|
||||
return createBooleanValueObject(fabs(getFloat(a) - getFloat(b)) < FLT_EPSILON);
|
||||
}
|
||||
|
||||
/** Tests if two floats are not equal.
|
||||
|
@ -2248,7 +2419,7 @@ ValueObject *opEqFloatFloat(ValueObject *a, /**< [in] The first value to test. *
|
|||
ValueObject *opNeqFloatFloat(ValueObject *a, /**< [in] The first value to test. */
|
||||
ValueObject *b) /**< [in] The second value to test. */
|
||||
{
|
||||
return createBooleanValueObject(getFloat(a) != getFloat(b));
|
||||
return createBooleanValueObject(fabs(getFloat(a) - getFloat(b)) > FLT_EPSILON);
|
||||
}
|
||||
|
||||
/** Tests if two boolean values are equal.
|
||||
|
@ -2608,7 +2779,11 @@ ReturnObject *interpretCastStmtNode(StmtNode *node, /**< [in] A pointer to t
|
|||
ValueObject *cast = NULL;
|
||||
if (!val) {
|
||||
IdentifierNode *id = (IdentifierNode *)(stmt->target);
|
||||
fprintf(stderr, "%s:%d: variable does not exist at: %s\n", id->fname, id->line, id->image);
|
||||
char *name = resolveIdentifierName(id, scope);
|
||||
if (name) {
|
||||
fprintf(stderr, "%s:%u: variable does not exist at: %s\n", id->fname, id->line, name);
|
||||
free(name);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
switch(stmt->newtype->type) {
|
||||
|
@ -2711,7 +2886,7 @@ ReturnObject *interpretInputStmtNode(StmtNode *node, /**< [in] A pointer to
|
|||
unsigned int size = 16;
|
||||
unsigned int cur = 0;
|
||||
char *temp = malloc(sizeof(char) * size);
|
||||
char c;
|
||||
int c;
|
||||
void *mem = NULL;
|
||||
InputStmtNode *stmt = (InputStmtNode *)node->stmt;
|
||||
ValueObject *val = NULL;
|
||||
|
@ -2719,7 +2894,7 @@ ReturnObject *interpretInputStmtNode(StmtNode *node, /**< [in] A pointer to
|
|||
/** \note The specification is unclear as to the exact semantics
|
||||
* of input. Here, we read up until the first newline or
|
||||
* EOF but do not store it. */
|
||||
if (c == EOF || c == '\r' || c == '\n') break;
|
||||
if (c == EOF || c == (int)'\r' || c == (int)'\n') break;
|
||||
if (cur > size - 1) {
|
||||
/* Increasing buffer size. */
|
||||
size *= 2;
|
||||
|
@ -2731,7 +2906,7 @@ ReturnObject *interpretInputStmtNode(StmtNode *node, /**< [in] A pointer to
|
|||
}
|
||||
temp = mem;
|
||||
}
|
||||
temp[cur] = c;
|
||||
temp[cur] = (char)c;
|
||||
cur++;
|
||||
}
|
||||
temp[cur] = '\0';
|
||||
|
@ -2815,7 +2990,11 @@ ReturnObject *interpretDeclarationStmtNode(StmtNode *node, /**< [in] A point
|
|||
ValueObject *init = NULL;
|
||||
if (getLocalScopeValue(scope, stmt->target)) {
|
||||
IdentifierNode *id = (IdentifierNode *)(stmt->target);
|
||||
fprintf(stderr, "%s:%d: redefinition of existing variable at: %s\n", id->fname, id->line, id->image);
|
||||
char *name = resolveIdentifierName(id, scope);
|
||||
if (name) {
|
||||
fprintf(stderr, "%s:%u: redefinition of existing variable at: %s\n", id->fname, id->line, name);
|
||||
free(name);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
if (stmt->expr)
|
||||
|
@ -2991,7 +3170,7 @@ ReturnObject *interpretSwitchStmtNode(StmtNode *node, /**< [in] A pointer to
|
|||
done = 1;
|
||||
break;
|
||||
case VT_FLOAT:
|
||||
if (getFloat(use1) == getFloat(use2))
|
||||
if (fabs(getFloat(use1) - getFloat(use2)) < FLT_EPSILON)
|
||||
done = 1;
|
||||
break;
|
||||
case VT_STRING:
|
||||
|
@ -3291,7 +3470,11 @@ ReturnObject *interpretFuncDefStmtNode(StmtNode *node, /**< Not used (see no
|
|||
ValueObject *init = NULL;
|
||||
if (getLocalScopeValue(scope, stmt->name)) {
|
||||
IdentifierNode *id = (IdentifierNode *)(stmt->name);
|
||||
fprintf(stderr, "%s:%d: function name already used by existing variable at: %s\n", id->fname, id->line, id->image);
|
||||
char *name = resolveIdentifierName(id, scope);
|
||||
if (name) {
|
||||
fprintf(stderr, "%s:%u: function name already used by existing variable at: %s\n", id->fname, id->line, name);
|
||||
free(name);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
init = createFunctionValueObject(stmt);
|
||||
|
|
|
@ -88,7 +88,7 @@ typedef struct scopeobject {
|
|||
struct scopeobject *parent; /**< A pointer to the parent ScopeObject. */
|
||||
ValueObject *impvar; /**< A pointer to the ValueObject representing the implicit variable for this scope. */
|
||||
unsigned int numvals; /**< The number of ValueObject structures in \a values. */
|
||||
IdentifierNode **names; /**< A pointer to the IdentifierNode structures naming the values in the scope. */
|
||||
char **names; /**< A pointer to the array of character strings naming the values in the scope. */
|
||||
ValueObject **values; /**< A pointer to an array of ValueObject structures in the scope. */
|
||||
} ScopeObject;
|
||||
|
||||
|
@ -103,6 +103,7 @@ ValueObject *copyValueObject(ValueObject *);
|
|||
void deleteValueObject(ValueObject *);
|
||||
ReturnObject *createReturnObject(ReturnType, ValueObject *);
|
||||
void deleteReturnObject(ReturnObject *);
|
||||
char *resolveIdentifierName(IdentifierNode *, ScopeObject *);
|
||||
ScopeObject *createScopeObject(ScopeObject *);
|
||||
void deleteScopeObject(ScopeObject *);
|
||||
ValueObject *getScopeValue(ScopeObject *, IdentifierNode *);
|
||||
|
|
19
lexer.c
19
lexer.c
|
@ -139,14 +139,15 @@ LexemeList *scanBuffer(const char *buffer, /**< [in] An array of characters to t
|
|||
const char *start = buffer;
|
||||
LexemeList *list = NULL;
|
||||
unsigned int line = 1;
|
||||
Lexeme *lex = NULL;
|
||||
list = createLexemeList();
|
||||
if (!list) return NULL;
|
||||
while (start < buffer + size) {
|
||||
char *temp = NULL;
|
||||
unsigned int len = 1;
|
||||
size_t len = 1;
|
||||
/* Comma (,) is a soft newline */
|
||||
if (*start == ',') {
|
||||
Lexeme *lex = createLexeme("\n", fname, line);
|
||||
lex = createLexeme("\n", fname, line);
|
||||
if (!lex) {
|
||||
deleteLexemeList(list);
|
||||
return NULL;
|
||||
|
@ -161,7 +162,7 @@ LexemeList *scanBuffer(const char *buffer, /**< [in] An array of characters to t
|
|||
}
|
||||
/* Bang (!) is its own lexeme */
|
||||
if (*start == '!') {
|
||||
Lexeme *lex = createLexeme("!", fname, line);
|
||||
lex = createLexeme("!", fname, line);
|
||||
if (!lex) {
|
||||
deleteLexemeList(list);
|
||||
return NULL;
|
||||
|
@ -186,7 +187,7 @@ LexemeList *scanBuffer(const char *buffer, /**< [in] An array of characters to t
|
|||
newline = 1;
|
||||
}
|
||||
if (newline) {
|
||||
Lexeme *lex = createLexeme("\n", fname, line);
|
||||
lex = createLexeme("\n", fname, line);
|
||||
if (!lex) {
|
||||
deleteLexemeList(list);
|
||||
return NULL;
|
||||
|
@ -212,7 +213,7 @@ LexemeList *scanBuffer(const char *buffer, /**< [in] An array of characters to t
|
|||
/* Make sure next line is not empty */
|
||||
while (*test && isspace(*test)) {
|
||||
if (*test == '\r' || *test == '\n') {
|
||||
fprintf(stderr, "%s:%d: a line with continuation may not be followed by an empty line\n", fname, line);
|
||||
fprintf(stderr, "%s:%u: a line with continuation may not be followed by an empty line\n", fname, line);
|
||||
deleteLexemeList(list);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -239,7 +240,7 @@ LexemeList *scanBuffer(const char *buffer, /**< [in] An array of characters to t
|
|||
start++;
|
||||
if (start == buffer || *start == ',' || *start == '\r' || *start == '\n')
|
||||
continue;
|
||||
fprintf(stderr, "%s:%d: multiple line comment may not appear on the same line as code\n", fname, line);
|
||||
fprintf(stderr, "%s:%u: multiple line comment may not appear on the same line as code\n", fname, line);
|
||||
deleteLexemeList(list);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -270,7 +271,7 @@ LexemeList *scanBuffer(const char *buffer, /**< [in] An array of characters to t
|
|||
&& *(start + len) != '!'
|
||||
&& strncmp(start + len, "...", 3)
|
||||
&& strncmp(start + len, "\xE2\x80\xA6", 3)) {
|
||||
fprintf(stderr, "%s:%d: expected token delimiter after string literal\n", fname, line);
|
||||
fprintf(stderr, "%s:%u: expected token delimiter after string literal\n", fname, line);
|
||||
deleteLexemeList(list);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -292,7 +293,7 @@ LexemeList *scanBuffer(const char *buffer, /**< [in] An array of characters to t
|
|||
}
|
||||
strncpy(temp, start, len);
|
||||
temp[len] = '\0';
|
||||
Lexeme *lex = createLexeme(temp, fname, line);
|
||||
lex = createLexeme(temp, fname, line);
|
||||
if (!lex) {
|
||||
free(temp);
|
||||
deleteLexemeList(list);
|
||||
|
@ -308,7 +309,7 @@ LexemeList *scanBuffer(const char *buffer, /**< [in] An array of characters to t
|
|||
start += len;
|
||||
}
|
||||
/* Create an end-of-file lexeme */
|
||||
Lexeme *lex = createLexeme("$", fname, line);
|
||||
lex = createLexeme("$", fname, line);
|
||||
if (!lex) {
|
||||
deleteLexemeList(list);
|
||||
return NULL;
|
||||
|
|
18
main.c
18
main.c
|
@ -96,7 +96,6 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include "lexer.h"
|
||||
|
@ -110,8 +109,8 @@ static char *program_name;
|
|||
|
||||
static char *shortopt = "hv";
|
||||
static struct option longopt[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, 'v' },
|
||||
{ "help", no_argument, NULL, (int)'h' },
|
||||
{ "version", no_argument, NULL, (int)'v' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
|
@ -129,8 +128,8 @@ static void version (char *revision) {
|
|||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
long size = 0;
|
||||
long length = 0;
|
||||
unsigned int size = 0;
|
||||
unsigned int length = 0;
|
||||
char *buffer = NULL;
|
||||
LexemeList *lexemes = NULL;
|
||||
Token **tokens = NULL;
|
||||
|
@ -148,12 +147,9 @@ int main(int argc, char **argv)
|
|||
fprintf (stderr, "Incorrect option '%c'\n", ch);
|
||||
help();
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
case 'h':
|
||||
help();
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
version(revision);
|
||||
exit(EXIT_SUCCESS);
|
||||
|
@ -188,7 +184,11 @@ int main(int argc, char **argv)
|
|||
length += fread((buffer + size) - READSIZE, 1, READSIZE, file);
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
if (fclose(file) != 0) {
|
||||
fprintf(stderr, "Error closing file.\n");
|
||||
if (buffer) free(buffer);
|
||||
return 1;
|
||||
}
|
||||
if (!buffer) return 1;
|
||||
buffer[length] = '\0';
|
||||
|
||||
|
|
263
parser.c
263
parser.c
|
@ -112,7 +112,10 @@ BlockNodeList *createBlockNodeList(void)
|
|||
* \a list will be updated accordingly.
|
||||
*
|
||||
* \retval 0 realloc was unable to allocate memory.
|
||||
* \retval 1 \a node was added to \a list. */
|
||||
* \retval 1 \a node was added to \a list.
|
||||
*
|
||||
* \see createBlockNodeList(void)
|
||||
* \see deleteBlockNodeList(BlockNodeList *) */
|
||||
int addBlockNode(BlockNodeList *list, /**< [in,out] A pointer to the BlockNodeList structure to add \a node to. */
|
||||
BlockNode *node) /**< [in] A pointer to the BlockNode structure to add to \a list. */
|
||||
{
|
||||
|
@ -245,9 +248,6 @@ void deleteConstantNode(ConstantNode *node) /**< [in,out] A pointer to the Const
|
|||
}
|
||||
|
||||
/** Creates an IdentifierNode structure.
|
||||
*
|
||||
* \note \a image is \b copied for use within the structure so it must be freed
|
||||
* by the caller.
|
||||
*
|
||||
* \return A pointer to an IdentifierNode structure with the desired
|
||||
* properties.
|
||||
|
@ -255,23 +255,25 @@ void deleteConstantNode(ConstantNode *node) /**< [in,out] A pointer to the Const
|
|||
* \retval NULL malloc was unable to allocate memory.
|
||||
*
|
||||
* \see deleteIdentifierNode(IdentifierNode *) */
|
||||
IdentifierNode *createIdentifierNode(char *image, /**< [in] An array of characters that name the identifier. */
|
||||
const char *fname, /**< [in] A pointer to the name of the file containing the identifier. */
|
||||
unsigned int line) /**< [in] The line number from the source file that the identifier occurred on. */
|
||||
IdentifierNode *createIdentifierNode(IdentifierType type, /**< [in] The type of IdentifierNode stored in \a id. */
|
||||
void *id, /**< [in] A pointer to the stored identifier data. */
|
||||
const char *fname, /**< [in] A pointer to the name of the file containing the identifier. */
|
||||
unsigned int line) /**< [in] The line number from the source file that the identifier occurred on. */
|
||||
{
|
||||
IdentifierNode *p = malloc(sizeof(IdentifierNode));
|
||||
if (!p) {
|
||||
perror("malloc");
|
||||
return NULL;
|
||||
}
|
||||
p->image = malloc(sizeof(char) * (strlen(image) + 1));
|
||||
if (!p->image) {
|
||||
free(p);
|
||||
perror("malloc");
|
||||
return NULL;
|
||||
p->type = type;
|
||||
p->id = id;
|
||||
if (fname) {
|
||||
p->fname = malloc(sizeof(char) * (strlen(fname) + 1));
|
||||
strcpy(p->fname, fname);
|
||||
}
|
||||
else {
|
||||
p->fname = NULL;
|
||||
}
|
||||
strcpy(p->image, image);
|
||||
p->fname = fname;
|
||||
p->line = line;
|
||||
return p;
|
||||
}
|
||||
|
@ -287,7 +289,20 @@ IdentifierNode *createIdentifierNode(char *image, /**< [in] An array of ch
|
|||
void deleteIdentifierNode(IdentifierNode *node) /**< [in,out] A pointer to the IdentifierNode structure to be deleted. */
|
||||
{
|
||||
if (!node) return;
|
||||
free(node->image);
|
||||
switch (node->type) {
|
||||
case IT_DIRECT: {
|
||||
free(node->id);
|
||||
break;
|
||||
}
|
||||
case IT_INDIRECT: {
|
||||
deleteExprNode(node->id);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fprintf(stderr, "Unable to delete unknown identifier type\n");
|
||||
break;
|
||||
}
|
||||
if (node->fname) free(node->fname);
|
||||
free(node);
|
||||
}
|
||||
|
||||
|
@ -320,7 +335,10 @@ IdentifierNodeList *createIdentifierNodeList(void)
|
|||
* \a list will be updated accordingly.
|
||||
*
|
||||
* \retval 0 realloc was unable to allocate memory.
|
||||
* \retval 1 \a node was added to \a list. */
|
||||
* \retval 1 \a node was added to \a list.
|
||||
*
|
||||
* \see createIdentifierNodeList(void)
|
||||
* \see deleteIdentifierNodeList(IdentifierNodeList *) */
|
||||
int addIdentifierNode(IdentifierNodeList *list, /**< [in,out] A pointer to the IdentifierNodeList structure to add \a node to. */
|
||||
IdentifierNode *node) /**< [in] A pointer to the IdentifierNode structure to add to \a list. */
|
||||
{
|
||||
|
@ -530,7 +548,10 @@ StmtNodeList *createStmtNodeList(void)
|
|||
* \a list will be updated accordingly.
|
||||
*
|
||||
* \retval 0 malloc was unable to allocate memory.
|
||||
* \retval 1 \a node was added to \a list. */
|
||||
* \retval 1 \a node was added to \a list.
|
||||
*
|
||||
* \see createStmtNodeList(void)
|
||||
* \see deleteStmtNodeList(StmtNodeList *) */
|
||||
int addStmtNode(StmtNodeList *list, /**< [in,out] A pointer to the StmtNodeList structure to add \a node to. */
|
||||
StmtNode *node) /**< [in] A pointer to the StmtNode structure to add to \a list. */
|
||||
{
|
||||
|
@ -1123,7 +1144,10 @@ ExprNodeList *createExprNodeList(void)
|
|||
* \a list will be updated accordingly.
|
||||
*
|
||||
* \retval 0 realloc was unable to allocate memory.
|
||||
* \retval 1 \a node was added to \a list. */
|
||||
* \retval 1 \a node was added to \a list.
|
||||
*
|
||||
* \see createExprNodeList(void)
|
||||
* \see deleteExprNodeList(ExprNodeList *) */
|
||||
int addExprNode(ExprNodeList *list, /**< [in,out] A pointer to the ExprNodeList structure to add \a node to. */
|
||||
ExprNode *node) /**< [in] A pointer to the ExprNode structure to add to \a list. */
|
||||
{
|
||||
|
@ -1367,7 +1391,7 @@ int nextToken(Token ***tokenp, /**< [in] A pointer to the position of the next t
|
|||
void error(const char *info, /**< [in] The array of characters to print. */
|
||||
Token **tokens) /**< [in] A pointer to an array of tokens to parse. */
|
||||
{
|
||||
fprintf(stderr, "%s:%d: %s at: %s\n", (*tokens)->fname, (*tokens)->line, info, (*tokens)->image);
|
||||
fprintf(stderr, "%s:%u: %s at: %s\n", (*tokens)->fname, (*tokens)->line, info, (*tokens)->image);
|
||||
}
|
||||
|
||||
/** Parses a set of tokens into a ConstantNode structure. Parsing begins at the
|
||||
|
@ -1451,7 +1475,7 @@ ConstantNode *parseConstantNode(Token ***tokenp)
|
|||
}
|
||||
/* String */
|
||||
else if (peekToken(&tokens, TT_STRING)) {
|
||||
unsigned int len = strlen((*tokens)->image);
|
||||
size_t len = strlen((*tokens)->image);
|
||||
data = malloc(sizeof(char) * (len - 1));
|
||||
if (!data) {
|
||||
perror("malloc");
|
||||
|
@ -1606,6 +1630,12 @@ parseTypeNodeAbort: /* Exception handling */
|
|||
* \see parseMainNode(Token **) */
|
||||
IdentifierNode *parseIdentifierNode(Token ***tokenp) /**< [in,out] A pointer to the position of the next token to parse. */
|
||||
{
|
||||
/* For direct identifier */
|
||||
char *temp = NULL;
|
||||
|
||||
/* For indirect identifier */
|
||||
ExprNode *expr = NULL;
|
||||
|
||||
IdentifierNode *ret = NULL;
|
||||
int status;
|
||||
|
||||
|
@ -1616,13 +1646,18 @@ IdentifierNode *parseIdentifierNode(Token ***tokenp) /**< [in,out] A pointer to
|
|||
shiftout();
|
||||
#endif
|
||||
|
||||
/* Make sure there is an identifier to parse */
|
||||
/* Direct identifier */
|
||||
if (peekToken(&tokens, TT_IDENTIFIER)) {
|
||||
#ifdef DEBUG
|
||||
debug("IDENTIFIER");
|
||||
debug("IT_DIRECT");
|
||||
#endif
|
||||
/* Copy the token image */
|
||||
temp = malloc(sizeof(char) * (strlen((*tokens)->image) + 1));
|
||||
if (!temp) goto parseIdentifierNodeAbort;
|
||||
strcpy(temp, (*tokens)->image);
|
||||
|
||||
/* Create the new IdentifierNode structure */
|
||||
ret = createIdentifierNode((*tokens)->image, (*tokens)->fname, (*tokens)->line);
|
||||
ret = createIdentifierNode(IT_DIRECT, temp, (*tokens)->fname, (*tokens)->line);
|
||||
if (!ret) goto parseIdentifierNodeAbort;
|
||||
|
||||
/* This should succeed; it was checked for above */
|
||||
|
@ -1632,6 +1667,18 @@ IdentifierNode *parseIdentifierNode(Token ***tokenp) /**< [in,out] A pointer to
|
|||
goto parseIdentifierNodeAbort;
|
||||
}
|
||||
}
|
||||
else if (acceptToken(&tokens, TT_SRS)) {
|
||||
#ifdef DEBUG
|
||||
debug("IT_INDIRECT");
|
||||
#endif
|
||||
/* Parse the expression representing the identifier */
|
||||
expr = parseExprNode(&tokens);
|
||||
if (!expr) goto parseIdentifierNodeAbort;
|
||||
|
||||
/* Create the new IdentifierNode structure */
|
||||
ret = createIdentifierNode(IT_INDIRECT, expr, (*tokens)->fname, (*tokens)->line);
|
||||
if (!ret) goto parseIdentifierNodeAbort;
|
||||
}
|
||||
else {
|
||||
error("expected identifier", tokens);
|
||||
}
|
||||
|
@ -1649,6 +1696,13 @@ parseIdentifierNodeAbort: /* Exception handling */
|
|||
|
||||
/* Clean up any allocated structures */
|
||||
if (ret) deleteIdentifierNode(ret);
|
||||
else {
|
||||
/* For indirect identifier */
|
||||
if (expr) deleteExprNode(expr);
|
||||
|
||||
/* For direct identifier */
|
||||
if (temp) free(temp);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1696,7 +1750,7 @@ ExprNode *parseCastExprNode(Token ***tokenp)
|
|||
if (!target) goto parseCastExprNodeAbort;
|
||||
|
||||
/* Optionally parse the cast-to token */
|
||||
acceptToken(&tokens, TT_A);
|
||||
status = acceptToken(&tokens, TT_A);
|
||||
|
||||
/* Parse the type to cast to */
|
||||
newtype = parseTypeNode(&tokens);
|
||||
|
@ -1748,7 +1802,6 @@ ExprNode *parseConstantExprNode(Token ***tokenp)
|
|||
{
|
||||
ConstantNode *node = NULL;
|
||||
ExprNode *ret = NULL;
|
||||
int status;
|
||||
|
||||
/* Work from a copy of the token stream in case something goes wrong */
|
||||
Token **tokens = *tokenp;
|
||||
|
@ -1802,7 +1855,6 @@ ExprNode *parseIdentifierExprNode(Token ***tokenp)
|
|||
{
|
||||
IdentifierNode *node = NULL;
|
||||
ExprNode *ret = NULL;
|
||||
int status;
|
||||
|
||||
/* Work from a copy of the token stream in case something goes wrong */
|
||||
Token **tokens = *tokenp;
|
||||
|
@ -1967,9 +2019,9 @@ parseFuncCallExprNodeAbort: /* Exception handling */
|
|||
ExprNode *parseOpExprNode(Token ***tokenp)
|
||||
{
|
||||
enum ArityType {
|
||||
AR_UNARY,
|
||||
AR_BINARY,
|
||||
AR_NARY,
|
||||
AT_UNARY,
|
||||
AT_BINARY,
|
||||
AT_NARY
|
||||
};
|
||||
enum ArityType arity;
|
||||
ExprNodeList *args = NULL;
|
||||
|
@ -1985,7 +2037,7 @@ ExprNode *parseOpExprNode(Token ***tokenp)
|
|||
/* Unary operations */
|
||||
if (acceptToken(&tokens, TT_NOT)) {
|
||||
type = OP_NOT;
|
||||
arity = AR_UNARY;
|
||||
arity = AT_UNARY;
|
||||
#ifdef DEBUG
|
||||
debug("ET_OP (OP_NOT)");
|
||||
#endif
|
||||
|
@ -1993,84 +2045,84 @@ ExprNode *parseOpExprNode(Token ***tokenp)
|
|||
/* Binary operations */
|
||||
else if (acceptToken(&tokens, TT_SUMOF)) {
|
||||
type = OP_ADD;
|
||||
arity = AR_BINARY;
|
||||
arity = AT_BINARY;
|
||||
#ifdef DEBUG
|
||||
debug("ET_OP (OP_ADD)");
|
||||
#endif
|
||||
}
|
||||
else if(acceptToken(&tokens, TT_DIFFOF)) {
|
||||
type = OP_SUB;
|
||||
arity = AR_BINARY;
|
||||
arity = AT_BINARY;
|
||||
#ifdef DEBUG
|
||||
debug("ET_OP (OP_SUB)");
|
||||
#endif
|
||||
}
|
||||
else if(acceptToken(&tokens, TT_PRODUKTOF)) {
|
||||
type = OP_MULT;
|
||||
arity = AR_BINARY;
|
||||
arity = AT_BINARY;
|
||||
#ifdef DEBUG
|
||||
debug("ET_OP (OP_MULT)");
|
||||
#endif
|
||||
}
|
||||
else if(acceptToken(&tokens, TT_QUOSHUNTOF)) {
|
||||
type = OP_DIV;
|
||||
arity = AR_BINARY;
|
||||
arity = AT_BINARY;
|
||||
#ifdef DEBUG
|
||||
debug("ET_OP (OP_DIV)");
|
||||
#endif
|
||||
}
|
||||
else if(acceptToken(&tokens, TT_MODOF)) {
|
||||
type = OP_MOD;
|
||||
arity = AR_BINARY;
|
||||
arity = AT_BINARY;
|
||||
#ifdef DEBUG
|
||||
debug("ET_OP (OP_MOD)");
|
||||
#endif
|
||||
}
|
||||
else if(acceptToken(&tokens, TT_BIGGROF)) {
|
||||
type = OP_MAX;
|
||||
arity = AR_BINARY;
|
||||
arity = AT_BINARY;
|
||||
#ifdef DEBUG
|
||||
debug("ET_OP (OP_MAX)");
|
||||
#endif
|
||||
}
|
||||
else if(acceptToken(&tokens, TT_SMALLROF)) {
|
||||
type = OP_MIN;
|
||||
arity = AR_BINARY;
|
||||
arity = AT_BINARY;
|
||||
#ifdef DEBUG
|
||||
debug("ET_OP (OP_MIN)");
|
||||
#endif
|
||||
}
|
||||
else if(acceptToken(&tokens, TT_BOTHOF)) {
|
||||
type = OP_AND;
|
||||
arity = AR_BINARY;
|
||||
arity = AT_BINARY;
|
||||
#ifdef DEBUG
|
||||
debug("ET_OP (OP_AND)");
|
||||
#endif
|
||||
}
|
||||
else if(acceptToken(&tokens, TT_EITHEROF)) {
|
||||
type = OP_OR;
|
||||
arity = AR_BINARY;
|
||||
arity = AT_BINARY;
|
||||
#ifdef DEBUG
|
||||
debug("ET_OP (OP_OR)");
|
||||
#endif
|
||||
}
|
||||
else if(acceptToken(&tokens, TT_WONOF)) {
|
||||
type = OP_XOR;
|
||||
arity = AR_BINARY;
|
||||
arity = AT_BINARY;
|
||||
#ifdef DEBUG
|
||||
debug("ET_OP (OP_XOR)");
|
||||
#endif
|
||||
}
|
||||
else if(acceptToken(&tokens, TT_BOTHSAEM)) {
|
||||
type = OP_EQ;
|
||||
arity = AR_BINARY;
|
||||
arity = AT_BINARY;
|
||||
#ifdef DEBUG
|
||||
debug("ET_OP (OP_EQ)");
|
||||
#endif
|
||||
}
|
||||
else if(acceptToken(&tokens, TT_DIFFRINT)) {
|
||||
type = OP_NEQ;
|
||||
arity = AR_BINARY;
|
||||
arity = AT_BINARY;
|
||||
#ifdef DEBUG
|
||||
debug("ET_OP (OP_NEQ)");
|
||||
#endif
|
||||
|
@ -2078,21 +2130,21 @@ ExprNode *parseOpExprNode(Token ***tokenp)
|
|||
/* N-ary operators */
|
||||
else if (acceptToken(&tokens, TT_ALLOF)) {
|
||||
type = OP_AND;
|
||||
arity = AR_NARY;
|
||||
arity = AT_NARY;
|
||||
#ifdef DEBUG
|
||||
debug("ET_OP (OP_AND)");
|
||||
#endif
|
||||
}
|
||||
else if(acceptToken(&tokens, TT_ANYOF)) {
|
||||
type = OP_OR;
|
||||
arity = AR_NARY;
|
||||
arity = AT_NARY;
|
||||
#ifdef DEBUG
|
||||
debug("ET_OP (OP_OR)");
|
||||
#endif
|
||||
}
|
||||
else if(acceptToken(&tokens, TT_SMOOSH)) {
|
||||
type = OP_CAT;
|
||||
arity = AR_NARY;
|
||||
arity = AT_NARY;
|
||||
#ifdef DEBUG
|
||||
debug("ET_OP (OP_CAT)");
|
||||
#endif
|
||||
|
@ -2107,7 +2159,7 @@ ExprNode *parseOpExprNode(Token ***tokenp)
|
|||
if (!args) goto parseOpExprNodeAbort;
|
||||
|
||||
/* Parse the operation arguments */
|
||||
if (arity == AR_UNARY) {
|
||||
if (arity == AT_UNARY) {
|
||||
/* Parse the argument */
|
||||
arg = parseExprNode(&tokens);
|
||||
if (!arg) goto parseOpExprNodeAbort;
|
||||
|
@ -2117,7 +2169,7 @@ ExprNode *parseOpExprNode(Token ***tokenp)
|
|||
if (!status) goto parseOpExprNodeAbort;
|
||||
arg = NULL;
|
||||
}
|
||||
else if (arity == AR_BINARY) {
|
||||
else if (arity == AT_BINARY) {
|
||||
/* Parse the first argument */
|
||||
arg = parseExprNode(&tokens);
|
||||
if (!arg) goto parseOpExprNodeAbort;
|
||||
|
@ -2128,7 +2180,7 @@ ExprNode *parseOpExprNode(Token ***tokenp)
|
|||
arg = NULL;
|
||||
|
||||
/* Optionally parse the argument-separator token */
|
||||
acceptToken(&tokens, TT_AN);
|
||||
status = acceptToken(&tokens, TT_AN);
|
||||
|
||||
/* Parse the second argument */
|
||||
arg = parseExprNode(&tokens);
|
||||
|
@ -2139,7 +2191,7 @@ ExprNode *parseOpExprNode(Token ***tokenp)
|
|||
if (!status) goto parseOpExprNodeAbort;
|
||||
arg = NULL;
|
||||
}
|
||||
else if (arity == AR_NARY) {
|
||||
else if (arity == AT_NARY) {
|
||||
/* Parse as many arguments as possible */
|
||||
while (1) {
|
||||
/* Parse an argument */
|
||||
|
@ -2155,7 +2207,7 @@ ExprNode *parseOpExprNode(Token ***tokenp)
|
|||
if (acceptToken(&tokens, TT_MKAY)) break;
|
||||
|
||||
/* Optionally parse the argument-separator token */
|
||||
acceptToken(&tokens, TT_AN);
|
||||
status = acceptToken(&tokens, TT_AN);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2227,7 +2279,8 @@ ExprNode *parseExprNode(Token ***tokenp) /**< [in,out] A pointer to the position
|
|||
ret = parseFuncCallExprNode(tokenp);
|
||||
}
|
||||
/* Identifier */
|
||||
else if (peekToken(&tokens, TT_IDENTIFIER)) {
|
||||
else if (peekToken(&tokens, TT_IDENTIFIER)
|
||||
|| peekToken(&tokens, TT_SRS)) {
|
||||
ret = parseIdentifierExprNode(tokenp);
|
||||
}
|
||||
/* Operation */
|
||||
|
@ -2419,7 +2472,7 @@ StmtNode *parsePrintStmtNode(Token ***tokenp)
|
|||
arg = NULL;
|
||||
|
||||
/* Arguments can optionally be separated by an AN keyword */
|
||||
acceptToken(&tokens, TT_AN);
|
||||
status = acceptToken(&tokens, TT_AN);
|
||||
} while (!peekToken(&tokens, TT_NEWLINE)
|
||||
&& !peekToken(&tokens, TT_BANG));
|
||||
|
||||
|
@ -2988,7 +3041,7 @@ StmtNode *parseSwitchStmtNode(Token ***tokenp)
|
|||
if (((c->type == CT_BOOLEAN || c->type == CT_INTEGER)
|
||||
&& c->data.i == test->data.i)
|
||||
|| (c->type == CT_FLOAT
|
||||
&& c->data.f == test->data.f)
|
||||
&& fabs(c->data.f - test->data.f) < FLT_EPSILON)
|
||||
|| (c->type == CT_STRING
|
||||
&& !strcmp(c->data.s, test->data.s))) {
|
||||
error("OMG literal must be unique", tokens);
|
||||
|
@ -3259,6 +3312,7 @@ StmtNode *parseLoopStmtNode(Token ***tokenp)
|
|||
IdentifierNode *name2 = NULL;
|
||||
LoopStmtNode *stmt = NULL;
|
||||
ExprNodeList *args = NULL;
|
||||
char *id = NULL;
|
||||
|
||||
/* For increment and decrement loops */
|
||||
IdentifierNode *varcopy = NULL;
|
||||
|
@ -3298,6 +3352,10 @@ StmtNode *parseLoopStmtNode(Token ***tokenp)
|
|||
/* Parse the loop name */
|
||||
name1 = parseIdentifierNode(&tokens);
|
||||
if (!name1) goto parseLoopStmtNodeAbort;
|
||||
else if (name1->type != IT_DIRECT) {
|
||||
error("expected loop name", tokens);
|
||||
goto parseLoopStmtNodeAbort;
|
||||
}
|
||||
|
||||
/* Check if an increment or decrement loop */
|
||||
if (peekToken(&tokens, TT_UPPIN) || peekToken(&tokens, TT_NERFIN)) {
|
||||
|
@ -3339,8 +3397,12 @@ StmtNode *parseLoopStmtNode(Token ***tokenp)
|
|||
shiftin();
|
||||
#endif
|
||||
/* Make a copy of the variable for use as a function argument */
|
||||
varcopy = createIdentifierNode(var->image, var->fname, var->line);
|
||||
id = malloc(sizeof(char) * (strlen(var->id) + 1));
|
||||
if (!id) goto parseLoopStmtNodeAbort;
|
||||
strcpy(id, var->id);
|
||||
varcopy = createIdentifierNode(IT_DIRECT, id, var->fname, var->line);
|
||||
if (!varcopy) goto parseLoopStmtNodeAbort;
|
||||
id = NULL;
|
||||
|
||||
/* Package the variable into an identifier expression */
|
||||
arg1 = createExprNode(ET_IDENTIFIER, varcopy);
|
||||
|
@ -3424,8 +3486,12 @@ StmtNode *parseLoopStmtNode(Token ***tokenp)
|
|||
arg = NULL;
|
||||
|
||||
/* Copy the identifier to make it the loop variable */
|
||||
var = createIdentifierNode(temp->image, temp->fname, temp->line);
|
||||
id = malloc(sizeof(char) * (strlen(temp->id) + 1));
|
||||
if (!id) goto parseLoopStmtNodeAbort;
|
||||
strcpy(id, temp->id);
|
||||
var = createIdentifierNode(IT_DIRECT, id, temp->fname, temp->line);
|
||||
if (!var) goto parseLoopStmtNodeAbort;
|
||||
id = NULL;
|
||||
|
||||
/* Check for unary function */
|
||||
status = acceptToken(&tokens, TT_MKAY);
|
||||
|
@ -3503,9 +3569,13 @@ StmtNode *parseLoopStmtNode(Token ***tokenp)
|
|||
/* Parse the end-of-loop name */
|
||||
name2 = parseIdentifierNode(&tokens);
|
||||
if (!name2) goto parseLoopStmtNodeAbort;
|
||||
else if (name2->type != IT_DIRECT) {
|
||||
error("expected loop name", tokens);
|
||||
goto parseLoopStmtNodeAbort;
|
||||
}
|
||||
|
||||
/* Make sure the beginning-of-loop and end-of-loop names match */
|
||||
if (strcmp(name1->image, name2->image)) {
|
||||
if (strcmp((char *)(name1->id), (char *)(name2->id))) {
|
||||
error("expected matching loop name", tokens);
|
||||
goto parseLoopStmtNodeAbort;
|
||||
}
|
||||
|
@ -3546,6 +3616,7 @@ parseLoopStmtNodeAbort: /* Exception handling */
|
|||
if (update) deleteExprNode(update);
|
||||
if (var) deleteIdentifierNode(var);
|
||||
if (name1) deleteIdentifierNode(name1);
|
||||
if (id) free(id);
|
||||
|
||||
/* For increment and decrement loops */
|
||||
if (op) deleteOpExprNode(op);
|
||||
|
@ -3646,6 +3717,8 @@ parseDeallocationStmtNodeAbort: /* Exception handling */
|
|||
else {
|
||||
if (target) deleteIdentifierNode(target);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Parses a set of tokens into a StmtNode structure containing a
|
||||
|
@ -3783,6 +3856,8 @@ parseFuncDefStmtNodeAbort: /* Exception handling */
|
|||
if (name) deleteIdentifierNode(name);
|
||||
if (scope) deleteIdentifierNode(scope);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Parses a set of tokens into a StmtNode structure. Parsing begins at the
|
||||
|
@ -3815,9 +3890,64 @@ StmtNode *parseStmtNode(Token ***tokenp) /**< [in,out] A pointer to the position
|
|||
shiftout();
|
||||
#endif
|
||||
|
||||
/* Casting */
|
||||
if (nextToken(&tokens, TT_ISNOWA)) {
|
||||
ret = parseCastStmtNode(tokenp);
|
||||
/* Parse context-sensitive expressions */
|
||||
if (peekToken(&tokens, TT_IDENTIFIER)
|
||||
|| peekToken(&tokens, TT_SRS)) {
|
||||
IdentifierNode *id = NULL;
|
||||
|
||||
/* Remove the identifier from the token stream */
|
||||
id = parseIdentifierNode(&tokens);
|
||||
if (!id) return NULL;
|
||||
|
||||
/* We do not need to hold onto it */
|
||||
deleteIdentifierNode(id);
|
||||
|
||||
/* Casting */
|
||||
if (peekToken(&tokens, TT_ISNOWA)) {
|
||||
ret = parseCastStmtNode(tokenp);
|
||||
}
|
||||
/* Assignment */
|
||||
else if (peekToken(&tokens, TT_R)) {
|
||||
ret = parseAssignmentStmtNode(tokenp);
|
||||
}
|
||||
/* Variable declaration */
|
||||
else if (peekToken(&tokens, TT_HASA)) {
|
||||
ret = parseDeclarationStmtNode(tokenp);
|
||||
}
|
||||
/* Deallocation */
|
||||
else if (peekToken(&tokens, TT_RNOOB)) {
|
||||
ret = parseDeallocationStmtNode(tokenp);
|
||||
}
|
||||
/* Bare identifier expression */
|
||||
else {
|
||||
/* Reset state and continue parsing */
|
||||
tokens = *tokenp;
|
||||
|
||||
/* Parse the expression */
|
||||
expr = parseExprNode(&tokens);
|
||||
if (!expr) return NULL;
|
||||
|
||||
#ifdef DEBUG
|
||||
debug("ST_EXPR");
|
||||
#endif
|
||||
|
||||
/* The expression should appear on its own line */
|
||||
if (!acceptToken(&tokens, TT_NEWLINE)) {
|
||||
error("expected end of expression", tokens);
|
||||
deleteExprNode(expr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Create the new StmtNode structure */
|
||||
ret = createStmtNode(ST_EXPR, expr);
|
||||
if (!ret) {
|
||||
deleteExprNode(expr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Since we're successful, update the token stream */
|
||||
*tokenp = tokens;
|
||||
}
|
||||
}
|
||||
/* Print */
|
||||
else if (peekToken(&tokens, TT_VISIBLE)) {
|
||||
|
@ -3827,14 +3957,6 @@ StmtNode *parseStmtNode(Token ***tokenp) /**< [in,out] A pointer to the position
|
|||
else if (peekToken(&tokens, TT_GIMMEH)) {
|
||||
ret = parseInputStmtNode(tokenp);
|
||||
}
|
||||
/* Assignment */
|
||||
else if (nextToken(&tokens, TT_R)) {
|
||||
ret = parseAssignmentStmtNode(tokenp);
|
||||
}
|
||||
/* Variable declaration */
|
||||
else if (nextToken(&tokens, TT_HASA)) {
|
||||
ret = parseDeclarationStmtNode(tokenp);
|
||||
}
|
||||
/* If/then/else */
|
||||
else if (peekToken(&tokens, TT_ORLY)) {
|
||||
ret = parseIfThenElseStmtNode(tokenp);
|
||||
|
@ -3855,15 +3977,11 @@ StmtNode *parseStmtNode(Token ***tokenp) /**< [in,out] A pointer to the position
|
|||
else if (peekToken(&tokens, TT_IMINYR)) {
|
||||
ret = parseLoopStmtNode(tokenp);
|
||||
}
|
||||
/* Deallocation */
|
||||
else if (nextToken(&tokens, TT_RNOOB)) {
|
||||
ret = parseDeallocationStmtNode(tokenp);
|
||||
}
|
||||
/* Function definition */
|
||||
else if (peekToken(&tokens, TT_HOWIZ)) {
|
||||
ret = parseFuncDefStmtNode(tokenp);
|
||||
}
|
||||
/* Expression evaluation */
|
||||
/* Bare expression */
|
||||
else if ((expr = parseExprNode(&tokens))) {
|
||||
int status;
|
||||
|
||||
|
@ -3879,6 +3997,7 @@ StmtNode *parseStmtNode(Token ***tokenp) /**< [in,out] A pointer to the position
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* Create the new StmtNode structure */
|
||||
ret = createStmtNode(ST_EXPR, expr);
|
||||
if (!ret) {
|
||||
deleteExprNode(expr);
|
||||
|
|
59
parser.h
59
parser.h
|
@ -41,7 +41,7 @@
|
|||
* ConstantNode ::= Boolean | Integer | Float | String
|
||||
*
|
||||
* \par
|
||||
* IdentifierNode ::= Identifier
|
||||
* IdentifierNode ::= Identifier | \c TT_SRS ExprNode
|
||||
*
|
||||
* \par
|
||||
* TypeNode ::= \c TT_NOOB | \c TT_TROOF | \c TT_NUMBR | \c TT_NUMBAR | \c TT_YARN
|
||||
|
@ -174,33 +174,13 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
|
||||
#include "tokenizer.h"
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
/** Stores an identifier. An identifier is the string of characters that are
|
||||
* used to uniquely name a particular variable.
|
||||
*
|
||||
* \see createIdentifierNode(char *, const char *, unsigned int)
|
||||
* \see deleteIdentifierNode(IdentifierNode *) */
|
||||
typedef struct {
|
||||
char *image; /**< An array of characters that name the identifier. */
|
||||
const char *fname; /**< A pointer to the name of the file containing the identifier. */
|
||||
unsigned int line; /**< The line number from the source file that the identifier occurred on. */
|
||||
} IdentifierNode;
|
||||
|
||||
/** Stores a list of identifiers. This structure allows sets of identifiers
|
||||
* to be grouped together.
|
||||
*
|
||||
* \see createIdentifierNodeList(void)
|
||||
* \see addIdentifierNode(IdentifierNodeList *, IdentifierNode *)
|
||||
* \see deleteIdentifierNodeList(IdentifierNodeList *) */
|
||||
typedef struct {
|
||||
unsigned int num; /**< The number of IdentifierNode structures stored. */
|
||||
IdentifierNode **ids; /**< A pointer to the array of IdentifierNode structures. */
|
||||
} IdentifierNodeList;
|
||||
|
||||
/** Denotes the type of statement a StmtNode stores. */
|
||||
typedef enum {
|
||||
ST_CAST, /**< A CastStmtNode structure. */
|
||||
|
@ -270,6 +250,35 @@ typedef struct {
|
|||
ExprNode **exprs; /**< A pointer to an array of ExprNode structures. */
|
||||
} ExprNodeList;
|
||||
|
||||
/** Denotes the type of identifier an IdentifierNode is. */
|
||||
typedef enum {
|
||||
IT_DIRECT, /**< A direct IdentifierNode structure. */
|
||||
IT_INDIRECT /**< An indirect IdentifierNode structure. */
|
||||
} IdentifierType;
|
||||
|
||||
/** Stores an identifier. An identifier either directly or indirectly names
|
||||
* particular variable.
|
||||
*
|
||||
* \see createIdentifierNode(IdentifierType, void *)
|
||||
* \see deleteIdentifierNode(IdentifierNode *) */
|
||||
typedef struct {
|
||||
IdentifierType type; /**< The type of identifier stored in \a id. */
|
||||
void *id; /**< The identifier data stored. */
|
||||
char *fname; /**< A pointer to the name of the file containing the identifier. */
|
||||
unsigned int line; /**< The line number from the source file that the identifier occurred on. */
|
||||
} IdentifierNode;
|
||||
|
||||
/** Stores a list of identifiers. This structure allows sets of identifiers
|
||||
* to be grouped together.
|
||||
*
|
||||
* \see createIdentifierNodeList(void)
|
||||
* \see addIdentifierNode(IdentifierNodeList *, IdentifierNode *)
|
||||
* \see deleteIdentifierNodeList(IdentifierNodeList *) */
|
||||
typedef struct {
|
||||
unsigned int num; /**< The number of IdentifierNode structures stored. */
|
||||
IdentifierNode **ids; /**< A pointer to the array of IdentifierNode structures. */
|
||||
} IdentifierNodeList;
|
||||
|
||||
/** Stores a a block of code. A block of code consists of a set of statements.
|
||||
*
|
||||
* \see createBlockNode(StmtNodeList *)
|
||||
|
@ -531,7 +540,7 @@ BlockNodeList *createBlockNodeList(void);
|
|||
int addBlockNode(BlockNodeList *, BlockNode *);
|
||||
void deleteBlockNodeList(BlockNodeList *);
|
||||
|
||||
IdentifierNode *createIdentifierNode(char *, const char *, unsigned int);
|
||||
IdentifierNode *createIdentifierNode(IdentifierType, void *, const char *, unsigned int);
|
||||
void deleteIdentifierNode(IdentifierNode *);
|
||||
|
||||
TypeNode *createTypeNode(ConstantType);
|
||||
|
@ -605,11 +614,13 @@ StmtNode *parseStmtNode(Token ***);
|
|||
BlockNode *parseBlockNode(Token ***);
|
||||
MainNode *parseMainNode(Token **);
|
||||
|
||||
ExprNode *parseCastExprNode(Token ***);
|
||||
ExprNode *parseConstantExprNode(Token ***);
|
||||
ExprNode *parseIdentifierExprNode(Token ***);
|
||||
ExprNode *parseFuncCallExprNode(Token ***);
|
||||
ExprNode *parseOpExprNode(Token ***);
|
||||
|
||||
StmtNode *parseCastStmtNode(Token ***);
|
||||
StmtNode *parsePrintStmtNode(Token ***);
|
||||
StmtNode *parseInputStmtNode(Token ***);
|
||||
StmtNode *parseAssignmentStmtNode(Token ***);
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
HAI 1.3
|
||||
I HAS A var1 ITZ 1
|
||||
I HAS A var2 ITZ 2.345
|
||||
I HAS A var3 ITZ "67890"
|
||||
I HAS A name ITZ "var"
|
||||
VISIBLE SRS "var1"
|
||||
VISIBLE SRS SMOOSH name AN SUM OF 1 AN 1 MKAY
|
||||
VISIBLE SRS ":{name}3"
|
||||
KTHXBYE
|
|
@ -0,0 +1,3 @@
|
|||
1
|
||||
2.34
|
||||
67890
|
|
@ -0,0 +1,3 @@
|
|||
This test checks the functionality of the indirect identifier keyword, ``SRS''
|
||||
to make sure it allows variable lookup using a provided string or expression
|
||||
evaluated as a string for variable output.
|
|
@ -0,0 +1,5 @@
|
|||
HAI 1.3
|
||||
I HAS A name ITZ "var"
|
||||
I HAS A SRS name ITZ 1
|
||||
VISIBLE var
|
||||
KTHXBYE
|
|
@ -0,0 +1 @@
|
|||
1
|
|
@ -0,0 +1,3 @@
|
|||
This test checks the functionality of the indirect identifier keyword, ``SRS''
|
||||
to make sure it allows variable lookup using a provided string or expression
|
||||
evaluated as a string for variable initialization.
|
|
@ -0,0 +1,6 @@
|
|||
HAI 1.3
|
||||
I HAS A name ITZ "var"
|
||||
I HAS A var ITZ 1
|
||||
SRS name R 2.345
|
||||
VISIBLE var
|
||||
KTHXBYE
|
|
@ -0,0 +1 @@
|
|||
2.34
|
|
@ -0,0 +1,3 @@
|
|||
This test checks the functionality of the indirect identifier keyword, ``SRS''
|
||||
to make sure it allows variable lookup using a provided string or expression
|
||||
evaluated as a string for variable assignment.
|
|
@ -0,0 +1,5 @@
|
|||
HAI 1.3
|
||||
I HAS A name ITZ "var"
|
||||
I HAS A SRS name ITZ A NUMBR
|
||||
VISIBLE var
|
||||
KTHXBYE
|
|
@ -0,0 +1 @@
|
|||
0
|
|
@ -0,0 +1,3 @@
|
|||
This test checks the functionality of the indirect identifier keyword, ``SRS''
|
||||
to make sure it allows variable lookup using a provided string or expression
|
||||
evaluated as a string for variable type initialization.
|
|
@ -0,0 +1,17 @@
|
|||
HAI 1.3
|
||||
I HAS A var1
|
||||
I HAS A var2 ITZ WIN
|
||||
I HAS A var3 ITZ 1
|
||||
I HAS A var4 ITZ 2.345
|
||||
I HAS A var5 ITZ "Lorem ipsum dolor sit."
|
||||
SRS "var1" R NOOB
|
||||
SRS "var2" R NOOB
|
||||
SRS "var3" R NOOB
|
||||
SRS "var4" R NOOB
|
||||
SRS "var5" R NOOB
|
||||
VISIBLE SUM OF 0 AN NOT var1
|
||||
VISIBLE SUM OF 0 AN NOT var2
|
||||
VISIBLE SUM OF 0 AN NOT var3
|
||||
VISIBLE SUM OF 0 AN NOT var4
|
||||
VISIBLE SUM OF 0 AN NOT var5
|
||||
KTHXBYE
|
|
@ -0,0 +1,5 @@
|
|||
1
|
||||
1
|
||||
1
|
||||
1
|
||||
1
|
|
@ -0,0 +1,3 @@
|
|||
This test checks the functionality of the indirect identifier keyword, ``SRS''
|
||||
to make sure it allows variable lookup using a provided string or expression
|
||||
evaluated as a string for variable deallocation.
|
|
@ -0,0 +1,15 @@
|
|||
HAI 1.3
|
||||
I HAS A name1 ITZ "fun"
|
||||
I HAS A name2 ITZ "arg"
|
||||
|
||||
HOW IZ I SRS SMOOSH name1 AN 1 MKAY
|
||||
VISIBLE "a"
|
||||
IF U SAY SO
|
||||
|
||||
HOW IZ I SRS SMOOSH name1 AN 2 MKAY YR SRS name2
|
||||
VISIBLE SRS name2
|
||||
IF U SAY SO
|
||||
|
||||
I IZ SRS SMOOSH name1 AN 1 MKAY MKAY
|
||||
I IZ SRS SMOOSH name1 AN 2 MKAY YR "b" MKAY
|
||||
KTHXBYE
|
|
@ -0,0 +1,2 @@
|
|||
a
|
||||
b
|
|
@ -0,0 +1,3 @@
|
|||
This test checks the functionality of the indirect identifier keyword, ``SRS''
|
||||
to make sure it allows variable lookup using a provided string or expression
|
||||
evaluated as a string for function declarations and calls.
|
113
tokenizer.c
113
tokenizer.c
|
@ -1,5 +1,75 @@
|
|||
#include "tokenizer.h"
|
||||
|
||||
static const char *keywords[] = {
|
||||
"", /* TT_INTEGER */
|
||||
"", /* TT_FLOAT */
|
||||
"", /* TT_STRING */
|
||||
"", /* TT_IDENTIFIER */
|
||||
"", /* TT_BOOLEAN */
|
||||
"IT", /* TT_IT */
|
||||
"NOOB", /* TT_NOOB */
|
||||
"NUMBR", /* TT_NUMBR */
|
||||
"NUMBAR", /* TT_NUMBAR */
|
||||
"TROOF", /* TT_TROOF */
|
||||
"YARN", /* TT_YARN */
|
||||
"", /* TT_EOF */
|
||||
"", /* TT_NEWLINE */
|
||||
"HAI", /* TT_HAI */
|
||||
"KTHXBYE", /* TT_KTHXBYE */
|
||||
"HAS A", /* TT_HASA */
|
||||
"ITZ A", /* TT_ITZA */
|
||||
"ITZ", /* TT_ITZ */
|
||||
"R NOOB", /* TT_RNOOB */
|
||||
"R", /* TT_R */
|
||||
"AN YR", /* TT_ANYR */
|
||||
"AN", /* TT_AN */
|
||||
"SUM OF", /* TT_SUMOF */
|
||||
"DIFF OF", /* TT_DIFFOF */
|
||||
"PRODUKT OF", /* TT_PRODUKTOF */
|
||||
"QUOSHUNT OF", /* TT_QUOSHUNTOF */
|
||||
"MOD OF", /* TT_MODOF */
|
||||
"BIGGR OF", /* TT_BIGGROF */
|
||||
"SMALLR OF", /* TT_SMALLROF */
|
||||
"BOTH OF", /* TT_BOTHOF */
|
||||
"EITHER OF", /* TT_EITHEROF */
|
||||
"WON OF", /* TT_WONOF */
|
||||
"NOT", /* TT_NOT */
|
||||
"MKAY", /* TT_MKAY */
|
||||
"ALL OF", /* TT_ALLOF */
|
||||
"ANY OF", /* TT_ANYOF */
|
||||
"BOTH SAEM", /* TT_BOTHSAEM */
|
||||
"DIFFRINT", /* TT_DIFFRINT */
|
||||
"MAEK", /* TT_MAEK */
|
||||
"A", /* TT_A */
|
||||
"IS NOW A", /* TT_ISNOWA */
|
||||
"VISIBLE", /* TT_VISIBLE */
|
||||
"SMOOSH", /* TT_SMOOSH */
|
||||
"!", /* TT_BANG */
|
||||
"GIMMEH", /* TT_GIMMEH */
|
||||
"O RLY?", /* TT_ORLY */
|
||||
"YA RLY", /* TT_YARLY */
|
||||
"MEBBE", /* TT_MEBBE */
|
||||
"NO WAI", /* TT_NOWAI */
|
||||
"OIC", /* TT_OIC */
|
||||
"WTF?", /* TT_WTF */
|
||||
"OMG", /* TT_OMG */
|
||||
"OMGWTF", /* TT_OMGWTF */
|
||||
"GTFO", /* TT_GTFO */
|
||||
"IM IN YR", /* TT_IMINYR */
|
||||
"UPPIN", /* TT_UPPIN */
|
||||
"NERFIN", /* TT_NERFIN */
|
||||
"YR", /* TT_YR */
|
||||
"TIL", /* TT_TIL */
|
||||
"WILE", /* TT_WILE */
|
||||
"IM OUTTA YR", /* TT_IMOUTTAYR */
|
||||
"HOW IZ", /* TT_HOWIZ */
|
||||
"IZ", /* TT_IZ */
|
||||
"IF U SAY SO", /* TT_IFUSAYSO */
|
||||
"FOUND YR", /* TT_FOUNDYR */
|
||||
"SRS", /* TT_SRS */
|
||||
"" /* TT_ENDOFTOKENS */
|
||||
};
|
||||
|
||||
/** Checks if a string of characters follows the format for an integer.
|
||||
* Specifically, it checks if the string of characters matches the regular
|
||||
* expression: [-]?[1-9][0-9]* | 0
|
||||
|
@ -145,20 +215,19 @@ void deleteToken(Token *token)
|
|||
* \post \a token will be added on to the end of \a list and the value at \a num
|
||||
* will be updated accordingly.
|
||||
*
|
||||
* \return A pointer to the added Token structure (will be the same as \a token).
|
||||
*
|
||||
* \retval NULL realloc was unable to allocate memory.
|
||||
* \retval 0 realloc was unable to allocate memory.
|
||||
* \retval 1 \a node was added to \a list.
|
||||
*
|
||||
* \see deleteTokens(Token **) */
|
||||
Token *addToken(Token ***list, /**< [in,out] A pointer to a pointer to an array of Token structures to add the new Token onto. */
|
||||
unsigned int *num, /**< [in,out] A pointer to the number of elements in \a list. */
|
||||
Token *token) /**< [in] A pointer to the Token structure to add to \a list. */
|
||||
int addToken(Token ***list, /**< [in,out] A pointer to a pointer to an array of Token structures to add the new Token onto. */
|
||||
unsigned int *num, /**< [in,out] A pointer to the number of elements in \a list. */
|
||||
Token *token) /**< [in] A pointer to the Token structure to add to \a list. */
|
||||
{
|
||||
unsigned int newsize = *num + 1;
|
||||
void *mem = realloc(*list, sizeof(Token *) * newsize);
|
||||
if (!mem) {
|
||||
perror("realloc");
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
*list = mem;
|
||||
(*list)[*num] = token;
|
||||
|
@ -166,7 +235,7 @@ Token *addToken(Token ***list, /**< [in,out] A pointer to a pointer to an ar
|
|||
#ifdef DEBUG
|
||||
fprintf(stderr, "Adding token type %d [%s]\n", token->type, token->image);
|
||||
#endif
|
||||
return token;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Deletes an array of Token structures.
|
||||
|
@ -199,14 +268,15 @@ unsigned int acceptLexemes(LexemeList *lexemes, /**< [in] A pointer to a LexemeL
|
|||
unsigned int offset = 0;
|
||||
unsigned int n;
|
||||
unsigned int i;
|
||||
for (n = 0, i = 0; match[n] || lexemes->lexemes[start + offset]->image[i]; n++, i++) {
|
||||
for (n = 0, i = 0; match[n] || lexemes->lexemes[start + offset]->image[i]; n++) {
|
||||
if (match[n] == ' ') {
|
||||
offset++;
|
||||
i = -1;
|
||||
i = 0;
|
||||
continue;
|
||||
}
|
||||
if (lexemes->lexemes[start + offset]->image[i] != match[n])
|
||||
return 0;
|
||||
i++;
|
||||
}
|
||||
return offset + 1;
|
||||
}
|
||||
|
@ -234,7 +304,7 @@ Token *isKeyword(LexemeList *lexemes, /**< [in] A pointer to a LexemeList struct
|
|||
const char *fname = lexemes->lexemes[*start]->fname;
|
||||
unsigned int line = lexemes->lexemes[*start]->line;
|
||||
for (type = 0; type != TT_ENDOFTOKENS; type++) {
|
||||
int num = acceptLexemes(lexemes, *start, keywords[type]);
|
||||
unsigned int num = acceptLexemes(lexemes, *start, keywords[type]);
|
||||
if (!num) continue;
|
||||
token = createToken(type, keywords[type], fname, line);
|
||||
*start += (num - 1);
|
||||
|
@ -272,12 +342,16 @@ Token **tokenizeLexemes(LexemeList *list) /**< [in] A pointer to a LexemeList st
|
|||
/* Float */
|
||||
else if (isFloat(image)) {
|
||||
token = createToken(TT_FLOAT, image, fname, line);
|
||||
sscanf(lexeme->image, "%f", &(token->data.f));
|
||||
if (sscanf(lexeme->image, "%f", &(token->data.f)) != 1) {
|
||||
fprintf(stderr, "Expected floating point decimal value.\n");
|
||||
}
|
||||
}
|
||||
/* Integer */
|
||||
else if (isInteger(image)) {
|
||||
token = createToken(TT_INTEGER, image, fname, line);
|
||||
sscanf(lexeme->image, "%i", &(token->data.i));
|
||||
if (sscanf(lexeme->image, "%i", &(token->data.i)) != 1) {
|
||||
fprintf(stderr, "Expected integer value.\n");
|
||||
}
|
||||
}
|
||||
/* FAIL */
|
||||
else if (!strcmp(image, "FAIL")) {
|
||||
|
@ -333,14 +407,23 @@ Token **tokenizeLexemes(LexemeList *list) /**< [in] A pointer to a LexemeList st
|
|||
token = createToken(TT_EOF, "end of file", fname, line);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "%s:%d: unknown token at: %s\n", fname, line, image);
|
||||
fprintf(stderr, "%s:%u: unknown token at: %s\n", fname, line, image);
|
||||
/* Clean up */
|
||||
deleteToken(ret[retsize - 1]);
|
||||
ret[retsize - 1] = NULL;
|
||||
deleteTokens(ret);
|
||||
return NULL;
|
||||
}
|
||||
addToken(&ret, &retsize, token);
|
||||
|
||||
/* Add the token to the token array */
|
||||
if (!addToken(&ret, &retsize, token)) {
|
||||
/* Clean up */
|
||||
if (token) deleteToken(token);
|
||||
deleteToken(ret[retsize - 1]);
|
||||
ret[retsize - 1] = NULL;
|
||||
deleteTokens(ret);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
mem = realloc(ret, sizeof(Token *) * ++retsize);
|
||||
if (!mem) {
|
||||
|
|
76
tokenizer.h
76
tokenizer.h
|
@ -24,7 +24,9 @@
|
|||
/** Denotes the type of token present. All of the token type names are
|
||||
* self-explainatory and correspond to either the semantic type of token data
|
||||
* (in the case of TT_INTEGER, TT_FLOAT, TT_STRING, or TT_IDENTIFIER) or the
|
||||
* lexemes which make up the particular token. */
|
||||
* lexemes which make up the particular token.
|
||||
*
|
||||
* \note Remember to update the keywords array with the token image. */
|
||||
typedef enum {
|
||||
TT_INTEGER,
|
||||
TT_FLOAT,
|
||||
|
@ -91,78 +93,10 @@ typedef enum {
|
|||
TT_IZ,
|
||||
TT_IFUSAYSO,
|
||||
TT_FOUNDYR,
|
||||
TT_SRS,
|
||||
TT_ENDOFTOKENS
|
||||
} TokenType;
|
||||
|
||||
static const char *keywords[] = {
|
||||
"", /* TT_INTEGER */
|
||||
"", /* TT_FLOAT */
|
||||
"", /* TT_STRING */
|
||||
"", /* TT_IDENTIFIER */
|
||||
"", /* TT_BOOLEAN */
|
||||
"IT", /* TT_IT */
|
||||
"NOOB", /* TT_NOOB */
|
||||
"NUMBR", /* TT_NUMBR */
|
||||
"NUMBAR", /* TT_NUMBAR */
|
||||
"TROOF", /* TT_TROOF */
|
||||
"YARN", /* TT_YARN */
|
||||
"", /* TT_EOF */
|
||||
"", /* TT_NEWLINE */
|
||||
"HAI", /* TT_HAI */
|
||||
"KTHXBYE", /* TT_KTHXBYE */
|
||||
"HAS A", /* TT_HASA */
|
||||
"ITZ A", /* TT_ITZA */
|
||||
"ITZ", /* TT_ITZ */
|
||||
"R NOOB", /* TT_RNOOB */
|
||||
"R", /* TT_R */
|
||||
"AN YR", /* TT_ANYR */
|
||||
"AN", /* TT_AN */
|
||||
"SUM OF", /* TT_SUMOF */
|
||||
"DIFF OF", /* TT_DIFFOF */
|
||||
"PRODUKT OF", /* TT_PRODUKTOF */
|
||||
"QUOSHUNT OF", /* TT_QUOSHUNTOF */
|
||||
"MOD OF", /* TT_MODOF */
|
||||
"BIGGR OF", /* TT_BIGGROF */
|
||||
"SMALLR OF", /* TT_SMALLROF */
|
||||
"BOTH OF", /* TT_BOTHOF */
|
||||
"EITHER OF", /* TT_EITHEROF */
|
||||
"WON OF", /* TT_WONOF */
|
||||
"NOT", /* TT_NOT */
|
||||
"MKAY", /* TT_MKAY */
|
||||
"ALL OF", /* TT_ALLOF */
|
||||
"ANY OF", /* TT_ANYOF */
|
||||
"BOTH SAEM", /* TT_BOTHSAEM */
|
||||
"DIFFRINT", /* TT_DIFFRINT */
|
||||
"MAEK", /* TT_MAEK */
|
||||
"A", /* TT_A */
|
||||
"IS NOW A", /* TT_ISNOWA */
|
||||
"VISIBLE", /* TT_VISIBLE */
|
||||
"SMOOSH", /* TT_SMOOSH */
|
||||
"!", /* TT_BANG */
|
||||
"GIMMEH", /* TT_GIMMEH */
|
||||
"O RLY?", /* TT_ORLY */
|
||||
"YA RLY", /* TT_YARLY */
|
||||
"MEBBE", /* TT_MEBBE */
|
||||
"NO WAI", /* TT_NOWAI */
|
||||
"OIC", /* TT_OIC */
|
||||
"WTF?", /* TT_WTF */
|
||||
"OMG", /* TT_OMG */
|
||||
"OMGWTF", /* TT_OMGWTF */
|
||||
"GTFO", /* TT_GTFO */
|
||||
"IM IN YR", /* TT_IMINYR */
|
||||
"UPPIN", /* TT_UPPIN */
|
||||
"NERFIN", /* TT_NERFIN */
|
||||
"YR", /* TT_YR */
|
||||
"TIL", /* TT_TIL */
|
||||
"WILE", /* TT_WILE */
|
||||
"IM OUTTA YR", /* TT_IMOUTTAYR */
|
||||
"HOW IZ", /* TT_HOWIZ */
|
||||
"IZ", /* TT_IZ */
|
||||
"IF U SAY SO", /* TT_IFUSAYSO */
|
||||
"FOUND YR", /* TT_FOUNDYR */
|
||||
"", /* TT_ENDOFTOKENS */
|
||||
};
|
||||
|
||||
/** Stores the data associated with a Token structure. */
|
||||
typedef union {
|
||||
int i; /**< Integer data. */
|
||||
|
@ -184,7 +118,7 @@ int isString(const char *);
|
|||
int isIdentifier(const char *);
|
||||
Token *createToken(TokenType, const char *, const char *, unsigned int);
|
||||
void deleteToken(Token *);
|
||||
Token *addToken(Token ***, unsigned int *, Token*);
|
||||
int addToken(Token ***, unsigned int *, Token*);
|
||||
void deleteTokens(Token **);
|
||||
unsigned int acceptLexemes(LexemeList *, unsigned int, const char *);
|
||||
Token *isKeyword(LexemeList *, unsigned int *);
|
||||
|
|
50
unicode.c
50
unicode.c
|
@ -36870,7 +36870,7 @@ int binarySearch(const char **strings, /**< [in] A pointer to an array of charac
|
|||
int end, /**< [in] The end of the range to search through. */
|
||||
const char *find) /**< [in] The entry to search for. */
|
||||
{
|
||||
unsigned int midpoint;
|
||||
int midpoint;
|
||||
int cmp;
|
||||
if (end < start) return -1;
|
||||
midpoint = ((end - start) / 2) + start;
|
||||
|
@ -36906,8 +36906,8 @@ long convertNormativeNameToCodePoint(const char *name) /**< [in] A pointer to a
|
|||
* \return The number of characters in the converted multi-byte character.
|
||||
*
|
||||
* \retval 0 An invalid Unicode code point was supplied. */
|
||||
unsigned int convertCodePointToUTF8(long codepoint, /**< [in] The Unicode code point to convert to UTF-8. */
|
||||
char *out) /**< [out] A pointer to the location to store the resulting UTF-8 bytes. */
|
||||
size_t convertCodePointToUTF8(unsigned long codepoint, /**< [in] The Unicode code point to convert to UTF-8. */
|
||||
char *out) /**< [out] A pointer to the location to store the resulting UTF-8 bytes. */
|
||||
{
|
||||
/* Out of range */
|
||||
if (codepoint > 0x10FFFF) {
|
||||
|
@ -36916,36 +36916,36 @@ unsigned int convertCodePointToUTF8(long codepoint, /**< [in] The Unicode code p
|
|||
}
|
||||
/* U+010000 to U+10FFFF */
|
||||
else if (codepoint >= 0x010000) {
|
||||
char x1 = codepoint & 0x003F;
|
||||
char x2 = (codepoint & 0x00C0) >> 6;
|
||||
char y1 = (codepoint & 0x0F00) >> 8;
|
||||
char y2 = (codepoint & 0xF000) >> 12;
|
||||
char z1 = (codepoint & 0x30000) >> 16;
|
||||
char z2 = (codepoint & 0x1C0000) >> 18;
|
||||
out[0] = 0xF0 | z2;
|
||||
out[1] = 0x80 | (z1 << 4) | y2;
|
||||
out[2] = 0x80 | (y1 << 2) | x2;
|
||||
out[3] = 0x80 | x1;
|
||||
char x1 = (char)(codepoint & 0x003F);
|
||||
char x2 = (char)((codepoint & 0x00C0) >> 6);
|
||||
char y1 = (char)((codepoint & 0x0F00) >> 8);
|
||||
char y2 = (char)((codepoint & 0xF000) >> 12);
|
||||
char z1 = (char)((codepoint & 0x30000) >> 16);
|
||||
char z2 = (char)((codepoint & 0x1C0000) >> 18);
|
||||
out[0] = (char)(0xF0 | z2);
|
||||
out[1] = (char)(0x80 | (z1 << 4) | y2);
|
||||
out[2] = (char)(0x80 | (y1 << 2) | x2);
|
||||
out[3] = (char)(0x80 | x1);
|
||||
return 4;
|
||||
}
|
||||
/* U+0800 to U+FFFF */
|
||||
else if (codepoint >= 0x0800) {
|
||||
char x1 = codepoint & 0x003F;
|
||||
char x2 = (codepoint & 0x00C0) >> 6;
|
||||
char y1 = (codepoint & 0x0F00) >> 8;
|
||||
char y2 = (codepoint & 0xF000) >> 12;
|
||||
out[0] = 0xE0 | y2;
|
||||
out[1] = 0x80 | (y1 << 2) | x2;
|
||||
out[2] = 0x80 | x1;
|
||||
char x1 = (char)(codepoint & 0x003F);
|
||||
char x2 = (char)((codepoint & 0x00C0) >> 6);
|
||||
char y1 = (char)((codepoint & 0x0F00) >> 8);
|
||||
char y2 = (char)((codepoint & 0xF000) >> 12);
|
||||
out[0] = (char)(0xE0 | y2);
|
||||
out[1] = (char)(0x80 | (y1 << 2) | x2);
|
||||
out[2] = (char)(0x80 | x1);
|
||||
return 3;
|
||||
}
|
||||
/* U+0080 to U+07FF */
|
||||
else if (codepoint & 0x0080) {
|
||||
char x1 = codepoint & 0x3F;
|
||||
char x2 = (codepoint & 0x00C0) >> 6;
|
||||
char y = (codepoint & 0x0700) >> 8;
|
||||
out[0] = 0xC0 | (y << 2) | x2;
|
||||
out[1] = 0x80 | x1;
|
||||
char x1 = (char)(codepoint & 0x3F);
|
||||
char x2 = (char)((codepoint & 0x00C0) >> 6);
|
||||
char y = (char)((codepoint & 0x0700) >> 8);
|
||||
out[0] = (char)(0xC0 | (y << 2) | x2);
|
||||
out[1] = (char)(0x80 | x1);
|
||||
return 2;
|
||||
}
|
||||
/* U+0080 to U+07FF */
|
||||
|
|
Loading…
Reference in New Issue