Updated Danish translation
[gcalctool.git] / src / mp-equation-parser.y
blob0f019de367c35fccd7b1c48a51366ea305a91ae6
1 %{
2 /* Copyright (c) 2004-2008 Sami Pietila
3 * Copyright (c) 2008-2009 Robert Ancell
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18 * 02111-1307, USA.
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <math.h>
24 #include <errno.h>
25 #include <assert.h>
27 #include "mp-equation-private.h"
28 #include "mp-equation-parser.h"
29 #include "mp-equation-lexer.h"
31 // fixme support x log x
32 // treat exp NAME exp as a function always and pass both arguments, i.e.
33 // can do mod using both and all others use $1 * NAME($3)
35 static void set_error(yyscan_t yyscanner, int error, const char *token)
37 _mp_equation_get_extra(yyscanner)->error = error;
38 if (token)
39 _mp_equation_get_extra(yyscanner)->error_token = strdup(token);
42 static void set_result(yyscan_t yyscanner, const MPNumber *x)
44 mp_set_from_mp(x, &(_mp_equation_get_extra(yyscanner))->ret);
47 char *
48 utf8_next_char (const char *c)
50 c++;
51 while ((*c & 0xC0) == 0x80)
52 c++;
53 return (char *)c;
56 static int get_variable(yyscan_t yyscanner, const char *name, int power, MPNumber *z)
58 int result = 0;
60 /* If defined, then get the variable */
61 if (_mp_equation_get_extra(yyscanner)->get_variable(_mp_equation_get_extra(yyscanner), name, z)) {
62 mp_xpowy_integer(z, power, z);
63 return 1;
66 /* If has more than one character then assume a multiplication of variables */
67 if (utf8_next_char(name)[0] != '\0') {
68 const char *c, *next;
69 char *buffer = malloc(sizeof(char) * strlen(name));
70 MPNumber value;
72 result = 1;
73 mp_set_from_integer(1, &value);
74 for (c = name; *c != '\0'; c = next) {
75 MPNumber t;
77 next = utf8_next_char(c);
78 snprintf(buffer, next - c + 1, "%s", c);
80 if (!_mp_equation_get_extra(yyscanner)->get_variable(_mp_equation_get_extra(yyscanner), buffer, &t)) {
81 result = 0;
82 break;
85 /* If last term do power */
86 if (*next == '\0')
87 mp_xpowy_integer(&t, power, &t);
89 mp_multiply(&value, &t, &value);
92 free(buffer);
93 if (result)
94 mp_set_from_mp(&value, z);
97 if (!result)
98 set_error(yyscanner, PARSER_ERR_UNKNOWN_VARIABLE, name);
100 return result;
103 static void set_variable(yyscan_t yyscanner, const char *name, MPNumber *x)
105 _mp_equation_get_extra(yyscanner)->set_variable(_mp_equation_get_extra(yyscanner), name, x);
108 static int get_function(yyscan_t yyscanner, const char *name, const MPNumber *x, MPNumber *z)
110 if (!_mp_equation_get_extra(yyscanner)->get_function(_mp_equation_get_extra(yyscanner), name, x, z)) {
111 set_error(yyscanner, PARSER_ERR_UNKNOWN_FUNCTION, name);
112 return 0;
114 return 1;
117 static void do_not(yyscan_t yyscanner, const MPNumber *x, MPNumber *z)
119 if (!mp_is_overflow(x, _mp_equation_get_extra(yyscanner)->options->wordlen)) {
120 set_error(yyscanner, PARSER_ERR_OVERFLOW, NULL);
122 mp_not(x, _mp_equation_get_extra(yyscanner)->options->wordlen, z);
125 static char *make_unit(const char *name, int power)
127 char *name2;
129 // FIXME: Hacky
130 if (power == 2) {
131 name2 = malloc(sizeof(char) * (strlen(name) + strlen("²") + 1));
132 sprintf(name2, "%s²", name);
134 else if (power == 3) {
135 name2 = malloc(sizeof(char) * (strlen(name) + strlen("³") + 1));
136 sprintf(name2, "%s³", name);
138 else {
139 name2 = malloc(sizeof(char) * (strlen(name) + strlen("?") + 1));
140 sprintf(name2, "%s?", name);
143 return name2;
146 static void do_conversion(yyscan_t yyscanner, const MPNumber *x, const char *x_units, const char *z_units, MPNumber *z)
148 if (!_mp_equation_get_extra(yyscanner)->convert(_mp_equation_get_extra(yyscanner), x, x_units, z_units, z))
149 set_error(yyscanner, PARSER_ERR_UNKNOWN_CONVERSION, NULL);
154 %pure-parser
155 %name-prefix="_mp_equation_"
156 %locations
157 %parse-param {yyscan_t yyscanner}
158 %lex-param {yyscan_t yyscanner}
160 %union {
161 MPNumber int_t;
162 int integer;
163 char *name;
166 %left <int_t> tNUMBER
167 %left UNARY_PLUS
168 %left tADD tSUBTRACT
169 %left tAND tOR tXOR tXNOR
170 %left tMULTIPLY tDIVIDE tMOD MULTIPLICATION
171 %left tNOT
172 %left tROOT tROOT3 tROOT4
173 %left <name> tVARIABLE tFUNCTION
174 %right <integer> tSUBNUM tSUPNUM tNSUPNUM
175 %left BOOLEAN_OPERATOR
176 %left PERCENTAGE
177 %left UNARY_MINUS
178 %right '^' '!' '|'
179 %left tIN
181 %type <int_t> exp variable term
182 %type <name> unit
183 %start statement
187 statement:
188 exp { set_result(yyscanner, &$1); }
189 | exp '=' { set_result(yyscanner, &$1); }
190 | tVARIABLE '=' exp {set_variable(yyscanner, $1, &$3); set_result(yyscanner, &$3); }
191 | tNUMBER unit tIN unit { MPNumber t; do_conversion(yyscanner, &$1, $2, $4, &t); set_result(yyscanner, &t); free($2); free($4); }
192 | unit tIN unit { MPNumber x, t; mp_set_from_integer(1, &x); do_conversion(yyscanner, &x, $1, $3, &t); set_result(yyscanner, &t); free($1); free($3); }
195 unit:
196 tVARIABLE {$$ = $1;}
197 | tVARIABLE tSUPNUM {$$ = make_unit($1, $2); free($1);}
199 /* |x| gets confused and thinks = |x|(...||) */
201 exp:
202 '(' exp ')' {mp_set_from_mp(&$2, &$$);}
203 | '|' exp '|' {mp_abs(&$2, &$$);}
204 | '|' tVARIABLE '|' {get_variable(yyscanner, $2, 1, &$$); mp_abs(&$$, &$$); free($2);} /* FIXME: Shouldn't need this rule but doesn't parse without it... */
205 | '|' tNUMBER tVARIABLE '|' {get_variable(yyscanner, $3, 1, &$$); mp_multiply(&$2, &$$, &$$); mp_abs(&$$, &$$); free($3);} /* FIXME: Shouldn't need this rule but doesn't parse without it... */
206 | exp '^' exp {mp_xpowy(&$1, &$3, &$$);}
207 | exp tSUPNUM {mp_xpowy_integer(&$1, $2, &$$);}
208 | exp tNSUPNUM {mp_xpowy_integer(&$1, $2, &$$);}
209 | exp '!' {mp_factorial(&$1, &$$);}
210 | variable {mp_set_from_mp(&$1, &$$);}
211 | tNUMBER variable %prec MULTIPLICATION {mp_multiply(&$1, &$2, &$$);}
212 | tSUBTRACT exp %prec UNARY_MINUS {mp_invert_sign(&$2, &$$);}
213 | tADD tNUMBER %prec UNARY_PLUS {mp_set_from_mp(&$2, &$$);}
214 | exp tDIVIDE exp {mp_divide(&$1, &$3, &$$);}
215 | exp tMOD exp {mp_modulus_divide(&$1, &$3, &$$);}
216 | exp tMULTIPLY exp {mp_multiply(&$1, &$3, &$$);}
217 | exp tADD exp '%' %prec PERCENTAGE {mp_add_integer(&$3, 100, &$3); mp_divide_integer(&$3, 100, &$3); mp_multiply(&$1, &$3, &$$);}
218 | exp tSUBTRACT exp '%' %prec PERCENTAGE {mp_add_integer(&$3, -100, &$3); mp_divide_integer(&$3, -100, &$3); mp_multiply(&$1, &$3, &$$);}
219 | exp tADD exp {mp_add(&$1, &$3, &$$);}
220 | exp tSUBTRACT exp {mp_subtract(&$1, &$3, &$$);}
221 | exp '%' {mp_divide_integer(&$1, 100, &$$);}
222 | tNOT exp {do_not(yyscanner, &$2, &$$);}
223 | exp tAND exp %prec BOOLEAN_OPERATOR {mp_and(&$1, &$3, &$$);}
224 | exp tOR exp %prec BOOLEAN_OPERATOR {mp_or(&$1, &$3, &$$);}
225 | exp tXOR exp %prec BOOLEAN_OPERATOR {mp_xor(&$1, &$3, &$$);}
226 | tNUMBER {mp_set_from_mp(&$1, &$$);}
230 variable:
231 term {mp_set_from_mp(&$1, &$$);}
232 | tFUNCTION exp {if (!get_function(yyscanner, $1, &$2, &$$)) YYABORT; free($1);}
233 | tFUNCTION tSUPNUM exp {if (!get_function(yyscanner, $1, &$3, &$$)) YYABORT; mp_xpowy_integer(&$$, $2, &$$); free($1);}
234 | tVARIABLE exp {set_error(yyscanner, PARSER_ERR_UNKNOWN_FUNCTION, $1); free($1); YYABORT;}
235 | tVARIABLE tSUPNUM exp {set_error(yyscanner, PARSER_ERR_UNKNOWN_FUNCTION, $1); free($1); YYABORT;}
236 | tSUBNUM tROOT exp {mp_root(&$3, $1, &$$);}
237 | tROOT exp {mp_sqrt(&$2, &$$);}
238 | tROOT3 exp {mp_root(&$2, 3, &$$);}
239 | tROOT4 exp {mp_root(&$2, 4, &$$);}
242 term:
243 tVARIABLE {if (!get_variable(yyscanner, $1, 1, &$$)) YYABORT; free($1);}
244 | tVARIABLE tSUPNUM {if (!get_variable(yyscanner, $1, $2, &$$)) YYABORT; free($1);}
245 | term term {mp_multiply(&$1, &$2, &$$);}