From 5337b65513840456a94b1ce186b1178c4aec66a0 Mon Sep 17 00:00:00 2001 From: Justin Meza Date: Sun, 24 Feb 2013 15:44:33 -0500 Subject: [PATCH] cleaning up binding code --- binding.c | 102 ++++++++++++++++++++++++++++++------------- binding.h | 25 ++--------- interpreter.c | 31 ++++++++++--- interpreter.h | 2 + lexer.c | 17 ++++++++ parser.c | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++ parser.h | 21 ++++++++- tokenizer.c | 9 ---- tokenizer.h | 4 ++ 9 files changed, 262 insertions(+), 67 deletions(-) diff --git a/binding.c b/binding.c index a36c489..0e7826b 100644 --- a/binding.c +++ b/binding.c @@ -3,28 +3,33 @@ struct returnobject; struct scopeobject; +ValueObject *getArg(struct scopeobject *scope, char *name) +{ + IdentifierNode *id = createIdentifierNode(IT_DIRECT, (void *)copyString(name), NULL, NULL, 0); + ValueObject *val = getScopeValueLocal(scope, scope, id); + deleteIdentifierNode(id); + return val; +} + struct returnobject *fopenWrapper(struct scopeobject *scope) { - IdentifierNode *id1 = createIdentifierNode(IT_DIRECT, (void *)copyString("filename"), NULL, NULL, 0); - ValueObject *val1 = getScopeValueLocal(scope, scope, id1); - IdentifierNode *id2 = createIdentifierNode(IT_DIRECT, (void *)copyString("mode"), NULL, NULL, 0); - ValueObject *val2 = getScopeValueLocal(scope, scope, id2); - char *filename = getString(val1); - char *mode = getString(val2); + ValueObject *arg1 = getArg(scope, "filename"); + ValueObject *arg2 = getArg(scope, "mode"); + char *filename = getString(arg1); + char *mode = getString(arg2); FILE *f = fopen(filename, mode); + ValueObject *ret = createBlobValueObject(f); return createReturnObject(RT_RETURN, ret); } struct returnobject *freadWrapper(struct scopeobject *scope) { - IdentifierNode *id1 = createIdentifierNode(IT_DIRECT, (void *)copyString("file"), NULL, NULL, 0); - ValueObject *val1 = getScopeValueLocal(scope, scope, id1); - IdentifierNode *id2 = createIdentifierNode(IT_DIRECT, (void *)copyString("length"), NULL, NULL, 0); - ValueObject *val2 = getScopeValueLocal(scope, scope, id2); - FILE *file = (FILE *)getBlob(val1); - int length = getInteger(val2); + ValueObject *arg1 = getArg(scope, "file"); + ValueObject *arg2 = getArg(scope, "length"); + FILE *file = (FILE *)getBlob(arg1); + int length = getInteger(arg2); char *buf = malloc((sizeof(char) * length) + 1); fread(buf, 1, length, file); @@ -36,46 +41,83 @@ struct returnobject *freadWrapper(struct scopeobject *scope) struct returnobject *fcloseWrapper(struct scopeobject *scope) { - IdentifierNode *id1 = createIdentifierNode(IT_DIRECT, (void *)copyString("file"), NULL, NULL, 0); - ValueObject *val1 = getScopeValueLocal(scope, scope, id1); - FILE *file = (FILE *)getBlob(val1); + ValueObject *arg1 = getArg(scope, "file"); + FILE *file = (FILE *)getBlob(arg1); fclose(file); + deleteValueObject(arg1); + return createReturnObject(RT_DEFAULT, NULL); } -void loadBinding(ScopeObject *scope) +void loadLibrary(ScopeObject *scope, IdentifierNode *name) +{ + /* TODO: make this select which library to load */ + + /* stdio */ + ScopeObject *lib = createScopeObject(scope); + IdentifierNode* id = createIdentifierNode(IT_DIRECT, (void *)copyString("STDIO"), NULL, NULL, 0); + createScopeValue(scope, scope, id); + ValueObject *val = createArrayValueObject(lib); + updateScopeValue(scope, scope, id, val); + loadBinding(lib, "FOPENIN", "filename mode", &fopenWrapper); + loadBinding(lib, "FREADIN", "file length", &freadWrapper); + loadBinding(lib, "FCLOSIN", "file", &fcloseWrapper); +} + +void loadBinding(ScopeObject *scope, char *name, const char *args, struct returnobject *(*binding)(struct scopeobject *)) { /* TODO: add error checking and handling */ - /* stdio */ - ScopeObject *stdio = createScopeObject(scope); - IdentifierNode* name_stdio = createIdentifierNode(IT_DIRECT, (void *)copyString("STDIO"), NULL, NULL, 0); - createScopeValue(scope, scope, name_stdio); - ValueObject *val_stdio = createArrayValueObject(stdio); - updateScopeValue(scope, scope, name_stdio, val_stdio); + IdentifierNode* id = createIdentifierNode(IT_DIRECT, (void *)copyString(name), NULL, NULL, 0); + StmtNodeList *stmts = createStmtNodeList(); + BindingStmtNode *stmt = createBindingStmtNode(binding); + StmtNode *wrapper = createStmtNode(ST_BINDING, stmt); + addStmtNode(stmts, wrapper); + BlockNode *body = createBlockNode(stmts); + + IdentifierNodeList *ids = createIdentifierNodeList(); + const char *start = args; + while (start != NULL) { + char *end = strchr(start, ' '); + char *temp = NULL; + unsigned int len = 0; + if (end != NULL) len = (end - start); + else len = strlen(start); + temp = malloc(sizeof(char) * (len + 1)); + strncpy(temp, start, len); + temp[len] = '\0'; + if (end != NULL) start = (end + 1); + else start = NULL; + IdentifierNode *arg = createIdentifierNode(IT_DIRECT, (void *)temp, NULL, NULL, 0); + addIdentifierNode(ids, arg); + } + + FuncDefStmtNode *interface = createFuncDefStmtNode(NULL, id, ids, body); + ValueObject *val = createFunctionValueObject(interface); + createScopeValue(scope, scope, id); + updateScopeValue(scope, scope, id, val); + return; /* fopen */ + /* { IdentifierNode* name = createIdentifierNode(IT_DIRECT, (void *)copyString("FOPENIN"), NULL, NULL, 0); - IdentifierNodeList *args = createIdentifierNodeList(); - IdentifierNode *filename = createIdentifierNode(IT_DIRECT, (void *)copyString("filename"), NULL, NULL, 0); - IdentifierNode *mode = createIdentifierNode(IT_DIRECT, (void *)copyString("mode"), NULL, NULL, 0); - addIdentifierNode(args, filename); - addIdentifierNode(args, mode); StmtNodeList *stmts = createStmtNodeList(); BindingStmtNode *binding = createBindingStmtNode(&fopenWrapper); StmtNode *wrapper = createStmtNode(ST_BINDING, binding); addStmtNode(stmts, wrapper); BlockNode *body = createBlockNode(stmts); - /* TODO: should this first parameter be NULL? */ + FuncDefStmtNode *interface = createFuncDefStmtNode(NULL, name, args, body); ValueObject *val = createFunctionValueObject(interface); createScopeValue(stdio, stdio, name); updateScopeValue(stdio, stdio, name, val); } + */ /* fread */ + /* { IdentifierNode* name = createIdentifierNode(IT_DIRECT, (void *)copyString("FREADIN"), NULL, NULL, 0); IdentifierNodeList *args = createIdentifierNodeList(); @@ -88,14 +130,15 @@ void loadBinding(ScopeObject *scope) StmtNode *wrapper = createStmtNode(ST_BINDING, binding); addStmtNode(stmts, wrapper); BlockNode *body = createBlockNode(stmts); - /* TODO: should this first parameter be NULL? */ FuncDefStmtNode *interface = createFuncDefStmtNode(NULL, name, args, body); ValueObject *val = createFunctionValueObject(interface); createScopeValue(stdio, stdio, name); updateScopeValue(stdio, stdio, name, val); } + */ /* fclose */ + /* { IdentifierNode* name = createIdentifierNode(IT_DIRECT, (void *)copyString("FCLOSIN"), NULL, NULL, 0); IdentifierNodeList *args = createIdentifierNodeList(); @@ -111,6 +154,7 @@ void loadBinding(ScopeObject *scope) createScopeValue(stdio, stdio, name); updateScopeValue(stdio, stdio, name, val); } + */ return; diff --git a/binding.h b/binding.h index 50936a9..eb2ac78 100644 --- a/binding.h +++ b/binding.h @@ -23,27 +23,8 @@ typedef struct { FuncDefStmtNode *interface; /**< The interface that exports the binding. */ } Binding; -void loadBinding(ScopeObject *); /* TODO: make this take an IdentifierNode library to load */ - -/** - * TODO: - * - At startup, check which bindings are imported (using "CAN HAS" syntax) - * - Package those bindings as VT_FUNCs in BUKKITs - * - Add those bindings to the top-level scope (maybe create a new, - * higher-than-global scope for this) - * - To implement a new binding, specify the interface, which will contain a - * BlockNode that contains a StmtListNode with one statement: a - * BindingStmtNode that implements a native function that modifies directly - * the scope. - * - Binding creation/deletion helper functions. - - IdentifierNode *scope = ??? what goes here again?; - IdentifierNode *name = createIdentifierNode("FileOpen"); - IdentifierNodeList *args = ... add these ... - BlockNode *block = ... block with appropriate BindingStmtNode ... - FuncDefStmtNode *def = createFuncDefStmtNode(); - Binding *binding = createBinding("STDIO", def); - -*/ +ValueObject *getArg(struct scopeobject *, char *); +void loadLibrary(ScopeObject *, IdentifierNode *); +void loadBinding(ScopeObject *, char *, const char *, struct returnobject *(*)(struct scopeobject *)); #endif /* __BINDING_H__ */ diff --git a/interpreter.c b/interpreter.c index 7ca6062..0f67529 100644 --- a/interpreter.c +++ b/interpreter.c @@ -3683,11 +3683,32 @@ ReturnObject *interpretBindingStmtNode(StmtNode *node, return (stmt->binding)(scope); } +/** + * Interprets a library import statement. + * + * \param [in] node The statement to interpret. + * + * \param [in] scope The scope to evaluate \a node under. + * + * \pre \a node contains a statement created by createImportStmtNode(). + * + * \return A pointer to a default return value. + * + * \retval NULL An error occurred during interpretation. + */ +ReturnObject *interpretImportStmtNode(StmtNode *node, + ScopeObject *scope) +{ + ImportStmtNode *stmt = (ImportStmtNode *)node->stmt; + loadLibrary(scope, stmt->name); + return createReturnObject(RT_DEFAULT, NULL); +} + /* * A jump table for statements. The index of a function in the table is given * by its its index in the enumerated StmtType type. */ -static ReturnObject *(*StmtJumpTable[15])(StmtNode *, ScopeObject *) = { +static ReturnObject *(*StmtJumpTable[16])(StmtNode *, ScopeObject *) = { interpretCastStmtNode, interpretPrintStmtNode, interpretInputStmtNode, @@ -3702,7 +3723,8 @@ static ReturnObject *(*StmtJumpTable[15])(StmtNode *, ScopeObject *) = { interpretFuncDefStmtNode, interpretExprStmtNode, interpretAltArrayDefStmtNode, - interpretBindingStmtNode }; + interpretBindingStmtNode, + interpretImportStmtNode }; /** * Interprets a statement. @@ -3798,10 +3820,7 @@ int interpretMainNode(MainNode *main) { ReturnObject *ret = NULL; if (!main) return 1; - ScopeObject *libs = createScopeObject(NULL); - if (!libs) return 1; - loadBinding(libs); - ret = interpretBlockNode(main->block, libs); + ret = interpretBlockNode(main->block, NULL); if (!ret) return 1; deleteReturnObject(ret); return 0; diff --git a/interpreter.h b/interpreter.h index 18d577a..bc5abad 100644 --- a/interpreter.h +++ b/interpreter.h @@ -260,6 +260,8 @@ ReturnObject *interpretDeallocationStmtNode(StmtNode *, ScopeObject *); ReturnObject *interpretFuncDefStmtNode(StmtNode *, ScopeObject *); ReturnObject *interpretExprStmtNode(StmtNode *, ScopeObject *); ReturnObject *interpretAltArrayDefStmtNode(StmtNode *, ScopeObject *); +ReturnObject *interpretBindingStmtNode(StmtNode *, ScopeObject *); +ReturnObject *interpretImportStmtNode(StmtNode *, ScopeObject *); /**@}*/ /** diff --git a/lexer.c b/lexer.c index 8f8b41e..bcba2eb 100644 --- a/lexer.c +++ b/lexer.c @@ -198,6 +198,21 @@ LexemeList *scanBuffer(const char *buffer, unsigned int size, const char *fname) start += 2; continue; } + /* Question mark (?) is its own lexeme */ + if (*start == '?') { + Lexeme *lex = createLexeme("?", fname, line); + if (!lex) { + deleteLexemeList(list); + return NULL; + } + if (!addLexeme(list, lex)) { + deleteLexeme(lex); + deleteLexemeList(list); + return NULL; + } + start++; + continue; + } /* Skip over leading whitespace */ while (isspace(*start)) { unsigned int newline = 0; @@ -292,6 +307,7 @@ LexemeList *scanBuffer(const char *buffer, unsigned int size, const char *fname) if (start[len] && !isspace(start[len]) && *(start + len) != ',' && *(start + len) != '!' + && *(start + len) != '?' && strncmp(start + len, "'Z", 2) && strncmp(start + len, "...", 3) && strncmp(start + len, "\xE2\x80\xA6", 3)) { @@ -305,6 +321,7 @@ LexemeList *scanBuffer(const char *buffer, unsigned int size, const char *fname) while (start[len] && !isspace(start[len]) && *(start + len) != ',' && *(start + len) != '!' + && *(start + len) != '?' && strncmp(start + len, "'Z", 2) && strncmp(start + len, "...", 3) && strncmp(start + len, "\xE2\x80\xA6", 3)) diff --git a/parser.c b/parser.c index fcf6d04..d20beb4 100644 --- a/parser.c +++ b/parser.c @@ -514,6 +514,16 @@ void deleteStmtNode(StmtNode *node) deleteAltArrayDefStmtNode(stmt); break; } + case ST_BINDING: { + BindingStmtNode *stmt = (BindingStmtNode *)node->stmt; + deleteBindingStmtNode(stmt); + break; + } + case ST_IMPORT: { + ImportStmtNode *stmt = (ImportStmtNode *)node->stmt; + deleteImportStmtNode(stmt); + break; + } default: error(PR_UNKNOWN_STATEMENT_TYPE); break; @@ -1105,6 +1115,40 @@ void deleteAltArrayDefStmtNode(AltArrayDefStmtNode *node) free(node); } +/** + * Creates a library import statement. + * + * \param [in] name The name of the library to import. + * + * \return A pointer to a library import statement with the desired properties. + * + * \retval NULL Memory allocation failed. + */ +ImportStmtNode *createImportStmtNode(IdentifierNode *name) +{ + ImportStmtNode *p = malloc(sizeof(ImportStmtNode)); + if (!p) { + perror("malloc"); + return NULL; + } + p->name = name; + return p; +} + +/** + * Deletes a library import statement. + * + * \param [in,out] node The library import statement to delete. + * + * \post The memory at \a node and all of its members will be freed. + */ +void deleteImportStmtNode(ImportStmtNode *node) +{ + if (!node) return; + deleteIdentifierNode(node->name); + free(node); +} + /** * Creates a binding statement. * @@ -3905,6 +3949,76 @@ parseAltArrayDefStmtNodeAbort: /* Exception handling */ return NULL; } +/** + * Parses tokens into a library import statement. + * + * \param [in] tokenp The position in a token list to start parsing at. + * + * \post \a tokenp will point to the next unparsed token. + * + * \return A pointer to a return statement. + * + * \retval NULL Unable to parse. + */ +StmtNode *parseImportStmtNode(Token ***tokenp) +{ + IdentifierNode *value = NULL; + ImportStmtNode *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_IMPORT"); +#endif + + /* Remove the library import keyword from the token stream */ + status = acceptToken(&tokens, TT_CANHAS); + if (!status) { + parser_error_expected_token(TT_CANHAS, tokens); + goto parseImportStmtNodeAbort; + } + + /* Parse the library name */ + value = parseIdentifierNode(&tokens); + if (!value) goto parseImportStmtNodeAbort; + + /* Check for the question mark token (currently optional) */ + acceptToken(&tokens, TT_QUESTION); + + /* The library import statement must reside on its own line */ + status = acceptToken(&tokens, TT_NEWLINE); + if (!status) { + parser_error(PR_EXPECTED_END_OF_EXPRESSION, tokens); + goto parseImportStmtNodeAbort; + } + + /* Create the new ImportStmtNode structure */ + stmt = createImportStmtNode(value); + if (!stmt) goto parseImportStmtNodeAbort; + + /* Create the new StmtNode structure */ + ret = createStmtNode(ST_IMPORT, stmt); + if (!ret) goto parseImportStmtNodeAbort; + + /* Since we're successful, update the token stream */ + *tokenp = tokens; + + return ret; + +parseImportStmtNodeAbort: /* Exception handling */ + + /* Clean up any allocated structures */ + if (ret) deleteStmtNode(ret); + else if (stmt) deleteImportStmtNode(stmt); + else { + if (value) deleteIdentifierNode(value); + } + return NULL; +} + /** * Parses tokens into a statement. * @@ -4023,6 +4137,10 @@ StmtNode *parseStmtNode(Token ***tokenp) else if (peekToken(&tokens, TT_OHAIIM)) { ret = parseAltArrayDefStmtNode(tokenp); } + /* Library import statement */ + else if (peekToken(&tokens, TT_CANHAS)) { + ret = parseImportStmtNode(tokenp); + } /* Bare expression */ else if ((expr = parseExprNode(&tokens))) { int status; diff --git a/parser.h b/parser.h index f631f79..6eb1f39 100644 --- a/parser.h +++ b/parser.h @@ -229,6 +229,7 @@ typedef enum { ST_EXPR, /**< Expression statement. */ ST_ALTARRAYDEF, /**< Function definition statement. */ ST_BINDING, /**< Binding to external library. */ + ST_IMPORT, /**< Library import statement. */ } StmtType; /** @@ -365,6 +366,13 @@ typedef struct { IdentifierNode *parent; /**< An optional inherited array. */ } AltArrayDefStmtNode; +/** + * Stores a library import statement. + */ +typedef struct { + IdentifierNode *name; /**< The name of the library to import. */ +} ImportStmtNode; + /** * Stores a binding to a native function. */ @@ -726,6 +734,16 @@ AltArrayDefStmtNode *createAltArrayDefStmtNode(IdentifierNode *, BlockNode *, Id void deleteAltArrayDefStmtNode(AltArrayDefStmtNode *); /**@}*/ +/** + * \name ImportStmtNode modifiers + * + * Functions for creating and deleting ImportStmtNodes. + */ +/**@{*/ +ImportStmtNode *createImportStmtNode(IdentifierNode *); +void deleteImportStmtNode(ImportStmtNode *); +/**@}*/ + /** * \name BindingStmtNode modifiers * @@ -734,7 +752,7 @@ void deleteAltArrayDefStmtNode(AltArrayDefStmtNode *); /**@{*/ struct returnobject; struct scopeobject; -BindingStmtNode *createBindingStmtNode(struct returnobject *(*binding)(struct scopeobject *)); +BindingStmtNode *createBindingStmtNode(struct returnobject *(*)(struct scopeobject *)); void deleteBindingStmtNode(BindingStmtNode *); /**@}*/ @@ -823,6 +841,7 @@ StmtNode *parseLoopStmtNode(Token ***); StmtNode *parseDeallocationStmtNode(Token ***); StmtNode *parseFuncDefStmtNode(Token ***); StmtNode *parseAltArrayDefStmtNode(Token ***); +StmtNode *parseImportStmtNode(Token ***); /**@}*/ /** diff --git a/tokenizer.c b/tokenizer.c index 4500ade..3873dab 100644 --- a/tokenizer.c +++ b/tokenizer.c @@ -319,15 +319,6 @@ Token **tokenizeLexemes(LexemeList *list) token = createToken(TT_BOOLEAN, "WIN", fname, line); token->data.i = 1; } - /* CAN HAS STDIO? */ - else if (n < list->num - 2 - && !strcmp(lexeme->image, "CAN") - && !strcmp(list->lexemes[n + 1]->image, "HAS") - && !strcmp(list->lexemes[n + 2]->image, "STDIO?")) { - n += 2; - /* Just for fun; not actually in spec */ - continue; - } /* Newline */ /* Note that the spec is unclear as to whether a command *must* * follow a comma. For now, we let commas end a line. */ diff --git a/tokenizer.h b/tokenizer.h index 6bbc3b7..94b7121 100644 --- a/tokenizer.h +++ b/tokenizer.h @@ -104,6 +104,8 @@ typedef enum { TT_OHAIIM, /**< Alternate array declaration. */ TT_IMLIEK, /**< Alternate inherited object declaration. */ TT_KTHX, /**< End of alternate array declaration. */ + TT_CANHAS, /**< Library import declaration. */ + TT_QUESTION, /**< End of library import declaration. */ TT_ENDOFTOKENS /**< Sentinel end of this enum -- don't move it! */ } TokenType; @@ -181,6 +183,8 @@ static const char *keywords[] = { "O HAI IM", /* TT_OHAIIM */ "IM LIEK", /* TT_IMLIEK */ "KTHX", /* TT_KTHX */ + "CAN HAS", /* TT_CANHAS */ + "?", /* TT_QUESTION */ "" /* TT_ENDOFTOKENS */ };