libgimpwidgets: add ratio expressions to eevl

Ratio expressions have the form 'x : y' (the ':' operator has the
highest precedence for a binary operator, and is left-associative).
Given a reference value 'a', the expression evaluates to
'a * (x / y)'.

Ratio expressions can be controlled by the caller by:

  - Enabling or disabling them:  They're meant to be used when the
    eevl servers two paired entries, and can be disabled otherwise.

  - Setting the reference value:  That's normally the value of the
    "other" entry of the pair--the one not currently being
    evaluated.

  - Inverting the ratios:  Normally, one entry refers to the
    antecedent term of the ratio, and the other entry refers to the
    consequent term of the ratio.  When evaluating the latter one,
    the ratio should be inverted.
This commit is contained in:
Ell 2017-10-04 12:14:41 -04:00
parent 7362d47922
commit 6caae9c53b
2 changed files with 55 additions and 10 deletions

View File

@ -40,7 +40,9 @@
* expression ::= term { ('+' | '-') term }* |
* <empty string> ;
*
* term ::= signed factor { ( '*' | '/' ) signed factor }* ;
* term ::= ratio { ( '*' | '/' ) ratio }* ;
*
* ratio ::= signed factor { ':' signed factor }* ;
*
* signed factor ::= ( '+' | '-' )? factor ;
*
@ -123,6 +125,7 @@ static void gimp_eevl_init (GimpEevl
static GimpEevlQuantity gimp_eevl_complete (GimpEevl *eva);
static GimpEevlQuantity gimp_eevl_expression (GimpEevl *eva);
static GimpEevlQuantity gimp_eevl_term (GimpEevl *eva);
static GimpEevlQuantity gimp_eevl_ratio (GimpEevl *eva);
static GimpEevlQuantity gimp_eevl_signed_factor (GimpEevl *eva);
static GimpEevlQuantity gimp_eevl_factor (GimpEevl *eva);
static gboolean gimp_eevl_accept (GimpEevl *eva,
@ -307,30 +310,61 @@ static GimpEevlQuantity
gimp_eevl_term (GimpEevl *eva)
{
gboolean division;
GimpEevlQuantity evaluated_signed_factors;
GimpEevlQuantity evaluated_ratios;
evaluated_signed_factors = gimp_eevl_signed_factor (eva);
evaluated_ratios = gimp_eevl_ratio (eva);
for (division = FALSE;
gimp_eevl_accept (eva, '*', NULL) ||
(division = gimp_eevl_accept (eva, '/', NULL));
division = FALSE)
{
GimpEevlQuantity new_signed_factor = gimp_eevl_signed_factor (eva);
GimpEevlQuantity new_ratio = gimp_eevl_ratio (eva);
if (division)
{
evaluated_signed_factors.value /= new_signed_factor.value;
evaluated_signed_factors.dimension -= new_signed_factor.dimension;
evaluated_ratios.value /= new_ratio.value;
evaluated_ratios.dimension -= new_ratio.dimension;
}
else
{
evaluated_signed_factors.value *= new_signed_factor.value;
evaluated_signed_factors.dimension += new_signed_factor.dimension;
evaluated_ratios.value *= new_ratio.value;
evaluated_ratios.dimension += new_ratio.dimension;
}
}
return evaluated_ratios;
}
static GimpEevlQuantity
gimp_eevl_ratio (GimpEevl *eva)
{
GimpEevlQuantity evaluated_signed_factors;
if (! eva->options.ratio_expressions)
return gimp_eevl_signed_factor (eva);
evaluated_signed_factors = gimp_eevl_signed_factor (eva);
while (gimp_eevl_accept (eva, ':', NULL))
{
GimpEevlQuantity new_signed_factor = gimp_eevl_signed_factor (eva);
if (eva->options.ratio_invert)
{
GimpEevlQuantity temp;
temp = evaluated_signed_factors;
evaluated_signed_factors = new_signed_factor;
new_signed_factor = temp;
}
evaluated_signed_factors.value *= eva->options.ratio_quantity.value /
new_signed_factor.value;
evaluated_signed_factors.dimension += eva->options.ratio_quantity.dimension -
new_signed_factor.dimension;
}
return evaluated_signed_factors;
}

View File

@ -59,18 +59,29 @@ typedef gboolean (* GimpEevlUnitResolverProc) (const gchar *identifier,
* GimpEevlOptions:
* @unit_resolver_proc: Unit resolver callback.
* @data: Data passed to unit resolver.
* @ratio_expressions: Allow ratio expressions
* @ratio_invert: Invert ratios
* @ratio_quantity: Quantity to multiply ratios by
*/
typedef struct
{
GimpEevlUnitResolverProc unit_resolver_proc;
gpointer data;
gboolean ratio_expressions;
gboolean ratio_invert;
GimpEevlQuantity ratio_quantity;
} GimpEevlOptions;
#define GIMP_EEVL_OPTIONS_INIT \
((const GimpEevlOptions) \
{ \
.unit_resolver_proc = NULL, \
.data = NULL \
.data = NULL, \
\
.ratio_expressions = FALSE, \
.ratio_invert = FALSE, \
.ratio_quantity = {0.0, 0} \
})