Mercurial > audlegacy-plugins
view src/paranormal/libcalc/parser.yacc @ 1833:15e7d3473974
paranormal: MK2
author | William Pitcock <nenolod@atheme.org> |
---|---|
date | Mon, 24 Sep 2007 13:57:28 -0500 |
parents | 117ae74e2715 |
children |
line wrap: on
line source
/* 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. */ /* suppress conflict warnings */ %expect 37 /* 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 = vfs_getc (pc->input)) == ' ' || c == '\t' || c == '\n'); /* End of input ? */ if (c == EOF) return 0; /* Char starts a number => parse the number. */ if (isdigit (c)) { vfs_fseek (pc->input, -1, SEEK_CUR); /* 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"); sscanf (((VFSBuffer *)(pc->input->handle))->iter, "%lf", &yylval->d_value); while (isdigit(c) || c == '.') { c = vfs_getc(pc->input); } vfs_fseek(pc->input, -1, SEEK_CUR); 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 = vfs_getc (pc->input); } while (c != EOF && isalnum (c)); vfs_fseek (pc->input, -1, SEEK_CUR); 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; VFSFile *stream; g_return_val_if_fail(str != NULL && dict != NULL, NULL); stream = vfs_buffer_new_from_string ( (char *) str ); pc.input = stream; pc.expr = expr_new (); pc.dict = dict; if (yyparse (&pc) != 0) { /* Check for error. */ expr_free (pc.expr); pc.expr = NULL; } vfs_fclose (stream); return pc.expr; }