summaryrefslogtreecommitdiff
path: root/capplets/screensaver/expr.c
diff options
context:
space:
mode:
Diffstat (limited to 'capplets/screensaver/expr.c')
-rw-r--r--capplets/screensaver/expr.c259
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;
+}