[gcalctool/gcalctool-new-parser] Get conversions working
- From: Robert Ancell <rancell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gcalctool/gcalctool-new-parser] Get conversions working
- Date: Sun, 16 Oct 2011 07:35:29 +0000 (UTC)
commit 919ac56fc39d1b660171e57ae33acdc50adb78ef
Author: Robert Ancell <robert ancell canonical com>
Date: Sun Oct 16 18:35:23 2011 +1100
Get conversions working
src/math-equation.c | 16 +---
src/mp-equation.c | 224 +++++++++++++++++++++++++++++++++---------------
src/mp-equation.h | 4 +-
src/test-mp-equation.c | 34 ++++----
4 files changed, 176 insertions(+), 102 deletions(-)
---
diff --git a/src/math-equation.c b/src/math-equation.c
index 0109a67..e1589ad 100644
--- a/src/math-equation.c
+++ b/src/math-equation.c
@@ -1132,19 +1132,9 @@ math_equation_solve_real(gpointer data)
_("Overflow. Try a bigger word size"));
break;
- case PARSER_ERR_UNKNOWN_VARIABLE:
- solvedata->error = g_strdup_printf(/* Error displayed to user when they an unknown variable is entered */
- _("Unknown variable '%s'"), error_token);
- break;
-
- case PARSER_ERR_UNKNOWN_FUNCTION:
- solvedata->error = g_strdup_printf(/* Error displayed to user when an unknown function is entered */
- _("Function '%s' is not defined"), error_token);
- break;
-
- case PARSER_ERR_UNKNOWN_CONVERSION:
- solvedata->error = g_strdup(/* Error displayed to user when an conversion with unknown units is attempted */
- _("Unknown conversion"));
+ case PARSER_ERR_UNKNOWN_SYMBOL:
+ solvedata->error = g_strdup_printf(/* Error displayed to user when they an unknown symbol is entered */
+ _("Unknown symbol '%s'"), error_token);
break;
case PARSER_ERR_MP:
diff --git a/src/mp-equation.c b/src/mp-equation.c
index fa0e7da..32000c2 100644
--- a/src/mp-equation.c
+++ b/src/mp-equation.c
@@ -250,16 +250,6 @@ get_function(MPEquationOptions *options, const char *name, const MPNumber *x, MP
}
-static int
-convert(MPEquationOptions *options, const MPNumber *x, const char *x_units, const char *z_units, MPNumber *z)
-{
- if (options->convert)
- return options->convert(x, x_units, z_units, z, options->callback_data);
- else
- return 0;
-}
-
-
typedef enum
{
TOKEN_NONE,
@@ -294,8 +284,9 @@ typedef enum
TOKEN_RIGHT_CEILING,
TOKEN_LEFT_FRACTION,
TOKEN_RIGHT_FRACTION,
- TOKEN_VARIABLE,
+ TOKEN_SYMBOL,
TOKEN_FUNCTION,
+ TOKEN_VARIABLE,
TOKEN_EXPRESSION
} TokenType;
@@ -322,7 +313,7 @@ token_new(TokenType type, const gchar *start, const gchar *end)
static gchar *
-token_get_string (Token *token)
+token_get_text (Token *token)
{
return g_strdup_printf("%.*s", (int)(token->end - token->start), token->start);
}
@@ -391,7 +382,7 @@ parse(MPEquationOptions *options, const gchar *expression, GList **tokens)
else if (unichar_issubdigit(c))
current_token = TOKEN_SUB_NUMBER;
else if (g_unichar_isalpha(c))
- current_token = TOKEN_VARIABLE;
+ current_token = TOKEN_SYMBOL;
else if (c == '+')
current_token = TOKEN_ADD;
else if (c == '-' || c == 0x2212 /* â */ )
@@ -472,7 +463,7 @@ parse(MPEquationOptions *options, const gchar *expression, GList **tokens)
current_token = TOKEN_NONE;
t = token_new(TOKEN_PERCENTAGE, token_start, i + 1);
- string = token_get_string(t);
+ string = token_get_text(t);
string[strlen (string) - 1] = '\0';
if (!mp_set_from_string(string, options->base, &t->value))
{
@@ -490,12 +481,12 @@ parse(MPEquationOptions *options, const gchar *expression, GList **tokens)
current_token = TOKEN_NONE;
t = token_new(TOKEN_NUMBER, token_start, i);
- string = token_get_string(t);
+ string = token_get_text(t);
if (!mp_set_from_string(string, options->base, &t->value))
*tokens = g_list_append(*tokens, t);
else if (g_unichar_isalpha(c)) {
- /* Try as a variable instead */
- current_token = TOKEN_VARIABLE;
+ /* Decode as a symbol instead */
+ current_token = TOKEN_SYMBOL;
}
else {
return PARSER_ERR_INVALID;
@@ -523,7 +514,7 @@ parse(MPEquationOptions *options, const gchar *expression, GList **tokens)
}
break;
- case TOKEN_VARIABLE:
+ case TOKEN_SYMBOL:
if (!g_unichar_isalpha(c) && !unichar_issubdigit(c)) {
gchar *name;
@@ -547,46 +538,9 @@ parse(MPEquationOptions *options, const gchar *expression, GList **tokens)
else if (strcmp(name, "xor") == 0) {
*tokens = g_list_append(*tokens, token_new(TOKEN_BOOLEAN_XOR, token_start, i));
}
- else if (function_is_defined(options, name)) {
- *tokens = g_list_append(*tokens, token_new(TOKEN_FUNCTION, token_start, i));
- }
- else if (variable_is_defined(options, name)) {
- Token *t;
- t = token_new(TOKEN_VARIABLE, token_start, i);
- get_variable(options, name, &t->value);
- *tokens = g_list_append(*tokens, t);
- }
else {
- const gchar *j;
- GString *v;
- GList *variables = NULL;
-
- /* If each value is defined then is a multiple of variables */
- v = g_string_new("");
- for (j = token_start; *j; j = g_utf8_next_char(j)) {
- Token *t;
-
- g_string_truncate(v, 0);
- g_string_append_unichar(v, g_utf8_get_char(j));
- if (!variable_is_defined(options, v->str) || j == i)
- break;
-
- t = token_new(TOKEN_VARIABLE, j, g_utf8_next_char(j));
- get_variable(options, v->str, &t->value);
- variables = g_list_append(variables, t);
- }
- g_string_free(v, TRUE);
-
- if (j != i)
- {
- g_list_foreach(variables, (GFunc) g_free, NULL);
- g_list_free(variables);
- return PARSER_ERR_UNKNOWN_VARIABLE;
- }
-
- *tokens = g_list_concat(*tokens, variables);
+ *tokens = g_list_append(*tokens, token_new(TOKEN_SYMBOL, token_start, i));
}
-
g_free(name);
current_token = TOKEN_NONE;
@@ -674,10 +628,8 @@ replace_block(GList **first, GList **last, GList *start, GList *end, MPNumber *r
link = start;
do {
GList *next = link->next;
- link->prev = NULL;
- link->next = NULL;
g_free(link->data);
- g_list_free(link);
+ g_list_free_1(link);
link = next;
} while (link != end);
}
@@ -781,7 +733,7 @@ do_function(MPEquationOptions *options, GList **first, GList **last, GList *func
exponent = 1;
}
else
- string = token_get_string(name);
+ string = token_get_text(name);
get_function(options, string, &arg->value, &result);
g_free(string);
@@ -913,6 +865,138 @@ print_tokens(GList *first, GList *last)
static MPErrorCode
+solve_conversion(MPEquationOptions *options, GList *first, GList *last, MPNumber *z)
+{
+ GList *i;
+ Token *x, *x_unit, *in, *z_unit;
+ char *text, *x_unit_name, *z_unit_name;
+ gboolean is_in, result = FALSE;
+
+ i = first;
+
+ x = i->data;
+ if (i == last || !has_value (x))
+ return PARSER_ERR_INVALID;
+
+ i = i->next;
+ x_unit = i->data;
+ if (i == last || x_unit->type != TOKEN_SYMBOL)
+ return PARSER_ERR_INVALID;
+
+ i = i->next;
+ in = i->data;
+ text = token_get_text (in);
+ is_in = strcmp (text, "in") == 0;
+ g_free (text);
+ if (i == last || !is_in)
+ return PARSER_ERR_INVALID;
+
+ i = i->next;
+ z_unit = i->data;
+ if (i != last || z_unit->type != TOKEN_SYMBOL)
+ return PARSER_ERR_INVALID;
+
+ x_unit_name = token_get_text (x_unit);
+ z_unit_name = token_get_text (z_unit);
+ if (options->convert)
+ result = options->convert(&x->value, x_unit_name, z_unit_name, z, options->callback_data);
+ g_free (x_unit_name);
+ g_free (z_unit_name);
+
+ if (result)
+ return PARSER_ERR_NONE;
+ else
+ return PARSER_ERR_MP;
+}
+
+
+static GList *
+expand_symbol (MPEquationOptions *options, Token *token)
+{
+ GList *tokens = NULL;
+ gchar *name;
+
+ name = token_get_text (token);
+ if (function_is_defined(options, name)) {
+ tokens = g_list_append(tokens, token_new(TOKEN_FUNCTION, token->start, token->end));
+ }
+ else if (variable_is_defined(options, name)) {
+ Token *t;
+ t = token_new(TOKEN_VARIABLE, token->start, token->end);
+ get_variable(options, name, &t->value);
+ tokens = g_list_append(tokens, t);
+ }
+ g_free (name);
+
+ /* Check if is a multiple of variables */
+ if (!tokens) {
+ const gchar *i;
+ GString *v;
+
+ v = g_string_new("");
+ for (i = token->start; i != token->end; i = g_utf8_next_char(i)) {
+ Token *t;
+
+ g_string_truncate(v, 0);
+ g_string_append_unichar(v, g_utf8_get_char(i));
+ if (!variable_is_defined(options, v->str))
+ {
+ g_list_free_full(tokens, g_free);
+ tokens = NULL;
+ break;
+ }
+
+ t = token_new(TOKEN_VARIABLE, i, g_utf8_next_char(i));
+ get_variable(options, v->str, &t->value);
+ tokens = g_list_append(tokens, t);
+ }
+ g_string_free(v, TRUE);
+ }
+
+ return tokens;
+}
+
+
+static MPErrorCode
+replace_symbols(MPEquationOptions *options, GList **tokens)
+{
+ GList *i;
+
+ for (i = *tokens; i; i = i->next)
+ {
+ Token *t = i->data;
+ GList *expanded, *last_expanded;
+
+ if (t->type != TOKEN_SYMBOL)
+ continue;
+
+ /* Expand this symbol into one or more tokens */
+ expanded = expand_symbol(options, t);
+ if (!expanded)
+ return PARSER_ERR_UNKNOWN_SYMBOL;
+ last_expanded = g_list_last (expanded);
+
+ /* Replace current token */
+ expanded->prev = i->prev;
+ if (expanded->prev)
+ expanded->prev->next = expanded;
+ else
+ *tokens = expanded;
+ last_expanded->next = i->next;
+ if (last_expanded->next)
+ last_expanded->next->prev = last_expanded;
+
+ /* Free the replaced token */
+ g_free (t);
+ g_list_free_1 (i);
+ i = last_expanded;
+ }
+
+ return PARSER_ERR_NONE;
+}
+
+
+static MPErrorCode
solve(MPEquationOptions *options, GList *first, GList *last, MPNumber *result)
{
while (TRUE) {
@@ -1216,7 +1300,7 @@ solve(MPEquationOptions *options, GList *first, GList *last, MPNumber *result)
MPErrorCode
mp_equation_parse(const char *expression, MPEquationOptions *options, MPNumber *result, char **error_token)
{
- GList *tokens, *last_token;
+ GList *tokens;
MPErrorCode error;
if (!(expression && result) || strlen(expression) == 0)
@@ -1228,8 +1312,14 @@ mp_equation_parse(const char *expression, MPEquationOptions *options, MPNumber *
if (error)
return error;
- last_token = g_list_last(tokens);
- error = solve(options, tokens, last_token, result);
+ error = solve_conversion(options, tokens, g_list_last(tokens), result);
+ if (!error)
+ return error;
+
+ error = replace_symbols (options, &tokens);
+ if (error)
+ return error;
+ error = solve(options, tokens, g_list_last(tokens), result);
if (error)
return error;
@@ -1251,12 +1341,8 @@ mp_error_code_to_string(MPErrorCode error_code)
return "PARSER_ERR_INVALID";
case PARSER_ERR_OVERFLOW:
return "PARSER_ERR_OVERFLOW";
- case PARSER_ERR_UNKNOWN_VARIABLE:
- return "PARSER_ERR_UNKNOWN_VARIABLE";
- case PARSER_ERR_UNKNOWN_FUNCTION:
- return "PARSER_ERR_UNKNOWN_FUNCTION";
- case PARSER_ERR_UNKNOWN_CONVERSION:
- return "PARSER_ERR_UNKNOWN_CONVERSION";
+ case PARSER_ERR_UNKNOWN_SYMBOL:
+ return "PARSER_ERR_UNKNOWN_SYMBOL";
case PARSER_ERR_MP:
return "PARSER_ERR_MP";
default:
diff --git a/src/mp-equation.h b/src/mp-equation.h
index d6c0f24..5672f8f 100644
--- a/src/mp-equation.h
+++ b/src/mp-equation.h
@@ -19,9 +19,7 @@ typedef enum
PARSER_ERR_NONE = 0,
PARSER_ERR_INVALID,
PARSER_ERR_OVERFLOW,
- PARSER_ERR_UNKNOWN_VARIABLE,
- PARSER_ERR_UNKNOWN_FUNCTION,
- PARSER_ERR_UNKNOWN_CONVERSION,
+ PARSER_ERR_UNKNOWN_SYMBOL,
PARSER_ERR_MP
} MPErrorCode;
diff --git a/src/test-mp-equation.c b/src/test-mp-equation.c
index dac35ec..1afcc65 100644
--- a/src/test-mp-equation.c
+++ b/src/test-mp-equation.c
@@ -215,18 +215,18 @@ test_equations()
test("7â", "", PARSER_ERR_INVALID); test("7â", "7", 0); test("7", "7", 0); test("7ââ", "7", 0);
test("8â", "", PARSER_ERR_INVALID); test("8â", "", PARSER_ERR_INVALID); test("8", "8", 0); test("8ââ", "8", 0);
test("9â", "", PARSER_ERR_INVALID); test("9â", "", PARSER_ERR_INVALID); test("9", "9", 0); test("9ââ", "9", 0);
- test("Aâ", "", PARSER_ERR_UNKNOWN_VARIABLE); test("Aâ", "", PARSER_ERR_UNKNOWN_VARIABLE); test("A", "", PARSER_ERR_UNKNOWN_VARIABLE); test("Aââ", "10", 0);
- test("Bâ", "", PARSER_ERR_UNKNOWN_VARIABLE); test("Bâ", "", PARSER_ERR_UNKNOWN_VARIABLE); test("B", "", PARSER_ERR_UNKNOWN_VARIABLE); test("Bââ", "11", 0);
- test("Câ", "", PARSER_ERR_UNKNOWN_VARIABLE); test("Câ", "", PARSER_ERR_UNKNOWN_VARIABLE); test("C", "", PARSER_ERR_UNKNOWN_VARIABLE); test("Cââ", "12", 0);
- test("Dâ", "", PARSER_ERR_UNKNOWN_VARIABLE); test("Dâ", "", PARSER_ERR_UNKNOWN_VARIABLE); test("D", "", PARSER_ERR_UNKNOWN_VARIABLE); test("Dââ", "13", 0);
- test("Eâ", "", PARSER_ERR_UNKNOWN_VARIABLE); test("Eâ", "", PARSER_ERR_UNKNOWN_VARIABLE); test("E", "", PARSER_ERR_UNKNOWN_VARIABLE); test("Eââ", "14", 0);
- test("Fâ", "", PARSER_ERR_UNKNOWN_VARIABLE); test("Fâ", "", PARSER_ERR_UNKNOWN_VARIABLE); test("F", "", PARSER_ERR_UNKNOWN_VARIABLE); test("Fââ", "15", 0);
- test("aâ", "", PARSER_ERR_UNKNOWN_VARIABLE); test("aâ", "", PARSER_ERR_UNKNOWN_VARIABLE); test("a", "", PARSER_ERR_UNKNOWN_VARIABLE); test("aââ", "10", 0);
- test("bâ", "", PARSER_ERR_UNKNOWN_VARIABLE); test("bâ", "", PARSER_ERR_UNKNOWN_VARIABLE); test("b", "", PARSER_ERR_UNKNOWN_VARIABLE); test("bââ", "11", 0);
- test("câ", "", PARSER_ERR_UNKNOWN_VARIABLE); test("câ", "", PARSER_ERR_UNKNOWN_VARIABLE); test("c", "", PARSER_ERR_UNKNOWN_VARIABLE); test("cââ", "12", 0);
- test("dâ", "", PARSER_ERR_UNKNOWN_VARIABLE); test("dâ", "", PARSER_ERR_UNKNOWN_VARIABLE); test("d", "", PARSER_ERR_UNKNOWN_VARIABLE); test("dââ", "13", 0);
- test("eâ", "", PARSER_ERR_UNKNOWN_VARIABLE); test("eâ", "", PARSER_ERR_UNKNOWN_VARIABLE); /* e is a built-in variable */ test("eââ", "14", 0);
- test("fâ", "", PARSER_ERR_UNKNOWN_VARIABLE); test("fâ", "", PARSER_ERR_UNKNOWN_VARIABLE); test("f", "", PARSER_ERR_UNKNOWN_VARIABLE); test("fââ", "15", 0);
+ test("Aâ", "", PARSER_ERR_UNKNOWN_SYMBOL); test("Aâ", "", PARSER_ERR_UNKNOWN_SYMBOL); test("A", "", PARSER_ERR_UNKNOWN_SYMBOL); test("Aââ", "10", 0);
+ test("Bâ", "", PARSER_ERR_UNKNOWN_SYMBOL); test("Bâ", "", PARSER_ERR_UNKNOWN_SYMBOL); test("B", "", PARSER_ERR_UNKNOWN_SYMBOL); test("Bââ", "11", 0);
+ test("Câ", "", PARSER_ERR_UNKNOWN_SYMBOL); test("Câ", "", PARSER_ERR_UNKNOWN_SYMBOL); test("C", "", PARSER_ERR_UNKNOWN_SYMBOL); test("Cââ", "12", 0);
+ test("Dâ", "", PARSER_ERR_UNKNOWN_SYMBOL); test("Dâ", "", PARSER_ERR_UNKNOWN_SYMBOL); test("D", "", PARSER_ERR_UNKNOWN_SYMBOL); test("Dââ", "13", 0);
+ test("Eâ", "", PARSER_ERR_UNKNOWN_SYMBOL); test("Eâ", "", PARSER_ERR_UNKNOWN_SYMBOL); test("E", "", PARSER_ERR_UNKNOWN_SYMBOL); test("Eââ", "14", 0);
+ test("Fâ", "", PARSER_ERR_UNKNOWN_SYMBOL); test("Fâ", "", PARSER_ERR_UNKNOWN_SYMBOL); test("F", "", PARSER_ERR_UNKNOWN_SYMBOL); test("Fââ", "15", 0);
+ test("aâ", "", PARSER_ERR_UNKNOWN_SYMBOL); test("aâ", "", PARSER_ERR_UNKNOWN_SYMBOL); test("a", "", PARSER_ERR_UNKNOWN_SYMBOL); test("aââ", "10", 0);
+ test("bâ", "", PARSER_ERR_UNKNOWN_SYMBOL); test("bâ", "", PARSER_ERR_UNKNOWN_SYMBOL); test("b", "", PARSER_ERR_UNKNOWN_SYMBOL); test("bââ", "11", 0);
+ test("câ", "", PARSER_ERR_UNKNOWN_SYMBOL); test("câ", "", PARSER_ERR_UNKNOWN_SYMBOL); test("c", "", PARSER_ERR_UNKNOWN_SYMBOL); test("cââ", "12", 0);
+ test("dâ", "", PARSER_ERR_UNKNOWN_SYMBOL); test("dâ", "", PARSER_ERR_UNKNOWN_SYMBOL); test("d", "", PARSER_ERR_UNKNOWN_SYMBOL); test("dââ", "13", 0);
+ test("eâ", "", PARSER_ERR_UNKNOWN_SYMBOL); test("eâ", "", PARSER_ERR_UNKNOWN_SYMBOL); /* e is a built-in variable */ test("eââ", "14", 0);
+ test("fâ", "", PARSER_ERR_UNKNOWN_SYMBOL); test("fâ", "", PARSER_ERR_UNKNOWN_SYMBOL); test("f", "", PARSER_ERR_UNKNOWN_SYMBOL); test("fââ", "15", 0);
test("+1", "1", 0);
test("â1", "â1", 0);
@@ -286,14 +286,14 @@ test_equations()
test("x", "2", 0);
test("y", "3", 0);
- test("z", "", PARSER_ERR_UNKNOWN_VARIABLE);
+ test("z", "", PARSER_ERR_UNKNOWN_SYMBOL);
test("2y", "6", 0);
test("y2", "", PARSER_ERR_INVALID);
test("y 2", "", PARSER_ERR_INVALID);
- test("2z", "", PARSER_ERR_UNKNOWN_VARIABLE);
- test("z2", "", PARSER_ERR_UNKNOWN_VARIABLE);
- test("z 2", "", PARSER_ERR_UNKNOWN_VARIABLE);
- test("z(2)", "", PARSER_ERR_UNKNOWN_VARIABLE);
+ test("2z", "", PARSER_ERR_UNKNOWN_SYMBOL);
+ test("z2", "", PARSER_ERR_UNKNOWN_SYMBOL);
+ test("z 2", "", PARSER_ERR_UNKNOWN_SYMBOL);
+ test("z(2)", "", PARSER_ERR_UNKNOWN_SYMBOL);
test("yÂ", "9", 0);
test("2yÂ", "18", 0);
test("xÃy", "6", 0);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]