diff --git a/Makefile b/Makefile index c908fd7..b686aec 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,7 @@ SRCS = lexer.c tokenizer.c parser.c interpreter.c unicode.c main.c HDRS = lexer.h tokenizer.h parser.h interpreter.h unicode.h INSTALL = /usr/local/bin/install -c CPPFLAGS = -O3 +LINT = splint -nullret -temptrans -compdestroy -usereleased -compdef -compmempass -mustfreefresh -boolops -predboolint -nullpass -nullderef +boolint -predboolothers -uniondef -unqualifiedtrans -nullstate -bufferoverflowhigh -branchstate -mustfreeonly -nullassign -shiftimplementation -exportlocal prefix = /usr/local bindir = $(prefix)/bin @@ -16,7 +17,10 @@ $(TARGET): $(OBJS) $(LIBS) $(CC) $(CPPFLAGS) -o $(TARGET) $(OBJS) $(LIBS) pedantic: $(OBJS) $(LIBS) - $(CC) -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wundef -W -Wall -ansi -pedantic -g -o $(TARGET) $(OBJS) $(LIBS) + $(CC) -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wundef -Wall -ansi -pedantic -g -o $(TARGET) $(SRCS) $(HDRS) $(LIBS) + +lint: all + $(LINT) $(SRCS) check: all @cd $(testdir) && ./testDir.sh -q ../$(TARGET) 1.3-Tests/ diff --git a/interpreter.c b/interpreter.c index 632a9aa..ddfca4a 100644 --- a/interpreter.c +++ b/interpreter.c @@ -20,7 +20,14 @@ char *createString(char *data) /**< [in] A pointer to the string data to store. * * \return A pointer to a nil type ValueObject structure. * - * \retval NULL malloc was unable to allocate memory. */ + * \retval NULL malloc was unable to allocate memory. + * + * \see createBooleanValueObject(int) + * \see createIntegerValueObject(int) + * \see createFloatValueObject(float) + * \see createStringValueObject(char *) + * \see createFunctionValueObject(FuncDefStmtNode *) + * \see deleteValueObject(ValueObject *) */ ValueObject *createNilValueObject(void) { ValueObject *p = malloc(sizeof(ValueObject)); @@ -38,7 +45,14 @@ ValueObject *createNilValueObject(void) * \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. */ + * \retval NULL malloc was unable to allocate memory. + * + * \see createNilValueObject(void) + * \see createIntegerValueObject(int) + * \see createFloatValueObject(float) + * \see createStringValueObject(char *) + * \see createFunctionValueObject(FuncDefStmtNode *) + * \see deleteValueObject(ValueObject *) */ ValueObject *createBooleanValueObject(int data) /**< [in] The boolean data to store. */ { ValueObject *p = malloc(sizeof(ValueObject)); @@ -57,7 +71,14 @@ ValueObject *createBooleanValueObject(int data) /**< [in] The boolean data to st * \return A pointer to an integer type ValueObject structure with value * \a data. * - * \retval NULL malloc was unable to allocate memory. */ + * \retval NULL malloc was unable to allocate memory. + * + * \see createNilValueObject(void) + * \see createBooleanValueObject(int) + * \see createFloatValueObject(float) + * \see createStringValueObject(char *) + * \see createFunctionValueObject(FuncDefStmtNode *) + * \see deleteValueObject(ValueObject *) */ ValueObject *createIntegerValueObject(int data) /**< [in] The integer data to store. */ { ValueObject *p = malloc(sizeof(ValueObject)); @@ -76,7 +97,14 @@ ValueObject *createIntegerValueObject(int data) /**< [in] The integer data to st * \return A pointer to a floating point decimal type ValueObject structure * with value \a data. * - * \retval NULL malloc was unable to allocate memory. */ + * \retval NULL malloc was unable to allocate memory. + * + * \see createNilValueObject(void) + * \see createBooleanValueObject(int) + * \see createIntegerValueObject(int) + * \see createStringValueObject(char *) + * \see createFunctionValueObject(FuncDefStmtNode *) + * \see deleteValueObject(ValueObject *) */ ValueObject *createFloatValueObject(float data) /**< [in] The floating point data to store. */ { ValueObject *p = malloc(sizeof(ValueObject)); @@ -94,7 +122,14 @@ ValueObject *createFloatValueObject(float data) /**< [in] The floating point dat * * \return A pointer to a string type ValueObject structure with value \a data. * - * \retval NULL malloc was unable to allocate memory. */ + * \retval NULL malloc was unable to allocate memory. + * + * \see createNilValueObject(void) + * \see createBooleanValueObject(int) + * \see createIntegerValueObject(int) + * \see createFloatValueObject(float) + * \see createFunctionValueObject(FuncDefStmtNode *) + * \see deleteValueObject(ValueObject *) */ ValueObject *createStringValueObject(char *data) /**< [in] The string data to store. */ { ValueObject *p = malloc(sizeof(ValueObject)); @@ -112,7 +147,14 @@ ValueObject *createStringValueObject(char *data) /**< [in] The string data to st * * \return A pointer to a function type ValueObject structure with definition \a data. * - * \retval NULL malloc was unable to allocate memory. */ + * \retval NULL malloc was unable to allocate memory. + * + * \see createNilValueObject(void) + * \see createBooleanValueObject(int) + * \see createIntegerValueObject(int) + * \see createFloatValueObject(float) + * \see createStringValueObject(char *) + * \see deleteValueObject(ValueObject *) */ ValueObject *createFunctionValueObject(FuncDefStmtNode *data) /**< [in] The function definition to store. */ { ValueObject *p = malloc(sizeof(ValueObject)); @@ -230,34 +272,68 @@ void deleteReturnObject(ReturnObject *object) /**< [in,out] The ReturnObject str free(object); } -/** \todo Document this function */ -char *resolveIdentifierName(IdentifierNode *id, - ScopeObject *scope) +/** Translates an identifier into a string naming a variable. + * + * \pre \a id was created by createIdentifierNode(IdentifierType, void *, const char *, unsigned int). + * \pre \a scope was created by createScopeObject(ScopeObject *) and contains + * contents added by createScopeValue(ScopeObject *, IdentifierNode *) and + * contents updated by updateScopeValue(ScopeObject *, IdentifierNode *, ValueObject *). + * + * \return A newly-allocated array of characters representing the name of the + * identifier. + * + * \retval NULL malloc was unable to allocate memory. */ +char *resolveIdentifierName(IdentifierNode *id, /**< [in] A pointer to the IdentifierNode structure to translate. */ + ScopeObject *scope) /**< [in] A pointer to the ScopeObject structure to translate \a id under. */ { + ValueObject *val = NULL; + ValueObject *str = NULL; char *ret = NULL; - if (!id) return NULL; + + if (!id) goto resolveIdentifierNameAbort; + if (id->type == IT_DIRECT) { - char *temp = (char *)(id->id); + /* Just return a copy of the character array */ + const char *temp = (char *)(id->id); ret = malloc(sizeof(char) * (strlen(temp) + 1)); strcpy(ret, temp); } else if (id->type == IT_INDIRECT) { ExprNode *expr = (ExprNode *)(id->id); - ValueObject *val = interpretExprNode(expr, scope); - ValueObject *str = castStringExplicit(val, scope); + + /* Interpret the identifier expression */ + val = interpretExprNode(expr, scope); + if (!val) goto resolveIdentifierNameAbort; + + /* Then cast it to a string */ + str = castStringExplicit(val, scope); + if (!str) goto resolveIdentifierNameAbort; deleteValueObject(val); + + /* Copy the evaluated string */ ret = createString(getString(str)); + if (!ret) goto resolveIdentifierNameAbort; deleteValueObject(str); } else { - fprintf(stderr, "%s:%d: invalid identifier type\n", id->fname, id->line); + fprintf(stderr, "%s:%u: invalid identifier type\n", id->fname, id->line); } + return ret; + +resolveIdentifierNameAbort: /* Exception handline */ + + /* Clean up any allocated structures */ + if (ret) free(ret); + if (str) deleteValueObject(str); + if (val) deleteValueObject(val); + + return NULL; } /** Creates a ScopeObject structure. * - * \pre \a scope was created by createScopeObject(ScopeObject *) and contains + * \pre \a parent was created by createScopeObject(ScopeObject *) and contains * contents added by createScopeValue(ScopeObject *, IdentifierNode *) and * contents updated by updateScopeValue(ScopeObject *, IdentifierNode *, ValueObject *) * or is \c NULL if creating the root parent. @@ -267,7 +343,7 @@ char *resolveIdentifierName(IdentifierNode *id, * \retval NULL malloc was unable to allocate memory. * * \see deleteScopeObject(ScopeObject *) */ -ScopeObject *createScopeObject(ScopeObject *parent) /**< [in] A pointer to the parent ScopeObject. */ +ScopeObject *createScopeObject(ScopeObject *parent) /**< [in] A pointer to the parent ScopeObject structure. */ { ScopeObject *p = malloc(sizeof(ScopeObject)); if (!p) { @@ -316,7 +392,7 @@ void deleteScopeObject(ScopeObject *scope) /**< [in,out] The ScopeObject structu * \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 \a target was created by createIdentifierNode(IdentifierType, void *, const char *, unsigned int). * * \return A pointer to the stored ValueObject structure named by \a target. * @@ -331,8 +407,11 @@ ValueObject *getScopeValue(ScopeObject *scope, /**< [in] The ScopeObject str { ScopeObject *current = scope; char *name = NULL; + + /* Look up the identifier name */ name = resolveIdentifierName(target, scope); if (!name) return NULL; + /* Traverse upwards through scopes */ do { unsigned int n; @@ -354,7 +433,7 @@ ValueObject *getScopeValue(ScopeObject *scope, /**< [in] The ScopeObject str * \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 \a target was created by createIdentifierNode(IdentifierType, void *, const char *, unsigned int). * * \return A pointer to the stored ValueObject structure named by \a target. * @@ -369,8 +448,11 @@ ValueObject *getLocalScopeValue(ScopeObject *scope, /**< [in] The ScopeObjec { unsigned int n; char *name = NULL; + + /* Look up the identifier name */ name = resolveIdentifierName(target, scope); if (!name) return NULL; + /* Check for value in current scope */ for (n = 0; n < scope->numvals; n++) { if (!strcmp(scope->names[n], name)) { @@ -387,7 +469,7 @@ ValueObject *getLocalScopeValue(ScopeObject *scope, /**< [in] The ScopeObjec * \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 \a target was created by createIdentifierNode(IdentifierType, void *, const char *, unsigned int). * * \return A pointer to the newly created ValueObject structure named by * \a target. @@ -404,8 +486,11 @@ ValueObject *createScopeValue(ScopeObject *scope, /**< [in,out] The ScopeObj unsigned int newnumvals = scope->numvals + 1; void *mem1 = NULL, *mem2 = NULL; char *name = NULL; + + /* Look up the identifier name */ name = resolveIdentifierName(target, scope); if (!name) return NULL; + /* Add value to local scope */ mem1 = realloc(scope->names, sizeof(IdentifierNode *) * newnumvals); if (!mem1) { @@ -435,7 +520,7 @@ ValueObject *createScopeValue(ScopeObject *scope, /**< [in,out] The ScopeObj * \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 \a target was created by createIdentifierNode(IdentifierType, void *, 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 *), @@ -456,8 +541,11 @@ ValueObject *updateScopeValue(ScopeObject *scope, /**< [in,out] A pointer to { ScopeObject *current = scope; char *name = NULL; + + /* Look up the identifier name */ name = resolveIdentifierName(target, scope); if (!name) return NULL; + /* Traverse upwards through scopes */ do { unsigned int n; @@ -476,7 +564,7 @@ ValueObject *updateScopeValue(ScopeObject *scope, /**< [in,out] A pointer to } } } while ((current = current->parent)); - fprintf(stderr, "%s:%d: unable to store variable\n", target->fname, target->line); + fprintf(stderr, "%s:%u: unable to store variable at: %s\n", target->fname, target->line, name); free(name); return NULL; } @@ -487,7 +575,7 @@ ValueObject *updateScopeValue(ScopeObject *scope, /**< [in,out] A pointer to * \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 \a target was created by createIdentifierNode(IdentifierType, void *, const char *, unsigned int). * * \see getScopeValue(ScopeObject *, IdentifierNode *) * \see getLocalScopeValue(ScopeObject *, IdentifierNode *) @@ -498,8 +586,11 @@ void deleteScopeValue(ScopeObject *scope, /**< [in,out] A pointer to the Sco { ScopeObject *current = scope; char *name = NULL; + + /* Look up the identifier name */ name = resolveIdentifierName(target, scope); if (!name) return; + /* Traverse upwards through scopes */ do { unsigned int n; @@ -545,8 +636,8 @@ void deleteScopeValue(ScopeObject *scope, /**< [in,out] A pointer to the Sco * \retval 1 The string of characters is a number. */ unsigned int isNumString(const char *stringdata) /**< [in] The array of characters to check the format of. */ { - unsigned int n; - unsigned int len = strlen(stringdata); + size_t n; + size_t len = strlen(stringdata); /* Check for empty string */ if (len == 0) return 0; /* Check for non-digit, non-hyphen, and non-period characters */ @@ -566,8 +657,8 @@ unsigned int isNumString(const char *stringdata) /**< [in] The array of characte * \retval 1 The string of characters is a hexadecimal number. */ unsigned int isHexString(const char *stringdata) /**< [in] The array of characters to check the format of. */ { - unsigned int n; - unsigned int len = strlen(stringdata); + size_t n; + size_t len = strlen(stringdata); /* Check for empty string */ if (len == 0) return 0; /* Check for non-digit and non-A-through-F characters */ @@ -736,7 +827,7 @@ ValueObject *castBooleanExplicit(ValueObject *node, /**< [in] The ValueObject s case VT_INTEGER: return createBooleanValueObject(getInteger(node) != 0); case VT_FLOAT: - return createBooleanValueObject(getFloat(node) != 0.0); + return createBooleanValueObject(fabs(getFloat(node) - 0.0) > FLT_EPSILON); case VT_STRING: if (strstr(getString(node), ":{")) { /* Perform interpolation */ @@ -749,9 +840,13 @@ ValueObject *castBooleanExplicit(ValueObject *node, /**< [in] The ValueObject s } else return createBooleanValueObject(getString(node)[0] != '\0'); + case VT_FUNC: + fprintf(stderr, "Cannot cast functions to booleans\n"); + return NULL; + default: + fprintf(stderr, "Unknown value type encountered during boolean cast\n"); + return NULL; } - fprintf(stderr, "Unknown value type encountered during boolean cast\n"); - return NULL; } /** Casts the contents of a ValueObject structure to integer type in an @@ -783,7 +878,7 @@ ValueObject *castIntegerExplicit(ValueObject *node, /**< [in] The ValueObject s case VT_INTEGER: return createIntegerValueObject(getInteger(node)); case VT_FLOAT: - return createIntegerValueObject(getFloat(node)); + return createIntegerValueObject((int)getFloat(node)); case VT_STRING: if (strstr(getString(node), ":{")) { /* Perform interpolation */ @@ -796,7 +891,11 @@ ValueObject *castIntegerExplicit(ValueObject *node, /**< [in] The ValueObject s deleteValueObject(interp); return NULL; } - sscanf(getString(interp), "%i", &value); + if (sscanf(getString(interp), "%i", &value) != 1) { + fprintf(stderr, "Expected integer value\n"); + deleteValueObject(interp); + return NULL; + } ret = createIntegerValueObject(value); deleteValueObject(interp); return ret; @@ -807,12 +906,19 @@ ValueObject *castIntegerExplicit(ValueObject *node, /**< [in] The ValueObject s fprintf(stderr, "Unable to cast value\n"); return NULL; } - sscanf(getString(node), "%i", &value); + if (sscanf(getString(node), "%i", &value) != 1) { + fprintf(stderr, "Expected integer value\n"); + return NULL; + } return createIntegerValueObject(value); } + case VT_FUNC: + fprintf(stderr, "Cannot cast functions to integers\n"); + return NULL; + default: + fprintf(stderr, "Unknown value type encountered during integer cast\n"); + return NULL; } - fprintf(stderr, "Unknown value type encountered during integer cast\n"); - return NULL; } /** Casts the contents of a ValueObject structure to floating point decimal @@ -842,7 +948,7 @@ ValueObject *castFloatExplicit(ValueObject *node, /**< [in] The ValueObject str return createFloatValueObject(0.0); case VT_BOOLEAN: case VT_INTEGER: - return createFloatValueObject(getInteger(node)); + return createFloatValueObject((float)getInteger(node)); case VT_FLOAT: return createFloatValueObject(getFloat(node)); case VT_STRING: @@ -857,7 +963,11 @@ ValueObject *castFloatExplicit(ValueObject *node, /**< [in] The ValueObject str deleteValueObject(interp); return NULL; } - sscanf(getString(interp), "%f", &value); + if (sscanf(getString(interp), "%f", &value) != 1) { + fprintf(stderr, "Expected floating point decimal value\n"); + deleteValueObject(interp); + return NULL; + } ret = createFloatValueObject(value); deleteValueObject(interp); return ret; @@ -868,12 +978,19 @@ ValueObject *castFloatExplicit(ValueObject *node, /**< [in] The ValueObject str fprintf(stderr, "Unable to cast value\n"); return NULL; } - sscanf(getString(node), "%f", &value); + if (sscanf(getString(node), "%f", &value) != 1) { + fprintf(stderr, "Expected floating point decimal value\n"); + return NULL; + } return createFloatValueObject(value); } + case VT_FUNC: + fprintf(stderr, "Cannot cast functions to floats\n"); + return NULL; + default: + fprintf(stderr, "Unknown value type encountered during floating point decimal cast\n"); + return NULL; } - fprintf(stderr, "Unknown value type encountered during floating point decimal cast\n"); - return NULL; } /** Casts the contents of a ValueObject structure to string type in an explicit @@ -941,7 +1058,8 @@ ValueObject *castStringExplicit(ValueObject *node, /**< [in] The ValueObject st char *temp = NULL; char *data = NULL; char *str = getString(node); - unsigned int a, b, size; + unsigned int a, b; + size_t size; /* Perform interpolation */ size = strlen(getString(node)) + 1; temp = malloc(sizeof(char) * size); @@ -969,12 +1087,19 @@ ValueObject *castStringExplicit(ValueObject *node, /**< [in] The ValueObject st else if (!strncmp(str + b, ":(", 2)) { const char *start = str + b + 2; const char *end = strchr(start, ')'); - unsigned short len = end - start; - char *image = malloc(sizeof(char) * (len + 1)); + size_t len; + char *image = NULL; long codepoint; char out[3]; - unsigned short num; + size_t num; void *mem = NULL; + if (end < start) { + fprintf(stderr, "Expected closing parenthesis after :(\n"); + free(temp); + return NULL; + } + len = (size_t)(end - start); + image = malloc(sizeof(char) * (len + 1)); strncpy(image, start, len); image[len] = '\0'; if (!isHexString(image)) { @@ -985,7 +1110,12 @@ ValueObject *castStringExplicit(ValueObject *node, /**< [in] The ValueObject st } codepoint = strtol(image, NULL, 16); free(image); - num = convertCodePointToUTF8(codepoint, out); + if (codepoint < 0) { + fprintf(stderr, "Code point is supposed to be positive\n"); + free(temp); + return NULL; + } + num = convertCodePointToUTF8((unsigned int)codepoint, out); if (num == 0) { free(temp); return NULL; @@ -1004,22 +1134,30 @@ ValueObject *castStringExplicit(ValueObject *node, /**< [in] The ValueObject st else if (!strncmp(str + b, ":[", 2)) { const char *start = str + b + 2; const char *end = strchr(start, ']'); - unsigned short len = end - start; - char *image = malloc(sizeof(char) * (len + 1)); + size_t len; + char *image = NULL; long codepoint; char out[3]; - unsigned short num; + size_t num; void *mem = NULL; + if (end < start) { + fprintf(stderr, "Expected closing square bracket after :[\n"); + free(temp); + return NULL; + } + len = (size_t)(end - start); + image = malloc(sizeof(char) * (len + 1)); strncpy(image, start, len); strncpy(image, start, len); image[len] = '\0'; codepoint = convertNormativeNameToCodePoint(image); free(image); if (codepoint < 0) { + fprintf(stderr, "Code point is supposed to be positive\n"); free(temp); return NULL; } - num = convertCodePointToUTF8(codepoint, out); + num = convertCodePointToUTF8((unsigned int)codepoint, out); size += num; mem = realloc(temp, size); if (!mem) { @@ -1037,9 +1175,16 @@ ValueObject *castStringExplicit(ValueObject *node, /**< [in] The ValueObject st /* Copy the variable name into image */ const char *start = str + b + 2; const char *end = strchr(start, '}'); - unsigned short len = end - start; - char *image = malloc(sizeof(char) * (len + 1)); + size_t len; + char *image = NULL; void *mem = NULL; + if (end < start) { + fprintf(stderr, "Expected closing curly brace after :{\n"); + free(temp); + return NULL; + } + len = (size_t)(end - start); + image = malloc(sizeof(char) * (len + 1)); strncpy(image, start, len); image[len] = '\0'; if (!strcmp(image, "IT")) @@ -1092,9 +1237,14 @@ ValueObject *castStringExplicit(ValueObject *node, /**< [in] The ValueObject st free(temp); return createStringValueObject(data); } + case VT_FUNC: { + fprintf(stderr, "Cannot cast functions to strings\n"); + return NULL; + } + default: + fprintf(stderr, "Unknown value type encountered during string cast\n"); + return NULL; } - fprintf(stderr, "Unknown value type encountered during string cast\n"); - return NULL; } /** Interprets an implicit variable expression. @@ -1179,7 +1329,7 @@ ValueObject *interpretCastExprNode(ExprNode *node, /**< [in] A pointer to an * * \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 *). + * structure created by createFuncCallExprNode(IdentifierNode *, IdentifierNode *, 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 *). @@ -1208,7 +1358,7 @@ ValueObject *interpretFuncCallExprNode(ExprNode *node, /**< [in] A pointer t IdentifierNode *id = (IdentifierNode *)(expr->name); char *name = resolveIdentifierName(id, scope); if (name) { - fprintf(stderr, "%s:%d: undefined function at: %s\n", id->fname, id->line, name); + fprintf(stderr, "%s:%u: undefined function at: %s\n", id->fname, id->line, name); free(name); } deleteScopeObject(outer); @@ -1219,7 +1369,7 @@ ValueObject *interpretFuncCallExprNode(ExprNode *node, /**< [in] A pointer t IdentifierNode *id = (IdentifierNode *)(expr->name); char *name = resolveIdentifierName(id, scope); if (name) { - fprintf(stderr, "%s:%d: incorrect number of arguments supplied to: %s\n", id->fname, id->line, name); + fprintf(stderr, "%s:%u: incorrect number of arguments supplied to: %s\n", id->fname, id->line, name); free(name); } deleteScopeObject(outer); @@ -1276,7 +1426,7 @@ ValueObject *interpretFuncCallExprNode(ExprNode *node, /**< [in] A pointer t * * \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). + * structure created by createIdentifierNode(IdentifierType, void *, const char *, unsigned int). * \pre \a scope was created by createScopeObject(ScopeObject *) and contains * contents added by createScopeValue(ScopeObject *, IdentifierNode *) and * contents updated by updateScopeValue(ScopeObject *, IdentifierNode *, ValueObject *). @@ -1297,14 +1447,12 @@ ValueObject *interpretFuncCallExprNode(ExprNode *node, /**< [in] A pointer t ValueObject *interpretIdentifierExprNode(ExprNode *node, /**< [in] A pointer to an ExprNode structure containing the IdentifierNode structure to interpret. */ ScopeObject *scope) /**< Not used (see note). */ { - IdentifierNode *id = NULL; - ValueObject *val = NULL; - id = (IdentifierNode *)(node->expr); - val = getScopeValue(scope, id); + ValueObject *val = getScopeValue(scope, node->expr); if (!val) { + IdentifierNode *id = (IdentifierNode *)(node->expr); char *name = resolveIdentifierName(id, scope); if (name) { - fprintf(stderr, "%s:%d: variable does not exist at: %s\n", id->fname, id->line, name); + fprintf(stderr, "%s:%u: variable does not exist at: %s\n", id->fname, id->line, name); free(name); } return NULL; @@ -1565,7 +1713,7 @@ ValueObject *opModIntegerInteger(ValueObject *a, /**< [in] The dividend. */ ValueObject *opAddIntegerFloat(ValueObject *a, /**< [in] The first term to add. */ ValueObject *b) /**< [in] The second term to add. */ { - return createFloatValueObject(getInteger(a) + getFloat(b)); + return createFloatValueObject((float)(getInteger(a) + getFloat(b))); } /** Subtracts an integer and a float. @@ -1585,7 +1733,7 @@ ValueObject *opAddIntegerFloat(ValueObject *a, /**< [in] The first term to add. ValueObject *opSubIntegerFloat(ValueObject *a, /**< [in] The minuend. */ ValueObject *b) /**< [in] The subtrahend. */ { - return createFloatValueObject(getInteger(a) - getFloat(b)); + return createFloatValueObject((float)(getInteger(a) - getFloat(b))); } /** Multiplies an integer and a float. @@ -1605,7 +1753,7 @@ ValueObject *opSubIntegerFloat(ValueObject *a, /**< [in] The minuend. */ ValueObject *opMultIntegerFloat(ValueObject *a, /**< [in] The first factor to multiply. */ ValueObject *b) /**< [in] The second factor to multiply. */ { - return createFloatValueObject(getInteger(a) * getFloat(b)); + return createFloatValueObject((float)(getInteger(a) * getFloat(b))); } /** Divides an integer and a float. @@ -1627,11 +1775,11 @@ ValueObject *opMultIntegerFloat(ValueObject *a, /**< [in] The first factor to mu ValueObject *opDivIntegerFloat(ValueObject *a, /**< [in] The dividend. */ ValueObject *b) /**< [in] The divisor. */ { - if (getFloat(b) == 0.0) { + if (fabs(getFloat(b) - 0.0) < FLT_EPSILON) { fprintf(stderr, "Division by zero undefined\n"); return NULL; } - return createFloatValueObject(getInteger(a) / getFloat(b)); + return createFloatValueObject((float)(getInteger(a) / getFloat(b))); } /** Finds the maximum of an integer and a float. @@ -1651,7 +1799,7 @@ ValueObject *opDivIntegerFloat(ValueObject *a, /**< [in] The dividend. */ ValueObject *opMaxIntegerFloat(ValueObject *a, /**< [in] The first number to compare. */ ValueObject *b) /**< [in] The second number to compare. */ { - return createFloatValueObject(getInteger(a) > getFloat(b) ? getInteger(a) : getFloat(b)); + return createFloatValueObject((float)(getInteger(a)) > getFloat(b) ? (float)(getInteger(a)) : getFloat(b)); } /** Finds the minimum of an integer and a float. @@ -1671,7 +1819,7 @@ ValueObject *opMaxIntegerFloat(ValueObject *a, /**< [in] The first number to com ValueObject *opMinIntegerFloat(ValueObject *a, /**< [in] The first number to compare. */ ValueObject *b) /**< [in] The second number to compare. */ { - return createFloatValueObject(getInteger(a) < getFloat(b) ? getInteger(a) : getFloat(b)); + return createFloatValueObject((float)(getInteger(a)) < getFloat(b) ? (float)(getInteger(a)) : getFloat(b)); } /** Calculates the modulus of an integer and a float. @@ -1691,11 +1839,11 @@ ValueObject *opMinIntegerFloat(ValueObject *a, /**< [in] The first number to com ValueObject *opModIntegerFloat(ValueObject *a, /**< [in] The dividend. */ ValueObject *b) /**< [in] The divisor. */ { - if (getFloat(b) == 0.0) { + if (fabs(getFloat(b) - 0.0) < FLT_EPSILON) { fprintf(stderr, "Division by zero undefined\n"); return NULL; } - return createFloatValueObject(fmod(getInteger(a), getFloat(b))); + return createFloatValueObject((float)(fmod((double)(getInteger(a)), getFloat(b)))); } /** Adds a float and an integer. @@ -1800,7 +1948,7 @@ ValueObject *opDivFloatInteger(ValueObject *a, /**< [in] The dividend. */ ValueObject *opMaxFloatInteger(ValueObject *a, /**< [in] The first number to compare. */ ValueObject *b) /**< [in] The second number to compare. */ { - return createFloatValueObject(getFloat(a) > getInteger(b) ? getFloat(a) : getInteger(b)); + return createFloatValueObject(getFloat(a) > (float)(getInteger(b)) ? getFloat(a) : (float)(getInteger(b))); } /** Finds the minimum of a float and an integer. @@ -1820,7 +1968,7 @@ ValueObject *opMaxFloatInteger(ValueObject *a, /**< [in] The first number to com ValueObject *opMinFloatInteger(ValueObject *a, /**< [in] The first number to compare. */ ValueObject *b) /**< [in] The second number to compare. */ { - return createFloatValueObject(getFloat(a) < getInteger(b) ? getFloat(a) : getInteger(b)); + return createFloatValueObject(getFloat(a) < (float)(getInteger(b)) ? getFloat(a) : (float)(getInteger(b))); } /** Calculates the modulus of a float and an integer. @@ -1844,7 +1992,7 @@ ValueObject *opModFloatInteger(ValueObject *a, /**< [in] The dividend. */ fprintf(stderr, "Division by zero undefined\n"); return NULL; } - return createFloatValueObject(fmod(getFloat(a), getInteger(b))); + return createFloatValueObject((float)(fmod(getFloat(a), (double)(getInteger(b))))); } /** Adds two floats. @@ -1922,7 +2070,7 @@ ValueObject *opMultFloatFloat(ValueObject *a, /**< [in] The first factor to mult ValueObject *opDivFloatFloat(ValueObject *a, /**< [in] The dividend. */ ValueObject *b) /**< [in] The divisor. */ { - if (getFloat(b) == 0.0) { + if (fabs(getFloat(b) - 0.0) < FLT_EPSILON) { fprintf(stderr, "Division by zero undefined\n"); return NULL; } @@ -1983,11 +2131,11 @@ ValueObject *opMinFloatFloat(ValueObject *a, /**< [in] The first number to compa ValueObject *opModFloatFloat(ValueObject *a, /**< [in] The dividend. */ ValueObject *b) /**< [in] The divisor. */ { - if (getFloat(b) == 0.0) { + if (fabs(getFloat(b) - 0.0) < FLT_EPSILON) { fprintf(stderr, "Division by zero undefined\n"); return NULL; } - return createFloatValueObject(fmod(getFloat(a), getFloat(b))); + return createFloatValueObject((float)(fmod(getFloat(a), getFloat(b)))); } /* A jump table for arithmetic operations. The first index determines the @@ -2159,7 +2307,7 @@ ValueObject *interpretBoolOpExprNode(OpExprNode *expr, /**< [in] A pointer to for (n = 0; n < expr->args->num; n++) { ValueObject *val = interpretExprNode(expr->args->exprs[n], scope); ValueObject *use = val; - unsigned int temp; + int temp; unsigned int cast = 0; if (!val) return NULL; if (val->type != VT_BOOLEAN && val->type != VT_INTEGER) { @@ -2238,7 +2386,7 @@ ValueObject *opNeqIntegerInteger(ValueObject *a, /**< [in] The first value to te ValueObject *opEqIntegerFloat(ValueObject *a, /**< [in] The first value to test. */ ValueObject *b) /**< [in] The second value to test. */ { - return createBooleanValueObject(getInteger(a) == getFloat(b)); + return createBooleanValueObject(fabs((float)(getInteger(a)) - getFloat(b)) < FLT_EPSILON); } /** Tests if an integer and a float are not equal. @@ -2253,7 +2401,7 @@ ValueObject *opEqIntegerFloat(ValueObject *a, /**< [in] The first value to test. ValueObject *opNeqIntegerFloat(ValueObject *a, /**< [in] The first value to test. */ ValueObject *b) /**< [in] The second value to test. */ { - return createBooleanValueObject(getInteger(a) != getFloat(b)); + return createBooleanValueObject(fabs((float)(getInteger(a)) - getFloat(b)) > FLT_EPSILON); } /** Tests if a float and an integer are equal. @@ -2268,7 +2416,7 @@ ValueObject *opNeqIntegerFloat(ValueObject *a, /**< [in] The first value to test ValueObject *opEqFloatInteger(ValueObject *a, /**< [in] The first value to test. */ ValueObject *b) /**< [in] The second value to test. */ { - return createBooleanValueObject(getFloat(a) == getInteger(b)); + return createBooleanValueObject(fabs(getFloat(a) - (float)(getInteger(b))) < FLT_EPSILON); } /** Tests if a float and an integer are not equal. @@ -2283,7 +2431,7 @@ ValueObject *opEqFloatInteger(ValueObject *a, /**< [in] The first value to test. ValueObject *opNeqFloatInteger(ValueObject *a, /**< [in] The first value to test. */ ValueObject *b) /**< [in] The second value to test. */ { - return createBooleanValueObject(getFloat(a) != getInteger(b)); + return createBooleanValueObject(fabs(getFloat(a) - (float)(getInteger(b))) > FLT_EPSILON); } /** Tests if two floats are equal. @@ -2297,7 +2445,7 @@ ValueObject *opNeqFloatInteger(ValueObject *a, /**< [in] The first value to test ValueObject *opEqFloatFloat(ValueObject *a, /**< [in] The first value to test. */ ValueObject *b) /**< [in] The second value to test. */ { - return createBooleanValueObject(getFloat(a) == getFloat(b)); + return createBooleanValueObject(fabs(getFloat(a) - getFloat(b)) < FLT_EPSILON); } /** Tests if two floats are not equal. @@ -2311,12 +2459,12 @@ ValueObject *opEqFloatFloat(ValueObject *a, /**< [in] The first value to test. * ValueObject *opNeqFloatFloat(ValueObject *a, /**< [in] The first value to test. */ ValueObject *b) /**< [in] The second value to test. */ { - return createBooleanValueObject(getFloat(a) != getFloat(b)); + return createBooleanValueObject(fabs(getFloat(a) - getFloat(b)) > FLT_EPSILON); } /** Tests if two boolean values are equal. * - * \pre \a a and \a b were created by createBooleanValueObject(float). + * \pre \a a and \a b were created by createBooleanValueObject(int). * * \return A pointer to a ValueObject structure containing a boolean value * indicating whether \a a is equal to \a b. @@ -2330,7 +2478,7 @@ ValueObject *opEqBooleanBoolean(ValueObject *a, /**< [in] The first value to tes /** Tests if two boolean values are not equal. * - * \pre \a a and \a b were created by createBooleanValueObject(float). + * \pre \a a and \a b were created by createBooleanValueObject(int). * * \return A pointer to a ValueObject structure containing a boolean value * indicating whether \a a is not equal to \a b. @@ -2673,7 +2821,7 @@ ReturnObject *interpretCastStmtNode(StmtNode *node, /**< [in] A pointer to t IdentifierNode *id = (IdentifierNode *)(stmt->target); char *name = resolveIdentifierName(id, scope); if (name) { - fprintf(stderr, "%s:%d: variable does not exist at: %s\n", id->fname, id->line, name); + fprintf(stderr, "%s:%u: variable does not exist at: %s\n", id->fname, id->line, name); free(name); } return NULL; @@ -2778,7 +2926,7 @@ ReturnObject *interpretInputStmtNode(StmtNode *node, /**< [in] A pointer to unsigned int size = 16; unsigned int cur = 0; char *temp = malloc(sizeof(char) * size); - char c; + int c; void *mem = NULL; InputStmtNode *stmt = (InputStmtNode *)node->stmt; ValueObject *val = NULL; @@ -2786,7 +2934,7 @@ ReturnObject *interpretInputStmtNode(StmtNode *node, /**< [in] A pointer to /** \note The specification is unclear as to the exact semantics * of input. Here, we read up until the first newline or * EOF but do not store it. */ - if (c == EOF || c == '\r' || c == '\n') break; + if (c == EOF || c == (int)'\r' || c == (int)'\n') break; if (cur > size - 1) { /* Increasing buffer size. */ size *= 2; @@ -2798,7 +2946,7 @@ ReturnObject *interpretInputStmtNode(StmtNode *node, /**< [in] A pointer to } temp = mem; } - temp[cur] = c; + temp[cur] = (char)c; cur++; } temp[cur] = '\0'; @@ -2854,7 +3002,7 @@ ReturnObject *interpretAssignmentStmtNode(StmtNode *node, /**< [in] A pointe /** 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 *). + * \a type is ST_DECLARATION and \a stmt was created by createDeclarationStmtNode(IdentifierNode *, IdentifierNode *, 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 *). @@ -2884,7 +3032,7 @@ ReturnObject *interpretDeclarationStmtNode(StmtNode *node, /**< [in] A point IdentifierNode *id = (IdentifierNode *)(stmt->target); char *name = resolveIdentifierName(id, scope); if (name) { - fprintf(stderr, "%s:%d: redefinition of existing variable at: %s\n", id->fname, id->line, name); + fprintf(stderr, "%s:%u: redefinition of existing variable at: %s\n", id->fname, id->line, name); free(name); } return NULL; @@ -3062,7 +3210,7 @@ ReturnObject *interpretSwitchStmtNode(StmtNode *node, /**< [in] A pointer to done = 1; break; case VT_FLOAT: - if (getFloat(use1) == getFloat(use2)) + if (fabs(getFloat(use1) - getFloat(use2)) < FLT_EPSILON) done = 1; break; case VT_STRING: @@ -3329,7 +3477,7 @@ ReturnObject *interpretDeallocationStmtNode(StmtNode *node, /**< [in] A poin /** 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 *). + * \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 *). @@ -3364,7 +3512,7 @@ ReturnObject *interpretFuncDefStmtNode(StmtNode *node, /**< Not used (see no IdentifierNode *id = (IdentifierNode *)(stmt->name); char *name = resolveIdentifierName(id, scope); if (name) { - fprintf(stderr, "%s:%d: function name already used by existing variable at: %s\n", id->fname, id->line, name); + fprintf(stderr, "%s:%u: function name already used by existing variable at: %s\n", id->fname, id->line, name); free(name); } return NULL; diff --git a/interpreter.h b/interpreter.h index 9ebe69e..41d0d88 100644 --- a/interpreter.h +++ b/interpreter.h @@ -103,6 +103,7 @@ ValueObject *copyValueObject(ValueObject *); void deleteValueObject(ValueObject *); ReturnObject *createReturnObject(ReturnType, ValueObject *); void deleteReturnObject(ReturnObject *); +char *resolveIdentifierName(IdentifierNode *, ScopeObject *); ScopeObject *createScopeObject(ScopeObject *); void deleteScopeObject(ScopeObject *); ValueObject *getScopeValue(ScopeObject *, IdentifierNode *); diff --git a/lexer.c b/lexer.c index 5988f7d..e582248 100644 --- a/lexer.c +++ b/lexer.c @@ -139,14 +139,15 @@ LexemeList *scanBuffer(const char *buffer, /**< [in] An array of characters to t const char *start = buffer; LexemeList *list = NULL; unsigned int line = 1; + Lexeme *lex = NULL; list = createLexemeList(); if (!list) return NULL; while (start < buffer + size) { char *temp = NULL; - unsigned int len = 1; + size_t len = 1; /* Comma (,) is a soft newline */ if (*start == ',') { - Lexeme *lex = createLexeme("\n", fname, line); + lex = createLexeme("\n", fname, line); if (!lex) { deleteLexemeList(list); return NULL; @@ -161,7 +162,7 @@ LexemeList *scanBuffer(const char *buffer, /**< [in] An array of characters to t } /* Bang (!) is its own lexeme */ if (*start == '!') { - Lexeme *lex = createLexeme("!", fname, line); + lex = createLexeme("!", fname, line); if (!lex) { deleteLexemeList(list); return NULL; @@ -186,7 +187,7 @@ LexemeList *scanBuffer(const char *buffer, /**< [in] An array of characters to t newline = 1; } if (newline) { - Lexeme *lex = createLexeme("\n", fname, line); + lex = createLexeme("\n", fname, line); if (!lex) { deleteLexemeList(list); return NULL; @@ -212,7 +213,7 @@ LexemeList *scanBuffer(const char *buffer, /**< [in] An array of characters to t /* Make sure next line is not empty */ while (*test && isspace(*test)) { if (*test == '\r' || *test == '\n') { - fprintf(stderr, "%s:%d: a line with continuation may not be followed by an empty line\n", fname, line); + fprintf(stderr, "%s:%u: a line with continuation may not be followed by an empty line\n", fname, line); deleteLexemeList(list); return NULL; } @@ -239,7 +240,7 @@ LexemeList *scanBuffer(const char *buffer, /**< [in] An array of characters to t start++; if (start == buffer || *start == ',' || *start == '\r' || *start == '\n') continue; - fprintf(stderr, "%s:%d: multiple line comment may not appear on the same line as code\n", fname, line); + fprintf(stderr, "%s:%u: multiple line comment may not appear on the same line as code\n", fname, line); deleteLexemeList(list); return NULL; } @@ -270,7 +271,7 @@ LexemeList *scanBuffer(const char *buffer, /**< [in] An array of characters to t && *(start + len) != '!' && strncmp(start + len, "...", 3) && strncmp(start + len, "\xE2\x80\xA6", 3)) { - fprintf(stderr, "%s:%d: expected token delimiter after string literal\n", fname, line); + fprintf(stderr, "%s:%u: expected token delimiter after string literal\n", fname, line); deleteLexemeList(list); return NULL; } @@ -292,7 +293,7 @@ LexemeList *scanBuffer(const char *buffer, /**< [in] An array of characters to t } strncpy(temp, start, len); temp[len] = '\0'; - Lexeme *lex = createLexeme(temp, fname, line); + lex = createLexeme(temp, fname, line); if (!lex) { free(temp); deleteLexemeList(list); @@ -308,7 +309,7 @@ LexemeList *scanBuffer(const char *buffer, /**< [in] An array of characters to t start += len; } /* Create an end-of-file lexeme */ - Lexeme *lex = createLexeme("$", fname, line); + lex = createLexeme("$", fname, line); if (!lex) { deleteLexemeList(list); return NULL; diff --git a/main.c b/main.c index 77faa2f..c084fab 100644 --- a/main.c +++ b/main.c @@ -96,7 +96,6 @@ #include #include -#include #include #include "lexer.h" @@ -110,8 +109,8 @@ static char *program_name; static char *shortopt = "hv"; static struct option longopt[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'v' }, + { "help", no_argument, NULL, (int)'h' }, + { "version", no_argument, NULL, (int)'v' }, { 0, 0, 0, 0 } }; @@ -129,8 +128,8 @@ static void version (char *revision) { int main(int argc, char **argv) { - long size = 0; - long length = 0; + unsigned int size = 0; + unsigned int length = 0; char *buffer = NULL; LexemeList *lexemes = NULL; Token **tokens = NULL; @@ -139,7 +138,7 @@ int main(int argc, char **argv) FILE *file = NULL; int ch; - char *revision = "v0.9.1"; + char *revision = "v0.10.1"; program_name = argv[0]; while ((ch = getopt_long(argc, argv, shortopt, longopt, NULL)) != -1) { @@ -148,12 +147,9 @@ int main(int argc, char **argv) fprintf (stderr, "Incorrect option '%c'\n", ch); help(); exit(EXIT_FAILURE); - case 'h': help(); exit(EXIT_SUCCESS); - break; - case 'v': version(revision); exit(EXIT_SUCCESS); @@ -188,7 +184,11 @@ int main(int argc, char **argv) length += fread((buffer + size) - READSIZE, 1, READSIZE, file); } - fclose(file); + if (fclose(file) != 0) { + fprintf(stderr, "Error closing file.\n"); + if (buffer) free(buffer); + return 1; + } if (!buffer) return 1; buffer[length] = '\0'; diff --git a/parser.c b/parser.c index c3c0a8e..7d992f8 100644 --- a/parser.c +++ b/parser.c @@ -111,22 +111,24 @@ BlockNodeList *createBlockNodeList(void) * \post \a node will be added on to the end of \a list and the size of * \a list will be updated accordingly. * - * \return A pointer to the added BlockNode structure (will be the same as \a node). + * \retval 0 realloc was unable to allocate memory. + * \retval 1 \a node was added to \a list. * - * \retval NULL realloc was unable to allocate memory. */ -BlockNode *addBlockNode(BlockNodeList *list, /**< [in,out] A pointer to the BlockNodeList structure to add \a node to. */ - BlockNode *node) /**< [in] A pointer to the BlockNode structure to add to \a list. */ + * \see createBlockNodeList(void) + * \see deleteBlockNodeList(BlockNodeList *) */ +int addBlockNode(BlockNodeList *list, /**< [in,out] A pointer to the BlockNodeList structure to add \a node to. */ + BlockNode *node) /**< [in] A pointer to the BlockNode structure to add to \a list. */ { unsigned int newsize = list->num + 1; void *mem = realloc(list->blocks, sizeof(BlockNode *) * newsize); if (!mem) { perror("realloc"); - return NULL; + return 0; } list->blocks = mem; list->blocks[list->num] = node; list->num = newsize; - return node; + return 1; } /** Deletes a BlockNodeList structure. @@ -278,12 +280,12 @@ IdentifierNode *createIdentifierNode(IdentifierType type, /**< [in] The type of /** Deletes an IdentifierNode structure. * - * \pre \a node was created by createIdentifierNode(IdentifierType, void *). + * \pre \a node was created by createIdentifierNode(IdentifierType, void *, const char *, unsigned int). * * \post The memory at \a node and any of its associated members will be * freed. * - * \see createIdentifierNode(IdentifierType, void *) */ + * \see createIdentifierNode(IdentifierType, void *, const char *, unsigned int) */ void deleteIdentifierNode(IdentifierNode *node) /**< [in,out] A pointer to the IdentifierNode structure to be deleted. */ { if (!node) return; @@ -327,28 +329,29 @@ IdentifierNodeList *createIdentifierNodeList(void) /** Adds an IdentifierNode structure to an IdentifierNodeList structure. * * \pre \a list was created by createIdentifierNodeList(void). - * \pre \a node was created by createIdentifierNode(IdentifierType, void *). + * \pre \a node was created by createIdentifierNode(IdentifierType, void *, const char *, unsigned int). * * \post \a node will be added on to the end of \a list and the size of * \a list will be updated accordingly. * - * \return A pointer to the added IdentifierNode structure (will be the same as - * \a node). + * \retval 0 realloc was unable to allocate memory. + * \retval 1 \a node was added to \a list. * - * \retval NULL realloc was unable to allocate memory. */ -IdentifierNode *addIdentifierNode(IdentifierNodeList *list, /**< [in,out] A pointer to the IdentifierNodeList structure to add \a node to. */ - IdentifierNode *node) /**< [in] A pointer to the IdentifierNode structure to add to \a list. */ + * \see createIdentifierNodeList(void) + * \see deleteIdentifierNodeList(IdentifierNodeList *) */ +int addIdentifierNode(IdentifierNodeList *list, /**< [in,out] A pointer to the IdentifierNodeList structure to add \a node to. */ + IdentifierNode *node) /**< [in] A pointer to the IdentifierNode structure to add to \a list. */ { unsigned int newsize = list->num + 1; void *mem = realloc(list->ids, sizeof(IdentifierNode *) * newsize); if (!mem) { perror("realloc"); - return NULL; + return 0; } list->ids = mem; list->ids[list->num] = node; list->num = newsize; - return node; + return 1; } /** Deletes an IdentifierNodeList structure. @@ -409,7 +412,7 @@ void deleteTypeNode(TypeNode *node) /**< [in,out] A pointer to the TypeNode stru * - ST_PRINT: createPrintStmtNode(ExprNodeList *, int) * - ST_INPUT: createInputStmtNode(IdentifierNode *) * - ST_ASSIGNMENT: createAssignmentStmtNode(IdentifierNode *, ExprNode *) - * - ST_DECLARATION: createDeclarationStmtNode(IdentifierNode *, IdentifierNode *, ExprNode *) + * - ST_DECLARATION: createDeclarationStmtNode(IdentifierNode *, IdentifierNode *, ExprNode *, TypeNode *) * - ST_IFTHENELSE: createIfThenElseStmtNode(BlockNode *, BlockNode *, ExprNodeList *, BlockNodeList *) * - ST_SWITCH: createSwitchStmtNode(ExprNodeList *, BlockNodeList *, BlockNode *) * - ST_BREAK: no structure needed, use \c NULL @@ -544,22 +547,24 @@ StmtNodeList *createStmtNodeList(void) * \post \a node will be added on to the end of \a list and the size of * \a list will be updated accordingly. * - * \return A pointer to the added StmtNode (will be the same as \a node). + * \retval 0 malloc was unable to allocate memory. + * \retval 1 \a node was added to \a list. * - * \retval NULL malloc was unable to allocate memory. */ -StmtNode *addStmtNode(StmtNodeList *list, /**< [in,out] A pointer to the StmtNodeList structure to add \a node to. */ - StmtNode *node) /**< [in] A pointer to the StmtNode structure to add to \a list. */ + * \see createStmtNodeList(void) + * \see deleteStmtNodeList(StmtNodeList *) */ +int addStmtNode(StmtNodeList *list, /**< [in,out] A pointer to the StmtNodeList structure to add \a node to. */ + StmtNode *node) /**< [in] A pointer to the StmtNode structure to add to \a list. */ { unsigned int newsize = list->num + 1; void *mem = realloc(list->stmts, sizeof(StmtNode *) * newsize); if (!mem) { perror("realloc"); - return NULL; + return 0; } list->stmts = mem; list->stmts[list->num] = node; list->num = newsize; - return node; + return 1; } /** Deletes a StmtNodeList structure. @@ -583,7 +588,7 @@ void deleteStmtNodeList(StmtNodeList *list) /**< [in,out] A pointer to the StmtN /** Creates a CastStmtNode structure. * - * \pre \a target was created by createIdentifierNode(IdentifierType, void *). + * \pre \a target was created by createIdentifierNode(IdentifierType, void *, const char *, unsigned int). * \pre \a newtype was created by createTypeNode(ConstantType). * * \return A pointer to a CastStmtNode structure with the desired properties. @@ -660,7 +665,7 @@ void deletePrintStmtNode(PrintStmtNode *node) /**< [in,out] A pointer to the Pri /** Creates an InputStmtNode structure. * - * \pre \a target was created by createIdentifierNode(IdentifierType, void *). + * \pre \a target was created by createIdentifierNode(IdentifierType, void *, const char *, unsigned int). * * \return A pointer to an InputStmtNode structure with the desired properties. * @@ -695,7 +700,7 @@ void deleteInputStmtNode(InputStmtNode *node) /**< [in,out] A pointer to the Inp /** Creates an AssignmentStmtNode structure. * - * \pre \a target was created by createIdentifierNode(IdentifierType, void *). + * \pre \a target was created by createIdentifierNode(IdentifierType, void *, const char *, unsigned int). * \pre \a expr was created by createExprNode(ExprType, void *). * * \return A pointer to an AssignmentStmtNode structure with the desired @@ -735,8 +740,8 @@ void deleteAssignmentStmtNode(AssignmentStmtNode *node) /**< [in,out] A pointer /** Creates a DeclarationStmtNode structure. * - * \pre \a scope was created by createIdentifierNode(IdentifierType, void *). - * \pre \a target was created by createIdentifierNode(IdentifierType, void *). + * \pre \a scope was created by createIdentifierNode(IdentifierType, void *, const char *, unsigned int). + * \pre \a target was created by createIdentifierNode(IdentifierType, void *, const char *, unsigned int). * \pre \a expr was created by createExprNode(ExprType, void *). * * \return A pointer to a DeclarationStmtNode structure with the desired @@ -764,12 +769,12 @@ DeclarationStmtNode *createDeclarationStmtNode(IdentifierNode *scope, /**< [in] /** Deletes a DeclarationStmtNode structure. * - * \pre \a node was created by createDeclarationStmtNode(IdentifierNode *, IdentifierNode *, ExprNode *). + * \pre \a node was created by createDeclarationStmtNode(IdentifierNode *, IdentifierNode *, ExprNode *, TypeNode *). * * \post The memory at \a node and any of its associated members will be * freed. * - * \see createDeclarationStmtNode(IdentifierNode *, IdentifierNode *, ExprNode *) */ + * \see createDeclarationStmtNode(IdentifierNode *, IdentifierNode *, ExprNode *, TypeNode *) */ void deleteDeclarationStmtNode(DeclarationStmtNode *node) /**< [in,out] A pointer to the DeclarationStmtNode structure to be deleted. */ { if (!node) return; @@ -912,8 +917,8 @@ void deleteReturnStmtNode(ReturnStmtNode *node) /**< [in,out] A pointer to the R /** Creates a LoopStmtNode structure. * - * \pre \a name was created by createIdentifierNode(IdentifierType, void *). - * \pre \a var was created by createIdentifierNode(IdentifierType, void *). + * \pre \a name was created by createIdentifierNode(IdentifierType, void *, const char *, unsigned int). + * \pre \a var was created by createIdentifierNode(IdentifierType, void *, const char *, unsigned int). * \pre \a guard was created by createExprNode(ExprType, void *). * \pre \a update was created by createExprNode(ExprType, void *). * \pre \a body was created by createBlockNode(StmtNodeList *). @@ -963,7 +968,7 @@ void deleteLoopStmtNode(LoopStmtNode *node) /**< [in,out] A pointer to the LoopS /** Creates a DeallocationStmtNode structure. * - * \pre \a target was created by createIdentifierNode(IdentifierType, void *). + * \pre \a target was created by createIdentifierNode(IdentifierType, void *, const char *, unsigned int). * * \return A pointer to a DeallocationStmtNode structure with the desired * properties. @@ -999,8 +1004,8 @@ void deleteDeallocationStmtNode(DeallocationStmtNode *node) /**< [in,out] A poin /** Creates a FuncDefStmtNode structure. * - * \pre \a scope was created by createIdentifierNode(IdentifierType, void *). - * \pre \a name was created by createIdentifierNode(IdentifierType, void *). + * \pre \a scope was created by createIdentifierNode(IdentifierType, void *, const char *, unsigned int). + * \pre \a name was created by createIdentifierNode(IdentifierType, void *, const char *, unsigned int). * \pre \a args was created by createIdentifierNodeList(void) and contains * items added by addIdentifierNode(IdentifierNodeList *, IdentifierNode *). * \pre \a body was created by createBlockNode(StmtNodeList *). @@ -1052,7 +1057,7 @@ void deleteFuncDefStmtNode(FuncDefStmtNode *node) /**< [in,out] A pointer to the * - ET_CAST: createCastExprNode(ExprNode *, TypeNode *) * - ET_CONSTANT: createBooleanConstantNode(int), createIntegerConstantNode(int), * createFloatConstantNode(float), or createStringConstantNode(char *) - * - ET_IDENTIFIER: createIdentifierNode(IdentifierType, void *) + * - ET_IDENTIFIER: createIdentifierNode(IdentifierType, void *, const char *, unsigned int) * - ET_FUNCCALL: createFuncCallExprNode(IdentifierNode *, IdentifierNode *, ExprNodeList *) * - ET_OP: createOpExprNode(OpType, ExprNodeList *) * - ET_IMPVAR: (for the \ref impvar "implicit variable") no structure needed, use \c NULL @@ -1138,23 +1143,24 @@ ExprNodeList *createExprNodeList(void) * \post \a node will be added on to the end of \a list and the size of * \a list will be updated accordingly. * - * \return A pointer to the added ExprNode structure (will be the same as - * \a node). + * \retval 0 realloc was unable to allocate memory. + * \retval 1 \a node was added to \a list. * - * \retval NULL realloc was unable to allocate memory. */ -ExprNode *addExprNode(ExprNodeList *list, /**< [in,out] A pointer to the ExprNodeList structure to add \a node to. */ - ExprNode *node) /**< [in] A pointer to the ExprNode structure to add to \a list. */ + * \see createExprNodeList(void) + * \see deleteExprNodeList(ExprNodeList *) */ +int addExprNode(ExprNodeList *list, /**< [in,out] A pointer to the ExprNodeList structure to add \a node to. */ + ExprNode *node) /**< [in] A pointer to the ExprNode structure to add to \a list. */ { unsigned int newsize = list->num + 1; void *mem = realloc(list->exprs, sizeof(ExprNode *) * newsize); if (!mem) { perror("realloc"); - return NULL; + return 0; } list->exprs = mem; list->exprs[list->num] = node; list->num = newsize; - return node; + return 1; } /** Deletes an ExprNodeList structure. @@ -1217,8 +1223,8 @@ void deleteCastExprNode(CastExprNode *node) /**< [in,out] A pointer to the CastE /** Creates a FuncCallExprNode structure. * - * \pre \a scope was created by createIdentifierNode(IdentifierType, void *). - * \pre \a name was created by createIdentifierNode(IdentifierType, void *). + * \pre \a scope was created by createIdentifierNode(IdentifierType, void *, const char *, unsigned int). + * \pre \a name was created by createIdentifierNode(IdentifierType, void *, const char *, unsigned int). * \pre \a args was created by createIdentifierNodeList(void) and contains * items added by addIdentifierNode(IdentifierNodeList *, IdentifierNode *). * @@ -1305,7 +1311,7 @@ void deleteOpExprNode(OpExprNode *node) /**< [in,out] A pointer to the OpExprNod * function \b does modify \a tokenp. * * \pre \a tokenp points to a position in an array of tokens created by - * tokenizeLexemes(Lexeme **). + * tokenizeLexemes(LexemeList *). * * \post If the token pointed to by \a tokenp does not match \a token, * \a tokenp will point to the same token as when the function was @@ -1334,7 +1340,7 @@ int acceptToken(Token ***tokenp, /**< [in,out] A pointer to the position of the * modify \a tokenp. * * \pre \a tokenp points to a position in an array of tokens created by - * tokenizeLexemes(Lexeme **). + * tokenizeLexemes(LexemeList *). * * \post \a tokenp will point to the same token as when the function was * called. @@ -1359,7 +1365,7 @@ int peekToken(Token ***tokenp, /**< [in] A pointer to the position of the next t * modify \a tokenp. * * \pre \a tokenp points to a position in an array of tokens created by - * tokenizeLexemes(Lexeme **). + * tokenizeLexemes(LexemeList *). * * \post \a tokenp will point to the same token as when the function was * called. @@ -1381,18 +1387,18 @@ int nextToken(Token ***tokenp, /**< [in] A pointer to the position of the next t * is the line the next token appears on, INFO is \a info and NEXT is the image * of the next token. * - * \pre \a tokens was created by tokenizeLexemes(Lexeme **). */ + * \pre \a tokens was created by tokenizeLexemes(LexemeList *). */ void error(const char *info, /**< [in] The array of characters to print. */ Token **tokens) /**< [in] A pointer to an array of tokens to parse. */ { - fprintf(stderr, "%s:%d: %s at: %s\n", (*tokens)->fname, (*tokens)->line, info, (*tokens)->image); + fprintf(stderr, "%s:%u: %s at: %s\n", (*tokens)->fname, (*tokens)->line, info, (*tokens)->image); } /** Parses a set of tokens into a ConstantNode structure. Parsing begins at the * token pointed to by \a tokenp. * * \pre \a tokenp points to a position in an array of tokens created by - * tokenizeLexemes(Lexeme **). + * tokenizeLexemes(LexemeList *). * * \post \a tokenp will point to the next \b unparsed token in the array. * @@ -1408,71 +1414,117 @@ void error(const char *info, /**< [in] The array of characters to print. */ * \see parseMainNode(Token **) */ ConstantNode *parseConstantNode(Token ***tokenp) { - Token **tokens = *tokenp; ConstantNode *ret = NULL; + char *data = NULL; + int status; + + /* Work from a copy of the token stream in case something goes wrong */ + Token **tokens = *tokenp; + #ifdef DEBUG shiftout(); #endif + /* Boolean */ if (peekToken(&tokens, TT_BOOLEAN)) { #ifdef DEBUG debug("CT_BOOLEAN"); #endif + /* Create the ConstantNode structure */ ret = createBooleanConstantNode((*tokens)->data.i); - if (!ret) return NULL; - acceptToken(&tokens, TT_BOOLEAN); /* Will succeed, checked for this earlier */ + if (!ret) goto parseConstantNodeAbort; + + /* This should succeed; it was checked for above */ + status = acceptToken(&tokens, TT_BOOLEAN); + if (!status) { + error("expected boolean", tokens); + goto parseConstantNodeAbort; + } } /* Integer */ else if (peekToken(&tokens, TT_INTEGER)) { #ifdef DEBUG debug("CT_INTEGER"); #endif + /* Create the ConstantNode structure */ ret = createIntegerConstantNode((*tokens)->data.i); - if (!ret) return NULL; - acceptToken(&tokens, TT_INTEGER); /* Will succeed, checked for this above */ + if (!ret) goto parseConstantNodeAbort; + + /* This should succeed; it was checked for above */ + status = acceptToken(&tokens, TT_INTEGER); + if (!status) { + error("expected integer", tokens); + goto parseConstantNodeAbort; + } } /* Float */ else if (peekToken(&tokens, TT_FLOAT)) { #ifdef DEBUG debug("CT_FLOAT"); #endif + /* Create the ConstantNode structure */ ret = createFloatConstantNode((*tokens)->data.f); - if (!ret) return NULL; - acceptToken(&tokens, TT_FLOAT); /* Will succeed, checked for this above */ + if (!ret) goto parseConstantNodeAbort; + + /* This should succeed; it was checked for above */ + status = acceptToken(&tokens, TT_FLOAT); + if (!status) { + error("expected float", tokens); + goto parseConstantNodeAbort; + } } /* String */ else if (peekToken(&tokens, TT_STRING)) { - unsigned int len = strlen((*tokens)->image); - char *data = malloc(sizeof(char) * (len - 1)); + size_t len = strlen((*tokens)->image); + data = malloc(sizeof(char) * (len - 1)); if (!data) { perror("malloc"); - return NULL; + goto parseConstantNodeAbort; } strncpy(data, (*tokens)->image + 1, len - 2); data[len - 2] = '\0'; #ifdef DEBUG debug("CT_STRING"); #endif + /* Create the ConstantNode structure */ ret = createStringConstantNode(data); - if (!ret) { - free(data); - return NULL; + if (!ret) goto parseConstantNodeAbort; + data = NULL; + + /* This should succeed; it was checked for above */ + status = acceptToken(&tokens, TT_STRING); + if (!status) { + error("expected string", tokens); + goto parseConstantNodeAbort; } - acceptToken(&tokens, TT_STRING); /* Will succeed, checked for this above */ } - else error("expected constant value", tokens); + else { + error("expected constant value", tokens); + } + #ifdef DEBUG shiftin(); #endif + + /* Since we're successful, update the token stream */ *tokenp = tokens; + return ret; + +parseConstantNodeAbort: /* Exception handling */ + + /* Clean up any allocated structures */ + if (data) free(data); + if (ret) deleteConstantNode(ret); + + return NULL; } /** Parses a set of tokens into a TypeNode structure. Parsing begins at the * token pointed to by \a tokenp. * * \pre \a tokenp points to a position in an array of tokens created by - * tokenizeLexemes(Lexeme **). + * tokenizeLexemes(LexemeList *). * * \post \a tokenp will point to the next \b unparsed token in the array. * @@ -1488,18 +1540,22 @@ ConstantNode *parseConstantNode(Token ***tokenp) * \see parseMainNode(Token **) */ TypeNode *parseTypeNode(Token ***tokenp) /**< [in,out] A pointer to the position of the next token to parse. */ { - Token **tokens = *tokenp; TypeNode *ret = NULL; + + /* Work from a copy of the token stream in case something goes wrong */ + Token **tokens = *tokenp; + #ifdef DEBUG shiftout(); #endif + /* Nil */ if (acceptToken(&tokens, TT_NOOB)) { #ifdef DEBUG debug("CT_NIL"); #endif ret = createTypeNode(CT_NIL); - if (!ret) return NULL; + if (!ret) goto parseTypeNodeAbort; } /* Boolean */ else if (acceptToken(&tokens, TT_TROOF)) { @@ -1507,7 +1563,7 @@ TypeNode *parseTypeNode(Token ***tokenp) /**< [in,out] A pointer to the position debug("CT_BOOLEAN"); #endif ret = createTypeNode(CT_BOOLEAN); - if (!ret) return NULL; + if (!ret) goto parseTypeNodeAbort; } /* Integer */ else if (acceptToken(&tokens, TT_NUMBR)) { @@ -1515,7 +1571,7 @@ TypeNode *parseTypeNode(Token ***tokenp) /**< [in,out] A pointer to the position debug("CT_INTEGER"); #endif ret = createTypeNode(CT_INTEGER); - if (!ret) return NULL; + if (!ret) goto parseTypeNodeAbort; } /* Float */ else if (acceptToken(&tokens, TT_NUMBAR)) { @@ -1523,7 +1579,7 @@ TypeNode *parseTypeNode(Token ***tokenp) /**< [in,out] A pointer to the position debug("CT_FLOAT"); #endif ret = createTypeNode(CT_FLOAT); - if (!ret) return NULL; + if (!ret) goto parseTypeNodeAbort; } /* String */ else if (acceptToken(&tokens, TT_YARN)) { @@ -1531,21 +1587,34 @@ TypeNode *parseTypeNode(Token ***tokenp) /**< [in,out] A pointer to the position debug("CT_STRING"); #endif ret = createTypeNode(CT_STRING); - if (!ret) return NULL; + if (!ret) goto parseTypeNodeAbort; } - else error("expected type", tokens); + else { + error("expected type", tokens); + } + #ifdef DEBUG shiftin(); #endif + + /* Since we're successful, update the token stream */ *tokenp = tokens; + return ret; + +parseTypeNodeAbort: /* Exception handling */ + + /* Clean up any allocated structures */ + if (ret) deleteTypeNode(ret); + + return NULL; } /** Parses a set of tokens into an IdentifierNode structure. Parsing begins at * the token pointed to by \a tokenp. * * \pre \a tokenp points to a position in an array of tokens created by - * tokenizeLexemes(Lexeme **). + * tokenizeLexemes(LexemeList *). * * \post \a tokenp will point to the next \b unparsed token in the array. * @@ -1561,50 +1630,618 @@ TypeNode *parseTypeNode(Token ***tokenp) /**< [in,out] A pointer to the position * \see parseMainNode(Token **) */ IdentifierNode *parseIdentifierNode(Token ***tokenp) /**< [in,out] A pointer to the position of the next token to parse. */ { - Token **tokens = *tokenp; + /* For direct identifier */ + char *temp = NULL; + + /* For indirect identifier */ + ExprNode *expr = NULL; + IdentifierNode *ret = NULL; + int status; + + /* Work from a copy of the token stream in case something goes wrong */ + Token **tokens = *tokenp; + #ifdef DEBUG shiftout(); #endif + /* Direct identifier */ if (peekToken(&tokens, TT_IDENTIFIER)) { - char *temp = NULL; #ifdef DEBUG debug("IT_DIRECT"); #endif + /* Copy the token image */ temp = malloc(sizeof(char) * (strlen((*tokens)->image) + 1)); + if (!temp) goto parseIdentifierNodeAbort; strcpy(temp, (*tokens)->image); + + /* Create the new IdentifierNode structure */ ret = createIdentifierNode(IT_DIRECT, temp, (*tokens)->fname, (*tokens)->line); - if (!ret) return NULL; - acceptToken(&tokens, TT_IDENTIFIER); /* Will succeed, checked for this above */ + if (!ret) goto parseIdentifierNodeAbort; + + /* This should succeed; it was checked for above */ + status = acceptToken(&tokens, TT_IDENTIFIER); + if (!status) { + error("expected identifier", tokens); + goto parseIdentifierNodeAbort; + } } - /* Indirect identifier */ else if (acceptToken(&tokens, TT_SRS)) { - ExprNode *expr = NULL; #ifdef DEBUG debug("IT_INDIRECT"); #endif + /* Parse the expression representing the identifier */ expr = parseExprNode(&tokens); - if (!expr) return NULL; + if (!expr) goto parseIdentifierNodeAbort; + + /* Create the new IdentifierNode structure */ ret = createIdentifierNode(IT_INDIRECT, expr, (*tokens)->fname, (*tokens)->line); - if (!ret) { - deleteExprNode(expr); - return NULL; - } + if (!ret) goto parseIdentifierNodeAbort; } - else error("expected identifier", tokens); + else { + error("expected identifier", tokens); + } + #ifdef DEBUG shiftin(); #endif + + /* Since we're successful, update the token stream */ *tokenp = tokens; + return ret; + +parseIdentifierNodeAbort: /* Exception handling */ + + /* Clean up any allocated structures */ + if (ret) deleteIdentifierNode(ret); + else { + /* For indirect identifier */ + if (expr) deleteExprNode(expr); + + /* For direct identifier */ + if (temp) free(temp); + } + + return NULL; +} + +/** Parses a set of tokens into an ExprNode structure containing a CastExprNode + * structure. Parsing begins at the token pointed to by \a tokenp. + * + * \pre \a tokenp points to a position in an array of tokens created by + * tokenizeLexemes(LexemeList *). + * + * \post \a tokenp will point to the next \b unparsed token in the array. + * + * \return A pointer to the generated ExprNode structure. + * + * \retval NULL An error occurred during parsing. + * + * \see parseConstantExprNode(Token ***) + * \see parseIdentifierExprNode(Token ***) + * \see parseFuncCallExprNode(Token ***) + * \see parseOpExprNode(Token ***) */ +ExprNode *parseCastExprNode(Token ***tokenp) +{ + ExprNode *target = NULL; + TypeNode *newtype = NULL; + CastExprNode *expr = NULL; + ExprNode *ret = NULL; + int status; + + /* Work from a copy of the token stream in case something goes wrong */ + Token **tokens = *tokenp; + +#ifdef DEBUG + debug("ET_CAST"); +#endif + + /* Parse the cast token */ + status = acceptToken(&tokens, TT_MAEK); + if (!status) { + error("expected MAEK", tokens); + goto parseCastExprNodeAbort; + } + + /* Parse the expression to cast */ + target = parseExprNode(&tokens); + if (!target) goto parseCastExprNodeAbort; + + /* Optionally parse the cast-to token */ + status = acceptToken(&tokens, TT_A); + + /* Parse the type to cast to */ + newtype = parseTypeNode(&tokens); + if (!newtype) goto parseCastExprNodeAbort; + + /* Create the new CastExprNode structure */ + expr = createCastExprNode(target, newtype); + if (!expr) goto parseCastExprNodeAbort; + + /* Create the new ExprNode structure */ + ret = createExprNode(ET_CAST, expr); + if (!ret) goto parseCastExprNodeAbort; + + /* Since we're successful, update the token stream */ + *tokenp = tokens; + + return ret; + +parseCastExprNodeAbort: /* Exception handling */ + + /* Clean up any allocated structures */ + if (ret) deleteExprNode(ret); + else if (expr) deleteCastExprNode(expr); + else { + if (newtype) deleteTypeNode(newtype); + if (target) deleteExprNode(target); + } + + return NULL; +} + +/** Parses a set of tokens into an ExprNode structure containing a ConstantExprNode + * structure. Parsing begins at the token pointed to by \a tokenp. + * + * \pre \a tokenp points to a position in an array of tokens created by + * tokenizeLexemes(LexemeList *). + * + * \post \a tokenp will point to the next \b unparsed token in the array. + * + * \return A pointer to the generated ExprNode structure. + * + * \retval NULL An error occurred during parsing. + * + * \see parseCastExprNode(Token ***) + * \see parseIdentifierExprNode(Token ***) + * \see parseFuncCallExprNode(Token ***) + * \see parseOpExprNode(Token ***) */ +ExprNode *parseConstantExprNode(Token ***tokenp) +{ + ConstantNode *node = NULL; + ExprNode *ret = NULL; + + /* Work from a copy of the token stream in case something goes wrong */ + Token **tokens = *tokenp; + +#ifdef DEBUG + debug("ET_CONSTANT"); +#endif + + /* Parse the constant */ + node = parseConstantNode(&tokens); + if (!node) goto parseConstantExprNodeAbort; + + /* Create the new ExprNode structure */ + ret = createExprNode(ET_CONSTANT, node); + if (!ret) goto parseConstantExprNodeAbort; + + /* Since we're successful, update the token stream */ + *tokenp = tokens; + + return ret; + +parseConstantExprNodeAbort: /* Exception handling */ + + /* Clean up any allocated structures */ + if (ret) deleteExprNode(ret); + else { + if (node) deleteConstantNode(node); + } + + return NULL; +} + +/** Parses a set of tokens into an ExprNode structure containing an + * IdentifierExprNode structure. Parsing begins at the token pointed to by + * \a tokenp. + * + * \pre \a tokenp points to a position in an array of tokens created by + * tokenizeLexemes(LexemeList *). + * + * \post \a tokenp will point to the next \b unparsed token in the array. + * + * \return A pointer to the generated ExprNode structure. + * + * \retval NULL An error occurred during parsing. + * + * \see parseCastExprNode(Token ***) + * \see parseConstantExprNode(Token ***) + * \see parseFuncCallExprNode(Token ***) + * \see parseOpExprNode(Token ***) */ +ExprNode *parseIdentifierExprNode(Token ***tokenp) +{ + IdentifierNode *node = NULL; + ExprNode *ret = NULL; + + /* Work from a copy of the token stream in case something goes wrong */ + Token **tokens = *tokenp; + +#ifdef DEBUG + debug("ET_IDENTIFIER"); +#endif + + /* Parse the identifier node */ + node = parseIdentifierNode(&tokens); + if (!node) goto parseIdentifierExprNodeAbort; + + /* Create the new ExprNode structure */ + ret = createExprNode(ET_IDENTIFIER, node); + if (!ret) goto parseIdentifierExprNodeAbort; + + /* Since we're successful, update the token stream */ + *tokenp = tokens; + + return ret; + +parseIdentifierExprNodeAbort: /* Exception handling */ + + /* Clean up any allocated structures */ + if (ret) deleteExprNode(ret); + else { + if (node) deleteIdentifierNode(node); + } + + return NULL; +} + +/** Parses a set of tokens into an ExprNode structure containing a + * FuncCallExprNode structure. Parsing begins at the token pointed to by + * \a tokenp. + * + * \pre \a tokenp points to a position in an array of tokens created by + * tokenizeLexemes(LexemeList *). + * + * \post \a tokenp will point to the next \b unparsed token in the array. + * + * \return A pointer to the generated ExprNode structure. + * + * \retval NULL An error occurred during parsing. + * + * \see parseCastExprNode(Token ***) + * \see parseConstantExprNode(Token ***) + * \see parseIdentifierExprNode(Token ***) + * \see parseOpExprNode(Token ***) */ +ExprNode *parseFuncCallExprNode(Token ***tokenp) +{ + IdentifierNode *scope = NULL; + IdentifierNode *name = NULL; + ExprNodeList *args = NULL; + ExprNode *arg = NULL; + FuncCallExprNode *expr = NULL; + ExprNode *ret = NULL; + int status; + + /* Work from a copy of the token stream in case something goes wrong */ + Token **tokens = *tokenp; + +#ifdef DEBUG + debug("ET_FUNCCALL"); +#endif + + /* Parse the scope name */ + scope = parseIdentifierNode(&tokens); + if (!scope) goto parseFuncCallExprNodeAbort; + + /* Parse the function call token */ + status = acceptToken(&tokens, TT_IZ); + if (!status) { + error("expected IZ", tokens); + goto parseFuncCallExprNodeAbort; + } + + /* Parse the function name */ + name = parseIdentifierNode(&tokens); + if (!name) goto parseFuncCallExprNodeAbort; + + /* Create an argument list */ + args = createExprNodeList(); + if (!args) goto parseFuncCallExprNodeAbort; + + /* Parse the first argument token */ + if (acceptToken(&tokens, TT_YR)) { + /* Parse the first argument */ + arg = parseExprNode(&tokens); + if (!arg) goto parseFuncCallExprNodeAbort; + + /* Add the first argument to the argument list */ + status = addExprNode(args, arg); + if (!status) goto parseFuncCallExprNodeAbort; + arg = NULL; + + /* Parse additional arguments */ + while (acceptToken(&tokens, TT_ANYR)) { + /* Parse the argument */ + arg = parseExprNode(&tokens); + if (!arg) goto parseFuncCallExprNodeAbort; + + /* Add the argument to the argument list */ + status = addExprNode(args, arg); + if (!status) goto parseFuncCallExprNodeAbort; + arg = NULL; + } + } + + /* Parse the end-of-argument token */ + status = acceptToken(&tokens, TT_MKAY); + if (!status) { + error("expected MKAY", tokens); + goto parseFuncCallExprNodeAbort; + } + + /* Create the new FuncCallExprNode structure */ + expr = createFuncCallExprNode(scope, name, args); + if (!expr) goto parseFuncCallExprNodeAbort; + + /* Create the new ExprNode structure */ + ret = createExprNode(ET_FUNCCALL, expr); + if (!ret) goto parseFuncCallExprNodeAbort; + + /* Since we're successful, update the token stream */ + *tokenp = tokens; + + return ret; + +parseFuncCallExprNodeAbort: /* Exception handling */ + + /* Clean up any allocated structures */ + if (ret) deleteExprNode(ret); + else if (expr) deleteFuncCallExprNode(expr); + else { + if (args) deleteExprNodeList(args); + if (arg) deleteExprNode(arg); + if (name) deleteIdentifierNode(name); + if (scope) deleteIdentifierNode(scope); + } + + return NULL; +} + +/** Parses a set of tokens into an ExprNode structure containing an OpExprNode + * structure. Parsing begins at the token pointed to by + * \a tokenp. + * + * \pre \a tokenp points to a position in an array of tokens created by + * tokenizeLexemes(LexemeList *). + * + * \post \a tokenp will point to the next \b unparsed token in the array. + * + * \return A pointer to the generated ExprNode structure. + * + * \retval NULL An error occurred during parsing. + * + * \see parseCastExprNode(Token ***) + * \see parseConstantExprNode(Token ***) + * \see parseFuncCallExprNode(Token ***) + * \see parseOpExprNode(Token ***) */ +ExprNode *parseOpExprNode(Token ***tokenp) +{ + enum ArityType { + AT_UNARY, + AT_BINARY, + AT_NARY + }; + enum ArityType arity; + ExprNodeList *args = NULL; + ExprNode *arg = NULL; + OpExprNode *expr = NULL; + OpType type; + ExprNode *ret = NULL; + int status; + + /* Work from a copy of the token stream in case something goes wrong */ + Token **tokens = *tokenp; + + /* Unary operations */ + if (acceptToken(&tokens, TT_NOT)) { + type = OP_NOT; + arity = AT_UNARY; +#ifdef DEBUG + debug("ET_OP (OP_NOT)"); +#endif + } + /* Binary operations */ + else if (acceptToken(&tokens, TT_SUMOF)) { + type = OP_ADD; + arity = AT_BINARY; +#ifdef DEBUG + debug("ET_OP (OP_ADD)"); +#endif + } + else if(acceptToken(&tokens, TT_DIFFOF)) { + type = OP_SUB; + arity = AT_BINARY; +#ifdef DEBUG + debug("ET_OP (OP_SUB)"); +#endif + } + else if(acceptToken(&tokens, TT_PRODUKTOF)) { + type = OP_MULT; + arity = AT_BINARY; +#ifdef DEBUG + debug("ET_OP (OP_MULT)"); +#endif + } + else if(acceptToken(&tokens, TT_QUOSHUNTOF)) { + type = OP_DIV; + arity = AT_BINARY; +#ifdef DEBUG + debug("ET_OP (OP_DIV)"); +#endif + } + else if(acceptToken(&tokens, TT_MODOF)) { + type = OP_MOD; + arity = AT_BINARY; +#ifdef DEBUG + debug("ET_OP (OP_MOD)"); +#endif + } + else if(acceptToken(&tokens, TT_BIGGROF)) { + type = OP_MAX; + arity = AT_BINARY; +#ifdef DEBUG + debug("ET_OP (OP_MAX)"); +#endif + } + else if(acceptToken(&tokens, TT_SMALLROF)) { + type = OP_MIN; + arity = AT_BINARY; +#ifdef DEBUG + debug("ET_OP (OP_MIN)"); +#endif + } + else if(acceptToken(&tokens, TT_BOTHOF)) { + type = OP_AND; + arity = AT_BINARY; +#ifdef DEBUG + debug("ET_OP (OP_AND)"); +#endif + } + else if(acceptToken(&tokens, TT_EITHEROF)) { + type = OP_OR; + arity = AT_BINARY; +#ifdef DEBUG + debug("ET_OP (OP_OR)"); +#endif + } + else if(acceptToken(&tokens, TT_WONOF)) { + type = OP_XOR; + arity = AT_BINARY; +#ifdef DEBUG + debug("ET_OP (OP_XOR)"); +#endif + } + else if(acceptToken(&tokens, TT_BOTHSAEM)) { + type = OP_EQ; + arity = AT_BINARY; +#ifdef DEBUG + debug("ET_OP (OP_EQ)"); +#endif + } + else if(acceptToken(&tokens, TT_DIFFRINT)) { + type = OP_NEQ; + arity = AT_BINARY; +#ifdef DEBUG + debug("ET_OP (OP_NEQ)"); +#endif + } + /* N-ary operators */ + else if (acceptToken(&tokens, TT_ALLOF)) { + type = OP_AND; + arity = AT_NARY; +#ifdef DEBUG + debug("ET_OP (OP_AND)"); +#endif + } + else if(acceptToken(&tokens, TT_ANYOF)) { + type = OP_OR; + arity = AT_NARY; +#ifdef DEBUG + debug("ET_OP (OP_OR)"); +#endif + } + else if(acceptToken(&tokens, TT_SMOOSH)) { + type = OP_CAT; + arity = AT_NARY; +#ifdef DEBUG + debug("ET_OP (OP_CAT)"); +#endif + } + else { + error("invalid operator", tokens); + return NULL; + } + + /* Create the argument list */ + args = createExprNodeList(); + if (!args) goto parseOpExprNodeAbort; + + /* Parse the operation arguments */ + if (arity == AT_UNARY) { + /* Parse the argument */ + arg = parseExprNode(&tokens); + if (!arg) goto parseOpExprNodeAbort; + + /* Add the argument to the argument list */ + status = addExprNode(args, arg); + if (!status) goto parseOpExprNodeAbort; + arg = NULL; + } + else if (arity == AT_BINARY) { + /* Parse the first argument */ + arg = parseExprNode(&tokens); + if (!arg) goto parseOpExprNodeAbort; + + /* Add the first argument to the argument list */ + status = addExprNode(args, arg); + if (!status) goto parseOpExprNodeAbort; + arg = NULL; + + /* Optionally parse the argument-separator token */ + status = acceptToken(&tokens, TT_AN); + + /* Parse the second argument */ + arg = parseExprNode(&tokens); + if (!arg) goto parseOpExprNodeAbort; + + /* Add the second argument to the argument list */ + status = addExprNode(args, arg); + if (!status) goto parseOpExprNodeAbort; + arg = NULL; + } + else if (arity == AT_NARY) { + /* Parse as many arguments as possible */ + while (1) { + /* Parse an argument */ + arg = parseExprNode(&tokens); + if (!arg) goto parseOpExprNodeAbort; + + /* Add the argument to the argument list */ + status = addExprNode(args, arg); + if (!status) goto parseOpExprNodeAbort; + arg = NULL; + + /* Stop if the end-of-arguments token is present */ + if (acceptToken(&tokens, TT_MKAY)) break; + + /* Optionally parse the argument-separator token */ + status = acceptToken(&tokens, TT_AN); + } + } + + /* Create the new OpExprNode structure */ + expr = createOpExprNode(type, args); + if (!expr) goto parseOpExprNodeAbort; + + /* Create the new ExprNode structure */ + ret = createExprNode(ET_OP, expr); + if (!ret) goto parseOpExprNodeAbort; + + /* Since we're successful, update the token stream */ + *tokenp = tokens; + + return ret; + +parseOpExprNodeAbort: /* Exception handling */ + + /* Clean up any allocated structures */ + if (ret) deleteExprNode(ret); + else if (expr) deleteOpExprNode(expr); + else { + if (arg) deleteExprNode(arg); + if (args) deleteExprNodeList(args); + } + + return NULL; } /** Parses a set of tokens into an ExprNode structure. Parsing begins at the * token pointed to by \a tokenp. * * \pre \a tokenp points to a position in an array of tokens created by - * tokenizeLexemes(Lexeme **). + * tokenizeLexemes(LexemeList *). * * \post \a tokenp will point to the next \b unparsed token in the array. * @@ -1622,135 +2259,31 @@ ExprNode *parseExprNode(Token ***tokenp) /**< [in,out] A pointer to the position { Token **tokens = *tokenp; ExprNode *ret = NULL; + #ifdef DEBUG shiftout(); #endif + /* Cast */ - if (acceptToken(&tokens, TT_MAEK)) { - ExprNode *target = NULL; - TypeNode *newtype = NULL; - CastExprNode *expr = NULL; -#ifdef DEBUG - debug("ET_CAST"); -#endif - target = parseExprNode(&tokens); - if (!target) return NULL; - acceptToken(&tokens, TT_A); - newtype = parseTypeNode(&tokens); - if (!newtype) { - deleteExprNode(target); - return NULL; - } - expr = createCastExprNode(target, newtype); - if (!expr) { - deleteExprNode(target); - deleteTypeNode(newtype); - return NULL; - } - ret = createExprNode(ET_CAST, expr); - if (!ret) { - deleteExprNode(target); - deleteTypeNode(newtype); - deleteCastExprNode(expr); - return NULL; - } - } - /* Implicit variable */ - else if (acceptToken(&tokens, TT_IT)) { - ret = createExprNode(ET_IMPVAR, NULL); - if (!ret) return NULL; + if (peekToken(&tokens, TT_MAEK)) { + ret = parseCastExprNode(tokenp); } /* Constant value */ else if (peekToken(&tokens, TT_BOOLEAN) || peekToken(&tokens, TT_INTEGER) || peekToken(&tokens, TT_FLOAT) - || peekToken(&tokens, TT_STRING)) { - ConstantNode *node = NULL; -#ifdef DEBUG - debug("ET_CONSTANT"); -#endif - node = parseConstantNode(&tokens); - if (!node) return NULL; - ret = createExprNode(ET_CONSTANT, node); - if (!ret) { - deleteConstantNode(node); - return NULL; - } - } - /* Function call */ + || peekToken(&tokens, TT_STRING)) + ret = parseConstantExprNode(tokenp); + /* Function call (must come before identifier) */ else if (nextToken(&tokens, TT_IZ)) { - IdentifierNode *scope = NULL; - IdentifierNode *name = NULL; - ExprNodeList *args = NULL; - FuncCallExprNode *node = NULL; -#ifdef DEBUG - debug("ET_FUNCCALL"); -#endif - scope = parseIdentifierNode(&tokens); - if (!scope) return NULL; - acceptToken(&tokens, TT_IZ); /* Will succeed, checked for this above */ - name = parseIdentifierNode(&tokens); - if (!name) { - deleteIdentifierNode(scope); - return NULL; - } - args = createExprNodeList(); - if (acceptToken(&tokens, TT_YR)) { - ExprNode *arg = parseExprNode(&tokens); - if (!arg) { - deleteIdentifierNode(scope); - deleteIdentifierNode(name); - deleteExprNodeList(args); - return NULL; - } - addExprNode(args, arg); - while (acceptToken(&tokens, TT_ANYR)) { - arg = parseExprNode(&tokens); - if (!arg) { - deleteIdentifierNode(scope); - deleteIdentifierNode(name); - deleteExprNodeList(args); - return NULL; - } - addExprNode(args, arg); - } - } - if (!acceptToken(&tokens, TT_MKAY)) { - error("expected MKAY", tokens); - deleteIdentifierNode(scope); - deleteIdentifierNode(name); - deleteExprNodeList(args); - return NULL; - } - node = createFuncCallExprNode(scope, name, args); - if (!node) { - deleteIdentifierNode(scope); - deleteIdentifierNode(name); - deleteExprNodeList(args); - return NULL; - } - ret = createExprNode(ET_FUNCCALL, node); - if (!ret) { - deleteFuncCallExprNode(node); - return NULL; - } + ret = parseFuncCallExprNode(tokenp); } /* Identifier */ else if (peekToken(&tokens, TT_IDENTIFIER) || peekToken(&tokens, TT_SRS)) { - IdentifierNode *node = NULL; -#ifdef DEBUG - debug("ET_IDENTIFIER"); -#endif - node = parseIdentifierNode(&tokens); - if (!node) return NULL; - ret = createExprNode(ET_IDENTIFIER, node); - if (!ret) { - deleteIdentifierNode(node); - return NULL; - } + ret = parseIdentifierExprNode(tokenp); } - /* Binary operations */ + /* Operation */ else if (peekToken(&tokens, TT_SUMOF) || peekToken(&tokens, TT_DIFFOF) || peekToken(&tokens, TT_PRODUKTOF) @@ -1762,214 +2295,1576 @@ ExprNode *parseExprNode(Token ***tokenp) /**< [in,out] A pointer to the position || peekToken(&tokens, TT_EITHEROF) || peekToken(&tokens, TT_WONOF) || peekToken(&tokens, TT_BOTHSAEM) - || peekToken(&tokens, TT_DIFFRINT)) { - ExprNodeList *args = NULL; - ExprNode *arg = NULL; - OpExprNode *op = NULL; - OpType type; - if (acceptToken(&tokens, TT_SUMOF)) { - type = OP_ADD; -#ifdef DEBUG - debug("ET_OP (OP_ADD)"); -#endif - } - else if(acceptToken(&tokens, TT_DIFFOF)) { - type = OP_SUB; -#ifdef DEBUG - debug("ET_OP (OP_SUB)"); -#endif - } - else if(acceptToken(&tokens, TT_PRODUKTOF)) { - type = OP_MULT; -#ifdef DEBUG - debug("ET_OP (OP_MULT)"); -#endif - } - else if(acceptToken(&tokens, TT_QUOSHUNTOF)) { - type = OP_DIV; -#ifdef DEBUG - debug("ET_OP (OP_DIV)"); -#endif - } - else if(acceptToken(&tokens, TT_MODOF)) { - type = OP_MOD; -#ifdef DEBUG - debug("ET_OP (OP_MOD)"); -#endif - } - else if(acceptToken(&tokens, TT_BIGGROF)) { - type = OP_MAX; -#ifdef DEBUG - debug("ET_OP (OP_MAX)"); -#endif - } - else if(acceptToken(&tokens, TT_SMALLROF)) { - type = OP_MIN; -#ifdef DEBUG - debug("ET_OP (OP_MIN)"); -#endif - } - else if(acceptToken(&tokens, TT_BOTHOF)) { - type = OP_AND; -#ifdef DEBUG - debug("ET_OP (OP_AND)"); -#endif - } - else if(acceptToken(&tokens, TT_EITHEROF)) { - type = OP_OR; -#ifdef DEBUG - debug("ET_OP (OP_OR)"); -#endif - } - else if(acceptToken(&tokens, TT_WONOF)) { - type = OP_XOR; -#ifdef DEBUG - debug("ET_OP (OP_XOR)"); -#endif - } - else if(acceptToken(&tokens, TT_BOTHSAEM)) { - type = OP_EQ; -#ifdef DEBUG - debug("ET_OP (OP_EQ)"); -#endif - } - else if(acceptToken(&tokens, TT_DIFFRINT)) { - type = OP_NEQ; -#ifdef DEBUG - debug("ET_OP (OP_NEQ)"); -#endif - } - else { - error("invalid binary operator", tokens); - return NULL; - } - args = createExprNodeList(); - if (!args) return NULL; - arg = parseExprNode(&tokens); - if (!arg) { - deleteExprNodeList(args); - return NULL; - } - if (!addExprNode(args, arg)) { - deleteExprNode(arg); - deleteExprNodeList(args); - return NULL; - } - acceptToken(&tokens, TT_AN); - arg = parseExprNode(&tokens); - if (!arg) { - deleteExprNodeList(args); - return NULL; - } - if (!addExprNode(args, arg)) { - deleteExprNode(arg); - deleteExprNodeList(args); - return NULL; - } - op = createOpExprNode(type, args); - if (!op) { - deleteExprNodeList(args); - return NULL; - } - ret = createExprNode(ET_OP, op); - if (!ret) { - deleteOpExprNode(op); - return NULL; - } - } - /* N-ary operations ending in MKAY */ - else if (peekToken(&tokens, TT_ALLOF) + || peekToken(&tokens, TT_DIFFRINT) || peekToken(&tokens, TT_ANYOF) - || peekToken(&tokens, TT_SMOOSH)) { - ExprNodeList *args = NULL; - OpExprNode *op = NULL; - OpType type; - if (acceptToken(&tokens, TT_ALLOF)) { - type = OP_AND; -#ifdef DEBUG - debug("ET_OP (OP_AND)"); -#endif - } - else if(acceptToken(&tokens, TT_ANYOF)) { - type = OP_OR; -#ifdef DEBUG - debug("ET_OP (OP_OR)"); -#endif - } - else if(acceptToken(&tokens, TT_SMOOSH)) { - type = OP_CAT; -#ifdef DEBUG - debug("ET_OP (OP_CAT)"); -#endif - } - else { - error("invalid n-ary operator", tokens); - return NULL; - } - if (!(args = createExprNodeList())) return NULL; - while (1) { - ExprNode *arg = NULL; - if (!(arg = parseExprNode(&tokens))) { - deleteExprNodeList(args); - return NULL; - } - if (!addExprNode(args, arg)) { - deleteExprNode(arg); - deleteExprNodeList(args); - return NULL; - } - if (acceptToken(&tokens, TT_MKAY)) break; - acceptToken(&tokens, TT_AN); - } - if (!(op = createOpExprNode(type, args))) { - deleteExprNodeList(args); - return NULL; - } - if (!(ret = createExprNode(ET_OP, op))) { - deleteOpExprNode(op); - return NULL; - } + || peekToken(&tokens, TT_ALLOF) + || peekToken(&tokens, TT_SMOOSH) + || peekToken(&tokens, TT_NOT)) { + ret = parseOpExprNode(tokenp); } - /* Logical NOT */ - else if (acceptToken(&tokens, TT_NOT)) { - ExprNodeList *args = NULL; - ExprNode *arg = NULL; - OpExprNode *op = NULL; + /* Implicit variable */ + else if (acceptToken(&tokens, TT_IT)) { #ifdef DEBUG - debug("ET_OP (OP_NOT)"); + debug("ET_IMPVAR"); #endif - if (!(args = createExprNodeList())) return NULL; - if (!(arg = parseExprNode(&tokens))) { - deleteExprNodeList(args); - return NULL; - } - if (!addExprNode(args, arg)) { - deleteExprNode(arg); - deleteExprNodeList(args); - return NULL; - } - if (!(op = createOpExprNode(OP_NOT, args))) { - deleteExprNodeList(args); - return NULL; - } - if (!(ret = createExprNode(ET_OP, op))) { - deleteOpExprNode(op); - return NULL; - } + + /* Create the new ExprNode structure */ + ret = createExprNode(ET_IMPVAR, NULL); + if (!ret) return NULL; + + /* Since we're successful, update the token stream */ + *tokenp = tokens; } - else error("expected expression", tokens); + else { + error("expected expression", tokens); + } + #ifdef DEBUG shiftin(); #endif - *tokenp = tokens; + return ret; } +/** Parses a set of tokens into a StmtNode structure containing a CastStmtNode + * structure. Parsing begins at the token pointed to by \a tokenp. + * + * \pre \a tokenp points to a position in an array of tokens created by + * tokenizeLexemes(LexemeList *). + * + * \post \a tokenp will point to the next \b unparsed token in the array. + * + * \return A pointer to the generated StmtNode structure. + * + * \retval NULL An error occurred during parsing. + * + * \see parsePrintStmtNode(Token ***) + * \see parseInputStmtNode(Token ***) + * \see parseAssignmentStmtNode(Token ***) + * \see parseDeclarationStmtNode(Token ***) + * \see parseIfThenElseStmtNode(Token ***) + * \see parseSwitchStmtNode(Token ***) + * \see parseBreakStmtNode(Token ***) + * \see parseReturnStmtNode(Token ***) + * \see parseLoopStmtNode(Token ***) + * \see parseDeallocationStmtNode(Token ***) + * \see parseFuncDefStmtNode(Token ***) */ +StmtNode *parseCastStmtNode(Token ***tokenp) +{ + IdentifierNode *target = NULL; + TypeNode *newtype = NULL; + CastStmtNode *stmt = NULL; + StmtNode *ret = NULL; + int status; + + /* Work from a copy of the token stream in case something goes wrong */ + Token **tokens = *tokenp; + +#ifdef DEBUG + debug("ST_CAST"); +#endif + + /* Parse the target of the cast statement */ + target = parseIdentifierNode(&tokens); + if (!target) goto parseCastStmtNodeAbort; + + /* Remove the cast keywords from the token stream */ + status = acceptToken(&tokens, TT_ISNOWA); + if (!status) { + error("expected IS NOW A", tokens); + goto parseCastStmtNodeAbort; + } + + /* Parse the type to cast to */ + newtype = parseTypeNode(&tokens); + if (!newtype) goto parseCastStmtNodeAbort; + + /* Make sure the statement ends with a newline */ + status = acceptToken(&tokens, TT_NEWLINE); + if (!status) { + error("expected end of expression", tokens); + goto parseCastStmtNodeAbort; + } + + /* Create the new CastStmtNode structure */ + stmt = createCastStmtNode(target, newtype); + if (!stmt) goto parseCastStmtNodeAbort; + + /* Create the new StmtNode structure */ + ret = createStmtNode(ST_CAST, stmt); + if (!ret) goto parseCastStmtNodeAbort; + + /* Since we're successful, update the token stream */ + *tokenp = tokens; + + return ret; + +parseCastStmtNodeAbort: /* Exception handling */ + + /* Clean up any allocated structures */ + if (ret) deleteStmtNode(ret); + else if (stmt) deleteCastStmtNode(stmt); + else { + if (newtype) deleteTypeNode(newtype); + if (target) deleteIdentifierNode(target); + } + + return NULL; +} + +/** Parses a set of tokens into a StmtNode structure containing a PrintStmtNode + * structure. Parsing begins at the token pointed to by \a tokenp. + * + * \pre \a tokenp points to a position in an array of tokens created by + * tokenizeLexemes(LexemeList *). + * + * \post \a tokenp will point to the next \b unparsed token in the array. + * + * \return A pointer to the generated StmtNode structure. + * + * \retval NULL An error occurred during parsing. + * + * \see parseCastStmtNode(Token ***) + * \see parseInputStmtNode(Token ***) + * \see parseAssignmentStmtNode(Token ***) + * \see parseDeclarationStmtNode(Token ***) + * \see parseIfThenElseStmtNode(Token ***) + * \see parseSwitchStmtNode(Token ***) + * \see parseBreakStmtNode(Token ***) + * \see parseReturnStmtNode(Token ***) + * \see parseLoopStmtNode(Token ***) + * \see parseDeallocationStmtNode(Token ***) + * \see parseFuncDefStmtNode(Token ***) */ +StmtNode *parsePrintStmtNode(Token ***tokenp) +{ + ExprNode *arg = NULL; + ExprNodeList *args = NULL; + int nonl = 0; + PrintStmtNode *stmt = NULL; + StmtNode *ret = NULL; + int status; + + /* Work from a copy of the token stream in case something goes wrong */ + Token **tokens = *tokenp; + +#ifdef DEBUG + debug("ST_PRINT"); +#endif + + /* Remove the print keyword from the token stream */ + status = acceptToken(&tokens, TT_VISIBLE); + if (!status) { + error("expected VISIBLE", tokens); + goto parsePrintStmtNodeAbort; + } + + /* Parse the arguments to the print statement */ + args = createExprNodeList(); + if (!args) goto parsePrintStmtNodeAbort; + do { + /* Parse an argument; it should be an expression */ + arg = parseExprNode(&tokens); + if (!arg) goto parsePrintStmtNodeAbort; + + /* Add it to the list of arguments */ + status = addExprNode(args, arg); + if (!status) goto parsePrintStmtNodeAbort; + arg = NULL; + + /* Arguments can optionally be separated by an AN keyword */ + status = acceptToken(&tokens, TT_AN); + } while (!peekToken(&tokens, TT_NEWLINE) + && !peekToken(&tokens, TT_BANG)); + + /* Check for the no-newline token */ + if(acceptToken(&tokens, TT_BANG)) nonl = 1; + + /* Make sure the statement ends with a newline */ + status = acceptToken(&tokens, TT_NEWLINE); + if (!status) { + error("expected end of expression", tokens); + goto parsePrintStmtNodeAbort; + } + + /* Create the new PrintStmtNode structure */ + stmt = createPrintStmtNode(args, nonl); + if (!stmt) goto parsePrintStmtNodeAbort; + + /* Create the new StmtNode structure */ + ret = createStmtNode(ST_PRINT, stmt); + if (!ret) goto parsePrintStmtNodeAbort; + + /* Since we're successful, update the token stream */ + *tokenp = tokens; + + return ret; + +parsePrintStmtNodeAbort: /* Exception handling */ + + /* Clean up any allocated structures */ + if (ret) deleteStmtNode(ret); + else if (stmt) deletePrintStmtNode(stmt); + else { + if (arg) deleteExprNode(arg); + if (args) deleteExprNodeList(args); + } + + return NULL; +} + +/** Parses a set of tokens into a StmtNode structure containing an InputStmtNode + * structure. Parsing begins at the token pointed to by \a tokenp. + * + * \pre \a tokenp points to a position in an array of tokens created by + * tokenizeLexemes(LexemeList *). + * + * \post \a tokenp will point to the next \b unparsed token in the array. + * + * \return A pointer to the generated StmtNode structure. + * + * \retval NULL An error occurred during parsing. + * + * \see parseCastStmtNode(Token ***) + * \see parsePrintStmtNode(Token ***) + * \see parseAssignmentStmtNode(Token ***) + * \see parseDeclarationStmtNode(Token ***) + * \see parseIfThenElseStmtNode(Token ***) + * \see parseSwitchStmtNode(Token ***) + * \see parseBreakStmtNode(Token ***) + * \see parseReturnStmtNode(Token ***) + * \see parseLoopStmtNode(Token ***) + * \see parseDeallocationStmtNode(Token ***) + * \see parseFuncDefStmtNode(Token ***) */ +StmtNode *parseInputStmtNode(Token ***tokenp) +{ + IdentifierNode *target = NULL; + InputStmtNode *stmt = NULL; + StmtNode *ret = NULL; + int status; + + /* Work from a copy of the token stream in case something goes wrong */ + Token **tokens = *tokenp; + +#ifdef DEBUG + debug("ST_INPUT"); +#endif + + /* Remove the input keyword from the token stream */ + status = acceptToken(&tokens, TT_GIMMEH); + if (!status) { + error("expected GIMMEH", tokens); + goto parseInputStmtNodeAbort; + } + + /* Parse the identifier to store the input into */ + target = parseIdentifierNode(&tokens); + if (!target) goto parseInputStmtNodeAbort; + + /* Make sure the statement ends with a newline */ + status = acceptToken(&tokens, TT_NEWLINE); + if (!status) { + error("expected end of expression", tokens); + goto parseInputStmtNodeAbort; + } + + /* Create the new InputStmtNode structure */ + stmt = createInputStmtNode(target); + if (!stmt) goto parseInputStmtNodeAbort; + + /* Create the new StmtNode structure */ + ret = createStmtNode(ST_INPUT, stmt); + if (!ret) goto parseInputStmtNodeAbort; + + /* Since we're successful, update the token stream */ + *tokenp = tokens; + + return ret; + +parseInputStmtNodeAbort: /* Exception handling */ + + /* Clean up any allocated structures */ + if (ret) deleteStmtNode(ret); + else if (stmt) deleteInputStmtNode(stmt); + else { + if (target) deleteIdentifierNode(target); + } + + return NULL; +} + +/** Parses a set of tokens into a StmtNode structure containing an + * AssignmentStmtNode structure. Parsing begins at the token pointed to by + * \a tokenp. + * + * \pre \a tokenp points to a position in an array of tokens created by + * tokenizeLexemes(LexemeList *). + * + * \post \a tokenp will point to the next \b unparsed token in the array. + * + * \return A pointer to the generated StmtNode structure. + * + * \retval NULL An error occurred during parsing. + * + * \see parseCastStmtNode(Token ***) + * \see parsePrintStmtNode(Token ***) + * \see parseInputStmtNode(Token ***) + * \see parseDeclarationStmtNode(Token ***) + * \see parseIfThenElseStmtNode(Token ***) + * \see parseSwitchStmtNode(Token ***) + * \see parseBreakStmtNode(Token ***) + * \see parseReturnStmtNode(Token ***) + * \see parseLoopStmtNode(Token ***) + * \see parseDeallocationStmtNode(Token ***) + * \see parseFuncDefStmtNode(Token ***) */ +StmtNode *parseAssignmentStmtNode(Token ***tokenp) +{ + IdentifierNode *target = NULL; + ExprNode *expr = NULL; + AssignmentStmtNode *stmt = NULL; + StmtNode *ret = NULL; + int status; + + /* Work from a copy of the token stream in case something goes wrong */ + Token **tokens = *tokenp; + +#ifdef DEBUG + debug("ST_ASSIGNMENT"); +#endif + + /* Parse the target of the assignment */ + target = parseIdentifierNode(&tokens); + if (!target) goto parseAssignmentStmtNodeAbort; + + /* Remove the assignment keyword from the token stream */ + if (!acceptToken(&tokens, TT_R)) { + error("expected R", tokens); + goto parseAssignmentStmtNodeAbort; + } + + /* Parse the expression to assign */ + expr = parseExprNode(&tokens); + if (!expr) goto parseAssignmentStmtNodeAbort; + + /* Make sure the statement ends with a newline */ + status = acceptToken(&tokens, TT_NEWLINE); + if (!status) { + error("expected end of statement", tokens); + goto parseAssignmentStmtNodeAbort; + } + + /* Create the new AssignmentStmtNode structure */ + stmt = createAssignmentStmtNode(target, expr); + if (!stmt) goto parseAssignmentStmtNodeAbort; + + /* Create the new StmtNode structure */ + ret = createStmtNode(ST_ASSIGNMENT, stmt); + if (!ret) goto parseAssignmentStmtNodeAbort; + + /* Since we're successful, update the token stream */ + *tokenp = tokens; + + return ret; + +parseAssignmentStmtNodeAbort: /* Exception handling */ + + /* Clean up any allocated structures */ + if (ret) deleteStmtNode(ret); + else if (stmt) deleteAssignmentStmtNode(stmt); + else { + if (expr) deleteExprNode(expr); + if (target) deleteIdentifierNode(target); + } + + return NULL; +} + +/** Parses a set of tokens into a StmtNode structure containing a + * DeclarationStmtNode structure. Parsing begins at the token pointed to by + * \a tokenp. + * + * \pre \a tokenp points to a position in an array of tokens created by + * tokenizeLexemes(LexemeList *). + * + * \post \a tokenp will point to the next \b unparsed token in the array. + * + * \return A pointer to the generated StmtNode structure. + * + * \retval NULL An error occurred during parsing. + * + * \see parseCastStmtNode(Token ***) + * \see parsePrintStmtNode(Token ***) + * \see parseInputStmtNode(Token ***) + * \see parseAssignmentStmtNode(Token ***) + * \see parseIfThenElseStmtNode(Token ***) + * \see parseSwitchStmtNode(Token ***) + * \see parseBreakStmtNode(Token ***) + * \see parseReturnStmtNode(Token ***) + * \see parseLoopStmtNode(Token ***) + * \see parseDeallocationStmtNode(Token ***) + * \see parseFuncDefStmtNode(Token ***) */ +StmtNode *parseDeclarationStmtNode(Token ***tokenp) +{ + IdentifierNode *scope = NULL; + IdentifierNode *target = NULL; + ExprNode *expr = NULL; + TypeNode *type = NULL; + DeclarationStmtNode *stmt = NULL; + StmtNode *ret = NULL; + int status; + + /* Work from a copy of the token stream in case something goes wrong */ + Token **tokens = *tokenp; + +#ifdef DEBUG + debug("ST_DECLARATION"); +#endif + + /* Parse the scope to declare the variable in */ + scope = parseIdentifierNode(&tokens); + if (!scope) goto parseDeclarationStmtNodeAbort; + + /* Remove the declaration keywords from the token stream */ + if (!acceptToken(&tokens, TT_HASA)) { + error("expected HAS A", tokens); + goto parseDeclarationStmtNodeAbort; + } + + /* Parse the identifier to declare */ + target = parseIdentifierNode(&tokens); + if (!target) goto parseDeclarationStmtNodeAbort; + + /* Check for an optional initialization */ + if (acceptToken(&tokens, TT_ITZ)) { + /* Parse the expression to initialize to */ + expr = parseExprNode(&tokens); + if (!expr) goto parseDeclarationStmtNodeAbort; + } + /* Check for an optional type initialization */ + else if (acceptToken(&tokens, TT_ITZA)) { + /* Parse the type to initialize to */ + type = parseTypeNode(&tokens); + if (!type) goto parseDeclarationStmtNodeAbort; + } + + /* Make sure the statement ends with a newline */ + status = acceptToken(&tokens, TT_NEWLINE); + if (!status) { + error("expected end of statement", tokens); + goto parseDeclarationStmtNodeAbort; + } + + /* Create the new DeclarationStmtNode structure */ + stmt = createDeclarationStmtNode(scope, target, expr, type); + if (!stmt) goto parseDeclarationStmtNodeAbort; + + /* Create the new StmtNode structure */ + ret = createStmtNode(ST_DECLARATION, stmt); + if (!ret) goto parseDeclarationStmtNodeAbort; + + /* Since we're successful, update the token stream */ + *tokenp = tokens; + + return ret; + +parseDeclarationStmtNodeAbort: /* Exception handling */ + + /* Clean up any allocated structures */ + if (ret) deleteStmtNode(ret); + else if (stmt) deleteDeclarationStmtNode(stmt); + else { + if (type) deleteTypeNode(type); + if (expr) deleteExprNode(expr); + if (target) deleteIdentifierNode(target); + if (scope) deleteIdentifierNode(scope); + } + + return NULL; +} + +/** Parses a set of tokens into a StmtNode structure containing an + * IfThenElseStmtNode structure. Parsing begins at the token pointed to by + * \a tokenp. + * + * \pre \a tokenp points to a position in an array of tokens created by + * tokenizeLexemes(LexemeList *). + * + * \post \a tokenp will point to the next \b unparsed token in the array. + * + * \return A pointer to the generated StmtNode structure. + * + * \retval NULL An error occurred during parsing. + * + * \see parseCastStmtNode(Token ***) + * \see parsePrintStmtNode(Token ***) + * \see parseInputStmtNode(Token ***) + * \see parseAssignmentStmtNode(Token ***) + * \see parseDeclarationStmtNode(Token ***) + * \see parseSwitchStmtNode(Token ***) + * \see parseBreakStmtNode(Token ***) + * \see parseReturnStmtNode(Token ***) + * \see parseLoopStmtNode(Token ***) + * \see parseDeallocationStmtNode(Token ***) + * \see parseFuncDefStmtNode(Token ***) */ +StmtNode *parseIfThenElseStmtNode(Token ***tokenp) +{ + BlockNode *yes = NULL; + ExprNodeList *guards = NULL; + BlockNodeList *blocks = NULL; + ExprNode *guard = NULL; + BlockNode *block = NULL; + BlockNode *no = NULL; + IfThenElseStmtNode *stmt = NULL; + StmtNode *ret = NULL; + int status; + + /* Work from a copy of the token stream in case something goes wrong */ + Token **tokens = *tokenp; + +#ifdef DEBUG + debug("ST_CONDITIONAL"); +#endif + + /* Remove the if keyword from the token stream */ + status = acceptToken(&tokens, TT_ORLY); + if (!status) { + error("expected O RLY?", tokens); + goto parseIfThenElseStmtNodeAbort; + } + + /* The if keyword must appear on its own line */ + if (!acceptToken(&tokens, TT_NEWLINE)) { + error("expected end of expression", tokens); + goto parseIfThenElseStmtNodeAbort; + } + + /* Parse the true branch keyword */ + status = acceptToken(&tokens, TT_YARLY); + if (!status) { + error("expected YA RLY", tokens); + goto parseIfThenElseStmtNodeAbort; + } + + /* The true branch keyword must appear on its own line */ + status = acceptToken(&tokens, TT_NEWLINE); + if (!status) { + error("expected end of expression", tokens); + goto parseIfThenElseStmtNodeAbort; + } + + /* Parse the true part of the branch */ + yes = parseBlockNode(&tokens); + if (!yes) goto parseIfThenElseStmtNodeAbort; + + /* Set up lists of guards and blocks */ + guards = createExprNodeList(); + if (!guards) goto parseIfThenElseStmtNodeAbort; + blocks = createBlockNodeList(); + if (!blocks) goto parseIfThenElseStmtNodeAbort; + + /* Parse the else-if keyword */ + while (acceptToken(&tokens, TT_MEBBE)) { + /* Parse an else-if guard */ + guard = parseExprNode(&tokens); + if (!guard) goto parseIfThenElseStmtNodeAbort; + + /* Add the else-if guard to the guard list */ + status = addExprNode(guards, guard); + if (!status) goto parseIfThenElseStmtNodeAbort; + guard = NULL; + + /* The else-if keyword and guard must be on their own line */ + status = acceptToken(&tokens, TT_NEWLINE); + if (!status) { + error("expected end of expression", tokens); + goto parseIfThenElseStmtNodeAbort; + } + + /* Parse the else-if block */ + block = parseBlockNode(&tokens); + if (!block) goto parseIfThenElseStmtNodeAbort; + + /* Add the else-if block to the block list */ + status = addBlockNode(blocks, block); + if (!status) goto parseIfThenElseStmtNodeAbort; + block = NULL; + } + + /* Parse the else keyword */ + if (acceptToken(&tokens, TT_NOWAI)) { + /* The else keyword must appear on its own line */ + status = acceptToken(&tokens, TT_NEWLINE); + if (!status) { + error("expected end of expression", tokens); + goto parseIfThenElseStmtNodeAbort; + } + + /* Parse the else block */ + no = parseBlockNode(&tokens); + if (!no) goto parseIfThenElseStmtNodeAbort; + } + + /* Parse the end-if-block keyword */ + status = acceptToken(&tokens, TT_OIC); + if (!status) { + error("expected OIC", tokens); + goto parseIfThenElseStmtNodeAbort; + } + + /* The end-if-block keyword must appear on its own line */ + status = acceptToken(&tokens, TT_NEWLINE); + if (!status) { + error("expected end of expression", tokens); + goto parseIfThenElseStmtNodeAbort; + } + + /* Create the new IfThenElseStmtNode structure */ + stmt = createIfThenElseStmtNode(yes, no, guards, blocks); + if (!stmt) goto parseIfThenElseStmtNodeAbort; + + /* Create the new StmtNode structure */ + ret = createStmtNode(ST_IFTHENELSE, stmt); + if (!ret) goto parseIfThenElseStmtNodeAbort; + + /* Since we're successful, update the token stream */ + *tokenp = tokens; + + return ret; + +parseIfThenElseStmtNodeAbort: /* Exception handling */ + + /* Clean up any allocated structures */ + if (ret) deleteStmtNode(ret); + else if (stmt) deleteIfThenElseStmtNode(stmt); + else { + if (no) deleteBlockNode(no); + if (blocks) deleteBlockNodeList(blocks); + if (guards) deleteExprNodeList(guards); + if (block) deleteBlockNode(block); + if (guard) deleteExprNode(guard); + if (yes) deleteBlockNode(yes); + } + + return NULL; +} + +/** Parses a set of tokens into a StmtNode structure containing a SwitchStmtNode + * structure. Parsing begins at the token pointed to by \a tokenp. + * + * \pre \a tokenp points to a position in an array of tokens created by + * tokenizeLexemes(LexemeList *). + * + * \post \a tokenp will point to the next \b unparsed token in the array. + * + * \return A pointer to the generated StmtNode structure. + * + * \retval NULL An error occurred during parsing. + * + * \see parseCastStmtNode(Token ***) + * \see parsePrintStmtNode(Token ***) + * \see parseInputStmtNode(Token ***) + * \see parseAssignmentStmtNode(Token ***) + * \see parseDeclarationStmtNode(Token ***) + * \see parseIfThenElseStmtNode(Token ***) + * \see parseBreakStmtNode(Token ***) + * \see parseReturnStmtNode(Token ***) + * \see parseLoopStmtNode(Token ***) + * \see parseDeallocationStmtNode(Token ***) + * \see parseFuncDefStmtNode(Token ***) */ +StmtNode *parseSwitchStmtNode(Token ***tokenp) +{ + ExprNodeList *guards = NULL; + BlockNodeList *blocks = NULL; + ConstantNode *c = NULL; + ExprNode *guard = NULL; + BlockNode *block = NULL; + BlockNode *def = NULL; + SwitchStmtNode *stmt = NULL; + StmtNode *ret = NULL; + int status; + + /* Work from a copy of the token stream in case something goes wrong */ + Token **tokens = *tokenp; + +#ifdef DEBUG + debug("ST_SWITCH"); +#endif + + /* Remove the switch keyword from the token stream */ + status = acceptToken(&tokens, TT_WTF); + if (!status) { + error("expected WTF?", tokens); + goto parseSwitchStmtNodeAbort; + } + + /* The switch keyword must appear on its own line */ + status = acceptToken(&tokens, TT_NEWLINE); + if (!status) { + error("expected end of expression", tokens); + goto parseSwitchStmtNodeAbort; + } + + /* Set up lists of guards and blocks */ + guards = createExprNodeList(); + if (!guards) goto parseSwitchStmtNodeAbort; + blocks = createBlockNodeList(); + if (!blocks) goto parseSwitchStmtNodeAbort; + + /* Parse at least one case */ + do { + unsigned int n = 0; + + /* Parse the case keyword */ + status = acceptToken(&tokens, TT_OMG); + if (!status) { + error("expected OMG", tokens); + goto parseSwitchStmtNodeAbort; + } + + /* Parse a constant for the case */ + /** \note The 1.2 specification only allows constant + * values for OMG guards thus this function + * explicitly checks for them. */ + c = parseConstantNode(&tokens); + if (!c) goto parseSwitchStmtNodeAbort; + + /* String interpolation is not allowed */ + if (c->type == CT_STRING && strstr(c->data.s, ":{")) { + error("cannot use an interpolated string as an OMG literal", tokens); + goto parseSwitchStmtNodeAbort; + } + + /* Make sure the constant is unique to this switch statement */ + for (n = 0; n < guards->num; n++) { + ConstantNode *test = guards->exprs[n]->expr; + if (c->type != test->type) continue; + /* Check for equivalent types and values */ + if (((c->type == CT_BOOLEAN || c->type == CT_INTEGER) + && c->data.i == test->data.i) + || (c->type == CT_FLOAT + && fabs(c->data.f - test->data.f) < FLT_EPSILON) + || (c->type == CT_STRING + && !strcmp(c->data.s, test->data.s))) { + error("OMG literal must be unique", tokens); + goto parseSwitchStmtNodeAbort; + } + } + + /* Package the constant in an expression */ + guard = createExprNode(ET_CONSTANT, c); + if (!guard) goto parseSwitchStmtNodeAbort; + + /* Add the guard to the list of guards */ + status = addExprNode(guards, guard); + if (!status) goto parseSwitchStmtNodeAbort; + guard = NULL; + + /* Make sure the guard appears on its own line */ + status = acceptToken(&tokens, TT_NEWLINE); + if (!status) { + error("expected end of expression", tokens); + goto parseSwitchStmtNodeAbort; + } + + /* Parse the block associated with the guard */ + block = parseBlockNode(&tokens); + if (!block) goto parseSwitchStmtNodeAbort; + + /* Add the block to the list of blocks */ + status = addBlockNode(blocks, block); + if (!status) goto parseSwitchStmtNodeAbort; + block = NULL; + } while (peekToken(&tokens, TT_OMG)); + + /* Check for the default case */ + if (acceptToken(&tokens, TT_OMGWTF)) { + /* Make sure the default case keyword appears on its own line */ + status = acceptToken(&tokens, TT_NEWLINE); + if (!status) { + error("expected end of expression", tokens); + goto parseSwitchStmtNodeAbort; + } + + /* Parse the default case block */ + def = parseBlockNode(&tokens); + if (!def) goto parseSwitchStmtNodeAbort; + } + + /* Parse the end-switch keyword */ + status = acceptToken(&tokens, TT_OIC); + if (!status) { + error("expected OIC", tokens); + goto parseSwitchStmtNodeAbort; + } + + /* Make sure the end-switch keyword appears on its own line */ + status = acceptToken(&tokens, TT_NEWLINE); + if (!status) { + error("expected end of expression", tokens); + goto parseSwitchStmtNodeAbort; + } + + /* Create the new SwitchStmtNode structure */ + stmt = createSwitchStmtNode(guards, blocks, def); + if (!stmt) goto parseSwitchStmtNodeAbort; + + /* Create the new StmtNode structure */ + ret = createStmtNode(ST_SWITCH, stmt); + if (!ret) goto parseSwitchStmtNodeAbort; + + /* Since we're successful, update the token stream */ + *tokenp = tokens; + + return ret; + +parseSwitchStmtNodeAbort: /* Exception handling */ + + /* Clean up any allocated structures */ + if (ret) deleteStmtNode(ret); + else if (stmt) deleteSwitchStmtNode(stmt); + else { + if (def) deleteBlockNode(def); + if (block) deleteBlockNode(block); + if (guard) deleteExprNode(guard); + if (c) deleteConstantNode(c); + if (blocks) deleteBlockNodeList(blocks); + if (guards) deleteExprNodeList(guards); + } + + return NULL; +} + +/** Parses a set of tokens into a StmtNode structure representing a break + * statement. Parsing begins at the token pointed to by \a tokenp. + * + * \pre \a tokenp points to a position in an array of tokens created by + * tokenizeLexemes(LexemeList *). + * + * \post \a tokenp will point to the next \b unparsed token in the array. + * + * \return A pointer to the generated StmtNode structure. + * + * \retval NULL An error occurred during parsing. + * + * \see parseCastStmtNode(Token ***) + * \see parsePrintStmtNode(Token ***) + * \see parseInputStmtNode(Token ***) + * \see parseAssignmentStmtNode(Token ***) + * \see parseDeclarationStmtNode(Token ***) + * \see parseIfThenElseStmtNode(Token ***) + * \see parseSwitchStmtNode(Token ***) + * \see parseReturnStmtNode(Token ***) + * \see parseLoopStmtNode(Token ***) + * \see parseDeallocationStmtNode(Token ***) + * \see parseFuncDefStmtNode(Token ***) + * \see parseExprNode(Token ***) */ +StmtNode *parseBreakStmtNode(Token ***tokenp) +{ + StmtNode *ret = NULL; + int status; + + /* Work from a copy of the token stream in case something goes wrong */ + Token **tokens = *tokenp; + +#ifdef DEBUG + debug("ST_BREAK"); +#endif + + /* Remove the break keyword from the token stream */ + status = acceptToken(&tokens, TT_GTFO); + if (!status) { + error("expected GTFO", tokens); + goto parseBreakStmtNodeAbort; + } + + /* The break keyword must appear on its own line */ + status = acceptToken(&tokens, TT_NEWLINE); + if (!status) { + error("expected end of expression", tokens); + goto parseBreakStmtNodeAbort; + } + + /* Create the new StmtNode structure */ + ret = createStmtNode(ST_BREAK, NULL); + if (!ret) goto parseBreakStmtNodeAbort; + + /* Since we're successful, update the token stream */ + *tokenp = tokens; + + return ret; + +parseBreakStmtNodeAbort: /* Exception handling */ + + /* Clean up any allocated structures */ + if (ret) deleteStmtNode(ret); + return NULL; +} + +/** Parses a set of tokens into a StmtNode structure containing a ReturnStmtNode + * structure. Parsing begins at the token pointed to by \a tokenp. + * + * \pre \a tokenp points to a position in an array of tokens created by + * tokenizeLexemes(LexemeList *). + * + * \post \a tokenp will point to the next \b unparsed token in the array. + * + * \return A pointer to the generated StmtNode structure. + * + * \retval NULL An error occurred during parsing. + * + * \see parseCastStmtNode(Token ***) + * \see parsePrintStmtNode(Token ***) + * \see parseInputStmtNode(Token ***) + * \see parseAssignmentStmtNode(Token ***) + * \see parseDeclarationStmtNode(Token ***) + * \see parseIfThenElseStmtNode(Token ***) + * \see parseSwitchStmtNode(Token ***) + * \see parseBreakStmtNode(Token ***) + * \see parseLoopStmtNode(Token ***) + * \see parseDeallocationStmtNode(Token ***) + * \see parseFuncDefStmtNode(Token ***) */ +StmtNode *parseReturnStmtNode(Token ***tokenp) +{ + ExprNode *value = NULL; + ReturnStmtNode *stmt = NULL; + StmtNode *ret = NULL; + int status; + + /* Work from a copy of the token stream in case something goes wrong */ + Token **tokens = *tokenp; + +#ifdef DEBUG + debug("ST_RETURN"); +#endif + + /* Remove the return keyword from the token stream */ + status = acceptToken(&tokens, TT_FOUNDYR); + if (!status) { + error("expected FOUND YR", tokens); + goto parseReturnStmtNodeAbort; + } + + /* Parse the return value */ + value = parseExprNode(&tokens); + if (!value) goto parseReturnStmtNodeAbort; + + /* The return statement must reside on its own line */ + status = acceptToken(&tokens, TT_NEWLINE); + if (!status) { + error("expected end of expression", tokens); + goto parseReturnStmtNodeAbort; + } + + /* Create the new ReturnStmtNode structure */ + stmt = createReturnStmtNode(value); + if (!stmt) goto parseReturnStmtNodeAbort; + + /* Create the new StmtNode structure */ + ret = createStmtNode(ST_RETURN, stmt); + if (!ret) goto parseReturnStmtNodeAbort; + + /* Since we're successful, update the token stream */ + *tokenp = tokens; + + return ret; + +parseReturnStmtNodeAbort: /* Exception handling */ + + /* Clean up any allocated structures */ + if (ret) deleteStmtNode(ret); + else if (stmt) deleteReturnStmtNode(stmt); + else { + if (value) deleteExprNode(value); + } + return NULL; +} + +/** Parses a set of tokens into a StmtNode structure containing a LoopStmtNode + * structure. Parsing begins at the token pointed to by \a tokenp. + * + * \pre \a tokenp points to a position in an array of tokens created by + * tokenizeLexemes(LexemeList *). + * + * \post \a tokenp will point to the next \b unparsed token in the array. + * + * \return A pointer to the generated StmtNode structure. + * + * \retval NULL An error occurred during parsing. + * + * \see parseCastStmtNode(Token ***) + * \see parsePrintStmtNode(Token ***) + * \see parseInputStmtNode(Token ***) + * \see parseAssignmentStmtNode(Token ***) + * \see parseDeclarationStmtNode(Token ***) + * \see parseIfThenElseStmtNode(Token ***) + * \see parseSwitchStmtNode(Token ***) + * \see parseBreakStmtNode(Token ***) + * \see parseReturnStmtNode(Token ***) + * \see parseDeallocationStmtNode(Token ***) + * \see parseFuncDefStmtNode(Token ***) */ +StmtNode *parseLoopStmtNode(Token ***tokenp) +{ + IdentifierNode *name1 = NULL; + IdentifierNode *var = NULL; + ExprNode *update = NULL; + ExprNode *guard = NULL; + BlockNode *body = NULL; + FuncDefStmtNode *def = NULL; + IdentifierNode *name2 = NULL; + LoopStmtNode *stmt = NULL; + ExprNodeList *args = NULL; + char *id = NULL; + + /* For increment and decrement loops */ + IdentifierNode *varcopy = NULL; + ExprNode *arg1 = NULL; + ConstantNode *one = NULL; + ExprNode *arg2 = NULL; + OpExprNode *op = NULL; + + /* For function loops */ + IdentifierNode *scope = NULL; + IdentifierNode *name = NULL; + FuncCallExprNode *node = NULL; + ExprNode *arg = NULL; + + /* For loop predicates */ + ExprNode *predarg = NULL; + ExprNodeList *predargs = NULL; + OpExprNode *predop = NULL; + + StmtNode *ret = NULL; + int status; + + /* Work from a copy of the token stream in case something goes wrong */ + Token **tokens = *tokenp; + +#ifdef DEBUG + debug("ST_LOOP"); +#endif + + /* Remove the loop-start keyword from the token stream */ + status = acceptToken(&tokens, TT_IMINYR); + if (!status) { + error("expected IM IN YR", tokens); + goto parseLoopStmtNodeAbort; + } + + /* Parse the loop name */ + name1 = parseIdentifierNode(&tokens); + if (!name1) goto parseLoopStmtNodeAbort; + else if (name1->type != IT_DIRECT) { + error("expected loop name", tokens); + goto parseLoopStmtNodeAbort; + } + + /* Check if an increment or decrement loop */ + if (peekToken(&tokens, TT_UPPIN) || peekToken(&tokens, TT_NERFIN)) { + OpType type; + + /* Parse the increment token or decrement token */ + if (acceptToken(&tokens, TT_UPPIN)) { + type = OP_ADD; +#ifdef DEBUG + shiftout(); + debug("ET_OP (OP_ADD)"); +#endif + } + else if (acceptToken(&tokens, TT_NERFIN)) { + type = OP_SUB; +#ifdef DEBUG + shiftout(); + debug("ET_OP (OP_SUB)"); +#endif + } + else { + error("expected UPPIN or NERFIN", tokens); + goto parseLoopStmtNodeAbort; + } + + /* Parse the required syntax */ + if (!acceptToken(&tokens, TT_YR)) { + error("expected YR", tokens); + goto parseLoopStmtNodeAbort; + } + + /* Parse the variable to operate on */ + var = parseIdentifierNode(&tokens); + if (!var) goto parseLoopStmtNodeAbort; +#ifdef DEBUG + shiftout(); + debug("ET_CONSTANT (CT_INTEGER)"); + shiftin(); + shiftin(); +#endif + /* Make a copy of the variable for use as a function argument */ + id = malloc(sizeof(char) * (strlen(var->id) + 1)); + if (!id) goto parseLoopStmtNodeAbort; + strcpy(id, var->id); + varcopy = createIdentifierNode(IT_DIRECT, id, var->fname, var->line); + if (!varcopy) goto parseLoopStmtNodeAbort; + id = NULL; + + /* Package the variable into an identifier expression */ + arg1 = createExprNode(ET_IDENTIFIER, varcopy); + if (!arg1) goto parseLoopStmtNodeAbort; + + /* Create a constant integer "1" */ + one = createIntegerConstantNode(1); + if (!one) goto parseLoopStmtNodeAbort; + + /* Package the constant into an expression */ + arg2 = createExprNode(ET_CONSTANT, one); + if (!arg2) goto parseLoopStmtNodeAbort; + + /* Create a list of arguments */ + args = createExprNodeList(); + if (!args) goto parseLoopStmtNodeAbort; + + /* Add the packaged arguments to the argument list */ + status = addExprNode(args, arg1); + if (!status) goto parseLoopStmtNodeAbort; + arg1 = NULL; + status = addExprNode(args, arg2); + if (!status) goto parseLoopStmtNodeAbort; + arg2 = NULL; + + /* Package the arguments and operation type in an expression */ + op = createOpExprNode(type, args); + if (!op) goto parseLoopStmtNodeAbort; + + /* Create the update expression */ + update = createExprNode(ET_OP, op); + if (!update) goto parseLoopStmtNodeAbort; + } + /* Check if a function loop */ + else if (nextToken(&tokens, TT_IZ)) { + IdentifierNode *temp = NULL; +#ifdef DEBUG + debug("ET_FUNCCALL"); +#endif + /* Parse the function scope */ + scope = parseIdentifierNode(&tokens); + if (!scope) goto parseLoopStmtNodeAbort; + + /* Parse the function indicator */ + status = acceptToken(&tokens, TT_IZ); + if (!status) { + error("expected IZ", tokens); + goto parseLoopStmtNodeAbort; + } + + /* Parse the function name */ + name = parseIdentifierNode(&tokens); + if (!name) goto parseLoopStmtNodeAbort; + + /* Create a list of arguments */ + args = createExprNodeList(); + if (!args) goto parseLoopStmtNodeAbort; + + /* Check for unary function */ + status = acceptToken(&tokens, TT_YR); + if (!status) { + error("expected unary function", tokens); + goto parseLoopStmtNodeAbort; + } + + /* Parse the unary function's single argument */ + arg = parseExprNode(&tokens); + if (!arg) goto parseLoopStmtNodeAbort; + + /* Make sure the argument is an identifier */ + if (arg->type != ET_IDENTIFIER) { + error("expected identifier", tokens); + goto parseLoopStmtNodeAbort; + } + + /* Add the argument to the argument list */ + status = addExprNode(args, arg); + if (!status) goto parseLoopStmtNodeAbort; + /* (Save a pointer to its expression for use, below) */ + temp = (IdentifierNode *)(arg->expr); + arg = NULL; + + /* Copy the identifier to make it the loop variable */ + id = malloc(sizeof(char) * (strlen(temp->id) + 1)); + if (!id) goto parseLoopStmtNodeAbort; + strcpy(id, temp->id); + var = createIdentifierNode(IT_DIRECT, id, temp->fname, temp->line); + if (!var) goto parseLoopStmtNodeAbort; + id = NULL; + + /* Check for unary function */ + status = acceptToken(&tokens, TT_MKAY); + if (!status) { + error("expected MKAY", tokens); + goto parseLoopStmtNodeAbort; + } + + /* Create a function call expression */ + node = createFuncCallExprNode(scope, name, args); + if (!node) goto parseLoopStmtNodeAbort; + + /* Package the function call in an expression */ + update = createExprNode(ET_FUNCCALL, node); + if (!update) goto parseLoopStmtNodeAbort; + } + + /* If there is an update, parse any predicates */ + if (update) { + /* Check for a while token */ + if (acceptToken(&tokens, TT_WILE)) { + /* Parse the while predicate */ + guard = parseExprNode(&tokens); + if (!guard) goto parseLoopStmtNodeAbort; + } + /* Check for a until token */ + else if (acceptToken(&tokens, TT_TIL)) { +#ifdef DEBUG + shiftout(); + debug("ET_OP (OP_NOT)"); +#endif + /* Parse the until predicate */ + predarg = parseExprNode(&tokens); + if (!predarg) goto parseLoopStmtNodeAbort; + + /* Create a list for predicate arguments */ + predargs = createExprNodeList(); + if (!predargs) goto parseLoopStmtNodeAbort; + + /* Add the until predicate to the list */ + status = addExprNode(predargs, predarg); + if (!status) goto parseLoopStmtNodeAbort; + predarg = NULL; +#ifdef DEBUG + shiftin(); +#endif + /* Create a NOT operation with the predicate */ + predop = createOpExprNode(OP_NOT, predargs); + if (!predop) goto parseLoopStmtNodeAbort; + + /* Package the NOT operation in an expression */ + guard = createExprNode(ET_OP, predop); + if (!guard) goto parseLoopStmtNodeAbort; + } + } + + /* All of the above should be on its own line */ + status = acceptToken(&tokens, TT_NEWLINE); + if (!status) { + error("expected end of expression", tokens); + goto parseLoopStmtNodeAbort; + } + + /* Parse the body of the loop */ + body = parseBlockNode(&tokens); + if (!body) goto parseLoopStmtNodeAbort; + + /* Parse the end-loop keywords */ + status = acceptToken(&tokens, TT_IMOUTTAYR); + if (!status) { + error("expected IM OUTTA YR", tokens); + goto parseLoopStmtNodeAbort; + } + + /* Parse the end-of-loop name */ + name2 = parseIdentifierNode(&tokens); + if (!name2) goto parseLoopStmtNodeAbort; + else if (name2->type != IT_DIRECT) { + error("expected loop name", tokens); + goto parseLoopStmtNodeAbort; + } + + /* Make sure the beginning-of-loop and end-of-loop names match */ + if (strcmp((char *)(name1->id), (char *)(name2->id))) { + error("expected matching loop name", tokens); + goto parseLoopStmtNodeAbort; + } + + /* We no longer need the end-of-loop name */ + deleteIdentifierNode(name2); + + /* The end-of-loop structure should appear on its own line */ + status = acceptToken(&tokens, TT_NEWLINE); + if (!status) { + error("expected end of expression", tokens); + goto parseLoopStmtNodeAbort; + } + + /* Create the new LoopStmtNode structure */ + stmt = createLoopStmtNode(name1, var, guard, update, body); + if (!stmt) goto parseLoopStmtNodeAbort; + + /* Create the new StmtNode structure */ + ret = createStmtNode(ST_LOOP, stmt); + if (!ret) goto parseLoopStmtNodeAbort; + + /* Since we're successful, update the token stream */ + *tokenp = tokens; + + return ret; + +parseLoopStmtNodeAbort: /* Exception handling */ + + /* Clean up any allocated structures */ + if (ret) deleteStmtNode(ret); + else if (stmt) deleteLoopStmtNode(stmt); + else { + if (name2) deleteIdentifierNode(name2); + if (def) deleteFuncDefStmtNode(def); + if (body) deleteBlockNode(body); + if (guard) deleteExprNode(guard); + if (update) deleteExprNode(update); + if (var) deleteIdentifierNode(var); + if (name1) deleteIdentifierNode(name1); + if (id) free(id); + + /* For increment and decrement loops */ + if (op) deleteOpExprNode(op); + if (args) deleteExprNodeList(args); + if (arg2) deleteExprNode(arg2); + if (one) deleteConstantNode(one); + if (arg1) deleteExprNode(arg1); + if (varcopy) deleteIdentifierNode(varcopy); + + /* For function loops */ + if (arg) deleteExprNode(arg); + if (node) deleteFuncCallExprNode(node); + if (name) deleteIdentifierNode(name); + if (scope) deleteIdentifierNode(scope); + + /* For loop predicates */ + if (predarg) deleteExprNode(predarg); + if (predargs) deleteExprNodeList(predargs); + if (predop) deleteOpExprNode(predop); + } + return NULL; +} + +/** Parses a set of tokens into a StmtNode structure containing a + * DeallocationStmtNode structure. Parsing begins at the token pointed to by + * \a tokenp. + * + * \pre \a tokenp points to a position in an array of tokens created by + * tokenizeLexemes(LexemeList *). + * + * \post \a tokenp will point to the next \b unparsed token in the array. + * + * \return A pointer to the generated StmtNode structure. + * + * \retval NULL An error occurred during parsing. + * + * \see parseCastStmtNode(Token ***) + * \see parsePrintStmtNode(Token ***) + * \see parseInputStmtNode(Token ***) + * \see parseAssignmentStmtNode(Token ***) + * \see parseDeclarationStmtNode(Token ***) + * \see parseIfThenElseStmtNode(Token ***) + * \see parseSwitchStmtNode(Token ***) + * \see parseBreakStmtNode(Token ***) + * \see parseReturnStmtNode(Token ***) + * \see parseLoopStmtNode(Token ***) + * \see parseFuncDefStmtNode(Token ***) */ +StmtNode *parseDeallocationStmtNode(Token ***tokenp) +{ + IdentifierNode *target = NULL; + DeallocationStmtNode *stmt = NULL; + StmtNode *ret = NULL; + int status; + + /* Work from a copy of the token stream in case something goes wrong */ + Token **tokens = *tokenp; + +#ifdef DEBUG + debug("ST_DEALLOCATION"); +#endif + + /* Parse the variable to deallocate */ + target = parseIdentifierNode(&tokens); + if (!target) goto parseDeallocationStmtNodeAbort; + + /* Parse the deallocation token */ + status = acceptToken(&tokens, TT_RNOOB); + if (!status) { + error("expected R NOOB", tokens); + goto parseDeallocationStmtNodeAbort; + } + + /* The deallocation statement must reside on its own line */ + status = acceptToken(&tokens, TT_NEWLINE); + if (!status) { + error("expected end of statement", tokens); + goto parseDeallocationStmtNodeAbort; + } + + /* Create the new DeallocationStmtNode structure */ + stmt = createDeallocationStmtNode(target); + if (!stmt) goto parseDeallocationStmtNodeAbort; + + /* Create the new StmtNode structure */ + ret = createStmtNode(ST_DEALLOCATION, stmt); + if (!ret) goto parseDeallocationStmtNodeAbort; + + /* Since we're successful, update the token stream */ + *tokenp = tokens; + + return ret; + +parseDeallocationStmtNodeAbort: /* Exception handling */ + + /* Clean up any allocated structures */ + if (ret) deleteStmtNode(ret); + else if (stmt) deleteDeallocationStmtNode(stmt); + else { + if (target) deleteIdentifierNode(target); + } + + return NULL; +} + +/** Parses a set of tokens into a StmtNode structure containing a + * FuncDefStmtNode structure. Parsing begins at the token pointed to by + * \a tokenp. + * + * \pre \a tokenp points to a position in an array of tokens created by + * tokenizeLexemes(LexemeList *). + * + * \post \a tokenp will point to the next \b unparsed token in the array. + * + * \return A pointer to the generated StmtNode structure. + * + * \retval NULL An error occurred during parsing. + * + * \see parseCastStmtNode(Token ***) + * \see parsePrintStmtNode(Token ***) + * \see parseInputStmtNode(Token ***) + * \see parseAssignmentStmtNode(Token ***) + * \see parseDeclarationStmtNode(Token ***) + * \see parseIfThenElseStmtNode(Token ***) + * \see parseSwitchStmtNode(Token ***) + * \see parseBreakStmtNode(Token ***) + * \see parseReturnStmtNode(Token ***) + * \see parseLoopStmtNode(Token ***) + * \see parseDeallocationStmtNode(Token ***) */ +StmtNode *parseFuncDefStmtNode(Token ***tokenp) +{ + IdentifierNode *scope = NULL; + IdentifierNode *name = NULL; + IdentifierNodeList *args = NULL; + IdentifierNode *arg = NULL; + BlockNode *body = NULL; + FuncDefStmtNode *stmt = NULL; + StmtNode *ret = NULL; + int status; + + /* Work from a copy of the token stream in case something goes wrong */ + Token **tokens = *tokenp; + +#ifdef DEBUG + debug("ST_FUNCDEF"); +#endif + + /* Parse the function definition token */ + status = acceptToken(&tokens, TT_HOWIZ); + if (!status) { + error("expected HOW IZ", tokens); + goto parseFuncDefStmtNodeAbort; + } + + /* Parse the scope to define the function in */ + scope = parseIdentifierNode(&tokens); + if (!scope) goto parseFuncDefStmtNodeAbort; + + /* Parse the name of the function */ + name = parseIdentifierNode(&tokens); + if (!name) goto parseFuncDefStmtNodeAbort; + + /* Create a list of arguments */ + args = createIdentifierNodeList(); + if (!args) goto parseFuncDefStmtNodeAbort; + + /* Parse the first argument indicator */ + if (acceptToken(&tokens, TT_YR)) { + /* Parse the first argument name */ + arg = parseIdentifierNode(&tokens); + if (!arg) goto parseFuncDefStmtNodeAbort; + + /* Add the first argument to the arguments list */ + status = addIdentifierNode(args, arg); + if (!status) goto parseFuncDefStmtNodeAbort; + arg = NULL; + + /* Continue parsing argument indicators */ + while (acceptToken(&tokens, TT_ANYR)) { + /* Parse the argument */ + arg = parseIdentifierNode(&tokens); + if (!arg) goto parseFuncDefStmtNodeAbort; + + /* Add the argument to the arguments list */ + status = addIdentifierNode(args, arg); + if (!status) goto parseFuncDefStmtNodeAbort; + arg = NULL; + } + } + + /* The function declaration should appear on its own line */ + status = acceptToken(&tokens, TT_NEWLINE); + if (!status) { + error("expected end of statement", tokens); + goto parseFuncDefStmtNodeAbort; + } + + /* Parse the body of the function */ + body = parseBlockNode(&tokens); + if (!body) goto parseFuncDefStmtNodeAbort; + + /* Parse the end-function token */ + status = acceptToken(&tokens, TT_IFUSAYSO); + if (!status) { + error("expected IF YOU SAY SO", tokens); + goto parseFuncDefStmtNodeAbort; + } + + /* The end-function token should appear on its own line */ + status = acceptToken(&tokens, TT_NEWLINE); + if (!status) { + error("expected end of statement", tokens); + goto parseFuncDefStmtNodeAbort; + } + + /* Create the new FuncDefStmtNode structure */ + stmt = createFuncDefStmtNode(scope, name, args, body); + if (!stmt) goto parseFuncDefStmtNodeAbort; + + /* Create the new StmtNode structure */ + ret = createStmtNode(ST_FUNCDEF, stmt); + if (!ret) goto parseFuncDefStmtNodeAbort; + + /* Since we're successful, update the token stream */ + *tokenp = tokens; + + return ret; + +parseFuncDefStmtNodeAbort: /* Exception handling */ + + /* Clean up any allocated structures */ + if (ret) deleteStmtNode(ret); + else if (stmt) deleteFuncDefStmtNode(stmt); + else { + if (body) deleteBlockNode(body); + if (args) deleteIdentifierNodeList(args); + if (arg) deleteIdentifierNode(arg); + if (name) deleteIdentifierNode(name); + if (scope) deleteIdentifierNode(scope); + } + + return NULL; +} + /** Parses a set of tokens into a StmtNode structure. Parsing begins at the * token pointed to by \a tokenp. * * \pre \a tokenp points to a position in an array of tokens created by - * tokenizeLexemes(Lexeme **). + * tokenizeLexemes(LexemeList *). * * \post \a tokenp will point to the next \b unparsed token in the array. * @@ -1985,993 +3880,141 @@ ExprNode *parseExprNode(Token ***tokenp) /**< [in,out] A pointer to the position * \see parseMainNode(Token **) */ StmtNode *parseStmtNode(Token ***tokenp) /**< [in,out] A pointer to the position of the next token to parse. */ { - Token **tokens = *tokenp; StmtNode *ret = NULL; ExprNode *expr = NULL; + + /* Work from a copy of the token stream in case something goes wrong */ + Token **tokens = *tokenp; + #ifdef DEBUG shiftout(); #endif + /* Parse context-sensitive expressions */ if (peekToken(&tokens, TT_IDENTIFIER) || peekToken(&tokens, TT_SRS)) { - IdentifierNode *id = parseIdentifierNode(&tokens); + IdentifierNode *id = NULL; + + /* Remove the identifier from the token stream */ + id = parseIdentifierNode(&tokens); if (!id) return NULL; + + /* We do not need to hold onto it */ + deleteIdentifierNode(id); + /* Casting */ - if (acceptToken(&tokens, TT_ISNOWA)) { - IdentifierNode *target = id; - TypeNode *newtype = NULL; - CastStmtNode *stmt = NULL; -#ifdef DEBUG - debug("ST_CAST"); -#endif - if (!(newtype = parseTypeNode(&tokens))) { - deleteIdentifierNode(target); - return NULL; - } - if (!acceptToken(&tokens, TT_NEWLINE)) { - error("expected end of expression", tokens); - deleteIdentifierNode(target); - deleteTypeNode(newtype); - return NULL; - } - if (!(stmt = createCastStmtNode(target, newtype))) { - deleteIdentifierNode(target); - deleteTypeNode(newtype); - return NULL; - } - if (!(ret = createStmtNode(ST_CAST, stmt))) { - deleteCastStmtNode(stmt); - return NULL; - } + if (peekToken(&tokens, TT_ISNOWA)) { + ret = parseCastStmtNode(tokenp); } /* Assignment */ - else if (acceptToken(&tokens, TT_R)) { - IdentifierNode *target = id; - ExprNode *expr = NULL; - AssignmentStmtNode *stmt = NULL; -#ifdef DEBUG - debug("ST_ASSIGNMENT"); -#endif - expr = parseExprNode(&tokens); - if (!expr) { - deleteIdentifierNode(target); - return NULL; - } - if (!acceptToken(&tokens, TT_NEWLINE)) { - error("expected end of statement", tokens); - deleteIdentifierNode(target); - deleteExprNode(expr); - return NULL; - } - stmt = createAssignmentStmtNode(target, expr); - if (!stmt) { - deleteIdentifierNode(target); - deleteExprNode(expr); - return NULL; - } - ret = createStmtNode(ST_ASSIGNMENT, stmt); - if (!ret) { - deleteAssignmentStmtNode(stmt); - return NULL; - } + else if (peekToken(&tokens, TT_R)) { + ret = parseAssignmentStmtNode(tokenp); } /* Variable declaration */ - else if (acceptToken(&tokens, TT_HASA)) { - IdentifierNode *scope = id; - IdentifierNode *target = NULL; - ExprNode *expr = NULL; - TypeNode *type = NULL; - DeclarationStmtNode *stmt = NULL; -#ifdef DEBUG - debug("ST_DECLARATION"); -#endif - target = parseIdentifierNode(&tokens); - if (!target) { - deleteIdentifierNode(scope); - return NULL; - } - if (acceptToken(&tokens, TT_ITZ)) { - expr = parseExprNode(&tokens); - if (!expr) { - deleteIdentifierNode(scope); - deleteIdentifierNode(target); - return NULL; - } - } - else if (acceptToken(&tokens, TT_ITZA)) { - type = parseTypeNode(&tokens); - if (!type) { - deleteIdentifierNode(scope); - deleteIdentifierNode(target); - return NULL; - } - } - if (!acceptToken(&tokens, TT_NEWLINE)) { - error("expected end of statement", tokens); - deleteIdentifierNode(scope); - deleteIdentifierNode(target); - if (expr) deleteExprNode(expr); - return NULL; - } - stmt = createDeclarationStmtNode(scope, target, expr, type); - if (!stmt) { - deleteIdentifierNode(scope); - deleteIdentifierNode(target); - if (expr) deleteExprNode(expr); - return NULL; - } - ret = createStmtNode(ST_DECLARATION, stmt); - if (!ret) { - deleteDeclarationStmtNode(stmt); - return NULL; - } + else if (peekToken(&tokens, TT_HASA)) { + ret = parseDeclarationStmtNode(tokenp); } /* Deallocation */ - else if (acceptToken(&tokens, TT_RNOOB)) { - IdentifierNode *target = id; - DeallocationStmtNode *stmt = NULL; -#ifdef DEBUG - debug("ST_DEALLOCATION"); -#endif - if (!acceptToken(&tokens, TT_NEWLINE)) { - error("expected end of statement", tokens); - deleteIdentifierNode(target); - return NULL; - } - stmt = createDeallocationStmtNode(target); - if (!stmt) { - deleteIdentifierNode(target); - return NULL; - } - ret = createStmtNode(ST_DEALLOCATION, stmt); - if (!ret) { - deleteDeallocationStmtNode(stmt); - return NULL; - } + else if (peekToken(&tokens, TT_RNOOB)) { + ret = parseDeallocationStmtNode(tokenp); } - /* Bare expression */ - else { - deleteIdentifierNode(id); - /* Reset token stream and try to parse expression */ + /* Bare identifier expression */ + else { + /* Reset state and continue parsing */ tokens = *tokenp; + + /* Parse the expression */ expr = parseExprNode(&tokens); if (!expr) return NULL; + #ifdef DEBUG debug("ST_EXPR"); #endif + + /* The expression should appear on its own line */ if (!acceptToken(&tokens, TT_NEWLINE)) { - deleteExprNode(expr); error("expected end of expression", tokens); + deleteExprNode(expr); return NULL; } + + /* Create the new StmtNode structure */ ret = createStmtNode(ST_EXPR, expr); + if (!ret) { + deleteExprNode(expr); + return NULL; + } + + /* Since we're successful, update the token stream */ + *tokenp = tokens; } } /* Print */ - else if (acceptToken(&tokens, TT_VISIBLE)) { - ExprNodeList *args = NULL; - int nonl = 0; - PrintStmtNode *stmt = NULL; -#ifdef DEBUG - debug("ST_PRINT"); -#endif - if (!(args = createExprNodeList())) return NULL; - do { - ExprNode *arg = NULL; - if (!(arg = parseExprNode(&tokens))) { - deleteExprNodeList(args); - return NULL; - } - if (!addExprNode(args, arg)) { - deleteExprNodeList(args); - deleteExprNode(arg); - return NULL; - } - acceptToken(&tokens, TT_AN); - } while (!peekToken(&tokens, TT_NEWLINE) && !peekToken(&tokens, TT_BANG)); - if (acceptToken(&tokens, TT_BANG)) nonl = 1; - if (!acceptToken(&tokens, TT_NEWLINE)) { - error("expected end of expression", tokens); - deleteExprNodeList(args); - return NULL; - } - if (!(stmt = createPrintStmtNode(args, nonl))) { - deleteExprNodeList(args); - return NULL; - } - if (!(ret = createStmtNode(ST_PRINT, stmt))) { - deletePrintStmtNode(stmt); - return NULL; - } + else if (peekToken(&tokens, TT_VISIBLE)) { + ret = parsePrintStmtNode(tokenp); } /* Input */ - else if (acceptToken(&tokens, TT_GIMMEH)) { - IdentifierNode *target = NULL; - InputStmtNode *stmt = NULL; -#ifdef DEBUG - debug("ST_INPUT"); -#endif - target = parseIdentifierNode(&tokens); - if (!target) return NULL; - if (!acceptToken(&tokens, TT_NEWLINE)) { - error("expected end of expression", tokens); - deleteIdentifierNode(target); - return NULL; - } - stmt = createInputStmtNode(target); - if (!stmt) { - deleteIdentifierNode(target); - return NULL; - } - ret = createStmtNode(ST_INPUT, stmt); - if (!ret) { - deleteInputStmtNode(stmt); - return NULL; - } + else if (peekToken(&tokens, TT_GIMMEH)) { + ret = parseInputStmtNode(tokenp); } /* If/then/else */ - else if (acceptToken(&tokens, TT_ORLY)) { - BlockNode *yes = NULL; - ExprNodeList *guards = NULL; - BlockNodeList *blocks = NULL; - BlockNode *no = NULL; - IfThenElseStmtNode *stmt = NULL; -#ifdef DEBUG - debug("ST_CONDITIONAL"); -#endif - if (!acceptToken(&tokens, TT_NEWLINE)) { - error("expected end of expression", tokens); - return NULL; - } - if (!acceptToken(&tokens, TT_YARLY)) { - error("expected YA RLY", tokens); - return NULL; - } - if (!acceptToken(&tokens, TT_NEWLINE)) { - error("expected end of expression", tokens); - return NULL; - } - yes = parseBlockNode(&tokens); - if (!yes) return NULL; - guards = createExprNodeList(); - if (!guards) { - deleteBlockNode(yes); - return NULL; - } - blocks = createBlockNodeList(); - if (!blocks) { - deleteBlockNode(yes); - deleteExprNodeList(guards); - return NULL; - } - while (acceptToken(&tokens, TT_MEBBE)) { - ExprNode *guard = NULL; - BlockNode *block = NULL; - guard = parseExprNode(&tokens); - if (!guard) { - deleteBlockNode(yes); - deleteExprNodeList(guards); - deleteBlockNodeList(blocks); - return NULL; - } - if (!addExprNode(guards, guard)) { - deleteBlockNode(yes); - deleteExprNodeList(guards); - deleteBlockNodeList(blocks); - deleteExprNode(guard); - return NULL; - } - if (!acceptToken(&tokens, TT_NEWLINE)) { - error("expected end of expression", tokens); - deleteBlockNode(yes); - deleteExprNodeList(guards); - deleteBlockNodeList(blocks); - return NULL; - } - block = parseBlockNode(&tokens); - if (!block) { - deleteBlockNode(yes); - deleteExprNodeList(guards); - deleteBlockNodeList(blocks); - return NULL; - } - if (!addBlockNode(blocks, block)) { - deleteBlockNode(yes); - deleteExprNodeList(guards); - deleteBlockNodeList(blocks); - deleteBlockNode(block); - return NULL; - } - } - if (acceptToken(&tokens, TT_NOWAI)) { - if (!acceptToken(&tokens, TT_NEWLINE)) { - error("expected end of expression", tokens); - deleteBlockNode(yes); - deleteExprNodeList(guards); - deleteBlockNodeList(blocks); - return NULL; - } - no = parseBlockNode(&tokens); - if (!no) { - deleteBlockNode(yes); - deleteExprNodeList(guards); - deleteBlockNodeList(blocks); - return NULL; - } - } - if (!acceptToken(&tokens, TT_OIC)) { - error("expected OIC", tokens); - deleteBlockNode(yes); - deleteExprNodeList(guards); - deleteBlockNodeList(blocks); - if (no) deleteBlockNode(no); - return NULL; - } - if (!acceptToken(&tokens, TT_NEWLINE)) { - error("expected end of expression", tokens); - deleteBlockNode(yes); - deleteExprNodeList(guards); - deleteBlockNodeList(blocks); - if (no) deleteBlockNode(no); - return NULL; - } - stmt = createIfThenElseStmtNode(yes, no, guards, blocks); - if (!stmt) { - deleteBlockNode(yes); - deleteExprNodeList(guards); - deleteBlockNodeList(blocks); - if (no) deleteBlockNode(no); - return NULL; - } - ret = createStmtNode(ST_IFTHENELSE, stmt); - if (!ret) { - deleteIfThenElseStmtNode(stmt); - return NULL; - } + else if (peekToken(&tokens, TT_ORLY)) { + ret = parseIfThenElseStmtNode(tokenp); } /* Switch */ - else if (acceptToken(&tokens, TT_WTF)) { - ExprNodeList *guards = NULL; - BlockNodeList *blocks = NULL; - BlockNode *def = NULL; - SwitchStmtNode *stmt = NULL; -#ifdef DEBUG - debug("ST_SWITCH"); -#endif - if (!acceptToken(&tokens, TT_NEWLINE)) { - error("expected end of expression", tokens); - return NULL; - } - guards = createExprNodeList(); - if (!guards) return NULL; - blocks = createBlockNodeList(); - if (!blocks) { - deleteExprNodeList(guards); - return NULL; - } - do { - ConstantNode *c = NULL; - ExprNode *guard = NULL; - BlockNode *block = NULL; - unsigned int n = 0; - if (!acceptToken(&tokens, TT_OMG)) { - error("expected OMG", tokens); - deleteExprNodeList(guards); - deleteBlockNodeList(blocks); - return NULL; - } - /** \note The 1.2 specification only allows constant - * values for OMG guards thus this function - * explicitly checks for them. */ - c = parseConstantNode(&tokens); - if (!c) { - deleteExprNodeList(guards); - deleteBlockNodeList(blocks); - return NULL; - } - /* Check for string interpolation */ - if (c->type == CT_STRING && strstr(c->data.s, ":{")) { - error("cannot use an interpolated string as an OMG literal", tokens); - return NULL; - } - /* Check if constant is unique */ - for (n = 0; n < guards->num; n++) { - ConstantNode *test = guards->exprs[n]->expr; - if (c->type == test->type) { - if (((c->type == CT_BOOLEAN || c->type == CT_INTEGER) - && c->data.i == test->data.i) - || (c->type == CT_FLOAT - && c->data.f == test->data.f) - || (c->type == CT_STRING - && !strcmp(c->data.s, test->data.s))) { - deleteExprNodeList(guards); - deleteBlockNodeList(blocks); - deleteConstantNode(c); - return NULL; - } - } - } - guard = createExprNode(ET_CONSTANT, c); - if (!guard) { - deleteExprNodeList(guards); - deleteBlockNodeList(blocks); - deleteConstantNode(c); - return NULL; - } - if (!addExprNode(guards, guard)) { - deleteExprNodeList(guards); - deleteBlockNodeList(blocks); - deleteExprNode(guard); - return NULL; - } - if (!acceptToken(&tokens, TT_NEWLINE)) { - error("expected end of expression", tokens); - deleteExprNodeList(guards); - deleteBlockNodeList(blocks); - return NULL; - } - block = parseBlockNode(&tokens); - if (!block) { - deleteExprNodeList(guards); - deleteBlockNodeList(blocks); - } - if (!addBlockNode(blocks, block)) { - deleteExprNodeList(guards); - deleteBlockNodeList(blocks); - deleteBlockNode(block); - return NULL; - } - } while (peekToken(&tokens, TT_OMG)); - if (acceptToken(&tokens, TT_OMGWTF)) { - if (!acceptToken(&tokens, TT_NEWLINE)) { - error("expected end of expression", tokens); - deleteExprNodeList(guards); - deleteBlockNodeList(blocks); - return NULL; - } - def = parseBlockNode(&tokens); - if (!def) { - deleteExprNodeList(guards); - deleteBlockNodeList(blocks); - return NULL; - } - } - if (!acceptToken(&tokens, TT_OIC)) { - error("expected OIC", tokens); - deleteExprNodeList(guards); - deleteBlockNodeList(blocks); - if (def) deleteBlockNode(def); - return NULL; - } - if (!acceptToken(&tokens, TT_NEWLINE)) { - error("expected end of expression", tokens); - deleteExprNodeList(guards); - deleteBlockNodeList(blocks); - if (def) deleteBlockNode(def); - return NULL; - } - stmt = createSwitchStmtNode(guards, blocks, def); - if (!stmt) { - deleteExprNodeList(guards); - deleteBlockNodeList(blocks); - if (def) deleteBlockNode(def); - return NULL; - } - ret = createStmtNode(ST_SWITCH, stmt); - if (!ret) { - deleteSwitchStmtNode(stmt); - } + else if (peekToken(&tokens, TT_WTF)) { + ret = parseSwitchStmtNode(tokenp); } /* Break */ - else if (acceptToken(&tokens, TT_GTFO)) { -#ifdef DEBUG - debug("ST_BREAK"); -#endif - if (!acceptToken(&tokens, TT_NEWLINE)) { - error("expected end of expression", tokens); - return NULL; - } - ret = createStmtNode(ST_BREAK, NULL); - if (!ret) return NULL; + else if (peekToken(&tokens, TT_GTFO)) { + ret = parseBreakStmtNode(tokenp); } /* Return */ - else if (acceptToken(&tokens, TT_FOUNDYR)) { - ExprNode *value = NULL; - ReturnStmtNode *stmt = NULL; -#ifdef DEBUG - debug("ST_RETURN"); -#endif - value = parseExprNode(&tokens); - if (!value) return NULL; - if (!acceptToken(&tokens, TT_NEWLINE)) { - error("expected end of expression", tokens); - deleteExprNode(value); - return NULL; - } - stmt = createReturnStmtNode(value); - if (!stmt) { - deleteExprNode(value); - return NULL; - } - ret = createStmtNode(ST_RETURN, stmt); - if (!ret) { - deleteReturnStmtNode(stmt); - return NULL; - } + else if (peekToken(&tokens, TT_FOUNDYR)) { + ret = parseReturnStmtNode(tokenp); } /* Loop */ - else if (acceptToken(&tokens, TT_IMINYR)) { - IdentifierNode *name1 = NULL; - IdentifierNode *var = NULL; - ExprNode *update = NULL; - ExprNode *guard = NULL; - BlockNode *body = NULL; - FuncDefStmtNode *def = NULL; - IdentifierNode *name2 = NULL; - LoopStmtNode *stmt = NULL; -#ifdef DEBUG - debug("ST_LOOP"); -#endif - name1 = parseIdentifierNode(&tokens); - if (!name1) return NULL; - else if (name1->type != IT_DIRECT) { - error("expected loop name", tokens); - deleteIdentifierNode(name1); - return NULL; - } - if (peekToken(&tokens, TT_UPPIN) || peekToken(&tokens, TT_NERFIN)) { - OpType type; - IdentifierNode *varcopy = NULL; - ExprNode *arg1 = NULL; - ConstantNode *one = NULL; - ExprNode *arg2 = NULL; - ExprNodeList *args = NULL; - OpExprNode *op = NULL; - char *id = NULL; - if (acceptToken(&tokens, TT_UPPIN)) { - type = OP_ADD; -#ifdef DEBUG - shiftout(); - debug("ET_OP (OP_ADD)"); -#endif - } - else if (acceptToken(&tokens, TT_NERFIN)) { - type = OP_SUB; -#ifdef DEBUG - shiftout(); - debug("ET_OP (OP_SUB)"); -#endif - } - else { - error("expected UPPIN or NERFIN", tokens); - return NULL; - } - if (!acceptToken(&tokens, TT_YR)) { - error("expected YR", tokens); - deleteIdentifierNode(name1); - return NULL; - } - var = parseIdentifierNode(&tokens); - if (!var) { - deleteIdentifierNode(name1); - return NULL; - } - else if (var->type != IT_DIRECT) { - error("expected variable name", tokens); - deleteIdentifierNode(name1); - return NULL; - } -#ifdef DEBUG - shiftout(); - debug("ET_CONSTANT (CT_INTEGER)"); - shiftin(); - shiftin(); -#endif - id = malloc(sizeof(char) * (strlen(var->id) + 1)); - strcpy(id, var->id); - varcopy = createIdentifierNode(IT_DIRECT, id, var->fname, var->line); - if (!varcopy) { - deleteIdentifierNode(name1); - deleteIdentifierNode(var); - return NULL; - } - arg1 = createExprNode(ET_IDENTIFIER, varcopy); - if (!arg1) { - deleteIdentifierNode(name1); - deleteIdentifierNode(var); - deleteIdentifierNode(varcopy); - return NULL; - } - one = createIntegerConstantNode(1); - if (!one) { - deleteIdentifierNode(name1); - deleteIdentifierNode(var); - deleteExprNode(arg1); - return NULL; - } - arg2 = createExprNode(ET_CONSTANT, one); - if (!arg2) { - deleteIdentifierNode(name1); - deleteIdentifierNode(var); - deleteExprNode(arg1); - deleteConstantNode(one); - return NULL; - } - args = createExprNodeList(); - if (!args) { - deleteIdentifierNode(name1); - deleteIdentifierNode(var); - deleteExprNode(arg1); - deleteExprNode(arg2); - return NULL; - } - if (!addExprNode(args, arg1)) { - deleteIdentifierNode(name1); - deleteIdentifierNode(var); - deleteExprNode(arg1); - deleteExprNode(arg2); - deleteExprNodeList(args); - return NULL; - } - if (!addExprNode(args, arg2)) { - deleteIdentifierNode(name1); - deleteIdentifierNode(var); - deleteExprNode(arg2); - deleteExprNodeList(args); - return NULL; - } - op = createOpExprNode(type, args); - if (!op) { - deleteIdentifierNode(name1); - deleteIdentifierNode(var); - deleteExprNodeList(args); - return NULL; - } - update = createExprNode(ET_OP, op); - if (!update) { - deleteIdentifierNode(name1); - deleteIdentifierNode(var); - deleteOpExprNode(op); - return NULL; - } - } - else if (nextToken(&tokens, TT_IZ)) { - IdentifierNode *scope = NULL; - IdentifierNode *name = NULL; - ExprNodeList *args = NULL; - FuncCallExprNode *node = NULL; - ExprNode *ret = NULL; - ExprNode *arg = NULL; - IdentifierNode *temp = NULL; - char *id = NULL; -#ifdef DEBUG - debug("ET_FUNCCALL"); -#endif - scope = parseIdentifierNode(&tokens); - if (!scope) return NULL; - acceptToken(&tokens, TT_IZ); /* Will succeed, checked for this above */ - name = parseIdentifierNode(&tokens); - if (!name) { - deleteIdentifierNode(scope); - return NULL; - } - args = createExprNodeList(); - /* Check for unary function */ - if (!acceptToken(&tokens, TT_YR)) { - error("expected unary function", tokens); - deleteIdentifierNode(name1); - deleteIdentifierNode(scope); - deleteIdentifierNode(name); - deleteExprNodeList(args); - return NULL; - } - arg = parseExprNode(&tokens); - if (!arg) { - deleteIdentifierNode(name1); - deleteIdentifierNode(scope); - deleteIdentifierNode(name); - deleteExprNodeList(args); - return NULL; - } - if (arg->type != ET_IDENTIFIER) { - error("expected identifier", tokens); - deleteExprNode(arg); - deleteIdentifierNode(name1); - deleteIdentifierNode(scope); - deleteIdentifierNode(name); - deleteExprNodeList(args); - return NULL; - } - if (!addExprNode(args, arg)) { - deleteExprNode(arg); - deleteIdentifierNode(name1); - deleteIdentifierNode(scope); - deleteIdentifierNode(name); - deleteExprNodeList(args); - return NULL; - } - temp = (IdentifierNode *)(arg->expr); - if (!temp || temp->type != IT_DIRECT) { - error("expected variable name", tokens); - deleteIdentifierNode(name1); - deleteIdentifierNode(scope); - deleteIdentifierNode(name); - deleteExprNodeList(args); - return NULL; - } - /* Copy the identifier to make it the loop variable */ - id = malloc(sizeof(char) * (strlen(temp->id) + 1)); - strcpy(id, temp->id); - var = createIdentifierNode(IT_DIRECT, id, temp->fname, temp->line); - if (!var) { - deleteIdentifierNode(name1); - deleteIdentifierNode(scope); - deleteIdentifierNode(name); - deleteExprNodeList(args); - return NULL; - } - /* Check for unary function */ - if (!acceptToken(&tokens, TT_MKAY)) { - error("expected MKAY", tokens); - deleteIdentifierNode(name1); - deleteIdentifierNode(scope); - deleteIdentifierNode(name); - deleteExprNodeList(args); - deleteIdentifierNode(var); - return NULL; - } - node = createFuncCallExprNode(scope, name, args); - if (!node) { - deleteIdentifierNode(name1); - deleteIdentifierNode(scope); - deleteIdentifierNode(name); - deleteExprNodeList(args); - deleteIdentifierNode(var); - return NULL; - } - update = createExprNode(ET_FUNCCALL, node); - if (!update) { - deleteFuncCallExprNode(node); - return NULL; - } - } - if (update) { - if (acceptToken(&tokens, TT_WILE)) { - guard = parseExprNode(&tokens); - if (!guard) { - deleteIdentifierNode(name1); - deleteExprNode(update); - return NULL; - } - } - else if (acceptToken(&tokens, TT_TIL)) { - ExprNode *arg = NULL; - ExprNodeList *args = NULL; - OpExprNode *op = NULL; -#ifdef DEBUG - shiftout(); - debug("ET_OP (OP_NOT)"); -#endif - arg = parseExprNode(&tokens); - if (!arg) { - deleteIdentifierNode(name1); - deleteExprNode(update); - return NULL; - } - args = createExprNodeList(); - if (!args) { - deleteIdentifierNode(name1); - deleteExprNode(update); - deleteExprNode(arg); - return NULL; - } - if(!addExprNode(args, arg)) { - deleteIdentifierNode(name1); - deleteExprNode(update); - deleteExprNode(arg); - deleteExprNodeList(args); - return NULL; - } -#ifdef DEBUG - shiftin(); -#endif - op = createOpExprNode(OP_NOT, args); - if (!op) { - deleteIdentifierNode(name1); - deleteExprNode(update); - deleteExprNodeList(args); - return NULL; - } - guard = createExprNode(ET_OP, op); - if (!guard) { - deleteIdentifierNode(name1); - deleteExprNode(update); - deleteOpExprNode(op); - return NULL; - } - } - } - if (!acceptToken(&tokens, TT_NEWLINE)) { - error("expected end of expression", tokens); - deleteIdentifierNode(name1); - if (update) deleteExprNode(update); - if (guard) deleteExprNode(guard); - return NULL; - } - body = parseBlockNode(&tokens); - if (!body) { - deleteIdentifierNode(name1); - if (update) deleteExprNode(update); - if (guard) deleteExprNode(guard); - return NULL; - } - if (!acceptToken(&tokens, TT_IMOUTTAYR)) { - error("expected IM OUTTA YR", tokens); - deleteIdentifierNode(name1); - if (update) deleteExprNode(update); - if (guard) deleteExprNode(guard); - deleteBlockNode(body); - return NULL; - } - name2 = parseIdentifierNode(&tokens); - if (!name2) { - deleteIdentifierNode(name1); - if (update) deleteExprNode(update); - if (guard) deleteExprNode(guard); - deleteBlockNode(body); - return NULL; - } - else if (name2->type != IT_DIRECT) { - error("expected loop name", tokens); - if (update) deleteExprNode(update); - if (guard) deleteExprNode(guard); - deleteBlockNode(body); - deleteIdentifierNode(name2); - return NULL; - } - if (strcmp((char *)name1->id, (char *)name2->id)) { - error("expected matching loop name", tokens); - deleteIdentifierNode(name1); - if (update) deleteExprNode(update); - if (guard) deleteExprNode(guard); - deleteBlockNode(body); - deleteIdentifierNode(name2); - return NULL; - } - deleteIdentifierNode(name2); - if (!acceptToken(&tokens, TT_NEWLINE)) { - error("expected end of expression", tokens); - deleteIdentifierNode(name1); - if (update) deleteExprNode(update); - if (guard) deleteExprNode(guard); - deleteBlockNode(body); - return NULL; - } - stmt = createLoopStmtNode(name1, var, guard, update, body); - if (!stmt) { - deleteIdentifierNode(name1); - if (update) deleteExprNode(update); - if (guard) deleteExprNode(guard); - deleteBlockNode(body); - return NULL; - } - ret = createStmtNode(ST_LOOP, stmt); - if (!ret) { - deleteLoopStmtNode(stmt); - return NULL; - } + else if (peekToken(&tokens, TT_IMINYR)) { + ret = parseLoopStmtNode(tokenp); } /* Function definition */ - else if (acceptToken(&tokens, TT_HOWIZ)) { - IdentifierNode *scope = NULL; - IdentifierNode *name = NULL; - IdentifierNodeList *args = NULL; - BlockNode *body; - FuncDefStmtNode *stmt = NULL; - scope = parseIdentifierNode(&tokens); - if (!scope) return NULL; - name = parseIdentifierNode(&tokens); - if (!name) { - deleteIdentifierNode(scope); - return NULL; - } - args = createIdentifierNodeList(); - if (!args) { - deleteIdentifierNode(scope); - deleteIdentifierNode(name); - } - if (acceptToken(&tokens, TT_YR)) { - IdentifierNode *arg = parseIdentifierNode(&tokens); - if (!arg) { - deleteIdentifierNode(scope); - deleteIdentifierNode(name); - deleteIdentifierNodeList(args); - return NULL; - } - if (!addIdentifierNode(args, arg)) { - deleteIdentifierNode(scope); - deleteIdentifierNode(name); - deleteIdentifierNodeList(args); - deleteIdentifierNode(arg); - return NULL; - } - while (acceptToken(&tokens, TT_ANYR)) { - arg = parseIdentifierNode(&tokens); - if (!arg) { - deleteIdentifierNode(scope); - deleteIdentifierNode(name); - deleteIdentifierNodeList(args); - return NULL; - } - if (!addIdentifierNode(args, arg)) { - deleteIdentifierNode(scope); - deleteIdentifierNode(name); - deleteIdentifierNodeList(args); - deleteIdentifierNode(arg); - return NULL; - } - } - } - if (!acceptToken(&tokens, TT_NEWLINE)) { - error("expected end of statement", tokens); - deleteIdentifierNode(scope); - deleteIdentifierNode(name); - deleteIdentifierNodeList(args); - return NULL; - } - body = parseBlockNode(&tokens); - if (!body) { - deleteIdentifierNode(scope); - deleteIdentifierNode(name); - deleteIdentifierNodeList(args); - return NULL; - } - if (!acceptToken(&tokens, TT_IFUSAYSO)) { - error("expected IF YOU SAY SO", tokens); - deleteIdentifierNode(scope); - deleteIdentifierNode(name); - deleteIdentifierNodeList(args); - deleteBlockNode(body); - return NULL; - } - if (!acceptToken(&tokens, TT_NEWLINE)) { - error("expected end of statement", tokens); - deleteIdentifierNode(scope); - deleteIdentifierNode(name); - deleteIdentifierNodeList(args); - deleteBlockNode(body); - return NULL; - } - stmt = createFuncDefStmtNode(scope, name, args, body); - if (!stmt) { - deleteIdentifierNode(scope); - deleteIdentifierNode(name); - deleteIdentifierNodeList(args); - deleteBlockNode(body); - return NULL; - } - ret = createStmtNode(ST_FUNCDEF, stmt); - if (!ret) { - deleteFuncDefStmtNode(stmt); - } + else if (peekToken(&tokens, TT_HOWIZ)) { + ret = parseFuncDefStmtNode(tokenp); } /* Bare expression */ else if ((expr = parseExprNode(&tokens))) { + int status; + #ifdef DEBUG debug("ST_EXPR"); #endif - if (!acceptToken(&tokens, TT_NEWLINE)) { - deleteExprNode(expr); + + /* The expression should appear on its own line */ + status = acceptToken(&tokens, TT_NEWLINE); + if (!status) { error("expected end of expression", tokens); + deleteExprNode(expr); return NULL; } + + /* Create the new StmtNode structure */ ret = createStmtNode(ST_EXPR, expr); + if (!ret) { + deleteExprNode(expr); + return NULL; + } + + /* Since we're successful, update the token stream */ + *tokenp = tokens; } - else error("expected statement", tokens); + else { + error("expected statement", tokens); + } + #ifdef DEBUG shiftin(); #endif - *tokenp = tokens; + return ret; } @@ -2979,7 +4022,7 @@ StmtNode *parseStmtNode(Token ***tokenp) /**< [in,out] A pointer to the position * token pointed to by \a tokenp. * * \pre \a tokenp points to a position in an array of tokens created by - * tokenizeLexemes(Lexeme **). + * tokenizeLexemes(LexemeList *). * * \post \a tokenp will point to the next \b unparsed token in the array. * @@ -2995,46 +4038,72 @@ StmtNode *parseStmtNode(Token ***tokenp) /**< [in,out] A pointer to the position * \see parseMainNode(Token **) */ BlockNode *parseBlockNode(Token ***tokenp) /**< [in,out] A pointer to the position of the next token to parse. */ { - Token **tokens = *tokenp; StmtNodeList *stmts = NULL; + StmtNode *stmt = NULL; BlockNode *block = NULL; + int status; + + /* Work from a copy of the token stream in case something goes wrong */ + Token **tokens = *tokenp; + #ifdef DEBUG shiftout(); debug(">ET_BLOCK"); #endif + + /* Create a list of statements */ stmts = createStmtNodeList(); - if (!stmts) return NULL; + if (!stmts) goto parseBlockNodeAbort; while (!peekToken(&tokens, TT_EOF) - && !peekToken(&tokens, TT_KTHXBYE) && !peekToken(&tokens, TT_OIC) - && !peekToken(&tokens, TT_YARLY) && !peekToken(&tokens, TT_NOWAI) - && !peekToken(&tokens, TT_MEBBE) && !peekToken(&tokens, TT_OMG) - && !peekToken(&tokens, TT_OMGWTF) && !peekToken(&tokens, TT_IMOUTTAYR) + && !peekToken(&tokens, TT_KTHXBYE) + && !peekToken(&tokens, TT_OIC) + && !peekToken(&tokens, TT_YARLY) + && !peekToken(&tokens, TT_NOWAI) + && !peekToken(&tokens, TT_MEBBE) + && !peekToken(&tokens, TT_OMG) + && !peekToken(&tokens, TT_OMGWTF) + && !peekToken(&tokens, TT_IMOUTTAYR) && !peekToken(&tokens, TT_IFUSAYSO)) { - StmtNode *s = parseStmtNode(&tokens); - if (!s) { - deleteStmtNodeList(stmts); - return NULL; - } - addStmtNode(stmts, s); + /* Parse the next statement */ + stmt = parseStmtNode(&tokens); + if (!stmt) goto parseBlockNodeAbort; + + /* Add the statement to the list */ + status = addStmtNode(stmts, stmt); + if (!status) goto parseBlockNodeAbort; + stmt = NULL; } + #ifdef DEBUG debug(" #include #include +#include +#include #include "tokenizer.h" @@ -535,7 +537,7 @@ void deleteMainNode(MainNode *); BlockNode *createBlockNode(StmtNodeList *); void deleteBlockNode(BlockNode *); BlockNodeList *createBlockNodeList(void); -BlockNode *addBlockNode(BlockNodeList *, BlockNode *); +int addBlockNode(BlockNodeList *, BlockNode *); void deleteBlockNodeList(BlockNodeList *); IdentifierNode *createIdentifierNode(IdentifierType, void *, const char *, unsigned int); @@ -547,7 +549,7 @@ void deleteTypeNode(TypeNode *); StmtNode *createStmtNode(StmtType, void *); void deleteStmtNode(StmtNode *); StmtNodeList *createStmtNodeList(void); -StmtNode *addStmtNode(StmtNodeList *, StmtNode *); +int addStmtNode(StmtNodeList *, StmtNode *); void deleteStmtNodeList(StmtNodeList *); CastStmtNode *createCastStmtNode(IdentifierNode *, TypeNode *); @@ -586,7 +588,7 @@ void deleteFuncDefStmtNode(FuncDefStmtNode *); ExprNode *createExprNode(ExprType, void *); void deleteExprNode(ExprNode *); ExprNodeList *createExprNodeList(void); -ExprNode *addExprNode(ExprNodeList *, ExprNode *); +int addExprNode(ExprNodeList *, ExprNode *); void deleteExprNodeList(ExprNodeList *); CastExprNode *createCastExprNode(ExprNode *, TypeNode *); @@ -612,6 +614,25 @@ StmtNode *parseStmtNode(Token ***); BlockNode *parseBlockNode(Token ***); MainNode *parseMainNode(Token **); +ExprNode *parseCastExprNode(Token ***); +ExprNode *parseConstantExprNode(Token ***); +ExprNode *parseIdentifierExprNode(Token ***); +ExprNode *parseFuncCallExprNode(Token ***); +ExprNode *parseOpExprNode(Token ***); + +StmtNode *parseCastStmtNode(Token ***); +StmtNode *parsePrintStmtNode(Token ***); +StmtNode *parseInputStmtNode(Token ***); +StmtNode *parseAssignmentStmtNode(Token ***); +StmtNode *parseDeclarationStmtNode(Token ***); +StmtNode *parseIfThenElseStmtNode(Token ***); +StmtNode *parseSwitchStmtNode(Token ***); +StmtNode *parseBreakStmtNode(Token ***); +StmtNode *parseReturnStmtNode(Token ***); +StmtNode *parseLoopStmtNode(Token ***); +StmtNode *parseDeallocationStmtNode(Token ***); +StmtNode *parseFuncDefStmtNode(Token ***); + ConstantNode *createBooleanConstantNode(int); ConstantNode *createIntegerConstantNode(int); ConstantNode *createFloatConstantNode(float); @@ -619,7 +640,7 @@ ConstantNode *createStringConstantNode(char *); void deleteConstantNode(ConstantNode *); IdentifierNodeList *createIdentifierNodeList(void); -IdentifierNode *addIdentifierNode(IdentifierNodeList *, IdentifierNode *); +int addIdentifierNode(IdentifierNodeList *, IdentifierNode *); void deleteIdentifierNodeList(IdentifierNodeList *); #endif /* __PARSER_H__ */ diff --git a/test/1.3-Tests/1-Structure/17-Includes/test.lol b/test/1.3-Tests/1-Structure/17-Includes/test.lol new file mode 100644 index 0000000..3e93008 --- /dev/null +++ b/test/1.3-Tests/1-Structure/17-Includes/test.lol @@ -0,0 +1,3 @@ +HAI 1.3 + CAN HAS STDIO? +KTHXBYE diff --git a/test/1.3-Tests/1-Structure/17-Includes/test.out b/test/1.3-Tests/1-Structure/17-Includes/test.out new file mode 100644 index 0000000..e69de29 diff --git a/test/1.3-Tests/1-Structure/17-Includes/test.readme b/test/1.3-Tests/1-Structure/17-Includes/test.readme new file mode 100644 index 0000000..b5e9d3e --- /dev/null +++ b/test/1.3-Tests/1-Structure/17-Includes/test.readme @@ -0,0 +1 @@ +This test checks that the include statement ``CAN HAS STDIO?'' is ignored. diff --git a/tokenizer.c b/tokenizer.c index b592e6d..e1dbf79 100644 --- a/tokenizer.c +++ b/tokenizer.c @@ -1,5 +1,75 @@ #include "tokenizer.h" +static const char *keywords[] = { + "", /* TT_INTEGER */ + "", /* TT_FLOAT */ + "", /* TT_STRING */ + "", /* TT_IDENTIFIER */ + "", /* TT_BOOLEAN */ + "IT", /* TT_IT */ + "NOOB", /* TT_NOOB */ + "NUMBR", /* TT_NUMBR */ + "NUMBAR", /* TT_NUMBAR */ + "TROOF", /* TT_TROOF */ + "YARN", /* TT_YARN */ + "", /* TT_EOF */ + "", /* TT_NEWLINE */ + "HAI", /* TT_HAI */ + "KTHXBYE", /* TT_KTHXBYE */ + "HAS A", /* TT_HASA */ + "ITZ A", /* TT_ITZA */ + "ITZ", /* TT_ITZ */ + "R NOOB", /* TT_RNOOB */ + "R", /* TT_R */ + "AN YR", /* TT_ANYR */ + "AN", /* TT_AN */ + "SUM OF", /* TT_SUMOF */ + "DIFF OF", /* TT_DIFFOF */ + "PRODUKT OF", /* TT_PRODUKTOF */ + "QUOSHUNT OF", /* TT_QUOSHUNTOF */ + "MOD OF", /* TT_MODOF */ + "BIGGR OF", /* TT_BIGGROF */ + "SMALLR OF", /* TT_SMALLROF */ + "BOTH OF", /* TT_BOTHOF */ + "EITHER OF", /* TT_EITHEROF */ + "WON OF", /* TT_WONOF */ + "NOT", /* TT_NOT */ + "MKAY", /* TT_MKAY */ + "ALL OF", /* TT_ALLOF */ + "ANY OF", /* TT_ANYOF */ + "BOTH SAEM", /* TT_BOTHSAEM */ + "DIFFRINT", /* TT_DIFFRINT */ + "MAEK", /* TT_MAEK */ + "A", /* TT_A */ + "IS NOW A", /* TT_ISNOWA */ + "VISIBLE", /* TT_VISIBLE */ + "SMOOSH", /* TT_SMOOSH */ + "!", /* TT_BANG */ + "GIMMEH", /* TT_GIMMEH */ + "O RLY?", /* TT_ORLY */ + "YA RLY", /* TT_YARLY */ + "MEBBE", /* TT_MEBBE */ + "NO WAI", /* TT_NOWAI */ + "OIC", /* TT_OIC */ + "WTF?", /* TT_WTF */ + "OMG", /* TT_OMG */ + "OMGWTF", /* TT_OMGWTF */ + "GTFO", /* TT_GTFO */ + "IM IN YR", /* TT_IMINYR */ + "UPPIN", /* TT_UPPIN */ + "NERFIN", /* TT_NERFIN */ + "YR", /* TT_YR */ + "TIL", /* TT_TIL */ + "WILE", /* TT_WILE */ + "IM OUTTA YR", /* TT_IMOUTTAYR */ + "HOW IZ", /* TT_HOWIZ */ + "IZ", /* TT_IZ */ + "IF U SAY SO", /* TT_IFUSAYSO */ + "FOUND YR", /* TT_FOUNDYR */ + "SRS", /* TT_SRS */ + "" /* TT_ENDOFTOKENS */ +}; + /** Checks if a string of characters follows the format for an integer. * Specifically, it checks if the string of characters matches the regular * expression: [-]?[1-9][0-9]* | 0 @@ -80,11 +150,6 @@ int isIdentifier(const char *image) /**< [in] The string of characters to compar cur++; while (*cur) { if (isalnum(*cur) || *cur == '_') cur++; - /* Proposed LOLCODE Version 1.3 identifiers - * Remember to update expression: [a-zA-Z][a-zA-Z0-9]*([!!|!?][a-zA-Z][a-zA-Z0-9]*)* - else if (*cur == '!' && *(cur + 1) && *(cur + 1) == '!') cur += 2; - else if (*cur == '!' && *(cur + 1) && *(cur + 1) == '?') cur += 2; - */ else return 0; } return 1; @@ -145,20 +210,19 @@ void deleteToken(Token *token) * \post \a token will be added on to the end of \a list and the value at \a num * will be updated accordingly. * - * \return A pointer to the added Token structure (will be the same as \a token). - * - * \retval NULL realloc was unable to allocate memory. + * \retval 0 realloc was unable to allocate memory. + * \retval 1 \a node was added to \a list. * * \see deleteTokens(Token **) */ -Token *addToken(Token ***list, /**< [in,out] A pointer to a pointer to an array of Token structures to add the new Token onto. */ - unsigned int *num, /**< [in,out] A pointer to the number of elements in \a list. */ - Token *token) /**< [in] A pointer to the Token structure to add to \a list. */ +int addToken(Token ***list, /**< [in,out] A pointer to a pointer to an array of Token structures to add the new Token onto. */ + unsigned int *num, /**< [in,out] A pointer to the number of elements in \a list. */ + Token *token) /**< [in] A pointer to the Token structure to add to \a list. */ { unsigned int newsize = *num + 1; void *mem = realloc(*list, sizeof(Token *) * newsize); if (!mem) { perror("realloc"); - return NULL; + return 0; } *list = mem; (*list)[*num] = token; @@ -166,7 +230,7 @@ Token *addToken(Token ***list, /**< [in,out] A pointer to a pointer to an ar #ifdef DEBUG fprintf(stderr, "Adding token type %d [%s]\n", token->type, token->image); #endif - return token; + return 1; } /** Deletes an array of Token structures. @@ -199,14 +263,15 @@ unsigned int acceptLexemes(LexemeList *lexemes, /**< [in] A pointer to a LexemeL unsigned int offset = 0; unsigned int n; unsigned int i; - for (n = 0, i = 0; match[n] || lexemes->lexemes[start + offset]->image[i]; n++, i++) { + for (n = 0, i = 0; match[n] || lexemes->lexemes[start + offset]->image[i]; n++) { if (match[n] == ' ') { offset++; - i = -1; + i = 0; continue; } if (lexemes->lexemes[start + offset]->image[i] != match[n]) return 0; + i++; } return offset + 1; } @@ -234,7 +299,7 @@ Token *isKeyword(LexemeList *lexemes, /**< [in] A pointer to a LexemeList struct const char *fname = lexemes->lexemes[*start]->fname; unsigned int line = lexemes->lexemes[*start]->line; for (type = 0; type != TT_ENDOFTOKENS; type++) { - int num = acceptLexemes(lexemes, *start, keywords[type]); + unsigned int num = acceptLexemes(lexemes, *start, keywords[type]); if (!num) continue; token = createToken(type, keywords[type], fname, line); *start += (num - 1); @@ -272,12 +337,16 @@ Token **tokenizeLexemes(LexemeList *list) /**< [in] A pointer to a LexemeList st /* Float */ else if (isFloat(image)) { token = createToken(TT_FLOAT, image, fname, line); - sscanf(lexeme->image, "%f", &(token->data.f)); + if (sscanf(lexeme->image, "%f", &(token->data.f)) != 1) { + fprintf(stderr, "Expected floating point decimal value.\n"); + } } /* Integer */ else if (isInteger(image)) { token = createToken(TT_INTEGER, image, fname, line); - sscanf(lexeme->image, "%i", &(token->data.i)); + if (sscanf(lexeme->image, "%i", &(token->data.i)) != 1) { + fprintf(stderr, "Expected integer value.\n"); + } } /* FAIL */ else if (!strcmp(image, "FAIL")) { @@ -333,14 +402,23 @@ Token **tokenizeLexemes(LexemeList *list) /**< [in] A pointer to a LexemeList st token = createToken(TT_EOF, "end of file", fname, line); } else { - fprintf(stderr, "%s:%d: unknown token at: %s\n", fname, line, image); + fprintf(stderr, "%s:%u: unknown token at: %s\n", fname, line, image); /* Clean up */ deleteToken(ret[retsize - 1]); ret[retsize - 1] = NULL; deleteTokens(ret); return NULL; } - addToken(&ret, &retsize, token); + + /* Add the token to the token array */ + if (!addToken(&ret, &retsize, token)) { + /* Clean up */ + if (token) deleteToken(token); + deleteToken(ret[retsize - 1]); + ret[retsize - 1] = NULL; + deleteTokens(ret); + return NULL; + } } mem = realloc(ret, sizeof(Token *) * ++retsize); if (!mem) { diff --git a/tokenizer.h b/tokenizer.h index 075aabe..ab1e2f6 100644 --- a/tokenizer.h +++ b/tokenizer.h @@ -24,7 +24,9 @@ /** Denotes the type of token present. All of the token type names are * self-explainatory and correspond to either the semantic type of token data * (in the case of TT_INTEGER, TT_FLOAT, TT_STRING, or TT_IDENTIFIER) or the - * lexemes which make up the particular token. */ + * lexemes which make up the particular token. + * + * \note Remember to update the keywords array with the token image. */ typedef enum { TT_INTEGER, TT_FLOAT, @@ -95,76 +97,6 @@ typedef enum { TT_ENDOFTOKENS } TokenType; -static const char *keywords[] = { - "", /* TT_INTEGER */ - "", /* TT_FLOAT */ - "", /* TT_STRING */ - "", /* TT_IDENTIFIER */ - "", /* TT_BOOLEAN */ - "IT", /* TT_IT */ - "NOOB", /* TT_NOOB */ - "NUMBR", /* TT_NUMBR */ - "NUMBAR", /* TT_NUMBAR */ - "TROOF", /* TT_TROOF */ - "YARN", /* TT_YARN */ - "", /* TT_EOF */ - "", /* TT_NEWLINE */ - "HAI", /* TT_HAI */ - "KTHXBYE", /* TT_KTHXBYE */ - "HAS A", /* TT_HASA */ - "ITZ A", /* TT_ITZA */ - "ITZ", /* TT_ITZ */ - "R NOOB", /* TT_RNOOB */ - "R", /* TT_R */ - "AN YR", /* TT_ANYR */ - "AN", /* TT_AN */ - "SUM OF", /* TT_SUMOF */ - "DIFF OF", /* TT_DIFFOF */ - "PRODUKT OF", /* TT_PRODUKTOF */ - "QUOSHUNT OF", /* TT_QUOSHUNTOF */ - "MOD OF", /* TT_MODOF */ - "BIGGR OF", /* TT_BIGGROF */ - "SMALLR OF", /* TT_SMALLROF */ - "BOTH OF", /* TT_BOTHOF */ - "EITHER OF", /* TT_EITHEROF */ - "WON OF", /* TT_WONOF */ - "NOT", /* TT_NOT */ - "MKAY", /* TT_MKAY */ - "ALL OF", /* TT_ALLOF */ - "ANY OF", /* TT_ANYOF */ - "BOTH SAEM", /* TT_BOTHSAEM */ - "DIFFRINT", /* TT_DIFFRINT */ - "MAEK", /* TT_MAEK */ - "A", /* TT_A */ - "IS NOW A", /* TT_ISNOWA */ - "VISIBLE", /* TT_VISIBLE */ - "SMOOSH", /* TT_SMOOSH */ - "!", /* TT_BANG */ - "GIMMEH", /* TT_GIMMEH */ - "O RLY?", /* TT_ORLY */ - "YA RLY", /* TT_YARLY */ - "MEBBE", /* TT_MEBBE */ - "NO WAI", /* TT_NOWAI */ - "OIC", /* TT_OIC */ - "WTF?", /* TT_WTF */ - "OMG", /* TT_OMG */ - "OMGWTF", /* TT_OMGWTF */ - "GTFO", /* TT_GTFO */ - "IM IN YR", /* TT_IMINYR */ - "UPPIN", /* TT_UPPIN */ - "NERFIN", /* TT_NERFIN */ - "YR", /* TT_YR */ - "TIL", /* TT_TIL */ - "WILE", /* TT_WILE */ - "IM OUTTA YR", /* TT_IMOUTTAYR */ - "HOW IZ", /* TT_HOWIZ */ - "IZ", /* TT_IZ */ - "IF U SAY SO", /* TT_IFUSAYSO */ - "FOUND YR", /* TT_FOUNDYR */ - "SRS", /* TT_SRS */ - "", /* TT_ENDOFTOKENS */ -}; - /** Stores the data associated with a Token structure. */ typedef union { int i; /**< Integer data. */ @@ -186,7 +118,7 @@ int isString(const char *); int isIdentifier(const char *); Token *createToken(TokenType, const char *, const char *, unsigned int); void deleteToken(Token *); -Token *addToken(Token ***, unsigned int *, Token*); +int addToken(Token ***, unsigned int *, Token*); void deleteTokens(Token **); unsigned int acceptLexemes(LexemeList *, unsigned int, const char *); Token *isKeyword(LexemeList *, unsigned int *); diff --git a/unicode.c b/unicode.c index e324ad3..a9b8369 100644 --- a/unicode.c +++ b/unicode.c @@ -36870,7 +36870,7 @@ int binarySearch(const char **strings, /**< [in] A pointer to an array of charac int end, /**< [in] The end of the range to search through. */ const char *find) /**< [in] The entry to search for. */ { - unsigned int midpoint; + int midpoint; int cmp; if (end < start) return -1; midpoint = ((end - start) / 2) + start; @@ -36906,8 +36906,8 @@ long convertNormativeNameToCodePoint(const char *name) /**< [in] A pointer to a * \return The number of characters in the converted multi-byte character. * * \retval 0 An invalid Unicode code point was supplied. */ -unsigned int convertCodePointToUTF8(long codepoint, /**< [in] The Unicode code point to convert to UTF-8. */ - char *out) /**< [out] A pointer to the location to store the resulting UTF-8 bytes. */ +size_t convertCodePointToUTF8(unsigned long codepoint, /**< [in] The Unicode code point to convert to UTF-8. */ + char *out) /**< [out] A pointer to the location to store the resulting UTF-8 bytes. */ { /* Out of range */ if (codepoint > 0x10FFFF) { @@ -36916,36 +36916,36 @@ unsigned int convertCodePointToUTF8(long codepoint, /**< [in] The Unicode code p } /* U+010000 to U+10FFFF */ else if (codepoint >= 0x010000) { - char x1 = codepoint & 0x003F; - char x2 = (codepoint & 0x00C0) >> 6; - char y1 = (codepoint & 0x0F00) >> 8; - char y2 = (codepoint & 0xF000) >> 12; - char z1 = (codepoint & 0x30000) >> 16; - char z2 = (codepoint & 0x1C0000) >> 18; - out[0] = 0xF0 | z2; - out[1] = 0x80 | (z1 << 4) | y2; - out[2] = 0x80 | (y1 << 2) | x2; - out[3] = 0x80 | x1; + char x1 = (char)(codepoint & 0x003F); + char x2 = (char)((codepoint & 0x00C0) >> 6); + char y1 = (char)((codepoint & 0x0F00) >> 8); + char y2 = (char)((codepoint & 0xF000) >> 12); + char z1 = (char)((codepoint & 0x30000) >> 16); + char z2 = (char)((codepoint & 0x1C0000) >> 18); + out[0] = (char)(0xF0 | z2); + out[1] = (char)(0x80 | (z1 << 4) | y2); + out[2] = (char)(0x80 | (y1 << 2) | x2); + out[3] = (char)(0x80 | x1); return 4; } /* U+0800 to U+FFFF */ else if (codepoint >= 0x0800) { - char x1 = codepoint & 0x003F; - char x2 = (codepoint & 0x00C0) >> 6; - char y1 = (codepoint & 0x0F00) >> 8; - char y2 = (codepoint & 0xF000) >> 12; - out[0] = 0xE0 | y2; - out[1] = 0x80 | (y1 << 2) | x2; - out[2] = 0x80 | x1; + char x1 = (char)(codepoint & 0x003F); + char x2 = (char)((codepoint & 0x00C0) >> 6); + char y1 = (char)((codepoint & 0x0F00) >> 8); + char y2 = (char)((codepoint & 0xF000) >> 12); + out[0] = (char)(0xE0 | y2); + out[1] = (char)(0x80 | (y1 << 2) | x2); + out[2] = (char)(0x80 | x1); return 3; } /* U+0080 to U+07FF */ else if (codepoint & 0x0080) { - char x1 = codepoint & 0x3F; - char x2 = (codepoint & 0x00C0) >> 6; - char y = (codepoint & 0x0700) >> 8; - out[0] = 0xC0 | (y << 2) | x2; - out[1] = 0x80 | x1; + char x1 = (char)(codepoint & 0x3F); + char x2 = (char)((codepoint & 0x00C0) >> 6); + char y = (char)((codepoint & 0x0700) >> 8); + out[0] = (char)(0xC0 | (y << 2) | x2); + out[1] = (char)(0x80 | x1); return 2; } /* U+0080 to U+07FF */ diff --git a/unicode.h b/unicode.h index 144f73a..a092379 100644 --- a/unicode.h +++ b/unicode.h @@ -1,5 +1,5 @@ /** Data and functions for converting from Unicode normative names to - * codepoints. + * code points. * * \file unicode.h * @@ -15,6 +15,6 @@ int binarySearch(const char **, int, int, const char *); long convertNormativeNameToCodePoint(const char *); -unsigned int convertCodePointToUTF8(long, char *); +size_t convertCodePointToUTF8(unsigned long, char *); #endif /* __UNICODE_H_ */