aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core-commands.c
diff options
context:
space:
mode:
authorRobin Haberkorn <rhaberkorn@fmsbw.de>2026-10-25 02:39:11 +0100
committerRobin Haberkorn <rhaberkorn@fmsbw.de>2026-10-25 11:38:05 +0100
commite0bf13622b0922252439e3fa8b43df9877678d75 (patch)
tree629c040970a3c6869a10bf3c74a853e5eed2d908 /src/core-commands.c
parentc4146a9e57a897c5393e1c4999110fd95208f43f (diff)
numbers are separate parser states and there are syntactic octal and hexadecimal constants nowHEADmaster-fmsbw-cimaster
* Instead of every digit being a stack-modifying standalone command, there is a single continuous parser state (teco_state_number) now - even though it has certain unique characteristics. They are consequently documented in the ARITHMETICS AND EXPRESSIONS chapter of sciteco(7). * A number will therefore be rubbed out entirely by CTRL+W, including a possible @-modifier. * (!) Spaces within constants are no longer ignored, but will push separate numbers to the stack instead (`1 2 3` pushes 3 numbers). The significance of the `,` operator is thus further reduced. * (!) You can no longer "append" to numbers on the stack as in `Qa001` - this was never actually used and caused more confusion. * (!) Digits outside the current radix are no longer accepted. E.g. digit 2 after `2^R`. This feature was also never used. * (!) Octal constants are supported with leading zeros as in C. This works regardless of the current radix set via `8^R` or `^O`. It remains to see whether this is actually useful or is rather annoying (since every constant beginning with 0 is automatically octal, you cannot left-pad arbitrary numbers with 0). * Hexadecimal constants are supported by at-modifying them as in `@0ff`. They must still begin with a digit 0-9 and since A-F are valid SciTECO commands, you may need additional spaces to separate hexadecimal constants from regular commands as in `@0ff D`. During syntax highlighting the number style is extended back to the at-sign. Note: Hexadecimal constants couldn't have been realized via `16^R` (or some shortcut) since that depends on runtime state, but we must know during parsing whether symbols A-F are part of the number of regular SciTECO commands. * The new hexadecimal constants are used in the color schemes now. Thanks to them, we no longer need workarounds like the "color.rgb" macro. * Since numbers don't have a dedicated terminator character, but any letter may terminate it, the number state must behave similar to a start state. Consequently, hexadecimal constants will currently be auto-case-folded if you enabled this feature. I recommend not to write hex constants in upper-case, though. Perhaps this should be worked around with a custom process_edit_cmd() callback. * Test suite updated
Diffstat (limited to 'src/core-commands.c')
-rw-r--r--src/core-commands.c106
1 files changed, 85 insertions, 21 deletions
diff --git a/src/core-commands.c b/src/core-commands.c
index 6362d95..f80cd59 100644
--- a/src/core-commands.c
+++ b/src/core-commands.c
@@ -55,6 +55,89 @@ static teco_state_t *teco_state_control_input(teco_machine_main_t *ctx, gunichar
static teco_state_t *teco_state_ctlc_control_input(teco_machine_main_t *ctx, gunichar chr, GError **error);
static teco_state_t *teco_state_endcond(teco_machine_main_t *ctx, const gchar *cmd, GError **error);
+static teco_state_t teco_state_number;
+
+static gboolean
+teco_state_number_end_of_macro(teco_machine_main_t *ctx, GError **error)
+{
+ teco_undo_guint(ctx->number.radix) = 0; /* default */
+
+ if (ctx->flags.mode > TECO_MODE_NORMAL)
+ return TRUE;
+
+ teco_expressions_push(ctx->number.value);
+ teco_undo_int(ctx->number.value) = 0;
+ return TRUE;
+}
+
+static teco_state_t *
+teco_state_number_input(teco_machine_main_t *ctx, gunichar chr, GError **error)
+{
+ /*
+ * Hexadecimal constants (@[0-9][0-9a-zA-Z]*) are terminated by any non-hexadecimal character.
+ * This means you may have to append a space or braces to stop parsing if the next
+ * command would begin with such a letter (e.g. `@0ff D`).
+ */
+ gboolean end_of_number = chr <= 0xFF && (ctx->number.radix == 16 ? !g_ascii_isxdigit(chr)
+ : !g_ascii_isdigit(chr));
+ if (end_of_number) {
+ teco_state_number_end_of_macro(ctx, error);
+ return teco_state_start_input(ctx, chr, error);
+ }
+
+ if (!ctx->number.radix) {
+ if (teco_machine_main_eval_at(ctx))
+ /* @[0-9] starts a hexadecimal constant */
+ teco_undo_guint(ctx->number.radix) = 16;
+ else if (!ctx->number.value && chr == '0')
+ /* a leading zero starts an octal constant */
+ teco_undo_guint(ctx->number.radix) = 8;
+ }
+
+ if (ctx->flags.mode > TECO_MODE_NORMAL)
+ return &teco_state_number;
+
+ teco_int_t radix = ctx->number.radix;
+ if (!radix) {
+ /*
+ * The ^R radix is only considered if we do not
+ * syntactically signify the radix (octal or hex constants).
+ *
+ * FIXME: We could just access qreg->integer here since
+ * we can assume that "^R" is a plain register.
+ */
+ teco_qreg_t *qreg = ctx->qreg_table_locals->radix;
+ qreg->vtable->get_integer(qreg, &radix, NULL);
+ }
+
+ chr = teco_ascii_toupper(chr);
+ guint digit = 'A' <= chr && chr <= 'F' ? chr-'A'+10 : chr-'0';
+ if (digit >= radix) {
+ g_set_error(error, TECO_ERROR, TECO_ERROR_FAILED,
+ "Digit \"%c\" not allowed in radix %" TECO_INT_FORMAT,
+ (gchar)chr, radix);
+ return NULL;
+ }
+
+ teco_undo_int(ctx->number.value) = ctx->number.value*radix + digit;
+
+ return &teco_state_number;
+}
+
+/*
+ * FIXME: This has to be a "command" since we chain to teco_state_start_input()
+ * and want case-folding to work properly.
+ * On the downside, this will also case-fold the hexadecimal constants (A-F).
+ * There would be cumbersome workarounds with custom process_edit_cmd callbacks,
+ * though.
+ */
+static TECO_DEFINE_STATE_START(teco_state_number,
+ .input_cb = (teco_state_input_cb_t)teco_state_number_input,
+ .end_of_macro_cb = (teco_state_end_of_macro_cb_t)teco_state_number_end_of_macro,
+ .style = SCE_SCITECO_NUMBER,
+ .is_start = FALSE
+);
+
/**
* Translate buffer range arguments from the expression stack to
* a from-position and length in bytes.
@@ -760,32 +843,13 @@ teco_state_start_input(teco_machine_main_t *ctx, gunichar chr, GError **error)
}
switch (chr) {
- /*$ 0 1 2 3 4 5 6 7 8 9 digit number
- * [n]0|1|2|3|4|5|6|7|8|9 -> n*Radix+X -- Append digit
- *
- * Integer constants in \*(ST may be thought of and are
- * technically sequences of single-digit commands.
- * These commands take one argument from the stack
- * (0 is implied), multiply it with the current radix
- * (2, 8, 10, 16, ...), add the digit's value and
- * return the resultant integer.
- *
- * The command-like semantics of digits may be abused
- * in macros, for instance to append digits to computed
- * integers.
- * It is not an error to append a digit greater than the
- * current radix - this may be changed in the future.
- */
case '0' ... '9':
- if (ctx->flags.modifier_at ||
- (ctx->flags.mode == TECO_MODE_NORMAL && ctx->flags.modifier_colon)) {
+ if (ctx->flags.mode == TECO_MODE_NORMAL && ctx->flags.modifier_colon) {
gchar cmd[] = {chr, '\0'};
teco_error_modifier_set(error, cmd);
return NULL;
}
- if (ctx->flags.mode == TECO_MODE_NORMAL)
- teco_expressions_add_digit(chr, ctx->qreg_table_locals->radix);
- return &teco_state_start;
+ return teco_state_number_input(ctx, chr, error);
case '*':
/*