From c412ec117a750ce6263fde015510d21917afc10b Mon Sep 17 00:00:00 2001 From: Justin Meza Date: Fri, 9 May 2014 23:59:18 -0400 Subject: [PATCH] patched ElColmo's system command code with some minor style changes --- error.c | 3 ++ error.h | 1 + interpreter.c | 65 +++++++++++++++++++++++++++++++- interpreter.h | 1 + parser.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++ parser.h | 38 +++++++++++++++---- tokenizer.h | 2 + 7 files changed, 201 insertions(+), 9 deletions(-) diff --git a/error.c b/error.c index be4bbe2..2bae0bf 100644 --- a/error.c +++ b/error.c @@ -145,6 +145,8 @@ static const char *err_msgs[] = { "%s:%u: function name already used by existing variable at: %s\n", /* IN_CANNOT_CAST_VALUE_TO_ARRAY */ "%s:%u: cannot cast value to array at: %s\n", + /* IN_UNABLE_TO_EXECUTE_COMMAND */ + "Unable to execute command\n", }; static const int err_codes[] = { @@ -227,6 +229,7 @@ static const int err_codes[] = { 537, /* IN_INVALID_TYPE */ 538, /* IN_FUNCTION_NAME_USED_BY_VARIABLE */ 539, /* IN_CANNOT_CAST_VALUE_TO_ARRAY */ + 540, /* IN_UNABLE_TO_EXECUTE_COMMAND */ }; int error(ErrorType e, ...) diff --git a/error.h b/error.h index ebf62c0..6f2d1f2 100644 --- a/error.h +++ b/error.h @@ -103,6 +103,7 @@ typedef enum { IN_INVALID_TYPE, IN_FUNCTION_NAME_USED_BY_VARIABLE, IN_CANNOT_CAST_VALUE_TO_ARRAY, + IN_UNABLE_TO_EXECUTE_COMMAND, } ErrorType; int error(ErrorType, ...); diff --git a/interpreter.c b/interpreter.c index 1553858..aab344f 100644 --- a/interpreter.c +++ b/interpreter.c @@ -1765,6 +1765,66 @@ ValueObject *interpretFuncCallExprNode(ExprNode *node, return ret; } +/** + * Interprets a system command + * + * \param [in] node A pointer to the expression to interpret. + * + * \param [in,out] scope A pointer to a scope to evaluate \a node under. + * + * \pre \a node contains an expression created by createSystemCommandExprNode(). + * + * \return A pointer to the returned value. + * + * \retval NULL An error occurred during interpretation. + */ +ValueObject *interpretSystemCommandExprNode(ExprNode *node, + ScopeObject *scope) +{ + SystemCommandExprNode *expr = (SystemCommandExprNode *)node->expr; + ValueObject *val = NULL; + FILE *f; + char *cmd = NULL; + unsigned int buflen = 2048; + char buf[buflen]; + char *out = NULL; + unsigned int len; + unsigned int total = 0; + unsigned int prev = 0; + + /* Sanity checks */ + if (scope == NULL) return NULL; + if (node->type != ET_SYSTEMCOMMAND) return NULL; + if (expr == NULL) return NULL; + + val = interpretExprNode(expr->cmd, scope); + if (!val) return NULL; + + cmd = getString(val); + + + /* Open the command for reading */ + f = popen(cmd, "r"); + if (f == NULL) { + error(IN_UNABLE_TO_EXECUTE_COMMAND); + return NULL; + } + + while ((len = fread(buf, 1, buflen, f)) > 0) { + prev = total; + total += len; + out = realloc(out, total + 1); + memcpy(out + prev, buf, len); + } + if (total > 0) out[total] = '\0'; + + /* Close */ + pclose(f); + + /* Return the command object */ + return createStringValueObject(out == NULL ? "" : out); +} + /** * Interprets an identifier. * @@ -2925,13 +2985,14 @@ ValueObject *interpretOpExprNode(ExprNode *node, * A jump table for expressions. The index of a function in the table is given * by its its index in the enumerated ExprType type. */ -static ValueObject *(*ExprJumpTable[6])(ExprNode *, ScopeObject *) = { +static ValueObject *(*ExprJumpTable[7])(ExprNode *, ScopeObject *) = { interpretCastExprNode, interpretConstantExprNode, interpretIdentifierExprNode, interpretFuncCallExprNode, interpretOpExprNode, - interpretImpVarExprNode }; + interpretImpVarExprNode, + interpretSystemCommandExprNode }; /** * Interprets an expression. diff --git a/interpreter.h b/interpreter.h index b3cefdc..7dbd9d6 100644 --- a/interpreter.h +++ b/interpreter.h @@ -225,6 +225,7 @@ ValueObject *interpretCastExprNode(ExprNode *, ScopeObject *); ValueObject *interpretFuncCallExprNode(ExprNode *, ScopeObject *); ValueObject *interpretIdentifierExprNode(ExprNode *, ScopeObject *); ValueObject *interpretConstantExprNode(ExprNode *, ScopeObject *); +ValueObject *interpretSystemCommandExprNode(ExprNode *, ScopeObject *); /**@}*/ /** diff --git a/parser.c b/parser.c index ce93c8c..73544f3 100644 --- a/parser.c +++ b/parser.c @@ -1234,6 +1234,9 @@ void deleteExprNode(ExprNode *node) break; case ET_IMPVAR: break; /* This expression type does not have any content */ + case ET_SYSTEMCOMMAND: + deleteSystemCommandExprNode((SystemCommandExprNode *)node->expr); + break; default: error(PR_UNKNOWN_EXPRESSION_TYPE); break; @@ -1372,6 +1375,26 @@ FuncCallExprNode *createFuncCallExprNode(IdentifierNode *scope, return p; } +/** + * Creates a system command expression. + * + * \param [in] cmd The command to execute. + * + * \return A pointer to a system command expression with the desired properties. + * + * \retval NULL Memory allocation failed. + */ +SystemCommandExprNode *createSystemCommandExprNode(ExprNode *cmd) +{ + SystemCommandExprNode *p = malloc(sizeof(SystemCommandExprNode)); + if (!p) { + perror("malloc"); + return NULL; + } + p->cmd = cmd; + return p; +} + /** * Deletes a function call expression. * @@ -1388,6 +1411,20 @@ void deleteFuncCallExprNode(FuncCallExprNode *node) free(node); } +/** + * Deletes a system command expression. + * + * \param [in,out] node The system command expression to delete. + * + * \post The memory at \a node and all of its members will be freed. + */ +void deleteSystemCommandExprNode(SystemCommandExprNode *node) +{ + if (!node) return; + deleteExprNode(node->cmd); + free(node); +} + /** * Creates an operation expression. * @@ -2134,6 +2171,65 @@ parseFuncCallExprNodeAbort: /* Exception handling */ return NULL; } +/** + * Parses tokens into a system command expression. + * + * \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 system command expression. + * + * \retval NULL Unable to parse. + */ +ExprNode *parseSystemCommandExprNode(Token ***tokenp) +{ + ExprNode *name = NULL; + SystemCommandExprNode *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_SYSTEMCOMMAND"); +#endif + + /* Parse the system command token */ + status = acceptToken(&tokens, TT_IDUZ); + if (!status) { + parser_error_expected_token(TT_IDUZ, tokens); + goto parseSystemCommandExprNodeAbort; + } + + /* Parse the expression name */ + name = parseExprNode(&tokens); + if (!name) goto parseSystemCommandExprNodeAbort; + + /* Create the new SystemCommandExprNode structure */ + expr = createSystemCommandExprNode(name); + if (!expr) goto parseSystemCommandExprNodeAbort; + + /* Create the new ExprNode structure */ + ret = createExprNode(ET_SYSTEMCOMMAND, expr); + if (!ret) goto parseSystemCommandExprNodeAbort; + + /* Since we're successful, update the token stream */ + *tokenp = tokens; + + return ret; + +parseSystemCommandExprNodeAbort: /* Exception handling */ + + /* Clean up any allocated structures */ + if (ret) deleteExprNode(ret); + else if (expr) deleteSystemCommandExprNode(expr); + else if (name) deleteExprNode(name); + + return NULL; +} + /** * Parses tokens into an operation expression. * @@ -2449,6 +2545,10 @@ ExprNode *parseExprNode(Token ***tokenp) /* Since we're successful, update the token stream */ *tokenp = tokens; } + else if (peekToken(&tokens, TT_IDUZ)) { + /* System command */ + ret = parseSystemCommandExprNode(tokenp); + } else { parser_error(PR_EXPECTED_EXPRESSION, tokens); } diff --git a/parser.h b/parser.h index f3e7717..fe1eb50 100644 --- a/parser.h +++ b/parser.h @@ -155,7 +155,7 @@ * * \par * ExprNode ::= CastExprNode | ConstantNode | IdentifierNode | FuncCallExprNode - * | OpExprNode | ImplicitVariable + * | OpExprNode | ImplicitVariable | SystemCommandExprNode * * \par * CastExprNode ::= \c TT_MAEK ExprNode \c TT_A TypeNode @@ -165,6 +165,9 @@ * TT_MKAY * * \par + * SystemCommandExprNode ::= \c TT_DUZ \c IdentifierNode + * + * \par * OpExprNode ::= UnaryOp | BinaryOp | NaryOp * * \par @@ -252,12 +255,13 @@ typedef struct { * Represents an expression type. */ typedef enum { - ET_CAST, /**< Cast expression. */ - ET_CONSTANT, /**< Constant expression. */ - ET_IDENTIFIER, /**< Identifier expression. */ - ET_FUNCCALL, /**< Function call expression. */ - ET_OP, /**< Operation expression. */ - ET_IMPVAR /**< \ref impvar "Implicit variable". */ + ET_CAST, /**< Cast expression. */ + ET_CONSTANT, /**< Constant expression. */ + ET_IDENTIFIER, /**< Identifier expression. */ + ET_FUNCCALL, /**< Function call expression. */ + ET_OP, /**< Operation expression. */ + ET_IMPVAR, /**< \ref impvar "Implicit variable". */ + ET_SYSTEMCOMMAND, /**< System command expression. */ } ExprType; /** @@ -522,6 +526,15 @@ typedef struct { ExprNodeList *args; /**< The arguments to supply the function. */ } FuncCallExprNode; +/** + * Stores a system command expression. This expression evaluates an identifier + * which contains a system command, and evaluates to the standard output of the + * executed system command. + */ +typedef struct { + ExprNode *cmd; /**< The expression containing the command to execute */ +} SystemCommandExprNode; + /** * Represents the type of operation an OpExprNode performs. */ @@ -789,6 +802,16 @@ FuncCallExprNode *createFuncCallExprNode(IdentifierNode *, IdentifierNode *, Exp void deleteFuncCallExprNode(FuncCallExprNode *); /**@}*/ +/** + * \name SystemCommandExprNode modifiers + * + * Functions for creating and deleting SystemCommandExprNode. + */ +/**@{*/ +SystemCommandExprNode *createSystemCommandExprNode(ExprNode *); +void deleteSystemCommandExprNode(SystemCommandExprNode *); +/**@}*/ + /** * \name OpExprNode modifiers * @@ -827,6 +850,7 @@ ExprNode *parseCastExprNode(Token ***); ExprNode *parseConstantExprNode(Token ***); ExprNode *parseIdentifierExprNode(Token ***); ExprNode *parseFuncCallExprNode(Token ***); +ExprNode *parseSystemCommandExprNode(Token ***); ExprNode *parseOpExprNode(Token ***); StmtNode *parseCastStmtNode(Token ***); StmtNode *parsePrintStmtNode(Token ***); diff --git a/tokenizer.h b/tokenizer.h index 9d744ad..2b9268e 100644 --- a/tokenizer.h +++ b/tokenizer.h @@ -104,6 +104,7 @@ typedef enum { TT_OHAIIM, /**< Alternate array declaration. */ TT_IMLIEK, /**< Alternate inherited object declaration. */ TT_KTHX, /**< End of alternate array declaration. */ + TT_IDUZ, /**< System command. */ TT_CANHAS, /**< Library import declaration. */ TT_QUESTION, /**< End of library import declaration. */ @@ -183,6 +184,7 @@ static const char *keywords[] = { "O HAI IM", /* TT_OHAIIM */ "IM LIEK", /* TT_IMLIEK */ "KTHX", /* TT_KTHX */ + "I DUZ", /* TT_IDUZ */ "CAN HAS", /* TT_CANHAS */ "?", /* TT_QUESTION */ "" /* TT_ENDOFTOKENS */