[gcalctool] Get some more variable powers working
- From: Robert Ancell <rancell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gcalctool] Get some more variable powers working
- Date: Thu, 18 Mar 2010 10:59:40 +0000 (UTC)
commit e379fed63f8921e66bac5a6a6f8f7bef4163b4e3
Author: Robert Ancell <robert ancell gmail com>
Date: Thu Mar 18 21:38:06 2010 +1100
Get some more variable powers working
src/display.c | 22 ++++++++++++
src/mp-equation-parser.y | 65 ++++++++++++++++++++++++++++++-----
src/mp-equation-private.h | 6 +++
src/mp-equation.c | 83 ++++++++++++++++++++++++++-------------------
src/mp-equation.h | 6 +++
src/unittest.c | 22 +++++++++---
6 files changed, 154 insertions(+), 50 deletions(-)
---
diff --git a/src/display.c b/src/display.c
index 35c228f..07565fd 100644
--- a/src/display.c
+++ b/src/display.c
@@ -747,6 +747,27 @@ display_make_number(GCDisplay *display, char *target, int target_len, const MPNu
}
}
+
+static int
+variable_is_defined(const char *name)
+{
+ char *c, *lower_name;
+
+ lower_name = strdup(name);
+ for (c = lower_name; *c; c++)
+ *c = tolower(*c);
+
+ if (strcmp(lower_name, "rand") == 0 ||
+ strcmp(lower_name, "ans") == 0) {
+ g_free (lower_name);
+ return 1;
+ }
+ g_free (lower_name);
+
+ return register_get_value(name) != NULL;
+}
+
+
static int
get_variable(const char *name, MPNumber *z, void *data)
{
@@ -964,6 +985,7 @@ parse(GCDisplay *display, const char *text, MPNumber *z, char **error_token)
memset(&options, 0, sizeof(options));
options.wordlen = display->word_size;
options.angle_units = display->angle_unit;
+ options.variable_is_defined = variable_is_defined;
options.get_variable = get_variable;
options.set_variable = set_variable;
options.convert = convert;
diff --git a/src/mp-equation-parser.y b/src/mp-equation-parser.y
index 89c6cc3..dce2f23 100644
--- a/src/mp-equation-parser.y
+++ b/src/mp-equation-parser.y
@@ -22,6 +22,7 @@
#include <stdlib.h>
#include <math.h>
#include <errno.h>
+#include <assert.h>
#include "mp-equation-private.h"
#include "mp-equation-parser.h"
@@ -43,14 +44,60 @@ static void set_result(yyscan_t yyscanner, const MPNumber *x)
mp_set_from_mp(x, &(_mp_equation_get_extra(yyscanner))->ret);
}
-static int get_variable(yyscan_t yyscanner, const char *name, MPNumber *z)
+char *
+utf8_next_char (const char *c)
{
- if (!_mp_equation_get_extra(yyscanner)->get_variable(_mp_equation_get_extra(yyscanner), name, z)) {
- set_error(yyscanner, PARSER_ERR_UNKNOWN_VARIABLE, name);
- return 0;
+ c++;
+ while ((*c & 0xC0) == 0x80)
+ c++;
+ return (char *)c;
+}
+
+static int get_variable(yyscan_t yyscanner, const char *name, int power, MPNumber *z)
+{
+ int result = 0;
+
+ /* If defined, then get the variable */
+ if (_mp_equation_get_extra(yyscanner)->get_variable(_mp_equation_get_extra(yyscanner), name, z)) {
+ mp_xpowy_integer(z, power, z);
+ return 1;
}
- return 1;
+ /* If has more than one character then assume a multiplication of variables */
+ if (utf8_next_char(name)[0] != '\0') {
+ const char *c, *next;
+ char *buffer = malloc(sizeof(char) * strlen(name));
+ MPNumber value;
+
+ result = 1;
+ mp_set_from_integer(1, &value);
+ for (c = name; *c != '\0'; c = next) {
+ MPNumber t;
+
+ next = utf8_next_char(c);
+ snprintf(buffer, next - c + 1, "%s", c);
+
+ if (!_mp_equation_get_extra(yyscanner)->get_variable(_mp_equation_get_extra(yyscanner), buffer, &t)) {
+ result = 0;
+ break;
+ }
+
+ /* If last term do power */
+ if (*next == '\0')
+ mp_xpowy_integer(&t, power, &t);
+
+ mp_multiply(&value, &t, &value);
+ }
+
+ free(buffer);
+ if (result)
+ mp_set_from_mp(&value, z);
+ }
+
+ if (!result)
+ set_error(yyscanner, PARSER_ERR_UNKNOWN_VARIABLE, name);
+
+ return result;
}
static void set_variable(yyscan_t yyscanner, const char *name, MPNumber *x)
@@ -132,8 +179,8 @@ statement:
exp:
'(' exp ')' {mp_set_from_mp(&$2, &$$);}
| '|' exp '|' {mp_abs(&$2, &$$);}
-| '|' tVARIABLE '|' {get_variable(yyscanner, $2, &$$); mp_abs(&$$, &$$); free($2);} /* FIXME: Shouldn't need this rule but doesn't parse without it... */
-| '|' tNUMBER tVARIABLE '|' {get_variable(yyscanner, $3, &$$); mp_multiply(&$2, &$$, &$$); mp_abs(&$$, &$$); free($3);} /* FIXME: Shouldn't need this rule but doesn't parse without it... */
+| '|' tVARIABLE '|' {get_variable(yyscanner, $2, 1, &$$); mp_abs(&$$, &$$); free($2);} /* FIXME: Shouldn't need this rule but doesn't parse without it... */
+| '|' tNUMBER tVARIABLE '|' {get_variable(yyscanner, $3, 1, &$$); mp_multiply(&$2, &$$, &$$); mp_abs(&$$, &$$); free($3);} /* FIXME: Shouldn't need this rule but doesn't parse without it... */
| exp '^' exp {mp_xpowy(&$1, &$3, &$$);}
| exp tSUPNUM {mp_xpowy_integer(&$1, $2, &$$);}
| exp tNSUPNUM {mp_xpowy_integer(&$1, $2, &$$);}
@@ -160,13 +207,13 @@ exp:
variable:
tVARIABLE exp {if (!get_function(yyscanner, $1, &$2, &$$)) YYABORT; free($1);}
-| tVARIABLE tSUPNUM {MPNumber t; if (!get_variable(yyscanner, $1, &t)) YYABORT; mp_xpowy_integer(&t, $2, &$$);; free($1);}
+| tVARIABLE tSUPNUM {MPNumber t; if (!get_variable(yyscanner, $1, $2, &$$)) YYABORT; free($1);}
| tVARIABLE tSUPNUM exp {if (!get_function(yyscanner, $1, &$3, &$$)) YYABORT; mp_xpowy_integer(&$$, $2, &$$); free($1);}
| tSUBNUM tROOT exp {mp_root(&$3, $1, &$$);}
| tROOT exp {mp_sqrt(&$2, &$$);}
| tROOT3 exp {mp_root(&$2, 3, &$$);}
| tROOT4 exp {mp_root(&$2, 4, &$$);}
-| tVARIABLE {if (!get_variable(yyscanner, $1, &$$)) YYABORT; free($1);}
+| tVARIABLE {if (!get_variable(yyscanner, $1, 1, &$$)) YYABORT; free($1);}
;
%%
diff --git a/src/mp-equation-private.h b/src/mp-equation-private.h
index 403ce2d..190c71a 100644
--- a/src/mp-equation-private.h
+++ b/src/mp-equation-private.h
@@ -29,12 +29,18 @@ struct MPEquationParserState {
/* User provided options */
MPEquationOptions *options;
+ /* Function to check if a variable is defined */
+ int (*variable_is_defined)(MPEquationParserState *state, const char *name);
+
/* Function to get variable values */
int (*get_variable)(MPEquationParserState *state, const char *name, MPNumber *z);
/* Function to set variable values */
void (*set_variable)(MPEquationParserState *state, const char *name, const MPNumber *x);
+ /* Function to check if a function is defined */
+ int (*function_is_defined)(MPEquationParserState *state, const char *name);
+
/* Function to solve functions */
int (*get_function)(MPEquationParserState *state, const char *name, const MPNumber *x, MPNumber *z);
diff --git a/src/mp-equation.c b/src/mp-equation.c
index 831dee6..180fff1 100644
--- a/src/mp-equation.c
+++ b/src/mp-equation.c
@@ -26,13 +26,15 @@
extern int _mp_equation_parse(yyscan_t yyscanner);
-char *
-utf8_next_char (const char *c)
+static int
+variable_is_defined(MPEquationParserState *state, const char *name)
{
- c++;
- while ((*c & 0xC0) == 0x80)
- c++;
- return (char *)c;
+ /* FIXME: Make more generic */
+ if (strcmp(name, "e") == 0 || strcmp(name, "i") == 0 || strcmp(name, "Ï?") == 0)
+ return 1;
+ if (state->options->variable_is_defined)
+ return state->options->variable_is_defined(name);
+ return 0;
}
@@ -52,34 +54,6 @@ get_variable(MPEquationParserState *state, const char *name, MPNumber *z)
else
result = 0;
- /* If has more than one character then assuming a multiplication of variables */
- if (!result && utf8_next_char(name)[0] != '\0') {
- const char *c, *next;
- char *buffer = malloc(sizeof(char) * strlen(name));
- MPNumber value;
-
- result = 1;
- mp_set_from_integer(1, &value);
- for (c = name; *c != '\0'; c = next)
- {
- MPNumber t;
-
- next = utf8_next_char(c);
- snprintf(buffer, next - c + 1, "%s", c);
-
- if (!get_variable(state, buffer, &t))
- {
- result = 0;
- break;
- }
- mp_multiply(&value, &t, &value);
- }
-
- free(buffer);
- if (result)
- mp_set_from_mp(&value, z);
- }
-
return result;
}
@@ -109,7 +83,7 @@ sub_atoi(const char *data)
do {
for(i = 0; digits[i] != NULL && strncmp(data, digits[i], strlen(digits[i])) != 0; i++);
if(digits[i] == NULL)
- return 0;
+ return -1;
data += strlen(digits[i]);
value = value * 10 + i;
} while(*data != '\0');
@@ -139,6 +113,43 @@ super_atoi(const char *data)
return sign * value;
}
+
+static int
+function_is_defined(MPEquationParserState *state, const char *name)
+{
+ char *c, *lower_name;
+ int result = 1;
+
+ lower_name = strdup(name);
+ for (c = lower_name; *c; c++)
+ *c = tolower(*c);
+
+ /* FIXME: Make more generic */
+ if (strcmp(lower_name, "log") == 0 ||
+ (strncmp(lower_name, "log", 3) == 0 && sub_atoi(lower_name + 3) >= 0) ||
+ strcmp(lower_name, "ln") == 0 ||
+ strcmp(lower_name, "sqrt") == 0 ||
+ strcmp(lower_name, "abs") == 0 ||
+ strcmp(lower_name, "int") == 0 ||
+ strcmp(lower_name, "frac") == 0 ||
+ strcmp(lower_name, "sin") == 0 || strcmp(lower_name, "cos") == 0 || strcmp(lower_name, "tan") == 0 ||
+ strcmp(lower_name, "sin�¹") == 0 || strcmp(lower_name, "cos�¹") == 0 || strcmp(lower_name, "tan�¹") == 0 ||
+ strcmp(lower_name, "sinh") == 0 || strcmp(lower_name, "cosh") == 0 || strcmp(lower_name, "tanh") == 0 ||
+ strcmp(lower_name, "sinh�¹") == 0 || strcmp(lower_name, "cosh�¹") == 0 || strcmp(lower_name, "tanh�¹") == 0 ||
+ strcmp(lower_name, "asinh") == 0 || strcmp(lower_name, "acosh") == 0 || strcmp(lower_name, "atanh") == 0 ||
+ strcmp(lower_name, "ones") == 0 ||
+ strcmp(lower_name, "twos") == 0) {
+ g_free (lower_name);
+ return 1;
+ }
+ g_free (lower_name);
+
+ if (state->options->function_is_defined)
+ return state->options->function_is_defined(name);
+ return 0;
+}
+
+
static int
get_function(MPEquationParserState *state, const char *name, const MPNumber *x, MPNumber *z)
{
@@ -224,8 +235,10 @@ mp_equation_parse(const char *expression, MPEquationOptions *options, MPNumber *
memset(&state, 0, sizeof(MPEquationParserState));
state.options = options;
+ state.variable_is_defined = variable_is_defined;
state.get_variable = get_variable;
state.set_variable = set_variable;
+ state.function_is_defined = function_is_defined;
state.get_function = get_function;
state.error = 0;
diff --git a/src/mp-equation.h b/src/mp-equation.h
index 4f1ad2e..5a51f43 100644
--- a/src/mp-equation.h
+++ b/src/mp-equation.h
@@ -46,6 +46,9 @@ typedef struct {
/* Data to pass to callbacks */
void *callback_data;
+
+ /* Function to check if a variable is defined */
+ int (*variable_is_defined)(const char *name);
/* Function to get variable values */
int (*get_variable)(const char *name, MPNumber *z, void *data);
@@ -53,6 +56,9 @@ typedef struct {
/* Function to set variable values */
void (*set_variable)(const char *name, const MPNumber *x, void *data);
+ /* Function to check if a function is defined */
+ int (*function_is_defined)(const char *name);
+
/* Function to solve functions */
int (*get_function)(const char *name, const MPNumber *x, MPNumber *z, void *data);
diff --git a/src/unittest.c b/src/unittest.c
index d3a140e..f7bcba0 100644
--- a/src/unittest.c
+++ b/src/unittest.c
@@ -86,7 +86,7 @@ test(char *expression, char *expected, int expected_error)
if(error == 0) {
mp_cast_to_string(&result, base, 9, 1, result_str, 1024);
if(expected_error != 0)
- fail("'%s' -> %s, expected error %d", expression, result_str, expected_error);
+ fail("'%s' -> %s, expected error %s", expression, result_str, error_code_to_string(expected_error));
else if(strcmp(result_str, expected) != 0)
fail("'%s' -> '%s', expected '%s'", expression, result_str, expected);
else
@@ -103,6 +103,13 @@ test(char *expression, char *expected, int expected_error)
int
+variable_is_defined(const char *name)
+{
+ return strcmp (name, "x") == 0 || strcmp (name, "y") == 0;
+}
+
+
+int
get_variable(const char *name, MPNumber *z, void *data)
{
if (strcmp (name, "x") == 0) {
@@ -130,6 +137,7 @@ test_parser()
base = 10;
options.wordlen = 32;
options.angle_units = MP_DEGREES;
+ options.variable_is_defined = variable_is_defined;
options.get_variable = get_variable;
options.set_variable = set_variable;
@@ -223,15 +231,17 @@ test_parser()
test("y2", "", PARSER_ERR_UNKNOWN_FUNCTION);
test("y²", "9", 0);
test("2y²", "18", 0);
+ test("xÃ?y", "6", 0);
test("xy", "6", 0);
test("yx", "6", 0);
test("2xy", "12", 0);
- //test("x²y", "12", 0);
- //test("xy²", "18", 0);
+ test("x²y", "12", 0);
+ test("xy²", "18", 0);
test("(xy)²", "36", 0);
- //test("2x²y", "24", 0);
- //test("2xy²", "36", 0);
- //test("2x²y²", "72", 0);
+ test("2x²y", "24", 0);
+ test("2xy²", "36", 0);
+ test("2x²y²", "72", 0);
+ test("x²yx²y", "324", 0);
test("Ï?", "3.141592654", 0);
test("e", "2.718281828", 0);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]