lci/interpreter.c

3473 lines
136 KiB
C

#include "interpreter.h"
/** Creates a string by copying the contents of another string.
*
* \return A pointer to a string containing the copied contents of \a data.
*
* \retval NULL malloc was unable to allocate memory. */
char *createString(char *data) /**< [in] A pointer to the string data to store. */
{
char *p = malloc(sizeof(char) * (strlen(data) + 1));
if (!p) {
perror("malloc");
return NULL;
}
strcpy(p, data);
return p;
}
/** Creates a nil type ValueObject structure.
*
* \return A pointer to a nil type ValueObject structure.
*
* \retval NULL malloc was unable to allocate memory. */
ValueObject *createNilValueObject(void)
{
ValueObject *p = malloc(sizeof(ValueObject));
if (!p) {
perror("malloc");
return NULL;
}
p->type = VT_NIL;
p->semaphore = 1;
return p;
}
/** Creates a boolean type ValueObject structure.
*
* \return A pointer to a boolean type ValueObject structure with value
* \c 0 if \a data equals 0 and \c 1 otherwise.
*
* \retval NULL malloc was unable to allocate memory. */
ValueObject *createBooleanValueObject(int data) /**< [in] The boolean data to store. */
{
ValueObject *p = malloc(sizeof(ValueObject));
if (!p) {
perror("malloc");
return NULL;
}
p->type = VT_BOOLEAN;
p->data.i = (data != 0);
p->semaphore = 1;
return p;
}
/** Creates an integer type ValueObject structure.
*
* \return A pointer to an integer type ValueObject structure with value
* \a data.
*
* \retval NULL malloc was unable to allocate memory. */
ValueObject *createIntegerValueObject(int data) /**< [in] The integer data to store. */
{
ValueObject *p = malloc(sizeof(ValueObject));
if (!p) {
perror("malloc");
return NULL;
}
p->type = VT_INTEGER;
p->data.i = data;
p->semaphore = 1;
return p;
}
/** Creates a floating point data decimal type ValueObject structure.
*
* \return A pointer to a floating point decimal type ValueObject structure
* with value \a data.
*
* \retval NULL malloc was unable to allocate memory. */
ValueObject *createFloatValueObject(float data) /**< [in] The floating point data to store. */
{
ValueObject *p = malloc(sizeof(ValueObject));
if (!p) {
perror("malloc");
return NULL;
}
p->type = VT_FLOAT;
p->data.f = data;
p->semaphore = 1;
return p;
}
/** Creates a string type ValueObject structure.
*
* \return A pointer to a string type ValueObject structure with value \a data.
*
* \retval NULL malloc was unable to allocate memory. */
ValueObject *createStringValueObject(char *data) /**< [in] The string data to store. */
{
ValueObject *p = malloc(sizeof(ValueObject));
if (!p) {
perror("malloc");
return NULL;
}
p->type = VT_STRING;
p->data.s = data;
p->semaphore = 1;
return p;
}
/** Creates a function type ValueObject structure.
*
* \return A pointer to a function type ValueObject structure with definition \a data.
*
* \retval NULL malloc was unable to allocate memory. */
ValueObject *createFunctionValueObject(FuncDefStmtNode *data) /**< [in] The function definition to store. */
{
ValueObject *p = malloc(sizeof(ValueObject));
if (!p) {
perror("malloc");
return NULL;
}
p->type = VT_FUNC;
p->data.fn = data;
p->semaphore = 1;
return p;
}
/** Copies a ValueObject structure.
*
* \note What this function actually does is increment a semaphore in \a value
* and return \a value. The semaphore gets decremented when \a value
* gets deleted by deleteValueObject(ValueObject *). This way, an
* immutable copy of a ValueObject structure may be made without actaully
* copying its blocks of memory; this reduces the overhead associated
* with copying a ValueObject strcuture while still preserving its
* functionality.
*
* \pre \a value was created by either createNilValueObject(void), createBooleanValueObject(int),
* createIntegerValueObject(int), createFloatValueObject(float), createStringValueObject(char *),
* or copied with copyValueObject(ValueObject *).
*
* \return A pointer to a ValueObject with the same type and contents as
* \a value.
*
* \retval NULL The type of \a value is unknown.
*
* \see createNilValueObject(void)
* \see createBooleanValueObject(int)
* \see createIntegerValueObject(int)
* \see createFloatValueObject(float)
* \see createStringValueObject(char *)
* \see deleteValueObject(ValueObject *) */
ValueObject *copyValueObject(ValueObject *value) /**< [in,out] The ValueObject structure to create a copy of. */
{
V(value);
return value;
}
/** Deletes a ValueObject structure.
*
* \pre \a value was created by either createNilValueObject(void), createBooleanValueObject(int),
* createIntegerValueObject(int), createFloatValueObject(float), createStringValueObject(char *),
* or copied with copyValueObject(ValueObject *).
*
* \post The memory at \a value and any of its associated members will be
* freed (see note).
*
* \note What this function actually does is decrement a semaphore in \a value
* and delete \a value if the semaphore reaches 0 as a result of the
* decrement. The semaphore gets incremented when either the value is
* created or it gets copied by copyValueObject(ValueObject *). This
* way, an immutable copy of a ValueObject structure may be made without
* actually copying its blocks of memory.
*
* \see createNilValueObject(void)
* \see createBooleanValueObject(int)
* \see createIntegerValueObject(int)
* \see createFloatValueObject(float)
* \see createStringValueObject(char *)
* \see copyValueObject(ValueObject *) */
void deleteValueObject(ValueObject *value) /**< [in,out] A pointer to the ValueObject structure to be deleted. */
{
if (!value) return;
P(value);
if (!value->semaphore) {
if (value->type == VT_STRING) free(value->data.s);
/* FuncDefStmtNode structures get freed with the parse tree */
free(value);
}
}
/** Creates a ReturnObject structure.
*
* \pre \a value was created by either createNilValueObject(void), createBooleanValueObject(int),
* createIntegerValueObject(int), createFloatValueObject(float), createStringValueObject(char *),
* or copied with copyValueObject(ValueObject *).
*
* \return A pointer to a ReturnObject structure with the desired properties.
*
* \retval NULL malloc was unable to allocate memory.
*
* \see deleteReturnObject(ReturnObject *) */
ReturnObject *createReturnObject(ReturnType type, /**< [in] The type of return encountered. */
ValueObject *value) /**< [in] A pointer to the ValueObject structure specifying the return value (optional, \c NULL if unused). */
{
ReturnObject *p = malloc(sizeof(ReturnObject));
if (!p) {
perror("malloc");
return NULL;
}
p->type = type;
p->value = value;
return p;
}
/** Deletes a ReturnObject structure.
*
* \pre \a object was created by createReturnObject(ReturnType, ValueObject *).
*
* \post The memory at \a object and any of its associated members will be
* freed.
*
* \see createReturnObject(ReturnType, ValueObject *) */
void deleteReturnObject(ReturnObject *object) /**< [in,out] The ReturnObject structure to be deleted. */
{
if (!object) return;
if (object->type == RT_RETURN)
deleteValueObject(object->value);
free(object);
}
/** Creates a ScopeObject structure.
*
* \pre \a scope 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.
*
* \return A pointer to a ScopeObject structure with the desired properties.
*
* \retval NULL malloc was unable to allocate memory.
*
* \see deleteScopeObject(ScopeObject *) */
ScopeObject *createScopeObject(ScopeObject *parent) /**< [in] A pointer to the parent ScopeObject. */
{
ScopeObject *p = malloc(sizeof(ScopeObject));
if (!p) {
perror("malloc");
return NULL;
}
p->impvar = createNilValueObject();
if (!p->impvar) {
free(p);
return NULL;
}
p->numvals = 0;
p->names = NULL;
p->values = NULL;
p->parent = parent;
return p;
}
/** Deletes a ScopeObject structure.
*
* \pre \a scope was created by createScopeObject(ScopeObject *) and contains
* contents added by createScopeValue(ScopeObject *, IdentifierNode *) and
* contents updated by updateScopeValue(ScopeObject *, IdentifierNode *, ValueObject *).
*
* \post The memory at \a scope and any of its associated members will be
* freed.
*
* \see createScopeObject(ScopeObject *) */
void deleteScopeObject(ScopeObject *scope) /**< [in,out] The ScopeObject structure to delete. */
{
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. */
deleteValueObject(scope->values[n]);
}
free(scope->names);
free(scope->values);
deleteValueObject(scope->impvar);
free(scope);
}
/** Retrieves a named ValueObject structure from a ScopeObject structure,
* traversing its parents if necessary.
*
* \pre \a scope was created by createScopeObject(ScopeObject *) and contains
* contents added by createScopeValue(ScopeObject *, IdentifierNode *) and
* contents updated by updateScopeValue(ScopeObject *, IdentifierNode *, ValueObject *).
* \pre \a target was created by createIdentifierNode(char *, const char *, unsigned int).
*
* \return A pointer to the stored ValueObject structure named by \a target.
*
* \retval NULL \a target could not be found in \a scope.
*
* \see getLocalScopeValue(ScopeObject *, IdentifierNode *)
* \see createScopeValue(ScopeObject *, IdentifierNode *)
* \see updateScopeValue(ScopeObject *, IdentifierNode *, ValueObject *)
* \see deleteScopeValue(ScopeObject *, IdentifierNode *) */
ValueObject *getScopeValue(ScopeObject *scope, /**< [in] The ScopeObject structure to check. */
IdentifierNode *target) /**< [in] The name of the value to find. */
{
ScopeObject *current = scope;
/* 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))
return current->values[n];
}
} while ((current = current->parent));
return NULL;
}
/** Retrieves a named ValueObject structure from a ScopeObject structure without
* traversing through its parents.
*
* \pre \a scope was created by createScopeObject(ScopeObject *) and contains
* contents added by createScopeValue(ScopeObject *, IdentifierNode *) and
* contents updated by updateScopeValue(ScopeObject *, IdentifierNode *, ValueObject *).
* \pre \a target was created by createIdentifierNode(char *, const char *, unsigned int).
*
* \return A pointer to the stored ValueObject structure named by \a target.
*
* \retval NULL \a target could not be found in \a scope.
*
* \see getScopeValue(ScopeObject *, IdentifierNode *)
* \see createScopeValue(ScopeObject *, IdentifierNode *)
* \see updateScopeValue(ScopeObject *, IdentifierNode *, ValueObject *)
* \see deleteScopeValue(ScopeObject *, IdentifierNode *) */
ValueObject *getLocalScopeValue(ScopeObject *scope, /**< [in] The ScopeObject structure to check. */
IdentifierNode *target) /**< [in] The name of the value to find. */
{
unsigned int n;
/* Check for value in current scope */
for (n = 0; n < scope->numvals; n++) {
if (!strcmp(scope->names[n]->image, target->image))
return scope->values[n];
}
return NULL;
}
/** Creates a new, nil, named ValueObject structure in a ScopeObject structure.
*
* \pre \a scope was created by createScopeObject(ScopeObject *) and contains
* contents added by createScopeValue(ScopeObject *, IdentifierNode *) and
* contents updated by updateScopeValue(ScopeObject *, IdentifierNode *, ValueObject *).
* \pre \a target was created by createIdentifierNode(char *, const char *, unsigned int).
*
* \return A pointer to the newly created ValueObject structure named by
* \a target.
*
* \retval NULL realloc was unable to allocate memory.
*
* \see getScopeValue(ScopeObject *, IdentifierNode *)
* \see getLocalScopeValue(ScopeObject *, IdentifierNode *)
* \see updateScopeValue(ScopeObject *, IdentifierNode *, ValueObject *)
* \see deleteScopeValue(ScopeObject *, IdentifierNode *) */
ValueObject *createScopeValue(ScopeObject *scope, /**< [in,out] The ScopeObject structure to add a value to. */
IdentifierNode *target) /**< [in] The name of the value to add. */
{
unsigned int newnumvals = scope->numvals + 1;
void *mem1 = NULL, *mem2 = NULL;
/* Add value to local scope */
mem1 = realloc(scope->names, sizeof(IdentifierNode *) * newnumvals);
if (!mem1) {
perror("realloc");
return NULL;
}
mem2 = realloc(scope->values, sizeof(ValueObject *) * newnumvals);
if (!mem2) {
perror("realloc");
return NULL;
}
scope->names = mem1;
scope->values = mem2;
scope->names[scope->numvals] = target;
scope->values[scope->numvals] = createNilValueObject();
if (!scope->values[scope->numvals])
return NULL;
scope->numvals = newnumvals;
return scope->values[scope->numvals - 1];
}
/** Updates a ValueObject structure named by an IdentifierNode structure in a
* ScopeObject structure.
*
* \pre \a scope was created by createScopeObject(ScopeObject *) and contains
* contents added by createScopeValue(ScopeObject *, IdentifierNode *) and
* contents updated by updateScopeValue(ScopeObject *, IdentifierNode *, ValueObject *).
* \pre \a target was created by createIdentifierNode(char *, const char *, unsigned int).
* \pre The value named by \a target was created by createScopeValue(ScopeObject *, IdentifierNode *).
* \pre \a value was created by either createNilValueObject(void), createBooleanValueObject(int),
* createIntegerValueObject(int), createFloatValueObject(float), createStringValueObject(char *),
* or copied with copyValueObject(ValueObject *).
*
* \return A pointer to the updated ValueObject structure named by \a target
* (will be the same as \a val).
*
* \retval NULL \a target could not be found in \a scope.
*
* \see getScopeValue(ScopeObject *, IdentifierNode *)
* \see getLocalScopeValue(ScopeObject *, IdentifierNode *)
* \see createScopeValue(ScopeObject *, IdentifierNode *)
* \see deleteScopeValue(ScopeObject *, IdentifierNode *) */
ValueObject *updateScopeValue(ScopeObject *scope, /**< [in,out] A pointer to the ScopeObject structure to update. */
IdentifierNode *target, /**< [in] A pointer to the IdentifierNode structure containing the name of the value to update. */
ValueObject *value) /**< [in] A pointer to the ValueObject structure containing the value to copy for the update. */
{
ScopeObject *current = scope;
/* 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)) {
/* Wipe out the old value */
deleteValueObject(current->values[n]);
/* Assign the new value */
if (value)
current->values[n] = value;
else
current->values[n] = createNilValueObject();
return current->values[n];
}
}
} while ((current = current->parent));
fprintf(stderr, "%s:%d: unable to store variable at: %s\n", target->fname, target->line, target->image);
return NULL;
}
/** Deletes a ValueObject structure named by an IdentifierNode structure in a
* ScopeObject structure.
*
* \pre \a scope was created by createScopeObject(ScopeObject *) and contains
* contents added by createScopeValue(ScopeObject *, IdentifierNode *) and
* contents updated by updateScopeValue(ScopeObject *, IdentifierNode *, ValueObject *).
* \pre \a target was created by createIdentifierNode(char *, const char *, unsigned int).
*
* \see getScopeValue(ScopeObject *, IdentifierNode *)
* \see getLocalScopeValue(ScopeObject *, IdentifierNode *)
* \see createScopeValue(ScopeObject *, IdentifierNode *)
* \see updateScopeValue(ScopeObject *, IdentifierNode *, ValueObject *) */
void deleteScopeValue(ScopeObject *scope, /**< [in,out] A pointer to the ScopeObject structure to delete from. */
IdentifierNode *target) /**< [in] A pointer to the IdentifierNode structure containing the name of the value to delete. */
{
ScopeObject *current = scope;
/* 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)) {
unsigned int i;
unsigned int newnumvals = scope->numvals - 1;
void *mem1 = NULL, *mem2 = NULL;
/* Don't delete anything in the names table
* because it's just pointers to IdentifierNode
* structures in the parse tree. */
/* Wipe out the value */
deleteValueObject(current->values[n]);
/* Reorder the tables */
for (i = n; i < current->numvals - 1; i++) {
current->names[i] = current->names[i + 1];
current->values[i] = current->values[i + 1];
}
/* Resize the tables */
mem1 = realloc(scope->names, sizeof(IdentifierNode *) * newnumvals);
if (!mem1) {
perror("realloc");
return;
}
mem2 = realloc(scope->values, sizeof(ValueObject *) * newnumvals);
if (!mem2) {
perror("realloc");
return;
}
scope->names = mem1;
scope->values = mem2;
scope->numvals = newnumvals;
return;
}
}
} while ((current = current->parent));
}
/** Checks if a string of characters follows the format for a number.
*
* \retval 0 The string of characters is not a number.
* \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);
/* Check for empty string */
if (len == 0) return 0;
/* Check for non-digit, non-hyphen, and non-period characters */
for (n = 0; n < len; n++) {
if (!isdigit(stringdata[n])
&& stringdata[n] != '.'
&& stringdata[n] != '-')
return 0;
}
return 1;
}
/** Checks if a string of characters follows the format for a hexadecimal
* number.
*
* \retval 0 The string of characters is not a hexadecimal number.
* \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);
/* Check for empty string */
if (len == 0) return 0;
/* Check for non-digit and non-A-through-F characters */
for (n = 0; n < len; n++) {
if (!isdigit(stringdata[n])
&& stringdata[n] != 'A'
&& stringdata[n] != 'B'
&& stringdata[n] != 'C'
&& stringdata[n] != 'D'
&& stringdata[n] != 'E'
&& stringdata[n] != 'F'
&& stringdata[n] != 'a'
&& stringdata[n] != 'b'
&& stringdata[n] != 'c'
&& stringdata[n] != 'd'
&& stringdata[n] != 'e'
&& stringdata[n] != 'f')
return 0;
}
return 1;
}
/** Casts the contents of a ValueObject structure to boolean type in an
* implicit context. Casting is not done directly to the ValueObject structure
* pointed to by \a node, instead, it is performed on a copy of that structure,
* which is what is returned.
*
* \pre \a node was created by either createNilValueObject(void), createBooleanValueObject(int),
* createIntegerValueObject(int), createFloatValueObject(float), createStringValueObject(char *),
* or copied with copyValueObject(ValueObject *).
* \pre \a scope was created by createScopeObject(ScopeObject *).
*
* \return A pointer to a ValueObject structure with a copy of the contents of
* \a node, cast to boolean type.
*
* \retval NULL An error occurred while casting.
*
* \see castIntegerImplicit(ValueObject *, ScopeObject *)
* \see castFloatImplicit(ValueObject *, ScopeObject *)
* \see castStringImplicit(ValueObject *, ScopeObject *) */
ValueObject *castBooleanImplicit(ValueObject *node, /**< [in] The ValueObject structure to cast. */
ScopeObject *scope) /**< [in] The ScopeObject structure to use for variable interpolation. */
{
if (!node) return NULL;
return castBooleanExplicit(node, scope);
}
/** Casts the contents of a ValueObject structure to integer type in an
* implicit context. Casting is not done directly to the ValueObject structure
* pointed to by \a node, instead, it is performed on a copy of that structure,
* which is what is returned.
*
* \pre \a node was created by either createNilValueObject(void), createBooleanValueObject(int),
* createIntegerValueObject(int), createFloatValueObject(float), createStringValueObject(char *),
* or copied with copyValueObject(ValueObject *).
* \pre \a scope was created by createScopeObject(ScopeObject *).
*
* \return A pointer to a ValueObject structure with a copy of the contents of
* \a node, cast to integer type.
*
* \retval NULL An error occurred while casting.
*
* \see castBooleanImplicit(ValueObject *, ScopeObject *)
* \see castFloatImplicit(ValueObject *, ScopeObject *)
* \see castStringImplicit(ValueObject *, ScopeObject *) */
ValueObject *castIntegerImplicit(ValueObject *node, /**< [in] The ValueObject structure to cast. */
ScopeObject *scope) /**< [in] The ScopeObject structure to use for variable interpolation. */
{
if (!node) return NULL;
if (node->type == VT_NIL) {
fprintf(stderr, "Cannot implicitly cast nil\n");
return NULL;
}
else return castIntegerExplicit(node, scope);
}
/** Casts the contents of a ValueObject structure to floating point decimal
* type in an implicit context. Casting is not done directly to the
* ValueObject structure pointed to by \a node, instead, it is performed on a
* copy of that structure, which is what is returned.
*
* \pre \a node was created by either createNilValueObject(void), createBooleanValueObject(int),
* createIntegerValueObject(int), createFloatValueObject(float), createStringValueObject(char *),
* or copied with copyValueObject(ValueObject *).
* \pre \a scope was created by createScopeObject(ScopeObject *).
*
* \return A pointer to a ValueObject structure with a copy of the contents of
* \a node, cast to floating point decimal type.
*
* \retval NULL An error occurred while casting.
*
* \see castBooleanImplicit(ValueObject *, ScopeObject *)
* \see castIntegerImplicit(ValueObject *, ScopeObject *)
* \see castStringImplicit(ValueObject *, ScopeObject *) */
ValueObject *castFloatImplicit(ValueObject *node, /**< [in] The ValueObject structure to cast. */
ScopeObject *scope) /**< [in] The ScopeObject structure to use for variable interpolation. */
{
if (!node) return NULL;
if (node->type == VT_NIL) {
fprintf(stderr, "Cannot implicitly cast nil\n");
return NULL;
}
else return castFloatExplicit(node, scope);
}
/** Casts the contents of a ValueObject structure to string type in an implicit
* context. Casting is not done directly to the ValueObject structure pointed
* to by \a node, instead, it is performed on a copy of that structure, which
* is what is returned.
*
* \note \a scope is used to resolve variable interpolation within the string
* before casting it. Therefore, a simple way to interpolate the
* variables within a string is to call this function with it.
*
* \pre \a node was created by either createNilValueObject(void), createBooleanValueObject(int),
* createIntegerValueObject(int), createFloatValueObject(float), createStringValueObject(char *),
* or copied with copyValueObject(ValueObject *).
* \pre \a scope was created by createScopeObject(ScopeObject *).
*
* \return A pointer to a ValueObject structure with a copy of the contents of
* \a node, cast to string type.
*
* \retval NULL An error occurred while casting.
*
* \see castBooleanImplicit(ValueObject *, ScopeObject *)
* \see castIntegerImplicit(ValueObject *, ScopeObject *)
* \see castFloatImplicit(ValueObject *, ScopeObject *) */
ValueObject *castStringImplicit(ValueObject *node, /**< [in] The ValueObject structure to cast. */
ScopeObject *scope) /**< [in] The ScopeObject structure to use for variable interpolation. */
{
if (!node) return NULL;
if (node->type == VT_NIL) {
fprintf(stderr, "Cannot implicitly cast nil\n");
return NULL;
}
else return castStringExplicit(node, scope);
}
/** Casts the contents of a ValueObject structure to boolean type in an
* explicit context. Casting is not done directly to the ValueObject structure
* pointed to by \a node, instead, it is performed on a copy of that structure,
* which is what is returned.
*
* \pre \a node was created by either createNilValueObject(void), createBooleanValueObject(int),
* createIntegerValueObject(int), createFloatValueObject(float), createStringValueObject(char *),
* or copied with copyValueObject(ValueObject *).
* \pre \a scope was created by createScopeObject(ScopeObject *).
*
* \return A pointer to a ValueObject structure with a copy of the contents of
* \a node, cast to boolean type.
*
* \retval NULL An error occurred while casting.
*
* \see castIntegerExplicit(ValueObject *, ScopeObject *)
* \see castFloatExplicit(ValueObject *, ScopeObject *)
* \see castStringExplicit(ValueObject *, ScopeObject *) */
ValueObject *castBooleanExplicit(ValueObject *node, /**< [in] The ValueObject structure to cast. */
ScopeObject *scope) /**< [in] The ScopeObject structure to use for variable interpolation. */
{
if (!node) return NULL;
switch (node->type) {
case VT_NIL:
return createBooleanValueObject(0);
case VT_BOOLEAN:
return createBooleanValueObject(getInteger(node));
case VT_INTEGER:
return createBooleanValueObject(getInteger(node) != 0);
case VT_FLOAT:
return createBooleanValueObject(getFloat(node) != 0.0);
case VT_STRING:
if (strstr(getString(node), ":{")) {
/* Perform interpolation */
ValueObject *ret = NULL;
ValueObject *interp = castStringExplicit(node, scope);
if (!interp) return NULL;
ret = createBooleanValueObject(getString(interp)[0] != '\0');
deleteValueObject(interp);
return ret;
}
else
return createBooleanValueObject(getString(node)[0] != '\0');
}
fprintf(stderr, "Unknown value type encountered during boolean cast\n");
return NULL;
}
/** Casts the contents of a ValueObject structure to integer type in an
* explicit context. Casting is not done directly to the ValueObject structure
* pointed to by \a node, instead, it is performed on a copy of that structure,
* which is what is returned.
*
* \pre \a node was created by either createNilValueObject(void), createBooleanValueObject(int),
* createIntegerValueObject(int), createFloatValueObject(float), createStringValueObject(char *),
* or copied with copyValueObject(ValueObject *).
* \pre \a scope was created by createScopeObject(ScopeObject *).
*
* \return A pointer to a ValueObject structure with a copy of the contents of
* \a node, cast to integer type.
*
* \retval NULL An error occurred while casting.
*
* \see castBooleanExplicit(ValueObject *, ScopeObject *)
* \see castFloatExplicit(ValueObject *, ScopeObject *)
* \see castStringExplicit(ValueObject *, ScopeObject *) */
ValueObject *castIntegerExplicit(ValueObject *node, /**< [in] The ValueObject structure to cast. */
ScopeObject *scope) /**< [in] The ScopeObject structure to use for variable interpolation. */
{
if (!node) return NULL;
switch (node->type) {
case VT_NIL:
return createIntegerValueObject(0);
case VT_BOOLEAN:
case VT_INTEGER:
return createIntegerValueObject(getInteger(node));
case VT_FLOAT:
return createIntegerValueObject(getFloat(node));
case VT_STRING:
if (strstr(getString(node), ":{")) {
/* Perform interpolation */
ValueObject *ret = NULL;
ValueObject *interp = castStringExplicit(node, scope);
int value;
if (!interp) return NULL;
if (!isNumString(getString(interp))) {
fprintf(stderr, "Unable to cast value\n");
deleteValueObject(interp);
return NULL;
}
sscanf(getString(interp), "%i", &value);
ret = createIntegerValueObject(value);
deleteValueObject(interp);
return ret;
}
else {
int value;
if (!isNumString(getString(node))) {
fprintf(stderr, "Unable to cast value\n");
return NULL;
}
sscanf(getString(node), "%i", &value);
return createIntegerValueObject(value);
}
}
fprintf(stderr, "Unknown value type encountered during integer cast\n");
return NULL;
}
/** Casts the contents of a ValueObject structure to floating point decimal
* type in an explicit context. Casting is not done directly to the
* ValueObject structure pointed to by \a node, instead, it is performed on a
* copy of that structure, which is what is returned.
*
* \pre \a node was created by either createNilValueObject(void), createBooleanValueObject(int),
* createIntegerValueObject(int), createFloatValueObject(float), createStringValueObject(char *),
* or copied with copyValueObject(ValueObject *).
* \pre \a scope was created by createScopeObject(ScopeObject *).
*
* \return A pointer to a ValueObject structure with a copy of the contents of
* \a node, cast to floating point decimal type.
*
* \retval NULL An error occurred while casting.
*
* \see castBooleanExplicit(ValueObject *, ScopeObject *)
* \see castIntegerExplicit(ValueObject *, ScopeObject *)
* \see castStringExplicit(ValueObject *, ScopeObject *) */
ValueObject *castFloatExplicit(ValueObject *node, /**< [in] The ValueObject structure to cast. */
ScopeObject *scope) /**< [in] The ScopeObject structure to use for variable interpolation. */
{
if (!node) return NULL;
switch (node->type) {
case VT_NIL:
return createFloatValueObject(0.0);
case VT_BOOLEAN:
case VT_INTEGER:
return createFloatValueObject(getInteger(node));
case VT_FLOAT:
return createFloatValueObject(getFloat(node));
case VT_STRING:
if (strstr(getString(node), ":{")) {
/* Perform interpolation */
ValueObject *ret = NULL;
ValueObject *interp = castStringExplicit(node, scope);
float value;
if (!interp) return NULL;
if (!isNumString(getString(interp))) {
fprintf(stderr, "Unable to cast value\n");
deleteValueObject(interp);
return NULL;
}
sscanf(getString(interp), "%f", &value);
ret = createFloatValueObject(value);
deleteValueObject(interp);
return ret;
}
else {
float value;
if (!isNumString(getString(node))) {
fprintf(stderr, "Unable to cast value\n");
return NULL;
}
sscanf(getString(node), "%f", &value);
return createFloatValueObject(value);
}
}
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
* context. Casting is not done to directly the ValueObject structure pointed
* to by \a node, instead, it is performed on a copy of that structure, which
* is what is returned.
*
* \note \a scope is used to resolve variable interpolation within the string
* before casting it. Therefore, a simple way to interpolate the
* variables within a string is to call this function with it.
*
* \pre \a node was created by either createNilValueObject(void), createBooleanValueObject(int),
* createIntegerValueObject(int), createFloatValueObject(float), createStringValueObject(char *),
* or copied with copyValueObject(ValueObject *).
* \pre \a scope was created by createScopeObject(ScopeObject *).
*
* \return A pointer to a ValueObject structure with a copy of the contents of
* \a node, cast to string type.
*
* \retval NULL An error occurred while casting.
*
* \see castBooleanExplicit(ValueObject *, ScopeObject *)
* \see castIntegerExplicit(ValueObject *, ScopeObject *)
* \see castFloatExplicit(ValueObject *, ScopeObject *) */
ValueObject *castStringExplicit(ValueObject *node, /**< [in] The ValueObject structure to cast. */
ScopeObject *scope) /**< [in] The ScopeObject structure to use for variable interpolation. */
{
if (!node) return NULL;
switch (node->type) {
case VT_NIL: {
char *str = createString("");
if (!str) return NULL;
return createStringValueObject(str);
}
case VT_BOOLEAN: {
/** \note The spec does not define how TROOFs may be
* cast to YARNs. */
fprintf(stderr, "Cannot cast TROOF to YARN\n");
return NULL;
}
case VT_INTEGER: {
char *data = NULL;
/* One character per integer bit plus one more for the
* null character */
size_t size = sizeof(int) * 8 + 1;
data = malloc(sizeof(char) * size);
if (!data) return NULL;
sprintf(data, "%i", getInteger(node));
return createStringValueObject(data);
}
case VT_FLOAT: {
char *data = NULL;
unsigned int precision = 2;
/* One character per float bit plus one more for the
* null character */
size_t size = sizeof(float) * 8 + 1;
data = malloc(sizeof(char) * size);
if (!data) return NULL;
sprintf(data, "%f", getFloat(node));
/* Truncate to a certain number of decimal places */
strchr(data, '.')[precision + 1] = '\0';
return createStringValueObject(data);
}
case VT_STRING: {
char *temp = NULL;
char *data = NULL;
char *str = getString(node);
unsigned int a, b, size;
/* Perform interpolation */
size = strlen(getString(node)) + 1;
temp = malloc(sizeof(char) * size);
for (a = 0, b = 0; str[b] != '\0'; ) {
if (!strncmp(str + b, ":)", 2)) {
temp[a] = '\n';
a++, b += 2;
}
else if (!strncmp(str + b, ":>", 2)) {
temp[a] = '\t';
a++, b += 2;
}
else if (!strncmp(str + b, ":o", 2)) {
temp[a] = '\a';
a++, b += 2;
}
else if (!strncmp(str + b, ":\"", 2)) {
temp[a] = '"';
a++, b += 2;
}
else if (!strncmp(str + b, "::", 2)) {
temp[a] = ':';
a++, b += 2;
}
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));
long codepoint;
char out[3];
unsigned short num;
void *mem = NULL;
strncpy(image, start, len);
image[len] = '\0';
if (!isHexString(image)) {
fprintf(stderr, "Please supply a valid hexadecimal number\n");
free(temp);
free(image);
return NULL;
}
codepoint = strtol(image, NULL, 16);
free(image);
num = convertCodePointToUTF8(codepoint, out);
if (num == 0) {
free(temp);
return NULL;
}
size += num;
mem = realloc(temp, size);
if (!mem) {
perror("realloc");
free(temp);
return NULL;
}
temp = mem;
strncpy(temp + a, out, num);
a += num, b += len + 3;
}
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));
long codepoint;
char out[3];
unsigned short num;
void *mem = NULL;
strncpy(image, start, len);
strncpy(image, start, len);
image[len] = '\0';
codepoint = convertNormativeNameToCodePoint(image);
free(image);
if (codepoint < 0) {
free(temp);
return NULL;
}
num = convertCodePointToUTF8(codepoint, out);
size += num;
mem = realloc(temp, size);
if (!mem) {
perror("realloc");
free(temp);
return NULL;
}
temp = mem;
strncpy(temp + a, out, num);
a += num, b += len + 3;
}
else if (!strncmp(str + b, ":{", 2)) {
IdentifierNode *target = NULL;
ValueObject *val = NULL, *use = NULL;
/* 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));
void *mem = NULL;
strncpy(image, start, len);
image[len] = '\0';
if (!strcmp(image, "IT"))
/* Lookup implicit variable */
val = scope->impvar;
else {
/* Create a new IdentifierNode
* structure and lookup its
* value */
target = createIdentifierNode(image, NULL, 0);
if (!target) {
free(temp);
return NULL;
}
val = getScopeValue(scope, target);
if (!val) {
fprintf(stderr, "Variable does not exist at: %s\n", image);
deleteIdentifierNode(target);
free(temp);
return NULL;
}
deleteIdentifierNode(target);
}
/* Cast the variable value to a string */
if (!(use = castStringImplicit(val, scope))) {
free(temp);
return NULL;
}
/* Update the size of the new string */
size += strlen(getString(use));
mem = realloc(temp, size);
if (!mem) {
perror("realloc");
free(temp);
}
temp = mem;
/* Copy the variable string into the new string */
strcpy(temp + a, getString(use));
a += strlen(getString(use)), b += len + 3;
deleteValueObject(use);
}
else {
temp[a] = str[b];
a++, b++;
}
}
temp[a] = '\0';
data = malloc(sizeof(char) * (strlen(temp) + 1));
strcpy(data, temp);
free(temp);
return createStringValueObject(data);
}
}
fprintf(stderr, "Unknown value type encountered during string cast\n");
return NULL;
}
/** Interprets an implicit variable expression.
*
* \pre \a node was created by createExprNode(ExprType type, void *expr)
* where \a type is ET_IMPVAR and \a expr is NULL.
* \pre \a scope was created by createScopeObject(ScopeObject *) and contains
* contents added by createScopeValue(ScopeObject *, IdentifierNode *) and
* contents updated by updateScopeValue(ScopeObject *, IdentifierNode *, ValueObject *).
*
* \note \a node is not used by this function but is still included in its
* prototype to allow this function to be stored in a jump table for fast
* execution.
*
* \return A pointer to a ValueObject structure containing the value of the
* current scope's implicit variable.
*
* \see interpretCastExprNode(ExprNode *, ScopeObject *)
* \see interpretFuncCallExprNode(ExprNode *, ScopeObject *)
* \see interpretIdentifierExprNode(ExprNode *, ScopeObject *)
* \see interpretConstantExprNode(ExprNode *, ScopeObject *) */
ValueObject *interpretImpVarExprNode(ExprNode *node, /**< [in] A pointer to an ExprNode structure with type set to ET_IMPVAR. */
ScopeObject *scope) /**< Not used (see note). */
{
node = NULL;
return scope->impvar;
}
/** Interprets a cast expression.
*
* \pre \a node was created by createExprNode(ExprType type, void *expr)
* where \a type is ET_CAST and \a expr is a CastExprNode structure
* created by createCastExprNode(ExprNode *, TypeNode *).
* \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 pointer to a ValueObject structure containing the result of the
* cast.
*
* \retval NULL An error occurred during interpretation.
*
* \see interpretImpVarExprNode(ExprNode *, ScopeObject *)
* \see interpretFuncCallExprNode(ExprNode *, ScopeObject *)
* \see interpretIdentifierExprNode(ExprNode *, ScopeObject *)
* \see interpretConstantExprNode(ExprNode *, ScopeObject *) */
ValueObject *interpretCastExprNode(ExprNode *node, /**< [in] A pointer to an ExprNode structure containing the CastExprNode structure to interpret. */
ScopeObject *scope) /**< [in,out] A pointer to a ScopeObject structure to evaluate \a node under. */
{
CastExprNode *expr = (CastExprNode *)node->expr;
ValueObject *val = interpretExprNode(expr->target, scope);
ValueObject *ret = NULL;
if (!val) return NULL;
switch(expr->newtype->type) {
case CT_NIL:
deleteValueObject(val);
return createNilValueObject();
case CT_BOOLEAN:
ret = castBooleanExplicit(val, scope);
deleteValueObject(val);
return ret;
case CT_INTEGER:
ret = castIntegerExplicit(val, scope);
deleteValueObject(val);
return ret;
case CT_FLOAT:
ret = castFloatExplicit(val, scope);
deleteValueObject(val);
return ret;
case CT_STRING:
ret = castStringExplicit(val, scope);
deleteValueObject(val);
return ret;
default:
fprintf(stderr, "Unknown cast type\n");
deleteValueObject(val);
return NULL;
}
}
/** Interprets a function call expression.
*
* \pre \a node was created by createExprNode(ExprType type, void *expr)
* where \a type is ET_FUNCCALL and \a expr is a FunctionCallExprNode
* structure created by createFuncCallExprNode(FuncDefStmtNode *, ExprNodeList *).
* \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 pointer to a ValueObject structure containing the return value of
* function.
*
* \retval NULL An error occurred during interpretation.
*
* \see interpretImpVarExprNode(ExprNode *, ScopeObject *)
* \see interpretCastExprNode(ExprNode *, ScopeObject *)
* \see interpretIdentifierExprNode(ExprNode *, ScopeObject *)
* \see interpretConstantExprNode(ExprNode *, ScopeObject *) */
ValueObject *interpretFuncCallExprNode(ExprNode *node, /**< [in] A pointer to an ExprNode structure containing the FuncCallExprNode structure to interpret. */
ScopeObject *scope) /**< [in,out] A pointer to a ScopeObject structure to evaluate \a node under. */
{
FuncCallExprNode *expr = (FuncCallExprNode *)node->expr;
unsigned int n;
ScopeObject *outer = createScopeObject(scope);
ValueObject *def = NULL;
ReturnObject *retval = NULL;
ValueObject *ret = NULL;
if (!outer) return NULL;
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);
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);
deleteScopeObject(outer);
return NULL;
}
for (n = 0; n < getFunction(def)->args->num; n++) {
ValueObject *val = NULL;
if (!createScopeValue(outer, getFunction(def)->args->ids[n])) {
deleteScopeObject(outer);
return NULL;
}
if (!(val = interpretExprNode(expr->args->exprs[n], scope))) {
deleteScopeObject(outer);
return NULL;
}
if (!updateScopeValue(outer, getFunction(def)->args->ids[n], val)) {
deleteScopeObject(outer);
deleteValueObject(val);
return NULL;
}
}
/* \note We use interpretStmtNodeList(StmtNodeList *, ScopeObject *)
* here because we want to have access to the function's ScopeObject
* as we may need to retrieve the implicit variable in the case of
* a default return. */
if (!(retval = interpretStmtNodeList(getFunction(def)->body->stmts, outer))) {
deleteScopeObject(outer);
return NULL;
}
switch (retval->type) {
case RT_DEFAULT:
/* Extract return value */
ret = outer->impvar;
outer->impvar = NULL;
break;
case RT_BREAK:
ret = createNilValueObject();
break;
case RT_RETURN:
/* Extract return value */
ret = retval->value;
retval->value = NULL;
break;
default:
fprintf(stderr, "Invalid return type\n");
break;
}
deleteReturnObject(retval);
deleteScopeObject(outer);
return ret;
}
/** Interprets an identifier expression.
*
* \pre \a node was created by createExprNode(ExprType type, void *expr)
* where \a type is ET_IDENTIFIER and \a expr is an IdentifierNode
* structure created by createIdentifierNode(char *, 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 *).
*
* \note \a scope is not used by this function but is still included in its
* prototype to allow this function to be stored in a jump table for fast
* execution.
*
* \return A pointer to a ValueObject structure containing the return value of
* function.
*
* \retval NULL An error occurred during interpretation.
*
* \see interpretImpVarExprNode(ExprNode *, ScopeObject *)
* \see interpretCastExprNode(ExprNode *, ScopeObject *)
* \see interpretFuncCallExprNode(ExprNode *, ScopeObject *)
* \see interpretConstantExprNode(ExprNode *, ScopeObject *) */
ValueObject *interpretIdentifierExprNode(ExprNode *node, /**< [in] A pointer to an ExprNode structure containing the IdentifierNode structure to interpret. */
ScopeObject *scope) /**< Not used (see note). */
{
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);
return NULL;
}
return copyValueObject(val);
}
/** Interprets a constant expression.
*
* \pre \a node was created by createExprNode(ExprType type, void *expr)
* where \a type is ET_CONSTANT and \a expr is a ConstantNode structure
* created by either createBooleanConstantNode(int), createIntegerConstantNode(int),
* createFloatConstantNode(float), or createStringConstantNode(char *).
* \pre \a scope was created by createScopeObject(ScopeObject *) and contains
* contents added by createScopeValue(ScopeObject *, IdentifierNode *) and
* contents updated by updateScopeValue(ScopeObject *, IdentifierNode *, ValueObject *).
*
* \note \a scope is not used by this function but is still included in its
* prototype to allow this function to be stored in a jump table for fast
* execution.
*
* \return A pointer to a ValueObject structure containing the return value of
* function.
*
* \retval NULL An error occurred during interpretation.
*
* \see interpretImpVarExprNode(ExprNode *, ScopeObject *)
* \see interpretCastExprNode(ExprNode *, ScopeObject *)
* \see interpretFuncCallExprNode(ExprNode *, ScopeObject *)
* \see interpretIdentifierExprNode(ExprNode *, ScopeObject *) */
ValueObject *interpretConstantExprNode(ExprNode *node, /**< [in] A pointer to an ExprNode structure containing the ConstantNode structure to interpret. */
ScopeObject *scope) /**< Not used (see note). */
{
ConstantNode *expr = (ConstantNode *)node->expr;
scope = NULL;
switch (expr->type) {
case CT_NIL:
return createNilValueObject();
case CT_BOOLEAN:
return createBooleanValueObject(expr->data.i);
case CT_INTEGER:
return createIntegerValueObject(expr->data.i);
case CT_FLOAT:
return createFloatValueObject(expr->data.f);
case CT_STRING: {
/** \note For efficiency, string interpolation should be
* performed by caller because it only needs to
* be performed when necessary. */
char *str = createString(expr->data.s);
if (!str) return NULL;
return createStringValueObject(str);
}
default:
fprintf(stderr, "Unknown constant type\n");
return NULL;
}
}
/** Interprets a logical NOT operation expression.
*
* \pre \a expr was created by createOpExprNode(OpType type, ExprNodeList *args)
* where \a type is OP_NOT and \a args was created by createExprNodeList(void)
* and populated with ExprNode structures using addExprNode(ExprNodeList *, ExprNode *).
* \pre \a scope was created by createScopeObject(ScopeObject *) and contains
* contents added by createScopeValue(ScopeObject *, IdentifierNode *) and
* contents updated by updateScopeValue(ScopeObject *, IdentifierNode *, ValueObject *).
*
* \note Only the first element in \a args is considered.
*
* \return A pointer to a ValueObject structure containing the interpreted
* operation expression value.
*
* \retval NULL An error occurred during interpretation.
*
* \see interpretArithOpExprNode(OpExprNode *, ScopeObject *)
* \see interpretBoolOpExprNode(OpExprNode *, ScopeObject *)
* \see interpretEqualityOpExprNode(OpExprNode *, ScopeObject *)
* \see interpretConcatOpExprNode(OpExprNode *, ScopeObject *) */
ValueObject *interpretNotOpExprNode(OpExprNode *expr, /**< [in] A pointer to the OpExprNode structure to interpret. */
ScopeObject *scope) /**< [in] A pointer to the ScopeObject structure to evaluate \a expr under. */
{
ValueObject *val = interpretExprNode(expr->args->exprs[0], scope);
ValueObject *use = val;
int retval;
unsigned short cast = 0;
if (!val) return NULL;
if (val->type != VT_BOOLEAN && val->type != VT_INTEGER) {
use = castBooleanImplicit(val, scope);
if (!use) {
deleteValueObject(val);
return NULL;
}
cast = 1;
}
retval = getInteger(use);
if (cast) deleteValueObject(use);
deleteValueObject(val);
return createBooleanValueObject(!retval);
}
/** Adds two integers.
*
* \pre \a a and \a b were created by createIntegerValueObject(int).
*
* \return A pointer to a ValueObject structure containing the sum of the
* values \a a and \a b.
*
* \see opSubIntegerInteger(ValueObject *, ValueObject *)
* \see opMultIntegerInteger(ValueObject *, ValueObject *)
* \see opDivIntegerInteger(ValueObject *, ValueObject *)
* \see opMaxIntegerInteger(ValueObject *, ValueObject *)
* \see opMinIntegerInteger(ValueObject *, ValueObject *)
* \see opModIntegerInteger(ValueObject *, ValueObject *) */
ValueObject *opAddIntegerInteger(ValueObject *a, /**< [in] The first term to add. */
ValueObject *b) /**< [in] The second term to add. */
{
return createIntegerValueObject(getInteger(a) + getInteger(b));
}
/** Subtracts two integers.
*
* \pre \a a and \a b were created by createIntegerValueObject(int).
*
* \return A pointer to a ValueObject structure containing the difference of
* the values \a a and \a b.
*
* \see opAddIntegerInteger(ValueObject *, ValueObject *)
* \see opMultIntegerInteger(ValueObject *, ValueObject *)
* \see opDivIntegerInteger(ValueObject *, ValueObject *)
* \see opMaxIntegerInteger(ValueObject *, ValueObject *)
* \see opMinIntegerInteger(ValueObject *, ValueObject *)
* \see opModIntegerInteger(ValueObject *, ValueObject *) */
ValueObject *opSubIntegerInteger(ValueObject *a, /**< [in] The minuend. */
ValueObject *b) /**< [in] The subtrahend. */
{
return createIntegerValueObject(getInteger(a) - getInteger(b));
}
/** Multiplies two integers.
*
* \pre \a a and \a b were created by createIntegerValueObject(int).
*
* \return A pointer to a ValueObject structure containing the product of the
* values \a a and \a b.
*
* \see opAddIntegerInteger(ValueObject *, ValueObject *)
* \see opSubIntegerInteger(ValueObject *, ValueObject *)
* \see opDivIntegerInteger(ValueObject *, ValueObject *)
* \see opMaxIntegerInteger(ValueObject *, ValueObject *)
* \see opMinIntegerInteger(ValueObject *, ValueObject *)
* \see opModIntegerInteger(ValueObject *, ValueObject *) */
ValueObject *opMultIntegerInteger(ValueObject *a, /**< [in] The first factor to multiply. */
ValueObject *b) /**< [in] The second factor to multiply. */
{
return createIntegerValueObject(getInteger(a) * getInteger(b));
}
/** Divides two integers.
*
* \pre \a a and \a b were created by createIntegerValueObject(int).
*
* \return A pointer to a ValueObject structure containing the quotient of the
* values \a a and \a b.
*
* \retval NULL Division by zero was attempted.
*
* \see opAddIntegerInteger(ValueObject *, ValueObject *)
* \see opSubIntegerInteger(ValueObject *, ValueObject *)
* \see opMultIntegerInteger(ValueObject *, ValueObject *)
* \see opMaxIntegerInteger(ValueObject *, ValueObject *)
* \see opMinIntegerInteger(ValueObject *, ValueObject *)
* \see opModIntegerInteger(ValueObject *, ValueObject *) */
ValueObject *opDivIntegerInteger(ValueObject *a, /**< [in] The dividend. */
ValueObject *b) /**< [in] The divisor. */
{
if (getInteger(b) == 0) {
fprintf(stderr, "Division by zero undefined\n");
return NULL;
}
return createIntegerValueObject(getInteger(a) / getInteger(b));
}
/** Finds the maximum of two integers.
*
* \pre \a a and \a b were created by createIntegerValueObject(int).
*
* \return A pointer to a ValueObject structure containing the maximum of the
* values \a a and \a b.
*
* \see opAddIntegerInteger(ValueObject *, ValueObject *)
* \see opSubIntegerInteger(ValueObject *, ValueObject *)
* \see opMultIntegerInteger(ValueObject *, ValueObject *)
* \see opDivIntegerInteger(ValueObject *, ValueObject *)
* \see opMinIntegerInteger(ValueObject *, ValueObject *)
* \see opModIntegerInteger(ValueObject *, ValueObject *) */
ValueObject *opMaxIntegerInteger(ValueObject *a, /**< [in] The first number to compare. */
ValueObject *b) /**< [in] The second number to compare. */
{
return createIntegerValueObject(getInteger(a) > getInteger(b) ? getInteger(a) : getInteger(b));
}
/** Finds the minimum of two integers.
*
* \pre \a a and \a b were created by createIntegerValueObject(int).
*
* \return A pointer to a ValueObject structure containing the minimum of the
* values \a a and \a b.
*
* \see opAddIntegerInteger(ValueObject *, ValueObject *)
* \see opSubIntegerInteger(ValueObject *, ValueObject *)
* \see opMultIntegerInteger(ValueObject *, ValueObject *)
* \see opDivIntegerInteger(ValueObject *, ValueObject *)
* \see opMaxIntegerInteger(ValueObject *, ValueObject *)
* \see opModIntegerInteger(ValueObject *, ValueObject *) */
ValueObject *opMinIntegerInteger(ValueObject *a, /**< [in] The first number to compare. */
ValueObject *b) /**< [in] The second number to compare. */
{
return createIntegerValueObject(getInteger(a) < getInteger(b) ? getInteger(a) : getInteger(b));
}
/** Calculates the modulus of two integers.
*
* \pre \a a and \a b were created by createIntegerValueObject(int).
*
* \return A pointer to a ValueObject structure containing the modulus of the
* values \a a and \a b.
*
* \see opAddIntegerInteger(ValueObject *, ValueObject *)
* \see opSubIntegerInteger(ValueObject *, ValueObject *)
* \see opMultIntegerInteger(ValueObject *, ValueObject *)
* \see opDivIntegerInteger(ValueObject *, ValueObject *)
* \see opMaxIntegerInteger(ValueObject *, ValueObject *)
* \see opMinIntegerInteger(ValueObject *, ValueObject *) */
ValueObject *opModIntegerInteger(ValueObject *a, /**< [in] The dividend. */
ValueObject *b) /**< [in] The divisor. */
{
if (getInteger(b) == 0) {
fprintf(stderr, "Division by zero undefined\n");
return NULL;
}
return createIntegerValueObject(getInteger(a) % getInteger(b));
}
/** Adds an integer and a float.
*
* \pre \a a was created by createIntegerValueObject(int) and \a b was created
* by createFloatValueObject(float).
*
* \return A pointer to a ValueObject structure containing the sum of the
* values \a a and \a b.
*
* \see opSubIntegerFloat(ValueObject *, ValueObject *)
* \see opMultIntegerFloat(ValueObject *, ValueObject *)
* \see opDivIntegerFloat(ValueObject *, ValueObject *)
* \see opMaxIntegerFloat(ValueObject *, ValueObject *)
* \see opMinIntegerFloat(ValueObject *, ValueObject *)
* \see opModIntegerFloat(ValueObject *, ValueObject *) */
ValueObject *opAddIntegerFloat(ValueObject *a, /**< [in] The first term to add. */
ValueObject *b) /**< [in] The second term to add. */
{
return createFloatValueObject(getInteger(a) + getFloat(b));
}
/** Subtracts an integer and a float.
*
* \pre \a a was created by createIntegerValueObject(int) and \a b was created
* by createFloatValueObject(float).
*
* \return A pointer to a ValueObject structure containing the difference of
* the values \a a and \a b.
*
* \see opAddIntegerFloat(ValueObject *, ValueObject *)
* \see opMultIntegerFloat(ValueObject *, ValueObject *)
* \see opDivIntegerFloat(ValueObject *, ValueObject *)
* \see opMaxIntegerFloat(ValueObject *, ValueObject *)
* \see opMinIntegerFloat(ValueObject *, ValueObject *)
* \see opModIntegerFloat(ValueObject *, ValueObject *) */
ValueObject *opSubIntegerFloat(ValueObject *a, /**< [in] The minuend. */
ValueObject *b) /**< [in] The subtrahend. */
{
return createFloatValueObject(getInteger(a) - getFloat(b));
}
/** Multiplies an integer and a float.
*
* \pre \a a was created by createIntegerValueObject(int) and \a b was created
* by createFloatValueObject(float).
*
* \return A pointer to a ValueObject structure containing the product of the
* values \a a and \a b.
*
* \see opAddIntegerFloat(ValueObject *, ValueObject *)
* \see opSubIntegerFloat(ValueObject *, ValueObject *)
* \see opDivIntegerFloat(ValueObject *, ValueObject *)
* \see opMaxIntegerFloat(ValueObject *, ValueObject *)
* \see opMinIntegerFloat(ValueObject *, ValueObject *)
* \see opModIntegerFloat(ValueObject *, ValueObject *) */
ValueObject *opMultIntegerFloat(ValueObject *a, /**< [in] The first factor to multiply. */
ValueObject *b) /**< [in] The second factor to multiply. */
{
return createFloatValueObject(getInteger(a) * getFloat(b));
}
/** Divides an integer and a float.
*
* \pre \a a was created by createIntegerValueObject(int) and \a b was created
* by createFloatValueObject(float).
*
* \return A pointer to a ValueObject structure containing the quotient of the
* values \a a and \a b.
*
* \retval NULL Division by zero was attempted.
*
* \see opAddIntegerFloat(ValueObject *, ValueObject *)
* \see opSubIntegerFloat(ValueObject *, ValueObject *)
* \see opMultIntegerFloat(ValueObject *, ValueObject *)
* \see opMaxIntegerFloat(ValueObject *, ValueObject *)
* \see opMinIntegerFloat(ValueObject *, ValueObject *)
* \see opModIntegerFloat(ValueObject *, ValueObject *) */
ValueObject *opDivIntegerFloat(ValueObject *a, /**< [in] The dividend. */
ValueObject *b) /**< [in] The divisor. */
{
if (getFloat(b) == 0.0) {
fprintf(stderr, "Division by zero undefined\n");
return NULL;
}
return createFloatValueObject(getInteger(a) / getFloat(b));
}
/** Finds the maximum of an integer and a float.
*
* \pre \a a was created by createIntegerValueObject(int) and \a b was created
* by createFloatValueObject(float).
*
* \return A pointer to a ValueObject structure containing the maximum of the
* values \a a and \a b.
*
* \see opAddIntegerFloat(ValueObject *, ValueObject *)
* \see opSubIntegerFloat(ValueObject *, ValueObject *)
* \see opMultIntegerFloat(ValueObject *, ValueObject *)
* \see opDivIntegerFloat(ValueObject *, ValueObject *)
* \see opMinIntegerFloat(ValueObject *, ValueObject *)
* \see opModIntegerFloat(ValueObject *, ValueObject *) */
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));
}
/** Finds the minimum of an integer and a float.
*
* \pre \a a was created by createIntegerValueObject(int) and \a b was created
* by createFloatValueObject(float).
*
* \return A pointer to a ValueObject structure containing the minimum of the
* values \a a and \a b.
*
* \see opAddIntegerFloat(ValueObject *, ValueObject *)
* \see opSubIntegerFloat(ValueObject *, ValueObject *)
* \see opMultIntegerFloat(ValueObject *, ValueObject *)
* \see opDivIntegerFloat(ValueObject *, ValueObject *)
* \see opMaxIntegerFloat(ValueObject *, ValueObject *)
* \see opModIntegerFloat(ValueObject *, ValueObject *) */
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));
}
/** Calculates the modulus of an integer and a float.
*
* \pre \a a was created by createIntegerValueObject(int) and \a b was created
* by createFloatValueObject(float).
*
* \return A pointer to a ValueObject structure containing the modulus of the
* values \a a and \a b.
*
* \see opAddIntegerFloat(ValueObject *, ValueObject *)
* \see opSubIntegerFloat(ValueObject *, ValueObject *)
* \see opMultIntegerFloat(ValueObject *, ValueObject *)
* \see opDivIntegerFloat(ValueObject *, ValueObject *)
* \see opMaxIntegerFloat(ValueObject *, ValueObject *)
* \see opMinIntegerFloat(ValueObject *, ValueObject *) */
ValueObject *opModIntegerFloat(ValueObject *a, /**< [in] The dividend. */
ValueObject *b) /**< [in] The divisor. */
{
if (getFloat(b) == 0.0) {
fprintf(stderr, "Division by zero undefined\n");
return NULL;
}
return createFloatValueObject(fmod(getInteger(a), getFloat(b)));
}
/** Adds a float and an integer.
*
* \pre \a a was created by createFloatValueObject(float) and \a b was created
* by createIntegerValueObject(int).
*
* \return A pointer to a ValueObject structure containing the sum of the
* values \a a and \a b.
*
* \see opSubFloatInteger(ValueObject *, ValueObject *)
* \see opMultFloatInteger(ValueObject *, ValueObject *)
* \see opDivFloatInteger(ValueObject *, ValueObject *)
* \see opMaxFloatInteger(ValueObject *, ValueObject *)
* \see opMinFloatInteger(ValueObject *, ValueObject *)
* \see opModFloatInteger(ValueObject *, ValueObject *) */
ValueObject *opAddFloatInteger(ValueObject *a, /**< [in] The first term to add. */
ValueObject *b) /**< [in] The second term to add. */
{
return createFloatValueObject(getFloat(a) + getInteger(b));
}
/** Subtracts a float and an integer.
*
* \pre \a a was created by createFloatValueObject(float) and \a b was created
* by createIntegerValueObject(int).
*
* \return A pointer to a ValueObject structure containing the difference of
* the values \a a and \a b.
*
* \see opAddFloatInteger(ValueObject *, ValueObject *)
* \see opMultFloatInteger(ValueObject *, ValueObject *)
* \see opDivFloatInteger(ValueObject *, ValueObject *)
* \see opMaxFloatInteger(ValueObject *, ValueObject *)
* \see opMinFloatInteger(ValueObject *, ValueObject *)
* \see opModFloatInteger(ValueObject *, ValueObject *) */
ValueObject *opSubFloatInteger(ValueObject *a, /**< [in] The minuend. */
ValueObject *b) /**< [in] The subtrahend. */
{
return createFloatValueObject(getFloat(a) - getInteger(b));
}
/** Multiplies a float and an integer.
*
* \pre \a a was created by createFloatValueObject(float) and \a b was created
* by createIntegerValueObject(int).
*
* \return A pointer to a ValueObject structure containing the product of the
* values \a a and \a b.
*
* \see opAddFloatInteger(ValueObject *, ValueObject *)
* \see opSubFloatInteger(ValueObject *, ValueObject *)
* \see opDivFloatInteger(ValueObject *, ValueObject *)
* \see opMaxFloatInteger(ValueObject *, ValueObject *)
* \see opMinFloatInteger(ValueObject *, ValueObject *)
* \see opModFloatInteger(ValueObject *, ValueObject *) */ ValueObject *opMultFloatInteger(ValueObject *a, /**< [in] The first factor to multiply. */
ValueObject *b) /**< [in] The second factor to multiply. */
{
return createFloatValueObject(getFloat(a) * getInteger(b));
}
/** Divides a float and an integer.
*
* \pre \a a was created by createFloatValueObject(float) and \a b was created
* by createIntegerValueObject(int).
*
* \return A pointer to a ValueObject structure containing the quotient of the
* values \a a and \a b.
*
* \retval NULL Division by zero was attempted.
*
* \see opAddFloatInteger(ValueObject *, ValueObject *)
* \see opSubFloatInteger(ValueObject *, ValueObject *)
* \see opMultFloatInteger(ValueObject *, ValueObject *)
* \see opMaxFloatInteger(ValueObject *, ValueObject *)
* \see opMinFloatInteger(ValueObject *, ValueObject *)
* \see opModFloatInteger(ValueObject *, ValueObject *) */
ValueObject *opDivFloatInteger(ValueObject *a, /**< [in] The dividend. */
ValueObject *b) /**< [in] The divisor. */
{
if (getInteger(b) == 0) {
fprintf(stderr, "Division by zero undefined\n");
return NULL;
}
return createFloatValueObject(getFloat(a) / getInteger(b));
}
/** Finds the maximum of a float and an integer.
*
* \pre \a a was created by createFloatValueObject(float) and \a b was created
* by createIntegerValueObject(int).
*
* \return A pointer to a ValueObject structure containing the maximum of the
* values \a a and \a b.
*
* \see opAddFloatInteger(ValueObject *, ValueObject *)
* \see opSubFloatInteger(ValueObject *, ValueObject *)
* \see opMultFloatInteger(ValueObject *, ValueObject *)
* \see opDivFloatInteger(ValueObject *, ValueObject *)
* \see opMinFloatInteger(ValueObject *, ValueObject *)
* \see opModFloatInteger(ValueObject *, ValueObject *) */
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));
}
/** Finds the minimum of a float and an integer.
*
* \pre \a a was created by createFloatValueObject(float) and \a b was created
* by createIntegerValueObject(int).
*
* \return A pointer to a ValueObject structure containing the minimum of the
* values \a a and \a b.
*
* \see opAddFloatInteger(ValueObject *, ValueObject *)
* \see opSubFloatInteger(ValueObject *, ValueObject *)
* \see opMultFloatInteger(ValueObject *, ValueObject *)
* \see opDivFloatInteger(ValueObject *, ValueObject *)
* \see opMaxFloatInteger(ValueObject *, ValueObject *)
* \see opModFloatInteger(ValueObject *, ValueObject *) */
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));
}
/** Calculates the modulus of a float and an integer.
*
* \pre \a a was created by createFloatValueObject(float) and \a b was created
* by createIntegerValueObject(int).
*
* \return A pointer to a ValueObject structure containing the modulus of the
* values \a a and \a b.
*
* \see opAddFloatInteger(ValueObject *, ValueObject *)
* \see opSubFloatInteger(ValueObject *, ValueObject *)
* \see opMultFloatInteger(ValueObject *, ValueObject *)
* \see opDivFloatInteger(ValueObject *, ValueObject *)
* \see opMaxFloatInteger(ValueObject *, ValueObject *)
* \see opMinFloatInteger(ValueObject *, ValueObject *) */
ValueObject *opModFloatInteger(ValueObject *a, /**< [in] The dividend. */
ValueObject *b) /**< [in] The divisor. */
{
if (getInteger(b) == 0) {
fprintf(stderr, "Division by zero undefined\n");
return NULL;
}
return createFloatValueObject(fmod(getFloat(a), getInteger(b)));
}
/** Adds two floats.
*
* \pre \a a and \a b were created by createFloatValueObject(float).
*
* \return A pointer to a ValueObject structure containing the sum of the
* values \a a and \a b.
*
* \see opSubFloatFloat(ValueObject *, ValueObject *)
* \see opMultFloatFloat(ValueObject *, ValueObject *)
* \see opDivFloatFloat(ValueObject *, ValueObject *)
* \see opMaxFloatFloat(ValueObject *, ValueObject *)
* \see opMinFloatFloat(ValueObject *, ValueObject *)
* \see opModFloatFloat(ValueObject *, ValueObject *) */
ValueObject *opAddFloatFloat(ValueObject *a, /**< [in] The first term to add. */
ValueObject *b) /**< [in] The second term to add. */
{
return createFloatValueObject(getFloat(a) + getFloat(b));
}
/** Subtracts two floats.
*
* \pre \a a and \a b were created by createFloatValueObject(float).
*
* \return A pointer to a ValueObject structure containing the difference of
* the values \a a and \a b.
*
* \see opAddFloatFloat(ValueObject *, ValueObject *)
* \see opMultFloatFloat(ValueObject *, ValueObject *)
* \see opDivFloatFloat(ValueObject *, ValueObject *)
* \see opMaxFloatFloat(ValueObject *, ValueObject *)
* \see opMinFloatFloat(ValueObject *, ValueObject *)
* \see opModFloatFloat(ValueObject *, ValueObject *) */
ValueObject *opSubFloatFloat(ValueObject *a, /**< [in] The minuend. */
ValueObject *b) /**< [in] The subtrahend. */
{
return createFloatValueObject(getFloat(a) - getFloat(b));
}
/** Multiplies two floats.
*
* \pre \a a and \a b were created by createFloatValueObject(float).
*
* \return A pointer to a ValueObject structure containing the product of the
* values \a a and \a b.
*
* \see opAddFloatFloat(ValueObject *, ValueObject *)
* \see opSubFloatFloat(ValueObject *, ValueObject *)
* \see opDivFloatFloat(ValueObject *, ValueObject *)
* \see opMaxFloatFloat(ValueObject *, ValueObject *)
* \see opMinFloatFloat(ValueObject *, ValueObject *)
* \see opModFloatFloat(ValueObject *, ValueObject *) */
ValueObject *opMultFloatFloat(ValueObject *a, /**< [in] The first factor to multiply. */
ValueObject *b) /**< [in] The second factor to multiply. */
{
return createFloatValueObject(getFloat(a) * getFloat(b));
}
/** Divides two floats.
*
* \pre \a a and \a b were created by createFloatValueObject(float).
*
* \return A pointer to a ValueObject structure containing the quotient of the
* values \a a and \a b.
*
* \retval NULL Division by zero was attempted.
*
* \see opAddFloatFloat(ValueObject *, ValueObject *)
* \see opSubFloatFloat(ValueObject *, ValueObject *)
* \see opMultFloatFloat(ValueObject *, ValueObject *)
* \see opMaxFloatFloat(ValueObject *, ValueObject *)
* \see opMinFloatFloat(ValueObject *, ValueObject *)
* \see opModFloatFloat(ValueObject *, ValueObject *) */
ValueObject *opDivFloatFloat(ValueObject *a, /**< [in] The dividend. */
ValueObject *b) /**< [in] The divisor. */
{
if (getFloat(b) == 0.0) {
fprintf(stderr, "Division by zero undefined\n");
return NULL;
}
return createFloatValueObject(getFloat(a) / getFloat(b));
}
/** Finds the maximum of two floats.
*
* \pre \a a and \a b were created by createFloatValueObject(float).
*
* \return A pointer to a ValueObject structure containing the maximum of the
* values \a a and \a b.
*
* \see opAddFloatFloat(ValueObject *, ValueObject *)
* \see opSubFloatFloat(ValueObject *, ValueObject *)
* \see opMultFloatFloat(ValueObject *, ValueObject *)
* \see opDivFloatFloat(ValueObject *, ValueObject *)
* \see opMinFloatFloat(ValueObject *, ValueObject *)
* \see opModFloatFloat(ValueObject *, ValueObject *) */
ValueObject *opMaxFloatFloat(ValueObject *a, /**< [in] The first number to compare. */
ValueObject *b) /**< [in] The second number to compare. */
{
return createFloatValueObject(getFloat(a) > getFloat(b) ? getFloat(a) : getFloat(b));
}
/** Finds the minimum of two floats.
*
* \pre \a a and \a b were created by createFloatValueObject(float).
*
* \return A pointer to a ValueObject structure containing the minimum of the
* values \a a and \a b.
*
* \see opAddFloatFloat(ValueObject *, ValueObject *)
* \see opSubFloatFloat(ValueObject *, ValueObject *)
* \see opMultFloatFloat(ValueObject *, ValueObject *)
* \see opDivFloatFloat(ValueObject *, ValueObject *)
* \see opMaxFloatFloat(ValueObject *, ValueObject *)
* \see opModFloatFloat(ValueObject *, ValueObject *) */
ValueObject *opMinFloatFloat(ValueObject *a, /**< [in] The first number to compare. */
ValueObject *b) /**< [in] The second number to compare. */
{
return createFloatValueObject(getFloat(a) < getFloat(b) ? getFloat(a) : getFloat(b));
}
/** Calculates the modulus of two floats.
*
* \pre \a a and \a b were created by createFloatValueObject(float).
*
* \return A pointer to a ValueObject structure containing the modulus of the
* values \a a and \a b.
*
* \see opAddFloatFloat(ValueObject *, ValueObject *)
* \see opSubFloatFloat(ValueObject *, ValueObject *)
* \see opMultFloatFloat(ValueObject *, ValueObject *)
* \see opDivFloatFloat(ValueObject *, ValueObject *)
* \see opMaxFloatFloat(ValueObject *, ValueObject *)
* \see opMinFloatFloat(ValueObject *, ValueObject *) */
ValueObject *opModFloatFloat(ValueObject *a, /**< [in] The dividend. */
ValueObject *b) /**< [in] The divisor. */
{
if (getFloat(b) == 0.0) {
fprintf(stderr, "Division by zero undefined\n");
return NULL;
}
return createFloatValueObject(fmod(getFloat(a), getFloat(b)));
}
/* A jump table for arithmetic operations. The first index determines the
* particular arithmetic operation to parform, the second index determines the
* type of the first argument, and the third index determines the type of the
* second object. */
static ValueObject *(*ArithOpJumpTable[7][2][2])(ValueObject *, ValueObject *) = {
{ { opAddIntegerInteger, opAddIntegerFloat }, { opAddFloatInteger, opAddFloatFloat } },
{ { opSubIntegerInteger, opSubIntegerFloat }, { opSubFloatInteger, opSubFloatFloat } },
{ { opMultIntegerInteger, opMultIntegerFloat }, { opMultFloatInteger, opMultFloatFloat } },
{ { opDivIntegerInteger, opDivIntegerFloat }, { opDivFloatInteger, opDivFloatFloat } },
{ { opModIntegerInteger, opModIntegerFloat }, { opModFloatInteger, opModFloatFloat } },
{ { opMaxIntegerInteger, opMaxIntegerFloat }, { opMaxFloatInteger, opMaxFloatFloat } },
{ { opMinIntegerInteger, opMinIntegerFloat }, { opMinFloatInteger, opMinFloatFloat } }
};
/** Interprets an arithmetic operation expression.
*
* \pre \a expr was created by createOpExprNode(OpType type, ExprNodeList *args)
* where \a type is either OP_ADD, OP_SUB, OP_MULT, OP_DIV, or OP_MOD and
* \a args was created by createExprNodeList(void) and populated with
* ExprNode structures using addExprNode(ExprNodeList *, ExprNode *).
* \pre \a scope was created by createScopeObject(ScopeObject *) and contains
* contents added by createScopeValue(ScopeObject *, IdentifierNode *) and
* contents updated by updateScopeValue(ScopeObject *, IdentifierNode *, ValueObject *).
*
* \note Only the first two elements in \a args are considered.
*
* \return A pointer to a ValueObject structure containing the interpreted
* operation expression value.
*
* \retval NULL An error occurred during interpretation.
*
* \see interpretNotOpExprNode(OpExprNode *, ScopeObject *)
* \see interpretBoolOpExprNode(OpExprNode *, ScopeObject *)
* \see interpretEqualityOpExprNode(OpExprNode *, ScopeObject *)
* \see interpretConcatOpExprNode(OpExprNode *, ScopeObject *) */
ValueObject *interpretArithOpExprNode(OpExprNode *expr, /**< [in] A pointer to the OpExprNode structure to interpret. */
ScopeObject *scope) /**< [in] A pointer to the ScopeObject structure to evaluate \a expr under. */
{
ValueObject *val1 = interpretExprNode(expr->args->exprs[0], scope);
ValueObject *val2 = interpretExprNode(expr->args->exprs[1], scope);
ValueObject *use1 = val1;
ValueObject *use2 = val2;
unsigned int cast1 = 0;
unsigned int cast2 = 0;
ValueObject *ret = NULL;
if (!val1 || !val2) {
deleteValueObject(val1);
deleteValueObject(val2);
return NULL;
}
/* Check if a floating point decimal string and cast */
switch (val1->type) {
case VT_NIL:
case VT_BOOLEAN:
use1 = castIntegerImplicit(val1, scope);
if (!use1) {
deleteValueObject(val1);
deleteValueObject(val2);
return NULL;
}
cast1 = 1;
break;
case VT_INTEGER:
case VT_FLOAT:
break;
case VT_STRING: {
/* Perform interpolation */
ValueObject *interp = castStringExplicit(val1, scope);
if (!interp) {
deleteValueObject(val1);
deleteValueObject(val2);
return NULL;
}
if (strchr(getString(interp), '.'))
use1 = castFloatImplicit(interp, scope);
else
use1 = castIntegerImplicit(interp, scope);
deleteValueObject(interp);
if (!use1) {
deleteValueObject(val1);
deleteValueObject(val2);
return NULL;
}
cast1 = 1;
break;
}
default:
fprintf(stderr, "Invalid operand type\n");
}
switch (val2->type) {
case VT_NIL:
case VT_BOOLEAN:
use2 = castIntegerImplicit(val2, scope);
if (!use2) {
deleteValueObject(val1);
deleteValueObject(val2);
if (cast1) deleteValueObject(use1);
return NULL;
}
cast2 = 1;
break;
case VT_INTEGER:
case VT_FLOAT:
break;
case VT_STRING: {
/* Perform interpolation */
ValueObject *interp = castStringExplicit(val2, scope);
if (!interp) {
deleteValueObject(val1);
deleteValueObject(val2);
if (cast1) deleteValueObject(use1);
return NULL;
}
if (strchr(getString(interp), '.'))
use2 = castFloatImplicit(interp, scope);
else
use2 = castIntegerImplicit(interp, scope);
deleteValueObject(interp);
if (!use2) {
deleteValueObject(val1);
deleteValueObject(val2);
if (cast1) deleteValueObject(use1);
return NULL;
}
cast2 = 1;
break;
}
default:
fprintf(stderr, "Invalid operand type\n");
}
/* Do math depending on value types */
ret = ArithOpJumpTable[expr->type][use1->type][use2->type](use1, use2);
/* Clean up after floating point decimal casts */
if (cast1) deleteValueObject(use1);
if (cast2) deleteValueObject(use2);
deleteValueObject(val1);
deleteValueObject(val2);
return ret;
}
/** Interprets a boolean operation expression.
*
* \pre \a expr was created by createOpExprNode(OpType type, ExprNodeList *args)
* where \a type is either OP_AND, OP_OR, or OP_XOR and \a args was
* created by createExprNodeList(void) and populated with ExprNode
* structures using addExprNode(ExprNodeList *, ExprNode *).
* \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 pointer to a ValueObject structure containing the interpreted
* operation expression value.
*
* \retval NULL An error occurred during interpretation.
*
* \see interpretArithOpExprNode(OpExprNode *, ScopeObject *)
* \see interpretNotOpExprNode(OpExprNode *, ScopeObject *)
* \see interpretEqualityOpExprNode(OpExprNode *, ScopeObject *)
* \see interpretConcatOpExprNode(OpExprNode *, ScopeObject *) */
ValueObject *interpretBoolOpExprNode(OpExprNode *expr, /**< [in] A pointer to the OpExprNode structure to interpret. */
ScopeObject *scope) /**< [in] A pointer to the ScopeObject structure to evaluate \a expr under. */
{
unsigned int n;
int acc = 0;
/* Proceed to apply the same operation on the accumulator for the
* remaining arguments. */
for (n = 0; n < expr->args->num; n++) {
ValueObject *val = interpretExprNode(expr->args->exprs[n], scope);
ValueObject *use = val;
unsigned int temp;
unsigned int cast = 0;
if (!val) return NULL;
if (val->type != VT_BOOLEAN && val->type != VT_INTEGER) {
use = castBooleanImplicit(val, scope);
if (!use) {
deleteValueObject(val);
return NULL;
}
cast = 1;
}
temp = getInteger(use);
if (cast) deleteValueObject(use);
deleteValueObject(val);
if (n == 0) acc = temp;
else {
switch (expr->type) {
case OP_AND:
acc &= temp;
break;
case OP_OR:
acc |= temp;
break;
case OP_XOR:
acc ^= temp;
break;
default:
fprintf(stderr, "Invalid boolean operation type\n");
return NULL;
}
}
/** \note The specification does not say whether boolean logic
* short circuits or not. Here, we assume it does. */
if (expr->type == OP_AND && acc == 0) break;
else if (expr->type == OP_OR && acc == 1) break;
}
return createBooleanValueObject(acc);
}
/** Tests if two integers are equal.
*
* \pre \a a and \a b were created by createIntegerValueObject(int).
*
* \return A pointer to a ValueObject structure containing a boolean value
* indicating whether \a a is equal to \a b.
*
* \see opNeqIntegerInteger(ValueObject *, ValueObject *) */
ValueObject *opEqIntegerInteger(ValueObject *a, /**< [in] The first value to test. */
ValueObject *b) /**< [in] The second value to test. */
{
return createBooleanValueObject(getInteger(a) == getInteger(b));
}
/** Tests if two integers are not equal.
*
* \pre \a a and \a b were created by createIntegerValueObject(int).
*
* \return A pointer to a ValueObject structure containing a boolean value
* indicating whether \a a is not equal to \a b.
*
* \see opEqIntegerInteger(ValueObject *, ValueObject *) */
ValueObject *opNeqIntegerInteger(ValueObject *a, /**< [in] The first value to test. */
ValueObject *b) /**< [in] The second value to test. */
{
return createBooleanValueObject(getInteger(a) != getInteger(b));
}
/** Tests if an integer and a float are equal.
*
* \pre \a a was created by createIntegerValueObject(int) and \a b was created
* by createFloatValueObject(float).
*
* \return A pointer to a ValueObject structure containing a boolean value
* indicating whether \a a is equal to \a b.
*
* \see opNeqIntegerFloat(ValueObject *, ValueObject *) */
ValueObject *opEqIntegerFloat(ValueObject *a, /**< [in] The first value to test. */
ValueObject *b) /**< [in] The second value to test. */
{
return createBooleanValueObject(getInteger(a) == getFloat(b));
}
/** Tests if an integer and a float are not equal.
*
* \pre \a a was created by createIntegerValueObject(int) and \a b was created
* by createFloatValueObject(float).
*
* \return A pointer to a ValueObject structure containing a boolean value
* indicating whether \a a is not equal to \a b.
*
* \see opEqIntegerFloat(ValueObject *, ValueObject *) */
ValueObject *opNeqIntegerFloat(ValueObject *a, /**< [in] The first value to test. */
ValueObject *b) /**< [in] The second value to test. */
{
return createBooleanValueObject(getInteger(a) != getFloat(b));
}
/** Tests if a float and an integer are equal.
*
* \pre \a a was created by createFloatValueObject(float) and \a b was created
* by createFloatValueObject(float).
*
* \return A pointer to a ValueObject structure containing a boolean value
* indicating whether \a a is equal to \a b.
*
* \see opNeqFloatInteger(ValueObject *, ValueObject *) */
ValueObject *opEqFloatInteger(ValueObject *a, /**< [in] The first value to test. */
ValueObject *b) /**< [in] The second value to test. */
{
return createBooleanValueObject(getFloat(a) == getInteger(b));
}
/** Tests if a float and an integer are not equal.
*
* \pre \a a was created by createFloatValueObject(float) and \a b was created
* by createFloatValueObject(float).
*
* \return A pointer to a ValueObject structure containing a boolean value
* indicating whether \a a is not equal to \a b.
*
* \see opEqFloatInteger(ValueObject *, ValueObject *) */
ValueObject *opNeqFloatInteger(ValueObject *a, /**< [in] The first value to test. */
ValueObject *b) /**< [in] The second value to test. */
{
return createBooleanValueObject(getFloat(a) != getInteger(b));
}
/** Tests if two floats are equal.
*
* \pre \a a and \a b were created by createFloatValueObject(float).
*
* \return A pointer to a ValueObject structure containing a boolean value
* indicating whether \a a is equal to \a b.
*
* \see opNeqFloatFloat(ValueObject *, ValueObject *) */
ValueObject *opEqFloatFloat(ValueObject *a, /**< [in] The first value to test. */
ValueObject *b) /**< [in] The second value to test. */
{
return createBooleanValueObject(getFloat(a) == getFloat(b));
}
/** Tests if two floats are not equal.
*
* \pre \a a and \a b were created by createFloatValueObject(float).
*
* \return A pointer to a ValueObject structure containing a boolean value
* indicating whether \a a is not equal to \a b.
*
* \see opNeqFloatFloat(ValueObject *, ValueObject *) */
ValueObject *opNeqFloatFloat(ValueObject *a, /**< [in] The first value to test. */
ValueObject *b) /**< [in] The second value to test. */
{
return createBooleanValueObject(getFloat(a) != getFloat(b));
}
/** Tests if two boolean values are equal.
*
* \pre \a a and \a b were created by createBooleanValueObject(float).
*
* \return A pointer to a ValueObject structure containing a boolean value
* indicating whether \a a is equal to \a b.
*
* \see opNeqBooleanBoolean(ValueObject *, ValueObject *) */
ValueObject *opEqBooleanBoolean(ValueObject *a, /**< [in] The first value to test. */
ValueObject *b) /**< [in] The second value to test. */
{
return createBooleanValueObject(getInteger(a) == getInteger(b));
}
/** Tests if two boolean values are not equal.
*
* \pre \a a and \a b were created by createBooleanValueObject(float).
*
* \return A pointer to a ValueObject structure containing a boolean value
* indicating whether \a a is not equal to \a b.
*
* \see opEqBooleanBoolean(ValueObject *, ValueObject *) */
ValueObject *opNeqBooleanBoolean(ValueObject *a, /**< [in] The first value to test. */
ValueObject *b) /**< [in] The second value to test. */
{
return createBooleanValueObject(getInteger(a) != getInteger(b));
}
/** Tests if two strings are equal.
*
* \pre \a a and \a b were created by createStringValueObject(char *).
*
* \return A pointer to a ValueObject structure containing a boolean value
* indicating whether \a a is equal to \a b.
*
* \see opNeqStringString(ValueObject *, ValueObject *) */
ValueObject *opEqStringString(ValueObject *a, /**< [in] The first value to test. */
ValueObject *b) /**< [in] The second value to test. */
{
return createBooleanValueObject(strcmp(getString(a), getString(b)) == 0);
}
/** Tests if two strings are not equal.
*
* \pre \a a and \a b were created by createStringValueObject(char *).
*
* \return A pointer to a ValueObject structure containing a boolean value
* indicating whether \a a is not equal to \a b.
*
* \see opEqStringString(ValueObject *, ValueObject *) */
ValueObject *opNeqStringString(ValueObject *a, /**< [in] The first value to test. */
ValueObject *b) /**< [in] The second value to test. */
{
return createBooleanValueObject(strcmp(getString(a), getString(b)) != 0);
}
/** Tests if two nil values are equal.
*
* \note Two nil values are \b always equal, therefore \a a and \a b are not
* used by this function but are still included in its prototype to allow
* this function to be stored in a jump table for fast execution.
*
* \pre \a a and \a b were created by createNilValueObject(void).
*
* \return A pointer to a ValueObject structure containing a boolean value
* indicating whether \a a is equal to \a b.
*
* \see opNeqNilNil(ValueObject *, ValueObject *) */
ValueObject *opEqNilNil(ValueObject *a, /**< Not used (see note). */
ValueObject *b) /**< Not used (see note). */
{
a = NULL;
b = NULL;
return createBooleanValueObject(1);
}
/** Tests if two nil values are not equal.
*
* \note Two nil values are \b always equal and thus \b never not equal,
* therefore \a a and \a b are not used by this function but are still
* included in its prototype to allow this function to be stored in a
* jump table for fast execution.
*
* \pre \a a and \a b were created by createNilValueObject(void).
*
* \return A pointer to a ValueObject structure containing a boolean value
* indicating whether \a a is not equal to \a b.
*
* \see opEqNilNil(ValueObject *, ValueObject *) */
ValueObject *opNeqNilNil(ValueObject *a, /**< Not used (see note). */
ValueObject *b) /**< Not used (see note). */
{
a = NULL;
b = NULL;
return createBooleanValueObject(0);
}
/* A jump table for boolean operations. The first index determines the
* particular boolean operation to perform, the second index determines the
* type of the first argument, and the third index determines the type of the
* second object. */
static ValueObject *(*BoolOpJumpTable[2][5][5])(ValueObject *, ValueObject *) = {
{ /* OP_EQ */
/* Integer, Float, Boolean, String, Nil */
/* Integer */ { opEqIntegerInteger, opEqIntegerFloat, NULL, NULL, NULL },
/* Float */ { opEqFloatInteger, opEqFloatFloat, NULL, NULL, NULL },
/* Boolean */ { NULL, NULL, opEqBooleanBoolean, NULL, NULL },
/* String */ { NULL, NULL, NULL, opEqStringString, NULL },
/* Nil */ { NULL, NULL, NULL, NULL, opEqNilNil }
},
{ /* OP_NEQ */
/* Integer, Float, Boolean, String, Nil */
/* Integer */ { opNeqIntegerInteger, opNeqIntegerFloat, NULL, NULL, NULL },
/* Float */ { opNeqFloatInteger, opNeqFloatFloat, NULL, NULL, NULL },
/* Boolean */ { NULL, NULL, opNeqBooleanBoolean, NULL, NULL },
/* String */ { NULL, NULL, NULL, opNeqStringString, NULL },
/* Nil */ { NULL, NULL, NULL, NULL, opNeqNilNil }
}
};
/** Interprets an equality operation expression.
*
* \pre \a expr was created by createOpExprNode(OpType type, ExprNodeList *args)
* where \a type is either OP_EQ or OP_NEQ and \a args was created by
* createExprNodeList(void) and populated with ExprNode structures using
* addExprNode(ExprNodeList *, ExprNode *).
* \pre \a scope was created by createScopeObject(ScopeObject *) and contains
* contents added by createScopeValue(ScopeObject *, IdentifierNode *) and
* contents updated by updateScopeValue(ScopeObject *, IdentifierNode *, ValueObject *).
*
* \note Only the first two elements in \a args are considered.
*
* \return A pointer to a ValueObject structure containing the interpreted
* operation expression value.
*
* \retval NULL An error occurred during interpretation.
*
* \see interpretArithOpExprNode(OpExprNode *, ScopeObject *)
* \see interpretNotOpExprNode(OpExprNode *, ScopeObject *)
* \see interpretBoolOpExprNode(OpExprNode *, ScopeObject *)
* \see interpretConcatOpExprNode(OpExprNode *, ScopeObject *) */
ValueObject *interpretEqualityOpExprNode(OpExprNode *expr, /**< [in] A pointer to the OpExprNode structure to interpret. */
ScopeObject *scope) /**< [in] A pointer to the ScopeObject structure to evaluate \a expr under. */
{
ValueObject *val1 = interpretExprNode(expr->args->exprs[0], scope);
ValueObject *val2 = interpretExprNode(expr->args->exprs[1], scope);
ValueObject *ret = NULL;
if (!val1 || !val2) {
deleteValueObject(val1);
deleteValueObject(val2);
return NULL;
}
/* Since there is no automatic casting, an equality (inequality) test
* against a non-number type will always fail (succeed). */
if ((val1->type != val2->type)
&& ((val1->type != VT_INTEGER && val1->type != VT_FLOAT)
|| (val2->type != VT_INTEGER && val2->type != VT_FLOAT))) {
switch (expr->type) {
case OP_EQ:
ret = createBooleanValueObject(0);
break;
case OP_NEQ:
ret = createBooleanValueObject(1);
break;
default:
fprintf(stderr, "Invalid equality operation type\n");
deleteValueObject(val1);
deleteValueObject(val2);
return NULL;
}
}
else
ret = BoolOpJumpTable[expr->type - OP_EQ][val1->type][val2->type](val1, val2);
deleteValueObject(val1);
deleteValueObject(val2);
return ret;
}
/** Interprets a concatenation operation expression.
*
* \pre \a expr was created by createOpExprNode(OpType type, ExprNodeList *args)
* where \a type is OP_CAT and \a args was created by createExprNodeList(void)
* and populated with ExprNode structures using addExprNode(ExprNodeList *, ExprNode *).
* \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 pointer to a ValueObject structure containing the concatenation of
* all the arguments in \a args.
*
* \retval NULL An error occurred during interpretation.
*
* \see interpretNotOpExprNode(OpExprNode *, ScopeObject *)
* \see interpretArithOpExprNode(OpExprNode *, ScopeObject *)
* \see interpretBoolOpExprNode(OpExprNode *, ScopeObject *)
* \see interpretEqualityOpExprNode(OpExprNode *, ScopeObject *) */
ValueObject *interpretConcatOpExprNode(OpExprNode *expr, /**< [in] A pointer to the OpExprNode structure to interpret. */
ScopeObject *scope) /**< [in] A pointer to the ScopeObject structure to evaluate \a expr under. */
{
unsigned int n;
/* Start out with the first string to concatenate. */
ValueObject *val = interpretExprNode(expr->args->exprs[0], scope);
ValueObject *use = castStringImplicit(val, scope);
char *acc = NULL;
void *mem = NULL;
if (!val || !use) {
deleteValueObject(val);
deleteValueObject(use);
return NULL;
}
/* Start out an accumulator with the first string. */
mem = realloc(acc, sizeof(char) * (strlen(getString(use)) + 1));
if (!mem) {
perror("realloc");
deleteValueObject(val);
deleteValueObject(use);
free(acc);
return NULL;
}
acc = mem;
acc[0] = '\0';
strcat(acc, getString(use));
deleteValueObject(val);
deleteValueObject(use);
for (n = 1; n < expr->args->num; n++) {
/* Grab the next string to concatenate. */
val = interpretExprNode(expr->args->exprs[n], scope);
use = castStringImplicit(val, scope);
if (!val || !use) {
deleteValueObject(val);
deleteValueObject(use);
free(acc);
return NULL;
}
/* Add the next string to the accumulator. */
mem = realloc(acc, sizeof(char) * (strlen(acc) + strlen(getString(use)) + 1));
if (!mem) {
perror("realloc");
deleteValueObject(val);
deleteValueObject(use);
free(acc);
return NULL;
}
acc = mem;
strcat(acc, getString(use));
deleteValueObject(val);
deleteValueObject(use);
}
return createStringValueObject(acc);
}
/* A jump table for operations. The index of a function in the table is given
* by its its index in the enumerated OpType type. */
static ValueObject *(*OpExprJumpTable[14])(OpExprNode *, ScopeObject *) = {
interpretArithOpExprNode,
interpretArithOpExprNode,
interpretArithOpExprNode,
interpretArithOpExprNode,
interpretArithOpExprNode,
interpretArithOpExprNode,
interpretArithOpExprNode,
interpretBoolOpExprNode,
interpretBoolOpExprNode,
interpretBoolOpExprNode,
interpretNotOpExprNode,
interpretEqualityOpExprNode,
interpretEqualityOpExprNode,
interpretConcatOpExprNode };
/** Interprets an operation expression.
*
* \pre \a expr was created by createOpExprNode(OpType, ExprNodeList *).
* \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 pointer to a ValueObject structure containing the interpreted
* operation expression value.
*
* \retval NULL An error occurred during interpretation.
*
* \see interpretNotOpExprNode(OpExprNode *, ScopeObject *)
* \see interpretArithOpExprNode(OpExprNode *, ScopeObject *)
* \see interpretBoolOpExprNode(OpExprNode *, ScopeObject *)
* \see interpretEqualityOpExprNode(OpExprNode *, ScopeObject *)
* \see interpretConcatOpExprNode(OpExprNode *, ScopeObject *) */
ValueObject *interpretOpExprNode(ExprNode *node, /**< [in] A pointer to an ExprNode structure to interpret. */
ScopeObject *scope) /**< [in] A pointer to a ScopeObject structure to evaluate \a node under. */
{
OpExprNode *expr = (OpExprNode *)node->expr;
return OpExprJumpTable[expr->type](expr, scope);
}
/* A jump table for expressions. The index of a function in the table is given
* by its its index in the enumerated ExprType type. */
static ValueObject *(*ExprJumpTable[6])(ExprNode *, ScopeObject *) = {
interpretCastExprNode,
interpretConstantExprNode,
interpretIdentifierExprNode,
interpretFuncCallExprNode,
interpretOpExprNode,
interpretImpVarExprNode };
/** Interprets the contents of an ExprNode structure.
*
* \pre \a node was created by parseExprNode(Token ***).
* \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 pointer to a ValueObject structure with the evaluated contents of
* \a node in the scope \a scope.
*
* \retval NULL An error occurred during interpretation.
*
* \see interpretStmtNode(StmtNode *, ScopeObject *)
* \see interpretStmtNodeList(StmtNodeList *, ScopeObject *)
* \see interpretBlockNode(BlockNode *, ScopeObject *)
* \see interpretMainNode(MainNode *) */
ValueObject *interpretExprNode(ExprNode *node, /**< [in] A pointer to an ExprNode structure to interpret. */
ScopeObject *scope) /**< [in] A pointer to a ScopeObject structure to evaluate \a node under. */
{
return ExprJumpTable[node->type](node, scope);
}
/** Interprets a cast statement.
*
* \pre \a node was created by createStmtNode(StmtType type, void *stmt)
* where \a type is ST_CAST and \a stmt was created by createCastStmtNode(IdentifierNode *, TypeNode *).
* \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 pointer to a ReturnObject structure with the default return value.
*
* \retval NULL An error occurred during interpretation.
*
* \see interpretPrintStmtNode(StmtNode *, ScopeObject *)
* \see interpretInputStmtNode(StmtNode *, ScopeObject *)
* \see interpretAssignmentStmtNode(StmtNode *, ScopeObject *)
* \see interpretDeclarationStmtNode(StmtNode *, ScopeObject *)
* \see interpretIfThenElseStmtNode(StmtNode *, ScopeObject *)
* \see interpretSwitchStmtNode(StmtNode *, ScopeObject *)
* \see interpretBreakStmtNode(StmtNode *, ScopeObject *)
* \see interpretReturnStmtNode(StmtNode *, ScopeObject *)
* \see interpretLoopStmtNode(StmtNode *, ScopeObject *)
* \see interpretDeallocationStmtNode(StmtNode *, ScopeObject *)
* \see interpretFuncDefStmtNode(StmtNode *, ScopeObject *)
* \see interpretExprStmtNode(StmtNode *, ScopeObject *) */
ReturnObject *interpretCastStmtNode(StmtNode *node, /**< [in] A pointer to the StmtNode structure containing the CastStmtNode structure to interpret. */
ScopeObject *scope) /**< [in,out] A pointer to the ScopeObject structure to evaluate \a node under. */
{
CastStmtNode *stmt = (CastStmtNode *)node->stmt;
ValueObject *val = getScopeValue(scope, stmt->target);
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);
return NULL;
}
switch(stmt->newtype->type) {
case CT_NIL:
if (!(cast = createNilValueObject())) return NULL;
break;
case CT_BOOLEAN:
if (!(cast = castBooleanExplicit(val, scope))) return NULL;
break;
case CT_INTEGER:
if (!(cast = castIntegerExplicit(val, scope))) return NULL;
break;
case CT_FLOAT:
if (!(cast = castFloatExplicit(val, scope))) return NULL;
break;
case CT_STRING:
if (!(cast = castStringExplicit(val, scope))) return NULL;
break;
}
if (!updateScopeValue(scope, stmt->target, cast)) {
deleteValueObject(cast);
return NULL;
}
return createReturnObject(RT_DEFAULT, NULL);
}
/** Interprets a print statement.
*
* \pre \a node was created by createStmtNode(StmtType type, void *stmt)
* where \a type is ST_PRINT and \a stmt was created by createPrintStmtNode(ExprNodeList *, 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 pointer to a ReturnObject structure with the default return value.
*
* \retval NULL An error occurred during interpretation.
*
* \see interpretCastStmtNode(StmtNode *, ScopeObject *)
* \see interpretInputStmtNode(StmtNode *, ScopeObject *)
* \see interpretAssignmentStmtNode(StmtNode *, ScopeObject *)
* \see interpretDeclarationStmtNode(StmtNode *, ScopeObject *)
* \see interpretIfThenElseStmtNode(StmtNode *, ScopeObject *)
* \see interpretSwitchStmtNode(StmtNode *, ScopeObject *)
* \see interpretBreakStmtNode(StmtNode *, ScopeObject *)
* \see interpretReturnStmtNode(StmtNode *, ScopeObject *)
* \see interpretLoopStmtNode(StmtNode *, ScopeObject *)
* \see interpretDeallocationStmtNode(StmtNode *, ScopeObject *)
* \see interpretFuncDefStmtNode(StmtNode *, ScopeObject *)
* \see interpretExprStmtNode(StmtNode *, ScopeObject *) */
ReturnObject *interpretPrintStmtNode(StmtNode *node, /**< [in] A pointer to a StmtNode structure containing the PrintStmtNode structure to interpret. */
ScopeObject *scope) /**< [in] A pointer to the ScopeObject structure to evaluate \a node under. */
{
PrintStmtNode *stmt = (PrintStmtNode *)node->stmt;
unsigned int n;
for (n = 0; n < stmt->args->num; n++) {
ValueObject *val = interpretExprNode(stmt->args->exprs[n], scope);
ValueObject *use = castStringImplicit(val, scope);
if (!val || !use) {
deleteValueObject(val);
deleteValueObject(use);
return NULL;
}
printf("%s", getString(use));
deleteValueObject(val);
deleteValueObject(use);
}
if (!stmt->nonl)
printf("\n");
return createReturnObject(RT_DEFAULT, NULL);
}
/** Interprets an input statement.
*
* \pre \a node was created by createStmtNode(StmtType type, void *stmt) where
* \a type is ST_INPUT and \a stmt was created by createInputStmtNode(IdentifierNode *).
* \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 pointer to a ReturnObject structure with the default return value.
*
* \retval NULL An error occurred during interpretation.
*
* \see interpretCastStmtNode(StmtNode *, ScopeObject *)
* \see interpretPrintStmtNode(StmtNode *, ScopeObject *)
* \see interpretAssignmentStmtNode(StmtNode *, ScopeObject *)
* \see interpretDeclarationStmtNode(StmtNode *, ScopeObject *)
* \see interpretIfThenElseStmtNode(StmtNode *, ScopeObject *)
* \see interpretSwitchStmtNode(StmtNode *, ScopeObject *)
* \see interpretBreakStmtNode(StmtNode *, ScopeObject *)
* \see interpretReturnStmtNode(StmtNode *, ScopeObject *)
* \see interpretLoopStmtNode(StmtNode *, ScopeObject *)
* \see interpretDeallocationStmtNode(StmtNode *, ScopeObject *)
* \see interpretFuncDefStmtNode(StmtNode *, ScopeObject *)
* \see interpretExprStmtNode(StmtNode *, ScopeObject *) */
ReturnObject *interpretInputStmtNode(StmtNode *node, /**< [in] A pointer to a StmtNode structure containing an InputStmtNode structure to interpret. */
ScopeObject *scope) /**< [in,out] A pointer to the ScopeObject structure to evaluate \a node under. */
{
unsigned int size = 16;
unsigned int cur = 0;
char *temp = malloc(sizeof(char) * size);
char c;
void *mem = NULL;
InputStmtNode *stmt = (InputStmtNode *)node->stmt;
ValueObject *val = NULL;
while ((c = getchar())) {
/** \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 (cur > size - 1) {
/* Increasing buffer size. */
size *= 2;
mem = realloc(temp, sizeof(char) * size);
if (!mem) {
perror("realloc");
free(temp);
return NULL;
}
temp = mem;
}
temp[cur] = c;
cur++;
}
temp[cur] = '\0';
val = createStringValueObject(temp);
if (!val) {
free(temp);
return NULL;
}
if (!updateScopeValue(scope, stmt->target, val)) {
deleteValueObject(val);
return NULL;
}
return createReturnObject(RT_DEFAULT, NULL);
}
/** Interprets an assignment statement.
*
* \pre \a node was created by createStmtNode(StmtType type, void *stmt) where
* \a type is ST_ASSIGNMENT and \a stmt was created by createAssignmentStmtNode(IdentifierNode *, ExprNode *).
* \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 pointer to a ReturnObject structure with the default return value.
*
* \retval NULL An error occurred during interpretation.
*
* \see interpretCastStmtNode(StmtNode *, ScopeObject *)
* \see interpretPrintStmtNode(StmtNode *, ScopeObject *)
* \see interpretInputStmtNode(StmtNode *, ScopeObject *)
* \see interpretDeclarationStmtNode(StmtNode *, ScopeObject *)
* \see interpretIfThenElseStmtNode(StmtNode *, ScopeObject *)
* \see interpretSwitchStmtNode(StmtNode *, ScopeObject *)
* \see interpretBreakStmtNode(StmtNode *, ScopeObject *)
* \see interpretReturnStmtNode(StmtNode *, ScopeObject *)
* \see interpretLoopStmtNode(StmtNode *, ScopeObject *)
* \see interpretDeallocationStmtNode(StmtNode *, ScopeObject *)
* \see interpretFuncDefStmtNode(StmtNode *, ScopeObject *)
* \see interpretExprStmtNode(StmtNode *, ScopeObject *) */
ReturnObject *interpretAssignmentStmtNode(StmtNode *node, /**< [in] A pointer to a StmtNode structure containing the AssignmentStmtNode structure to interpret. */
ScopeObject *scope) /**< [in,out] A pointer to the ScopeObject structure to evaluate \a node under. */
{
AssignmentStmtNode *stmt = (AssignmentStmtNode *)node->stmt;
ValueObject *val = interpretExprNode(stmt->expr, scope);
if (!val) return NULL;
if (!updateScopeValue(scope, stmt->target, val)) {
deleteValueObject(val);
return NULL;
}
return createReturnObject(RT_DEFAULT, NULL);
}
/** Interprets a declaration statement.
*
* \pre \a node was created by createStmtNode(StmtType type, void *stmt) where
* \a type is ST_DECLARATION and \a stmt was created by createDeclarationStmtNode(IdentifierNode *, IdentifierNode *, ExprNode *).
* \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 pointer to a ReturnObject structure with the default return value.
*
* \retval NULL An error occurred during interpretation.
*
* \see interpretCastStmtNode(StmtNode *, ScopeObject *)
* \see interpretPrintStmtNode(StmtNode *, ScopeObject *)
* \see interpretInputStmtNode(StmtNode *, ScopeObject *)
* \see interpretAssignmentStmtNode(StmtNode *, ScopeObject *)
* \see interpretIfThenElseStmtNode(StmtNode *, ScopeObject *)
* \see interpretSwitchStmtNode(StmtNode *, ScopeObject *)
* \see interpretBreakStmtNode(StmtNode *, ScopeObject *)
* \see interpretReturnStmtNode(StmtNode *, ScopeObject *)
* \see interpretLoopStmtNode(StmtNode *, ScopeObject *)
* \see interpretDeallocationStmtNode(StmtNode *, ScopeObject *)
* \see interpretFuncDefStmtNode(StmtNode *, ScopeObject *)
* \see interpretExprStmtNode(StmtNode *, ScopeObject *) */
ReturnObject *interpretDeclarationStmtNode(StmtNode *node, /**< [in] A pointer to a StmtNode structure containing the DeclarationStmtNode structure to interpret. */
ScopeObject *scope) /**< [in,out] A pointer to the ScopeObject structure to evaluate \a node under. */
{
DeclarationStmtNode *stmt = (DeclarationStmtNode *)node->stmt;
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);
return NULL;
}
if (stmt->expr)
init = interpretExprNode(stmt->expr, scope);
else if (stmt->type) {
switch (stmt->type->type) {
case CT_NIL:
init = createNilValueObject();
break;
case CT_BOOLEAN:
init = createBooleanValueObject(0);
break;
case CT_INTEGER:
init = createIntegerValueObject(0);
break;
case CT_FLOAT:
init = createFloatValueObject(0.0);
break;
case CT_STRING:
init = createStringValueObject(createString(""));
break;
}
}
else
init = createNilValueObject();
if (!init) return NULL;
if (!createScopeValue(scope, stmt->target)) {
deleteValueObject(init);
return NULL;
}
if (!updateScopeValue(scope, stmt->target, init)) {
deleteValueObject(init);
return NULL;
}
return createReturnObject(RT_DEFAULT, NULL);
}
/** Interprets an if/then/else statement.
*
* \pre \a node was created by createStmtNode(StmtType type, void *stmt) where
* \a type is ST_IFTHENELSE and \a stmt was created by createIfThenElseStmtNode(BlockNode *, BlockNode *, ExprNodeList *, BlockNodeList *).
* \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 pointer to a ReturnObject structure with the default return value.
*
* \retval NULL An error occurred during interpretation.
*
* \see interpretCastStmtNode(StmtNode *, ScopeObject *)
* \see interpretPrintStmtNode(StmtNode *, ScopeObject *)
* \see interpretInputStmtNode(StmtNode *, ScopeObject *)
* \see interpretAssignmentStmtNode(StmtNode *, ScopeObject *)
* \see interpretDeclarationStmtNode(StmtNode *, ScopeObject *)
* \see interpretSwitchStmtNode(StmtNode *, ScopeObject *)
* \see interpretBreakStmtNode(StmtNode *, ScopeObject *)
* \see interpretReturnStmtNode(StmtNode *, ScopeObject *)
* \see interpretLoopStmtNode(StmtNode *, ScopeObject *)
* \see interpretDeallocationStmtNode(StmtNode *, ScopeObject *)
* \see interpretFuncDefStmtNode(StmtNode *, ScopeObject *)
* \see interpretExprStmtNode(StmtNode *, ScopeObject *) */
ReturnObject *interpretIfThenElseStmtNode(StmtNode *node, /**< [in] A pointer to a StmtNode structure containing the IfThenElseStmtNode structure to interpret. */
ScopeObject *scope) /**< [in,out] A pointer to the ScopeObject structure to evaluate \a node under. */
{
IfThenElseStmtNode *stmt = (IfThenElseStmtNode *)node->stmt;
ValueObject *use1 = scope->impvar;
int use1val;
unsigned int cast1 = 0;
BlockNode *path = NULL;
if (scope->impvar->type != VT_BOOLEAN && scope->impvar->type != VT_INTEGER) {
use1 = castBooleanImplicit(scope->impvar, scope);
if (!use1) return NULL;
cast1 = 1;
}
use1val = getInteger(use1);
if (cast1) deleteValueObject(use1);
/* Determine which block of code to execute */
if (use1val)
path = stmt->yes;
else {
unsigned int n;
for (n = 0; n < stmt->guards->num; n++) {
ValueObject *val = interpretExprNode(stmt->guards->exprs[n], scope);
ValueObject *use2 = val;
int use2val;
unsigned int cast2 = 0;
if (!val) return NULL;
if (val->type != VT_BOOLEAN && val->type != VT_INTEGER) {
use2 = castBooleanImplicit(val, scope);
if (!use2) {
deleteValueObject(val);
return NULL;
}
cast2 = 1;
}
use2val = getInteger(use2);
deleteValueObject(val);
if (cast2) deleteValueObject(use2);
if (use2val) {
path = stmt->blocks->blocks[n];
break;
}
}
/* Reached the end without satisfying any guard */
if (n == stmt->guards->num)
path = stmt->no;
}
/* Interpret a path if one was reached */
if (path) {
ReturnObject *r = interpretBlockNode(path, scope);
if (!r)
return NULL;
/* Pass this up to the outer block to handle. */
else if (r->type == RT_BREAK || r->type == RT_RETURN)
return r;
else
deleteReturnObject(r);
}
return createReturnObject(RT_DEFAULT, NULL);
}
/** Interprets a switch statement.
*
* \note The specification is unclear as to whether guards are implicitly cast
* to the type of the implicit variable. This only matters in the case
* that mixed guard types are present and in this code, the action that
* is performed is the same as the comparison operator, that is, in order
* for a guard to match, both its type and value must match the implicit
* variable.
*
* \pre \a node was created by createStmtNode(StmtType type, void *stmt) where
* \a type is ST_SWITCH and \a stmt was created by createSwitchStmtNode(ExprNodeList *, BlockNodeList *, BlockNode *).
* \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 pointer to a ReturnObject structure with the return value after
* interpreting \a node in the scope \a scope.
*
* \retval NULL An error occurred during interpretation.
*
* \see interpretCastStmtNode(StmtNode *, ScopeObject *)
* \see interpretPrintStmtNode(StmtNode *, ScopeObject *)
* \see interpretInputStmtNode(StmtNode *, ScopeObject *)
* \see interpretAssignmentStmtNode(StmtNode *, ScopeObject *)
* \see interpretDeclarationStmtNode(StmtNode *, ScopeObject *)
* \see interpretIfThenElseStmtNode(StmtNode *, ScopeObject *)
* \see interpretBreakStmtNode(StmtNode *, ScopeObject *)
* \see interpretReturnStmtNode(StmtNode *, ScopeObject *)
* \see interpretLoopStmtNode(StmtNode *, ScopeObject *)
* \see interpretDeallocationStmtNode(StmtNode *, ScopeObject *)
* \see interpretFuncDefStmtNode(StmtNode *, ScopeObject *)
* \see interpretExprStmtNode(StmtNode *, ScopeObject *) */
ReturnObject *interpretSwitchStmtNode(StmtNode *node, /**< [in] A pointer to the StmtNode structure containing the SwitchStmtNode structure to interpret. */
ScopeObject *scope) /**< [in,out] A pointer to the ScopeObject structure to evaluate \a node under. */
{
SwitchStmtNode *stmt = (SwitchStmtNode *)node->stmt;
unsigned int n;
/* Loop over each of the guards, checking if any match the implicit
* variable. */
for (n = 0; n < stmt->guards->num; n++) {
ValueObject *use1 = scope->impvar;
ValueObject *use2 = interpretExprNode(stmt->guards->exprs[n], scope);
unsigned int done = 0;
if (!use2) return NULL;
if (use1->type == use2->type) {
switch (use1->type) {
case VT_NIL:
break;
case VT_BOOLEAN:
case VT_INTEGER:
if (getInteger(use1) == getInteger(use2))
done = 1;
break;
case VT_FLOAT:
if (getFloat(use1) == getFloat(use2))
done = 1;
break;
case VT_STRING:
/** \note Strings with interpolation
* should have already been
* checked for. */
if (!strcmp(getString(use1), getString(use2)))
done = 1;
break;
default:
fprintf(stderr, "Invalid type\n");
deleteValueObject(use2);
return NULL;
}
}
deleteValueObject(use2);
if (done) break;
}
/* If none of the guards match and a default block exists */
if (n == stmt->blocks->num && stmt->def) {
ReturnObject *r = interpretBlockNode(stmt->def, scope);
if (!r)
return NULL;
else if (r->type == RT_RETURN)
return r;
else
deleteReturnObject(r);
}
else {
/* Keep interpreting blocks starting at n until a break or
* return is encountered. */
for (; n < stmt->blocks->num; n++) {
ReturnObject *r = interpretBlockNode(stmt->blocks->blocks[n], scope);
if (!r)
return NULL;
else if (r->type == RT_BREAK) {
deleteReturnObject(r);
break;
}
else if (r->type == RT_RETURN)
return r;
else
deleteReturnObject(r);
}
}
return createReturnObject(RT_DEFAULT, NULL);
}
/** Interprets a break statement.
*
* \pre \a node was created by createStmtNode(StmtType type, void *stmt) where
* \a type is ST_BREAK and \a stmt is NULL.
* \pre \a scope was created by createScopeObject(ScopeObject *) and contains
* contents added by createScopeValue(ScopeObject *, IdentifierNode *) and
* contents updated by updateScopeValue(ScopeObject *, IdentifierNode *, ValueObject *).
*
* \note \a node and \a scope are not used by this function but are still
* included in its prototype to allow this function to be stored in a
* jump table for fast execution.
*
* \return A pointer to a ReturnObject structure indicating a break occurred.
*
* \retval NULL An error occurred during interpretation.
*
* \see interpretCastStmtNode(StmtNode *, ScopeObject *)
* \see interpretPrintStmtNode(StmtNode *, ScopeObject *)
* \see interpretInputStmtNode(StmtNode *, ScopeObject *)
* \see interpretAssignmentStmtNode(StmtNode *, ScopeObject *)
* \see interpretDeclarationStmtNode(StmtNode *, ScopeObject *)
* \see interpretIfThenElseStmtNode(StmtNode *, ScopeObject *)
* \see interpretSwitchStmtNode(StmtNode *, ScopeObject *)
* \see interpretReturnStmtNode(StmtNode *, ScopeObject *)
* \see interpretLoopStmtNode(StmtNode *, ScopeObject *)
* \see interpretDeallocationStmtNode(StmtNode *, ScopeObject *)
* \see interpretFuncDefStmtNode(StmtNode *, ScopeObject *)
* \see interpretExprStmtNode(StmtNode *, ScopeObject *) */
ReturnObject *interpretBreakStmtNode(StmtNode *node, /**< Not used (see note). */
ScopeObject *scope) /**< Not used (see note). */
{
node = NULL;
scope = NULL;
return createReturnObject(RT_BREAK, NULL);
}
/** Interprets a return statement.
*
* \pre \a node was created by createStmtNode(StmtType type, void *stmt) where
* \a type is ST_RETURN and \a stmt was created by createReturnStmtNode(ExprNode *).
* \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 pointer to a ReturnObject structure with the return value after
* interpreting \a node in the scope \a scope.
*
* \retval NULL An error occurred during interpretation.
*
* \see interpretCastStmtNode(StmtNode *, ScopeObject *)
* \see interpretPrintStmtNode(StmtNode *, ScopeObject *)
* \see interpretInputStmtNode(StmtNode *, ScopeObject *)
* \see interpretAssignmentStmtNode(StmtNode *, ScopeObject *)
* \see interpretDeclarationStmtNode(StmtNode *, ScopeObject *)
* \see interpretIfThenElseStmtNode(StmtNode *, ScopeObject *)
* \see interpretSwitchStmtNode(StmtNode *, ScopeObject *)
* \see interpretBreakStmtNode(StmtNode *, ScopeObject *)
* \see interpretLoopStmtNode(StmtNode *, ScopeObject *)
* \see interpretDeallocationStmtNode(StmtNode *, ScopeObject *)
* \see interpretFuncDefStmtNode(StmtNode *, ScopeObject *)
* \see interpretExprStmtNode(StmtNode *, ScopeObject *) */
ReturnObject *interpretReturnStmtNode(StmtNode *node, /**< [in] A pointer to the StmtNode structure containing the ReturnStmtNode structure to interpret. */
ScopeObject *scope) /**< [in] A pointer to the ScopeObject structure to evaluate \a node under. */
{
/* Evaluate and return the expression. */
ReturnStmtNode *stmt = (ReturnStmtNode *)node->stmt;
ValueObject *value = interpretExprNode(stmt->value, scope);
if (!value) return NULL;
return createReturnObject(RT_RETURN, value);
}
/** Interprets a loop statement.
*
* \pre \a node was created by createStmtNode(StmtType type, void *stmt) where
* \a type is ST_LOOP and \a stmt was created by createLoopStmtNode(IdentifierNode *, IdentifierNode *, ExprNode *, ExprNode *, BlockNode *).
* \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 pointer to a ReturnObject structure with the return value after
* interpreting \a node in the scope \a scope.
*
* \retval NULL An error occurred during interpretation.
*
* \see interpretCastStmtNode(StmtNode *, ScopeObject *)
* \see interpretPrintStmtNode(StmtNode *, ScopeObject *)
* \see interpretInputStmtNode(StmtNode *, ScopeObject *)
* \see interpretAssignmentStmtNode(StmtNode *, ScopeObject *)
* \see interpretDeclarationStmtNode(StmtNode *, ScopeObject *)
* \see interpretIfThenElseStmtNode(StmtNode *, ScopeObject *)
* \see interpretSwitchStmtNode(StmtNode *, ScopeObject *)
* \see interpretBreakStmtNode(StmtNode *, ScopeObject *)
* \see interpretReturnStmtNode(StmtNode *, ScopeObject *)
* \see interpretDeallocationStmtNode(StmtNode *, ScopeObject *)
* \see interpretFuncDefStmtNode(StmtNode *, ScopeObject *)
* \see interpretExprStmtNode(StmtNode *, ScopeObject *) */
ReturnObject *interpretLoopStmtNode(StmtNode *node, /**< [in] A pointer to the StmtNode structure containing the LoopStmtNode structure to interpret. */
ScopeObject *scope) /**< [in,out] A pointer to the ScopeObject structure to evaluate \a node under. */
{
LoopStmtNode *stmt = (LoopStmtNode *)node->stmt;
ScopeObject *outer = createScopeObject(scope);
ValueObject *var = NULL;
if (!outer) return NULL;
/* Create a temporary loop variable if required */
if (stmt->var) {
var = createScopeValue(outer, stmt->var);
if (!var) {
deleteScopeObject(outer);
return NULL;
}
var->type = VT_INTEGER;
var->data.i = 0;
var->semaphore = 1;
}
while (1) {
if (stmt->guard) {
ValueObject *val = interpretExprNode(stmt->guard, outer);
ValueObject *use = val;
unsigned short cast = 0;
int guardval;
if (val->type != VT_BOOLEAN && val->type != VT_INTEGER) {
use = castBooleanImplicit(val, scope);
if (!use) {
deleteScopeObject(outer);
deleteValueObject(val);
return NULL;
}
cast = 1;
}
guardval = getInteger(use);
if (cast) deleteValueObject(use);
deleteValueObject(val);
if (guardval == 0) break;
}
if (stmt->body) {
ReturnObject *result = interpretBlockNode(stmt->body, outer);
if (!result) {
deleteScopeObject(outer);
return NULL;
}
else if (result->type == RT_BREAK) {
deleteReturnObject(result);
break;
}
else if (result->type == RT_RETURN) {
deleteScopeObject(outer);
return result;
}
else
deleteReturnObject(result);
}
if (stmt->update) {
/* A little efficiency hack: if we know the operation
* to perform, don't bother evaluating the ExprNode
* structure, just go ahead and do it to the loop
* variable. */
if (stmt->update->type == ET_OP) {
OpExprNode *op = (OpExprNode *)stmt->update->expr;
if (op->type == OP_ADD)
var->data.i++;
else if (op->type == OP_SUB)
var->data.i--;
}
else {
ValueObject *update = interpretExprNode(stmt->update, outer);
if (!update) {
deleteScopeObject(outer);
return NULL;
}
if (!updateScopeValue(outer, stmt->var, update)) {
deleteScopeObject(outer);
deleteValueObject(update);
return NULL;
}
}
}
}
deleteScopeObject(outer);
return createReturnObject(RT_DEFAULT, NULL);
}
/** Interprets a deallocation statement.
*
* \pre \a node was created by createStmtNode(StmtType type, void *stmt) where
* \a type is ST_DEALLOCATION and \a stmt was created by createDeallocationStmtNode(IdentifierNode *).
* \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 pointer to a ReturnObject structure with the default return value.
*
* \retval NULL An error occurred during interpretation.
*
* \see interpretCastStmtNode(StmtNode *, ScopeObject *)
* \see interpretPrintStmtNode(StmtNode *, ScopeObject *)
* \see interpretInputStmtNode(StmtNode *, ScopeObject *)
* \see interpretDeclarationStmtNode(StmtNode *, ScopeObject *)
* \see interpretIfThenElseStmtNode(StmtNode *, ScopeObject *)
* \see interpretSwitchStmtNode(StmtNode *, ScopeObject *)
* \see interpretBreakStmtNode(StmtNode *, ScopeObject *)
* \see interpretReturnStmtNode(StmtNode *, ScopeObject *)
* \see interpretLoopStmtNode(StmtNode *, ScopeObject *)
* \see interpretFuncDefStmtNode(StmtNode *, ScopeObject *)
* \see interpretExprStmtNode(StmtNode *, ScopeObject *) */
ReturnObject *interpretDeallocationStmtNode(StmtNode *node, /**< [in] A pointer to a StmtNode structure containing the DeallocationStmtNode structure to interpret. */
ScopeObject *scope) /**< [in,out] A pointer to the ScopeObject structure to evaluate \a node under. */
{
DeallocationStmtNode *stmt = (DeallocationStmtNode *)node->stmt;
if (!updateScopeValue(scope, stmt->target, NULL)) return NULL;
/* If we want to completely remove the variable, use:
deleteScopeValue(scope, stmt->target);
*/
return createReturnObject(RT_DEFAULT, NULL);
}
/** Interprets a function definition statement.
*
* \pre \a node was created by createStmtNode(StmtType type, void *stmt) where
* \a type is ST_SWITCH and \a stmt was created by createSwitchStmtNode(IdentifierNode *, IdentifierNode *, IdentifierNodeList *, BlockNode *).
* \pre \a scope was created by createScopeObject(ScopeObject *) and contains
* contents added by createScopeValue(ScopeObject *, IdentifierNode *) and
* contents updated by updateScopeValue(ScopeObject *, IdentifierNode *, ValueObject *).
*
* \note \a node and \a scope are not used by this function but are still
* included in its prototype to allow this function to be stored in a
* jump table for fast execution.
*
* \return A pointer to a ReturnObject structure with the default return value.
*
* \retval NULL An error occurred during interpretation.
*
* \see interpretCastStmtNode(StmtNode *, ScopeObject *)
* \see interpretPrintStmtNode(StmtNode *, ScopeObject *)
* \see interpretInputStmtNode(StmtNode *, ScopeObject *)
* \see interpretAssignmentStmtNode(StmtNode *, ScopeObject *)
* \see interpretDeclarationStmtNode(StmtNode *, ScopeObject *)
* \see interpretIfThenElseStmtNode(StmtNode *, ScopeObject *)
* \see interpretSwitchStmtNode(StmtNode *, ScopeObject *)
* \see interpretBreakStmtNode(StmtNode *, ScopeObject *)
* \see interpretReturnStmtNode(StmtNode *, ScopeObject *)
* \see interpretLoopStmtNode(StmtNode *, ScopeObject *)
* \see interpretDeallocationStmtNode(StmtNode *, ScopeObject *)
* \see interpretExprStmtNode(StmtNode *, ScopeObject *) */
ReturnObject *interpretFuncDefStmtNode(StmtNode *node, /**< Not used (see note). */
ScopeObject *scope) /**< Not used (see note). */
{
/* Add the function to the current scope */
FuncDefStmtNode *stmt = (FuncDefStmtNode *)node->stmt;
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);
return NULL;
}
init = createFunctionValueObject(stmt);
if (!init) return NULL;
if (!createScopeValue(scope, stmt->name)) {
deleteValueObject(init);
return NULL;
}
if (!updateScopeValue(scope, stmt->name, init)) {
deleteValueObject(init);
return NULL;
}
return createReturnObject(RT_DEFAULT, NULL);
}
/** Interprets an expression statement.
*
* \pre \a node was created by createStmtNode(StmtType type, void *stmt) where
* \a type is ST_EXPR and \a stmt was created by createExprNode(ExprType, void *).
* \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 pointer to a ReturnObject structure with the default return value.
*
* \retval NULL An error occurred during interpretation.
*
* \see interpretCastStmtNode(StmtNode *, ScopeObject *)
* \see interpretPrintStmtNode(StmtNode *, ScopeObject *)
* \see interpretInputStmtNode(StmtNode *, ScopeObject *)
* \see interpretAssignmentStmtNode(StmtNode *, ScopeObject *)
* \see interpretDeclarationStmtNode(StmtNode *, ScopeObject *)
* \see interpretIfThenElseStmtNode(StmtNode *, ScopeObject *)
* \see interpretSwitchStmtNode(StmtNode *, ScopeObject *)
* \see interpretBreakStmtNode(StmtNode *, ScopeObject *)
* \see interpretReturnStmtNode(StmtNode *, ScopeObject *)
* \see interpretLoopStmtNode(StmtNode *, ScopeObject *)
* \see interpretDeallocationStmtNode(StmtNode *, ScopeObject *)
* \see interpretFuncDefStmtNode(StmtNode *, ScopeObject *) */
ReturnObject *interpretExprStmtNode(StmtNode *node, /**< [in] A pointer to a StmtNode structure containing the ExprNode structure to interpret. */
ScopeObject *scope) /**< [in,out] A pointer to the ScopeObject structure to evaluate \a node under. */
{
/* Set the implicit variable to the result of the expression */
ExprNode *expr = (ExprNode *)node->stmt;
deleteValueObject(scope->impvar);
scope->impvar = interpretExprNode(expr, scope);
if (!scope->impvar) return NULL;
return createReturnObject(RT_DEFAULT, NULL);
}
/* A jump table for statements. The index of a function in the table is given
* by its its index in the enumerated StmtType type. */
static ReturnObject *(*StmtJumpTable[13])(StmtNode *, ScopeObject *) = {
interpretCastStmtNode,
interpretPrintStmtNode,
interpretInputStmtNode,
interpretAssignmentStmtNode,
interpretDeclarationStmtNode,
interpretIfThenElseStmtNode,
interpretSwitchStmtNode,
interpretBreakStmtNode,
interpretReturnStmtNode,
interpretLoopStmtNode,
interpretDeallocationStmtNode,
interpretFuncDefStmtNode,
interpretExprStmtNode };
/** Interprets the contents of a StmtNode structure.
*
* \pre \a node was created by parseStmtNode(Token ***).
* \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 pointer to a ReturnObject structure with the return state of the
* interpreted \a node.
*
* \retval NULL An error occurred during interpretation.
*
* \see interpretExprNode(ExprNode *, ScopeObject *)
* \see interpretStmtNodeList(StmtNodeList *, ScopeObject *)
* \see interpretBlockNode(BlockNode *, ScopeObject *)
* \see interpretMainNode(MainNode *) */
ReturnObject *interpretStmtNode(StmtNode *node, /**< [in] A pointer to a StmtNode structure to interpret. */
ScopeObject *scope) /**< [in,out] A pointer to a ScopeObject structure to evaluate \a node under. */
{
return StmtJumpTable[node->type](node, scope);
}
/** Interprets the contents of a StmtNodeList structure.
*
* \pre \a list was created by createStmtNodeList(void) and contains contents
* added by addStmtNode(StmtNodeList *, StmtNode *).
* \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 pointer to a ReturnObject structure with the return state of the
* interpreted \a list.
*
* \retval NULL An error occurred during interpretation.
*
* \see interpretExprNode(ExprNode *, ScopeObject *)
* \see interpretStmtNode(StmtNode *, ScopeObject *)
* \see interpretBlockNode(BlockNode *, ScopeObject *)
* \see interpretMainNode(MainNode *) */
ReturnObject *interpretStmtNodeList(StmtNodeList *list, /**< [in] A pointer to the StmtNodeList structure to interpret. */
ScopeObject *scope) /**< [in,out] A pointer to the ScopeObject structure to evaluate \a list under. */
{
ReturnObject *ret = NULL;
unsigned int n;
for (n = 0; n < list->num; n++) {
ret = interpretStmtNode(list->stmts[n], scope);
if (!ret)
return NULL;
else if (ret->type == RT_BREAK || ret->type == RT_RETURN)
return ret;
else {
deleteReturnObject(ret);
ret = NULL;
}
}
if (!ret) ret = createReturnObject(RT_DEFAULT, NULL);
return ret;
}
/** Interprets the contents of a BlockNode structure.
*
* \pre \a node was created by parseBlockNode(Token ***).
* \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 pointer to a ReturnObject structure with the return state of the
* interpreted \a node.
*
* \retval NULL An error occurred during interpretation.
*
* \see interpretExprNode(ExprNode *, ScopeObject *)
* \see interpretStmtNode(StmtNode *, ScopeObject *)
* \see interpretStmtNodeList(StmtNodeList *, ScopeObject *)
* \see interpretMainNode(MainNode *) */
ReturnObject *interpretBlockNode(BlockNode *node, /**< [in] A pointer to a BlockNode structure to interpret. */
ScopeObject *scope) /**< [in,out] A pointer to a ScopeObject structure to evaluate \a node under. */
{
ReturnObject *ret = NULL;
ScopeObject *inner = createScopeObject(scope);
if (!inner) return NULL;
ret = interpretStmtNodeList(node->stmts, inner);
deleteScopeObject(inner);
return ret;
}
/** Interprets the contents of a MainNode structure.
*
* \pre \a node was created by parseMainNode(Token **).
* \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 The return status of the interpreted MainNode structure.
*
* \retval 0 \a main was interpreted without any errors.
* \retval 1 An error occurred while interpreting \a main.
*
* \see interpretExprNode(ExprNode *, ScopeObject *)
* \see interpretStmtNode(StmtNode *, ScopeObject *)
* \see interpretStmtNodeList(StmtNodeList *, ScopeObject *)
* \see interpretBlockNode(BlockNode *, ScopeObject *) */
int interpretMainNode(MainNode *main) /**< [in] A pointer to the MainNode structure to interpret. */
{
ReturnObject *ret = NULL;
if (!main) return 1;
ret = interpretBlockNode(main->block, NULL);
if (!ret) return 1;
deleteReturnObject(ret);
return 0;
}