diff options
Diffstat (limited to 'capplets/screensaver/expr.c')
-rw-r--r-- | capplets/screensaver/expr.c | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/capplets/screensaver/expr.c b/capplets/screensaver/expr.c new file mode 100644 index 000000000..45046a803 --- /dev/null +++ b/capplets/screensaver/expr.c @@ -0,0 +1,259 @@ +/* -*- mode: c; style: linux -*- */ + +/* expr.c + * Copyright (C) 2000 Helix Code, Inc. + * + * Written by Bradford Hovinen (hovinen@helixcode.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "expr.h" + +static gdouble int_parse_sentence (GScanner *scanner); +static gdouble int_parse_unary (GScanner *scanner); +static gdouble int_parse_atom (GScanner *scanner); +static gdouble int_parse_expr (GScanner *scanner, gboolean expr, + gboolean neg); +static gdouble int_parse_term (GScanner *scanner, gboolean expr, + gboolean inv); +static gdouble int_parse_factor (GScanner *scanner, gboolean expr); + +gboolean +parse_sentence (gchar *sentence, GScanner *scanner) +{ + g_scanner_input_text (scanner, sentence, strlen (sentence)); + g_scanner_get_next_token (scanner); + return int_parse_sentence (scanner) != 0.0; +} + +gdouble +parse_expr (gchar *expr, gdouble var) +{ + static GScannerConfig config; + GScanner *scanner; + gchar *var_string; + gfloat ret; + + config.cset_skip_characters = " \t\n"; + config.cset_identifier_first = "abcdefghijklmnopqrstuvwxyz"; + config.cset_identifier_nth = "abcdefghijklmnopqrstuvwxyz_"; + config.scan_symbols = TRUE; + config.scan_identifier = TRUE; + + scanner = g_scanner_new (&config); + g_scanner_input_text (scanner, expr, strlen (expr)); + g_scanner_get_next_token (scanner); + g_scanner_set_scope (scanner, 0); + var_string = g_strdup_printf ("%f", var); + g_scanner_scope_add_symbol (scanner, 0, "var", var_string); + + ret = int_parse_expr (scanner, TRUE, FALSE); + + g_free (var_string); + g_scanner_destroy (scanner); + return ret; +} + +static gdouble +int_parse_sentence (GScanner *scanner) +{ + GTokenType token_type; + GTokenValue value; + gdouble left; + + left = int_parse_unary (scanner); + + token_type = g_scanner_cur_token (scanner); + value = g_scanner_cur_value (scanner); + + if ((token_type == G_TOKEN_CHAR && value.v_char == '&') || + (token_type == G_TOKEN_SYMBOL && value.v_symbol == SYMBOL_AND)) + { + g_scanner_get_next_token (scanner); + return (int_parse_sentence (scanner) != 0.0 && + left != 0.0) ? 1.0 : 0.0; + } + else if ((token_type == G_TOKEN_CHAR && value.v_char == '|') || + (token_type == G_TOKEN_SYMBOL && + value.v_symbol == SYMBOL_OR)) + { + g_scanner_get_next_token (scanner); + return (int_parse_sentence (scanner) != 0.0 || + left != 0.0) ? 1.0 : 0.0; + } + + return left; +} + +static gdouble +int_parse_unary (GScanner *scanner) +{ + GTokenType token_type; + GTokenValue value; + + token_type = g_scanner_cur_token (scanner); + value = g_scanner_cur_value (scanner); + + if ((token_type == G_TOKEN_CHAR && value.v_char == '!') || + (token_type == G_TOKEN_SYMBOL && value.v_symbol == SYMBOL_NOT)) + { + g_scanner_get_next_token (scanner); + return (int_parse_unary (scanner) != 0.0) ? 0.0 : 1.0; + } else { + return (int_parse_atom (scanner) != 0.0) ? 1.0 : 0.0; + } +} + +static gdouble +int_parse_atom (GScanner *scanner) +{ + GTokenType token_type; + GTokenValue value; + gdouble left; + + left = int_parse_expr (scanner, FALSE, FALSE); + + token_type = g_scanner_cur_token (scanner); + + if (token_type == G_TOKEN_CHAR) { + value = g_scanner_cur_value (scanner); + if (value.v_char == '=') { + g_scanner_get_next_token (scanner); + return (int_parse_expr (scanner, FALSE, FALSE) + == left) ? 1.0 : 0.0; + } + else if (value.v_char == '<') { + g_scanner_get_next_token (scanner); + return (int_parse_expr (scanner, FALSE, FALSE) + > left) ? 1.0 : 0.0; + } + else if (value.v_char == '>') { + g_scanner_get_next_token (scanner); + return (int_parse_expr (scanner, FALSE, FALSE) + < left) ? 1.0 : 0.0; + } + } + + return left; +} + +static gdouble +int_parse_expr (GScanner *scanner, gboolean expr, gboolean neg) +{ + GTokenType token_type; + GTokenValue value; + gdouble left; + gdouble ret; + + left = int_parse_term (scanner, expr, FALSE); + + token_type = g_scanner_cur_token (scanner); + + if (token_type == G_TOKEN_CHAR) { + value = g_scanner_cur_value (scanner); + if (value.v_char == '+') { + g_scanner_get_next_token (scanner); + return left + int_parse_expr (scanner, expr, FALSE); + } + else if (value.v_char == '-') { + g_scanner_get_next_token (scanner); + ret = int_parse_expr (scanner, expr, TRUE); + if (neg) + return left + ret; + else + return left - ret; + } + } + + return left; +} + +static gdouble +int_parse_term (GScanner *scanner, gboolean expr, gboolean inv) +{ + GTokenType token_type; + GTokenValue value; + gdouble left; + gdouble ret; + + left = int_parse_factor (scanner, expr); + + token_type = g_scanner_cur_token (scanner); + + if (token_type == G_TOKEN_CHAR) { + value = g_scanner_cur_value (scanner); + if (token_type == '*') { + g_scanner_get_next_token (scanner); + return left * int_parse_term (scanner, expr, FALSE); + } + else if (token_type == '/') { + g_scanner_get_next_token (scanner); + ret = int_parse_term (scanner, expr, TRUE); + if (inv) + return left * ret; + else + return left / ret; + } + } + + return left; +} + +static gdouble +int_parse_factor (GScanner *scanner, gboolean expr) +{ + GTokenType token_type; + GTokenValue value; + gdouble ret; + + token_type = g_scanner_cur_token (scanner); + value = g_scanner_cur_value (scanner); + g_scanner_get_next_token (scanner); + + if (token_type == G_TOKEN_CHAR && value.v_char == '(') { + if (expr) + ret = int_parse_expr (scanner, TRUE, FALSE); + else + ret = int_parse_sentence (scanner); + + g_scanner_get_next_token (scanner); + return ret; + } + else if (token_type == G_TOKEN_INT) { + return value.v_int; + } + else if (token_type == G_TOKEN_FLOAT) { + return value.v_float; + } + else if (token_type == G_TOKEN_SYMBOL) { + if (value.v_symbol == (gpointer) 1) + return (gint) value.v_symbol; + else + return g_strtod (value.v_symbol, NULL); + } + else if (token_type == G_TOKEN_IDENTIFIER) { + return 0.0; + } else { + g_scanner_error (scanner, "Parse error in expression"); + } + + return 0; +} |