From 4aa2b717f9e050783b567540d9bb0193d692e3e9 Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Sat, 31 Oct 2026 13:46:11 +0100 Subject: support floating point numbers * Extends the SciTECO type system. A number on the expression stack or in a Q-register can be either an integer or a float. * Floating point constants begin with a digit (like all other numbers), are followed by a `.` and an optional fractional part. Exponents cannot currently be written. E.g. `1.` == `1.0`. But `.0` would still be `.,0`. (!) To push an integer followed by dot, you must now write e.g. `1,.` or `1 .`. * All of the basic arithmetic operators operate like this: If both operands are integers, the result is also an integer (integer arithmetics). If at least one of the operands is a float, the result is also a float (float arithmetics). * All of the binary operators (AND, OR, XOR) always cast all operands to integer and the result is always an integer as well. * You can "cast" integers to float by `*1.` or `/1.`. You can "cast" floats to integers using `#0`. * Most commands still accept only integers. Floats are implicitly casted to integers. Float-aware commands are: =, \, ^W, Qq, Uq, %q and the conditionals. * `%q` will not change the current type of register q. * Numeric part of "lexer.font" is now a float (in points). * You cannot currently print octal and hexadecimal floats. `==` and `===` are identical to `=` on floats. * `===` is now printing hex integers in lower case. This is because SciTECO's coding style for hex constants is also lower case. * `--with-teco-integer` renamed to `--with-teco-number`. --- src/expressions.h | 76 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 65 insertions(+), 11 deletions(-) (limited to 'src/expressions.h') diff --git a/src/expressions.h b/src/expressions.h index 37aef70..1c1b4e9 100644 --- a/src/expressions.h +++ b/src/expressions.h @@ -79,7 +79,8 @@ typedef enum { TECO_OP_NIL = 0x00, TECO_OP_NEW, TECO_OP_BRACE, - TECO_OP_NUMBER, + TECO_OP_INTEGER, + TECO_OP_FLOAT, /* * Real operators */ @@ -102,7 +103,23 @@ teco_set_num_sign(gint sign) teco_undo_gint(teco_num_sign) = sign; } -void teco_expressions_push_int(teco_int_t number); +teco_operator_t teco_expressions_peek_op(guint index); +teco_operator_t teco_expressions_pop_op(guint index); +void teco_expressions_push_op(teco_operator_t op); + +void teco_expressions_push_num(teco_number_t number, gboolean is_float); + +static inline void +teco_expressions_push_int(teco_int_t number) +{ + teco_expressions_push_num((teco_number_t){.i = number}, FALSE); +} + +static inline void +teco_expressions_push_float(teco_float_t number) +{ + teco_expressions_push_num((teco_number_t){.f = number}, TRUE); +} /** Push characters of a C-string. */ static inline void @@ -112,11 +129,46 @@ teco_expressions_push_str(const gchar *str) teco_expressions_push_int(*str++); } -teco_int_t teco_expressions_peek_num(guint index); -teco_int_t teco_expressions_pop_num(guint index); -gboolean teco_expressions_pop_num_calc(teco_int_t *ret, teco_int_t imply, GError **error); +teco_number_t teco_expressions_peek_num(guint index); + +static inline teco_int_t +teco_expressions_peek_int(guint index) +{ + teco_number_t number = teco_expressions_peek_num(index); + return teco_expressions_peek_op(index) == TECO_OP_FLOAT ? (teco_int_t)number.f : number.i; +} + +teco_number_t teco_expressions_pop_num(guint index, gboolean *is_float); + +static inline teco_int_t +teco_expressions_pop_int(guint index) +{ + gboolean is_float; + teco_number_t number = teco_expressions_pop_num(index, &is_float); + return is_float ? (teco_int_t)number.f : number.i; +} + +gboolean teco_expressions_pop_num_calc(teco_number_t *ret, gboolean *is_float, + teco_int_t imply, GError **error); + +/** + * Pop an integer from the number stack. + * + * This automatically casts floats to integers. + * + * @see teco_expressions_pop_num_calc + */ +static inline gboolean +teco_expressions_pop_int_calc(teco_int_t *ret, teco_int_t imply, GError **error) +{ + teco_number_t number; + gboolean is_float; + if (!teco_expressions_pop_num_calc(&number, &is_float, imply, error)) + return FALSE; + *ret = is_float ? (teco_int_t)number.f : number.i; + return TRUE; +} -void teco_expressions_push_op(teco_operator_t op); gboolean teco_expressions_push_calc(teco_operator_t op, GError **error); /* @@ -124,12 +176,10 @@ gboolean teco_expressions_push_calc(teco_operator_t op, GError **error); */ #define teco_expressions_push(X) \ (_Generic((X), default : teco_expressions_push_int, \ + teco_float_t : teco_expressions_push_float, \ char * : teco_expressions_push_str, \ const char * : teco_expressions_push_str)(X)) -teco_operator_t teco_expressions_peek_op(guint index); -teco_operator_t teco_expressions_pop_op(guint index); - gboolean teco_expressions_eval(gboolean pop_brace, GError **error); guint teco_expressions_args(void); @@ -146,8 +196,12 @@ gboolean teco_expressions_brace_close(GError **error); void teco_expressions_clear(void); -/** Maximum size required to format a number if radix == 2 */ +/** + * Maximum size required to format a teco_int_t if radix == 2. + * It's also sufficient for formatting a teco_float_t. + */ #define TECO_EXPRESSIONS_FORMAT_LEN \ (1 + sizeof(teco_int_t)*8 + 1) -gchar *teco_expressions_format(gchar *buffer, teco_int_t number, teco_qreg_t *radix); +gchar *teco_expressions_format_int(gchar *buffer, teco_int_t number, teco_qreg_t *radix); +gchar *teco_expressions_format_float(gchar *buffer, teco_float_t number, guint precision); -- cgit v1.2.3