diff options
author | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2014-11-10 01:03:01 +0100 |
---|---|---|
committer | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2014-11-10 01:03:01 +0100 |
commit | 7b9d5bad396bdd1cfa81cb2a76e5f1d47b145cf6 (patch) | |
tree | 86f3a2983334e9520589fcf02a767e15e40e5d5b | |
parent | 40e4813831fd863d146d483bb6d87afa4776edd1 (diff) | |
download | sciteco-7b9d5bad396bdd1cfa81cb2a76e5f1d47b145cf6.tar.gz |
support new "~" conditional: useful for implying default parameters in macros
-rw-r--r-- | doc/sciteco.7.template | 35 | ||||
-rw-r--r-- | src/parser.cpp | 23 |
2 files changed, 44 insertions, 14 deletions
diff --git a/doc/sciteco.7.template b/doc/sciteco.7.template index 340f58b..42d1425 100644 --- a/doc/sciteco.7.template +++ b/doc/sciteco.7.template @@ -1004,8 +1004,8 @@ They correspond to structured IF-THEN-ELSE statements in other imperative languages. The general syntax of conditionals is as follows: .br -\# n"c if [| else ]' -\fIn\fB"\fIc if \fR[\fB|\fI else \fR] \fB'\fR +\# [n]"c if [| else ]' +[\fIn\fP]\fB"\fIc if \fR[\fB|\fI else \fR] \fB'\fR .br Whereas \fIn\fP is a value on the stack to test, \fIc\fP is a case-insignificant character identifying a @@ -1013,12 +1013,31 @@ condition to check for, \fIif\fP is a code block to execute if the condition applies and \fIelse\fP is an optional code block to execute if the condition does not apply. -The first command in the \fIif\fP block will not see -any arguments on the expression stack but values accumulated -on the expression stack by the \fIif\fP or \fIelse\fP blocks -are not discarded by the terminating single-quote. -In other words, conditionals may return values. -The possible conditions are defined in the following list: +The conditional pops at most one argument from the expression +stack \(em the remaining arguments may be evaluated by the +\fIif\fP or \fIelse\fP blocks. +Values accumulated on the expression stack by the \fIif\fP or \fIelse\fP +blocks are not discarded by the terminating single-quote. +In other words, conditionals may also return values. +The possible conditions are defined in the following list. +Unless \fIn\fP is defined optional, the conditionals described +below yield an error if \fIn\fP is omitted: +.TP +\# [n]"~ +[\fIn\fP]\fB\(dq~\fP +Applies if \fIn\fP is \fBnot\fP given (i.e. the argument +stack is empty). +If \fIn\fP is given (i.e. the stack is not empty), it is \fBnot\fP +removed from the expression stack. +This construct is especially useful in macros to imply default +parameter values. +For instance the following macro inserts \fIn\fP tab characters +(one by default): +.EX +@^Ut{ + "~1'<@^I//> +} +.EE .TP .IB n \(dqA Applies if \fIn\fP is the code of an alphabetic character. diff --git a/src/parser.cpp b/src/parser.cpp index 1510352..9f5be4c 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1594,17 +1594,30 @@ StateCondCommand::custom(gchar chr) switch (mode) { case MODE_PARSE_ONLY_COND: - undo.push_var<gint>(nest_level); - nest_level++; + undo.push_var(nest_level)++; break; + case MODE_NORMAL: + expressions.eval(); + + if (chr == '~') + /* don't pop value for ~ conditionals */ + break; + + if (!expressions.args()) + throw ArgExpectedError('"'); value = expressions.pop_num_calc(); break; + default: break; } switch (g_ascii_toupper(chr)) { + case '~': + BEGIN_EXEC(&States::start); + result = !expressions.args(); + break; case 'A': BEGIN_EXEC(&States::start); result = g_ascii_isalpha((gchar)value); @@ -1663,11 +1676,9 @@ StateCondCommand::custom(gchar chr) throw Error("Invalid conditional type \"%c\"", chr); } - if (!result) { + if (!result) /* skip to ELSE-part or end of conditional */ - undo.push_var<Mode>(mode); - mode = MODE_PARSE_ONLY_COND; - } + undo.push_var(mode) = MODE_PARSE_ONLY_COND; return &States::start; } |