Mercurial > audlegacy-plugins
diff src/paranormal/libcalc/parser.y @ 282:3e160f6c04d2 trunk
[svn] - add libcalc from xvs and link to build
author | nenolod |
---|---|
date | Mon, 20 Nov 2006 13:26:09 -0800 |
parents | |
children | 795d83dcfdb7 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/paranormal/libcalc/parser.y Mon Nov 20 13:26:09 2006 -0800 @@ -0,0 +1,284 @@ +/* parser.y -- Bison parser for libexp + * + * Copyright (C) 2001 Janusz Gregorczyk <jgregor@kki.net.pl> + * + * This file is part of xvs. + * + * 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 of the License, 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. + */ + +/* C declarations. */ +%{ +#include <ctype.h> +#include <glib.h> +#include <locale.h> +#include <math.h> +#include <stdio.h> +#include <string.h> + +#include "dict.h" +#include "execute.h" +#include "function.h" +#include "parser.h" +#include "storage.h" + +#define YYPARSE_PARAM yyparam +#define YYLEX_PARAM yyparam + +static gboolean expr_add_compile (expression_t *expr, symbol_dict_t *dict, + char *str); + +#define GENERATE(str) if (!expr_add_compile (((parser_control *)yyparam)->expr, \ + ((parser_control *)yyparam)->dict, str)) \ + YYABORT; +%} + +%pure_parser + +/* Data types. */ +%union { +char *s_value; +char c_value; +double d_value; +int i_value; +} + +/* Terminal symbols. */ +%token <s_value> NAME +%token <d_value> NUMBER + +/* Precedence rules. */ +%right '=' +%left '-' '+' +%left '*' '/' +%left NEG +%right '^' + +/* Grammar follows */ +%% + +/* Input consits of a (possibly empty) list of expressions. */ +input: /* empty */ + | input expression_list +; + +/* expression_list is a ';' separated list of expressions. */ +expression_list: /* empty */ + | expression + { } + | expression_list ';' + | error ';' + { yyerrok; } + +/* argument list is a comma separated list od expressions */ +argument_list: + expression + { + } + | argument_list ',' expression + { + } + +/* expression is a C-like expression. */ +expression: NUMBER + { + char *buf = g_strdup_printf ("c%f:", $1); + GENERATE (buf); + g_free (buf); + } + | NAME + { + char *buf = g_strdup_printf ("l%s:", $1); + GENERATE (buf); + g_free (buf); + } + | NAME '=' expression + { + char *buf = g_strdup_printf ("s%s:", $1); + GENERATE (buf); + g_free (buf); + } + | NAME '(' argument_list ')' + { + char *buf = g_strdup_printf ("f%s:", $1); + GENERATE (buf); + g_free (buf); + } + + | expression '>' expression + { GENERATE (">"); } + | expression '<' expression + { GENERATE ("<"); } + + | expression '+' expression + { GENERATE ("+"); } + | expression '-' expression + { GENERATE ("-"); } + | expression '*' expression + { GENERATE ("*"); } + | expression '/' expression + { GENERATE ("/"); } + | '-' expression %prec NEG + { GENERATE ("n"); } + | expression '^' expression + { GENERATE ("^"); } + | '(' expression ')' + { } +; + +%% +/* End of grammar */ + +/* Called by yyparse on error. */ +int yyerror (char *s) { + /* Ignore errors, just print a warning. */ + g_warning ("%s\n", s); + return 0; +} + +int yylex (YYSTYPE *yylval, void *yyparam) { + int c; + parser_control *pc = (parser_control *) yyparam; + + /* Ignore whitespace, get first nonwhite character. */ + while ((c = fgetc (pc->input)) == ' ' || c == '\t' || c == '\n'); + + /* End of input ? */ + if (c == EOF) + return 0; + + /* Char starts a number => parse the number. */ + if (isdigit (c)) { + ungetc (c, pc->input);/* Put the char back. */ + { + char *old_locale, *saved_locale; + + old_locale = setlocale (LC_ALL, NULL); + saved_locale = g_strdup (old_locale); + setlocale (LC_ALL, "C"); + fscanf (pc->input, "%lf", &yylval->d_value); + setlocale (LC_ALL, saved_locale); + g_free (saved_locale); + } + return NUMBER; + } + + /* Char starts an identifier => read the name. */ + if (isalpha (c)) { + GString *sym_name; + + sym_name = g_string_new (NULL); + + do { + sym_name = g_string_append_c (sym_name, c); + + /* Get another character. */ + c = fgetc (pc->input); + } while (c != EOF && isalnum (c)); + + ungetc (c, pc->input); + + yylval->s_value = sym_name->str; + + g_string_free (sym_name, FALSE); + + return NAME; + } + + /* Any other character is a token by itself. */ + return c; +} + +static int load_name (char *str, char **name) { + int count = 0; + GString *new = g_string_new (NULL); + + while (*str != 0 && *str != ':') { + g_string_append_c (new, *str++); + count++; + } + + *name = new->str; + g_string_free (new, FALSE); + + return count; +} + +static gboolean expr_add_compile (expression_t *expr, symbol_dict_t *dict, + char *str) { + char op; + double dval; + int i; + char *name; + + while ((op = *str++)) { + switch (op) { + case 'c': /* A constant. */ + store_byte (expr, 'c'); + sscanf (str, "%lf%n", &dval, &i); + str += i; + store_double (expr, dval); + str++; /* Skip ';' */ + break; + + case 'f': /* A function call. */ + store_byte (expr, 'f'); + str += load_name (str, &name); + i = function_lookup (name); + if (i < 0) return FALSE; /* Fail on error. */ + store_int (expr, i); + g_free (name); + str++; /* Skip ';' */ + break; + + case 'l': /* Load a variable. */ + case 's': /* Store a variable. */ + store_byte (expr, op); + str += load_name (str, &name); + i = dict_lookup (dict, name); + store_int (expr, i); + g_free (name); + str++; /* Skip ';' */ + break; + + default: /* Copy verbatim. */ + store_byte (expr, op); + break; + } + } + + return TRUE; +} + +expression_t *expr_compile_string (const char* str, symbol_dict_t *dict) { + parser_control pc; + FILE *stream; + + stream = fmemopen (str, strlen (str), "r"); + + pc.input = stream; + pc.expr = expr_new (); + pc.dict = dict; + + if (yyparse (&pc) != 0) { + /* Check for error. */ + expr_free (pc.expr); + pc.expr = NULL; + } + + fclose (stream); + + return pc.expr; +}