diff --git a/interpreter.c b/interpreter.c index 20987b9..2425280 100644 --- a/interpreter.c +++ b/interpreter.c @@ -3087,12 +3087,12 @@ ReturnObject *interpretPrintStmtNode(StmtNode *node, deleteValueObject(use); return NULL; } - printf("%s", getString(use)); + fprintf(stmt->file, "%s", getString(use)); deleteValueObject(val); deleteValueObject(use); } if (!stmt->nonl) - printf("\n"); + putc('\n', stmt->file); return createReturnObject(RT_DEFAULT, NULL); } diff --git a/parser.c b/parser.c index 2b6a037..1df2606 100644 --- a/parser.c +++ b/parser.c @@ -629,6 +629,8 @@ void deleteCastStmtNode(CastStmtNode *node) * * \param [in] args The expressions to print. * + * \param [in] file Where to print (\c stdout or \c stderr). + * * \param [in] nonl Whether an ending newline should be surpressed. * * \return A pointer to the print statement with the desired properties. @@ -636,6 +638,7 @@ void deleteCastStmtNode(CastStmtNode *node) * \retval NULL Memory allocation failed. */ PrintStmtNode *createPrintStmtNode(ExprNodeList *args, + FILE *file, int nonl) { PrintStmtNode *p = malloc(sizeof(PrintStmtNode)); @@ -644,6 +647,7 @@ PrintStmtNode *createPrintStmtNode(ExprNodeList *args, return NULL; } p->args = args; + p->file = file; p->nonl = nonl; return p; } @@ -2477,6 +2481,7 @@ StmtNode *parsePrintStmtNode(Token ***tokenp) { ExprNode *arg = NULL; ExprNodeList *args = NULL; + FILE *file = stdout; int nonl = 0; PrintStmtNode *stmt = NULL; StmtNode *ret = NULL; @@ -2489,13 +2494,21 @@ StmtNode *parsePrintStmtNode(Token ***tokenp) debug("ST_PRINT"); #endif - /* Remove the print keyword from the token stream */ + /** + * Remove the print keyword from the token stream + * A "quad-bool" is used to indicate whether we succeeded or failed to + * accept either a \c TT_VISIBLE or \c TT_INVISIBLE token. + */ status = acceptToken(&tokens, TT_VISIBLE); - if (!status) { - parser_error_expected_token(TT_VISIBLE, tokens); + if (!status) status = acceptToken(&tokens, TT_INVISIBLE) ? 2 : -1; + if (status < 1) { + parser_error_expected_token(TT_VISIBLE - status, tokens); goto parsePrintStmtNodeAbort; } + /* Use standard error if we accepted a \c TT_INVISIBLE above */ + if (status == 2) file = stderr; + /* Parse the arguments to the print statement */ args = createExprNodeList(); if (!args) goto parsePrintStmtNodeAbort; @@ -2515,7 +2528,7 @@ StmtNode *parsePrintStmtNode(Token ***tokenp) && !peekToken(&tokens, TT_BANG)); /* Check for the no-newline token */ - if(acceptToken(&tokens, TT_BANG)) nonl = 1; + if (acceptToken(&tokens, TT_BANG)) nonl = 1; /* Make sure the statement ends with a newline */ status = acceptToken(&tokens, TT_NEWLINE); @@ -2525,7 +2538,7 @@ StmtNode *parsePrintStmtNode(Token ***tokenp) } /* Create the new PrintStmtNode structure */ - stmt = createPrintStmtNode(args, nonl); + stmt = createPrintStmtNode(args, file, nonl); if (!stmt) goto parsePrintStmtNodeAbort; /* Create the new StmtNode structure */ @@ -3963,6 +3976,10 @@ StmtNode *parseStmtNode(Token ***tokenp) else if (peekToken(&tokens, TT_VISIBLE)) { ret = parsePrintStmtNode(tokenp); } + /* Warn */ + else if (peekToken(&tokens, TT_INVISIBLE)) { + ret = parsePrintStmtNode(tokenp); + } /* Input */ else if (peekToken(&tokens, TT_GIMMEH)) { ret = parseInputStmtNode(tokenp); diff --git a/parser.h b/parser.h index a09b249..85a3076 100644 --- a/parser.h +++ b/parser.h @@ -70,6 +70,7 @@ * * \par * PrintStmtNode ::= \c TT_VISIBLE ExprNodeList \c TT_BANG ? \c TT_NEWLINE + * | \c TT_INVISIBLE ExprNodeList \c TT_BANG ? \c TT_NEWLINE * * \par * InputStmtNode ::= \c TT_GIMMEH IdentifierNode \c TT_NEWLINE @@ -395,6 +396,7 @@ typedef struct { */ typedef struct { ExprNodeList *args; /**< The expressions to print. */ + FILE *file; /**< Where to print (\c stdout or \c stderr). */ int nonl; /**< Whether to print an ending newline. */ } PrintStmtNode; @@ -612,7 +614,7 @@ void deleteCastStmtNode(CastStmtNode *); * Functions for creating and deleting PrintStmtNodes. */ /**@{*/ -PrintStmtNode *createPrintStmtNode(ExprNodeList *, int); +PrintStmtNode *createPrintStmtNode(ExprNodeList *, FILE *, int); void deletePrintStmtNode(PrintStmtNode *); /**@}*/ diff --git a/tokenizer.h b/tokenizer.h index 81f9fd2..cab948d 100644 --- a/tokenizer.h +++ b/tokenizer.h @@ -76,6 +76,7 @@ typedef enum { TT_A, /**< Cast target separator. */ TT_ISNOWA, /**< In-place cast. */ TT_VISIBLE, /**< Print. */ + TT_INVISIBLE, /**< Print to standard error. */ TT_SMOOSH, /**< String concatenation. */ TT_BANG, /**< Exclamation point (!) */ TT_GIMMEH, /**< Input. */ @@ -153,6 +154,7 @@ static const char *keywords[] = { "A", /* TT_A */ "IS NOW A", /* TT_ISNOWA */ "VISIBLE", /* TT_VISIBLE */ + "INVISIBLE", /* TT_INVISIBLE */ "SMOOSH", /* TT_SMOOSH */ "!", /* TT_BANG */ "GIMMEH", /* TT_GIMMEH */