[gcalctool] Update parser to be more flexible



commit ca85a62e83ded88445e1ca555ae9d6404e3031fe
Author: Robert Ancell <robert ancell gmail com>
Date:   Tue Jul 14 13:12:19 2009 +1000

    Update parser to be more flexible

 src/functions.c          |   14 ++-
 src/mp-binary.c          |    6 +-
 src/mp-equation-lexer.l  |  123 ++++++++---------
 src/mp-equation-parser.y |  343 ++++++++++++++++------------------------------
 src/mp-equation.c        |  130 +++++++++++++++---
 src/mp-equation.h        |   39 ++++--
 src/mp.c                 |    9 +-
 src/mp.h                 |    6 +-
 src/unittest.c           |  137 ++++++++++++++++--
 9 files changed, 448 insertions(+), 359 deletions(-)
---
diff --git a/src/functions.c b/src/functions.c
index 7504ff9..56b68c5 100644
--- a/src/functions.c
+++ b/src/functions.c
@@ -177,7 +177,7 @@ do_function(int index)
     assert(index >= 0);
     assert(index <= 9);
 
-    ret = mp_equation_udf_parse(function_get_value(index));
+    ret = 0;//FIXME: mp_equation_udf_parse(function_get_value(index));
     if (!ret) {
         ui_set_statusbar("", "");
     } else {
@@ -559,6 +559,18 @@ do_expression(int function, int arg, int cursor_start, int cursor_end)
                        message = _("Overflow. Try a bigger word size");
                        break;
 
+                    case -PARSER_ERR_UNKNOWN_VARIABLE:
+                        /* Translators; Error displayd to user when they
+                         * an unknown variable is entered */
+                       message = _("Unknown variable");
+                       break;
+
+                    case -PARSER_ERR_UNKNOWN_FUNCTION:
+                        /* Translators; Error displayd to user when they
+                         * an unknown function is entered */
+                       message = _("Unknown function");
+                       break;
+
                     case -MPMATH_ERR:
                         message = v->math_error_text;
                         break;
diff --git a/src/mp-binary.c b/src/mp-binary.c
index b97fc98..8d609b5 100644
--- a/src/mp-binary.c
+++ b/src/mp-binary.c
@@ -144,7 +144,7 @@ mp_shift(const MPNumber *x, int count, MPNumber *z)
 
 
 void
-mp_1s_complement(const MPNumber *x, int wordlen, MPNumber *z)
+mp_ones_complement(const MPNumber *x, int wordlen, MPNumber *z)
 {
     MPNumber t;
     mp_set_from_integer(0, &t);
@@ -153,8 +153,8 @@ mp_1s_complement(const MPNumber *x, int wordlen, MPNumber *z)
 
 
 void
-mp_2s_complement(const MPNumber *x, int wordlen, MPNumber *z)
+mp_twos_complement(const MPNumber *x, int wordlen, MPNumber *z)
 {
-    mp_1s_complement (x, wordlen, z);
+    mp_ones_complement (x, wordlen, z);
     mp_add_integer (z, 1, z);
 }
diff --git a/src/mp-equation-lexer.l b/src/mp-equation-lexer.l
index d6e35be..5bb6a2e 100644
--- a/src/mp-equation-lexer.l
+++ b/src/mp-equation-lexer.l
@@ -7,9 +7,7 @@
 
 %{
 
-/*  $Header: /cvs/gnome/gcalctool/gcalctool/ce_tokeniser.l,v 1.16 2006/12/15 15:27:37 richb Exp $
- *
- *  Copyright (C) 2004-2008 Sami Pietila
+/*  Copyright (C) 2004-2008 Sami Pietila
  *  Copyright (C) 2008-2009 Robert Ancell
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -70,75 +68,67 @@ static int sub_atoi(const char *data)
 }
 %}
 
-DECIMAL	     "."|","
-BIN          [0-1]
-OCT          [0-7]
-DEC          [0-9]
-HEX          [0-9]|[A-F]|[a-f]
-EXP          "e"|"e+"|"e-"|"E"|"E+"|"E-"
-SUPER_DIGITS "�"|"¹"|"²"|"³"|"�"|"�"|"�"|"�"|"�"|"�"
-SUB_DIGITS   "â??"|"â??"|"â??"|"â??"|"â??"|"â??"|"â??"|"â??"|"â??"|"â??"
-FRACTION     "½"|"â??"|"â??"|"¼"|"¾"|"â??"|"â??"|"â??"|"â??"|"â??"|"â??"|"â??"|"â??"|"â??"|"â??"
+
+ZERO          "0"|"Ù "|"Û°"|"ß?"|"०"|"০"|"੦"|"૦"|"à­¦"|"௦"|"౦"|"೦"|"൦"|"à¹?"|"à»?"
+ONE           "1"|"Ù¡"|"Û±"|"ß?"|"१"|"১"|"੧"|"૧"|"à­§"|"௧"|"౧"|"೧"|"൧"|"à¹?"|"à»?"
+TWO           "2"|"Ù¢"|"Û²"|"ß?"|"२"|"২"|"੨"|"૨"|"à­¨"|"௨"|"౨"|"೨"|"൨"|"à¹?"|"à»?"
+THREE         "3"|"Ù£"|"Û³"|"ß?"|"३"|"৩"|"à©©"|"à«©"|"à­©"|"௩"|"౩"|"೩"|"൩"|"à¹?"|"à»?"
+FOUR          "4"|"Ù¤"|"Û´"|"ß?"|"४"|"৪"|"੪"|"૪"|"à­ª"|"௪"|"౪"|"೪"|"൪"|"à¹?"|"à»?"
+FIVE          "5"|"Ù¥"|"Ûµ"|"ß?"|"५"|"৫"|"à©«"|"à««"|"à­«"|"௫"|"౫"|"೫"|"൫"|"à¹?"|"à»?"
+SIX           "6"|"Ù¦"|"Û¶"|"ß?"|"६"|"৬"|"੬"|"૬"|"à­¬"|"௬"|"౬"|"೬"|"൬"|"à¹?"|"à»?"
+SEVEN         "7"|"Ù§"|"Û·"|"ß?"|"७"|"৭"|"à©­"|"à«­"|"à­­"|"௭"|"à±­"|"à³­"|"൭"|"à¹?"|"à»?"
+EIGHT         "8"|"Ù¨"|"Û¸"|"ß?"|"८"|"৮"|"à©®"|"à«®"|"à­®"|"௮"|"à±®"|"à³®"|"൮"|"à¹?"|"à»?"
+NINE          "9"|"Ù©"|"Û¹"|"ß?"|"९"|"৯"|"੯"|"૯"|"à­¯"|"௯"|"౯"|"೯"|"൯"|"à¹?"|"à»?"
+DECIMAL	      "."|","
+BIN           {ZERO}|{ONE}
+OCT           {ZERO}|{ONE}|{TWO}|{THREE}|{FOUR}|{FIVE}|{SIX}|{SEVEN}
+DEC           {ZERO}|{ONE}|{TWO}|{THREE}|{FOUR}|{FIVE}|{SIX}|{SEVEN}|{EIGHT}|{NINE}
+HEX           {DEC}|[A-F]|[a-f]
+EXP           "e"|"e+"|"e-"|"E"|"E+"|"E-"
+SI_SUFFIX     "T"|"G"|"M"|"k"|"d"|"c"|"m"|"u"|"µ"|"n"|"p"|"f"
+SUPER_DIGITS  "�"|"¹"|"²"|"³"|"�"|"�"|"�"|"�"|"�"|"�"
+SUB_DIGITS    "â??"|"â??"|"â??"|"â??"|"â??"|"â??"|"â??"|"â??"|"â??"|"â??"
+FRACTION      "½"|"â??"|"â??"|"¼"|"¾"|"â??"|"â??"|"â??"|"â??"|"â??"|"â??"|"â??"|"â??"|"â??"|"â??"
+INVERSE       "�¹"
 
 HEX_NUM {HEX}+|{HEX}*{DECIMAL}{HEX}+
-DEC_NUM {DEC}+|{DEC}*{DECIMAL}{DEC}+|{FRACTION}|{DEC}{FRACTION}
+DEC_NUM {DEC}+|{DEC}+{SI_SUFFIX}|{DEC}*{DECIMAL}{DEC}+|{DEC}*{SI_SUFFIX}{DEC}+|{FRACTION}|{DEC}{FRACTION}
 OCT_NUM {OCT}+|{OCT}*{DECIMAL}{OCT}+
 BIN_NUM {BIN}+|{BIN}*{DECIMAL}{BIN}+
-SUP_NUM {SUPER_DIGITS}+
-SUB_NUM {SUB_DIGITS}+
+SUP_NUM  {SUPER_DIGITS}+
+SUB_NUM  {SUB_DIGITS}+
+GREEKS   "α"|"β"|"γ"|"δ"|"ε"|"ζ"|"η"|"θ"|"ι"|"κ"|"λ"|"μ"|"ν"|"ξ"|"ο"|"Ï?"|"Ï?"|"Ï?"|"Ï?"|"Ï?"|"Ï?"|"Ï?"|"Ï?"|"Ï?"|"Ï?"
+REGISTERS "Râ??"|"Râ??"|"Râ??"|"Râ??"|"Râ??"|"Râ??"|"Râ??"|"Râ??"|"Râ??"|"Râ??"
+VARIABLE {REGISTERS}|{GREEKS}|"e"
+VARIABLE_NAME [a-zA-Z]+
+FUNCTION {VARIABLE_NAME}|{VARIABLE_NAME}{INVERSE}|{VARIABLE_NAME}{SUB_NUM}
+
+MOD  [mM][oO][dD]
+AND  "â?§"|[aA][nN][dD]
+OR   "â?¨"|[oO][rR]
+XOR  "â??"|[xX][oO][rR]
+XNOR [xX][nN][oO][rR]
+NOT  "¬"|"~"|[nN][oO][tT]
 
 %%
 
-"+"     {return tADD;}
-"-"|"â??" {return tSUBTRACT;}
-"*"|"Ã?" {return tMULTIPLY;}
-"/"|"÷" {return tDIVIDE;}
-"abs"|"Abs"|"ABS" {return tABS_FUNC;}
-"|" {return tABS;}
-"sin"|"Sin"|"SIN" {return tSIN;}
-"cos"|"Cos"|"COS" {return tCOS;}
-"tan"|"Tan"|"TAN" {return tTAN;}
-"sin�¹"|"asin"|"Asin"|"ASIN" {return tASIN;}
-"cos�¹"|"acos"|"Acos"|"ACOS" {return tACOS;}
-"tan�¹"|"atan"|"Atan"|"ATAN" {return tATAN;}
-"sinh"|"Sinh"|"SINH" {return tSINH;}
-"cosh"|"Cosh"|"COSH" {return tCOSH;}
-"tanh"|"Tanh"|"TANH" {return tTANH;}
-"sinh�¹"|"asinh"|"Asinh"|"ASINH" {return tASINH;}
-"cosh�¹"|"acosh"|"Acosh"|"ACOSH" {return tACOSH;}
-"tanh�¹"|"atanh"|"Atanh"|"ATANH" {return tATANH;}
-"â?§"|"and"|"And"|"AND" {return tAND;}
-"ans"|"Ans"|"ANS" {return tANS;}
-"chs"|"Chs"|"CHS" {return tCHS;}
-"clr"|"Clr"|"CLR" {return tCLR;}
-"eng"|"Eng"|"ENG" {return tEXP;}
-"frac"|"Frac"|"FRAC" {return tFRAC;}
-"int"|"Int"|"INT" {return tINT;}
-"ln"|"Ln"|"LN" {return tLN;}
-"log"|"Log"|"LOG" {return tLOG;}
-"mod"|"Mod"|"MOD" {return tMOD;}
-"¬"|"~" {return tNOT;}
-"â?¨"|"or"|"Or"|"OR" {return tOR;}
-"Ï?"|"pi"|"Pi"|"PI" {return tPI;}
-"rand"|"Rand"|"RAND" {return tRAND;}
-"rcl"|"Rcl"|"RCL" {return tRCL;}
-"â??"|"sqrt"|"Sqrt"|"SQRT" {return tROOT;}
-"â??"|"cbrt"|"Cbrt"|"CBRT" {return tROOT3;}
-"â??" {return tROOT4;}
-"sto"|"Sto"|"STO" {return tSTO;}
-"trunc"|"Trunc"|"TRUNC" {return tTRUNC;}
-"ones" {return t1S;}
-"twos" {return t2S;}
-"xnor"|"Xnor"|"XNOR" {return tXNOR;}
-"â??"|"xor"|"Xor"|"XOR" {return tXOR;}
-
-"R"{DEC}+ {
-yylval->integer = atoi(yytext+1);  
-return tREG;
-}
-
-{SUP_NUM} { yylval->integer = super_atoi(yytext); return tSUPNUM; }
-{SUB_NUM} { yylval->integer = sub_atoi(yytext); return tSUBNUM; }
+"+"        {return tADD;}
+"-"|"â??"    {return tSUBTRACT;}
+"*"|"Ã?"    {return tMULTIPLY;}
+"/"|"÷"    {return tDIVIDE;}
+{MOD}      {return tMOD;}
+"â??"        {return tROOT;}
+"â??"        {return tROOT3;}
+"â??"        {return tROOT4;}
+{NOT}      {return tNOT;}
+{AND}      {return tAND;}
+{OR}       {return tOR;}
+{XOR}      {return tXOR;}
+{XNOR}     {return tXNOR;}
+{SUP_NUM}  {yylval->integer = super_atoi(yytext); return tSUPNUM; }
+{SUB_NUM}  {yylval->integer = sub_atoi(yytext); return tSUBNUM; }
+{VARIABLE} {yylval->name = strdup(yytext); return tVARIABLE;}
+{INVERSE}  {return tINVERSE;}
 
 {DEC_NUM}{EXP}{DEC_NUM} {
 if (_mp_equation_get_extra(yyscanner)->base == 16) REJECT;
@@ -175,8 +165,9 @@ mp_set_from_string(yytext, _mp_equation_get_extra(yyscanner)->base, &yylval->int
 return tNUMBER;
 }
 
+{FUNCTION} {yylval->name = strdup(yytext); return tFUNCTION;}
 
 [ \t\n]
-.        {return *yytext; }
+.          {return *yytext;}
 
 %% 
diff --git a/src/mp-equation-parser.y b/src/mp-equation-parser.y
index 7fe28bd..d92af90 100644
--- a/src/mp-equation-parser.y
+++ b/src/mp-equation-parser.y
@@ -1,8 +1,6 @@
 %{
 
-/*  $Header: /cvs/gnome/gcalctool/gcalctool/ce_parser.y,v 1.16 2006/12/08 15:54:43 richb Exp $
- *
- *  Copyright (C) 2004-2008 Sami Pietila
+/*  Copyright (C) 2004-2008 Sami Pietila
  *  Copyright (C) 2008-2009 Robert Ancell
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -26,257 +24,148 @@
 #include <math.h>
 #include <errno.h>
 
-#include "calctool.h" // FIXME: Can be removed soon
-#include "register.h" // FIXME: Can be removed soon
 #include "mp-equation.h"
 #include "mp-equation-parser.h"
 #include "mp-equation-lexer.h"
-%}
 
-%define api.pure
-%name-prefix "_mp_equation_"
-%locations
-%parse-param {yyscan_t yyscanner}
-%lex-param {yyscan_t yyscanner}
+// fixme support x log x
+// treat exp NAME exp as a function always and pass both arguments, i.e.
+// can do mod using both and all others use $1 * NAME($3)
 
-%union {
-  MPNumber int_t;
-  int integer;
+static void set_error(yyscan_t yyscanner, int error)
+{
+    _mp_equation_get_extra(yyscanner)->error = error;
 }
 
-%token tADD
-%token tSUBTRACT
-%token tMULTIPLY
-%token tDIVIDE
-%token tABS
-%token tABS_FUNC
-%token tACOS
-%token tACOSH
-%token tAND
-%token tANS
-%token tASIN
-%token tASINH
-%token tATAN
-%token tATANH
-%token tCHS
-%token tCLR
-%token tCOS
-%token tCOSH
-%token tEXP
-%token tFRAC
-%token tINT
-%token tLN
-%token tLOG
-%token tMOD
-%token t1S
-%token t2S
-%token tNOT
-%token tOR
-%token tPI
-%token tRAND
-%token tRCL
-%token tSIN
-%token tSINH
-%token tROOT
-%token tROOT3
-%token tROOT4
-%token tSQRT
-%token tSTO
-%token tTAN
-%token tTANH
-%token tTRUNC
-%token tXNOR
-%token tXOR
-
-%token <int_t> tNUMBER
-%token <integer> tREG tSUBNUM tSUPNUM
-
-%token NEG
-
-%type  <int_t> exp rcl value term func number
-
-%start statement
-%left tADD tSUBTRACT tMULTIPLY tDIVIDE
-%left MED
-%left LNEG
-%left NEG
-%left POS
-%right '^'
-%right '!'
-%right '%'
-%right tSQUARED tCUBED
-%left HIGH
-
-%%
-
-statement: 
-  seq
-| value { mp_set_from_mp(&$1, &(_mp_equation_get_extra(yyscanner))->ret); (_mp_equation_get_extra(yyscanner))->have_result = 1; }
-| error {
-  (_mp_equation_get_extra(yyscanner))->error = -EINVAL; 
-  YYABORT;
+static void get_variable(yyscan_t yyscanner, const char *name, MPNumber *z)
+{
+    if (!_mp_equation_get_extra(yyscanner)->get_variable(_mp_equation_get_extra(yyscanner), name, z))
+        set_error(yyscanner, -PARSER_ERR_UNKNOWN_VARIABLE);
 }
-;
 
-seq:
-  udf
-| seq udf
-;
-
-udf:
-  value '=' {
-  display_set_number(&v->display, &$1);
-  }
-| value '=' tSTO '(' tNUMBER ')' {
-  int val = mp_cast_to_int(&$5);
-  register_set(val, &$1);
-}
-| value tSTO '(' tNUMBER ')' {
-  int val = mp_cast_to_int(&$4);
-  register_set(val, &$1);
+static void set_variable(yyscan_t yyscanner, const char *name, MPNumber *x)
+{
+    _mp_equation_get_extra(yyscanner)->set_variable(_mp_equation_get_extra(yyscanner), name, x);
 }
-| tCLR {
-  display_clear(&v->display);
-}
-;
-
-value: 
-  exp {mp_set_from_mp(&$1, &$$);}
-;
 
-exp: 
-  term {mp_set_from_mp(&$1, &$$);}
-| exp tADD term '%' {mp_add_integer(&$3, 100, &$3); mp_divide_integer(&$3, 100, &$3); mp_multiply(&$1, &$3, &$$);}
-| exp tSUBTRACT term '%' {mp_add_integer(&$3, -100, &$3); mp_divide_integer(&$3, -100, &$3); mp_multiply(&$1, &$3, &$$);}
-| exp tROOT term {MPNumber t; mp_sqrt(&$3, &t); mp_multiply(&$1, &t, &$$);}
-| exp tROOT3 term {MPNumber t; mp_root(&$3, 3, &t); mp_multiply(&$1, &t, &$$);}
-| exp tROOT4 term {MPNumber t; mp_root(&$3, 4, &t); mp_multiply(&$1, &t, &$$);}
-| exp tADD exp {mp_add(&$1, &$3, &$$);}
-| exp tSUBTRACT exp {mp_subtract(&$1, &$3, &$$);}
-| exp tMOD exp %prec MED {
-    if (!mp_is_integer(&$1) || !mp_is_integer(&$3)) {
-	(_mp_equation_get_extra(yyscanner))->error = -PARSER_ERR_MODULUSOP;
-    } else {
-      if (mp_modulus_divide(&$1, &$3, &$$)) {
-        (_mp_equation_get_extra(yyscanner))->error = -EINVAL;
-      }			   
-    }
+static void get_function(yyscan_t yyscanner, const char *name, const MPNumber *x, MPNumber *z)
+{
+    if (!_mp_equation_get_extra(yyscanner)->get_function(_mp_equation_get_extra(yyscanner), name, x, z))
+        set_error(yyscanner, -PARSER_ERR_UNKNOWN_FUNCTION);
 }
-| exp tAND exp {
-    if (!mp_is_natural(&$1) || !mp_is_natural(&$3)) {
-	(_mp_equation_get_extra(yyscanner))->error = -PARSER_ERR_BITWISEOP;
-    }
-    mp_and(&$1, &$3, &$$);
+
+static void do_bitwise(yyscan_t yyscanner, void (*mp_fn)(const MPNumber *x, const MPNumber *y, MPNumber *z), const MPNumber *x, const MPNumber *y, MPNumber *z)
+{
+    if (!mp_is_natural(x) || !mp_is_natural(y))
+	set_error(yyscanner, -PARSER_ERR_BITWISEOP);
+    else
+        mp_fn(x, y, z);
 }
-| exp tOR exp {
-    if (!mp_is_natural(&$1) || !mp_is_natural(&$3)) {
-	(_mp_equation_get_extra(yyscanner))->error = -PARSER_ERR_BITWISEOP;
+
+static void do_xnor(yyscan_t yyscanner, const MPNumber *x, const MPNumber *y, MPNumber *z)
+{
+    if (!mp_is_natural(x)) {
+	set_error(yyscanner, -PARSER_ERR_BITWISEOP);
+    } else if (!mp_is_overflow(x, _mp_equation_get_extra(yyscanner)->wordlen)) {
+	set_error(yyscanner, -PARSER_ERR_OVERFLOW);
     }
-    mp_or(&$1, &$3, &$$);
+    mp_xnor(x, y, _mp_equation_get_extra(yyscanner)->wordlen, z);
 }
-| exp tXNOR exp {
-    if (!mp_is_natural(&$1) || !mp_is_natural(&$3)) {
-	(_mp_equation_get_extra(yyscanner))->error = -PARSER_ERR_BITWISEOP;
+
+static void do_not(yyscan_t yyscanner, const MPNumber *x, MPNumber *z)
+{
+    if (!mp_is_natural(x)) {
+	set_error(yyscanner, -PARSER_ERR_BITWISEOP);
+    } else if (!mp_is_overflow(x, _mp_equation_get_extra(yyscanner)->wordlen)) {
+	set_error(yyscanner, -PARSER_ERR_OVERFLOW);
     }
-    mp_xnor(&$1, &$3, _mp_equation_get_extra(yyscanner)->wordlen, &$$);
+    mp_not(x, _mp_equation_get_extra(yyscanner)->wordlen, z);
 }
-| exp tXOR exp {
-    if (!mp_is_natural(&$1) || !mp_is_natural(&$3)) {
-	(_mp_equation_get_extra(yyscanner))->error = -PARSER_ERR_BITWISEOP;
+
+static void do_mod(yyscan_t yyscanner, const MPNumber *x, const MPNumber *y, MPNumber *z)
+{
+    if (!mp_is_integer(x) || !mp_is_integer(y)) {
+	set_error(yyscanner, -PARSER_ERR_MODULUSOP);
+    } else {
+        mp_modulus_divide(x, y, z);
     }
-    mp_xor(&$1, &$3, &$$);
 }
-;
+%}
 
+%define api.pure
+%name-prefix "_mp_equation_"
+%locations
+%parse-param {yyscan_t yyscanner}
+%lex-param {yyscan_t yyscanner}
 
-term:
-  number {mp_set_from_mp(&$1, &$$);}
-| tPI {mp_get_pi(&$$);}
-| rcl {mp_set_from_mp(&$1, &$$);}
-| tSUBNUM tROOT term {mp_root(&$3, $1, &$$);}
-| tROOT term {mp_sqrt(&$2, &$$);}
-| tROOT3 term {mp_root(&$2, 3, &$$);}
-| tROOT4 term {mp_root(&$2, 4, &$$);}
-| term tDIVIDE term {mp_divide(&$1, &$3, &$$);}
-| term tMULTIPLY term {mp_multiply(&$1, &$3, &$$);}
-| tABS exp tABS {mp_abs(&$2, &$$);}
-| 'e' '^' term {mp_epowy(&$3, &$$);} 
-| term '!' {mp_factorial(&$1, &$$);}
-| term tSUPNUM {mp_xpowy_integer(&$1, $2, &$$);}
-| term '%' {mp_divide_integer(&$1, 100, &$$);}
-| tNOT term %prec LNEG {
-    if (!mp_is_natural(&$2)) {
-	(_mp_equation_get_extra(yyscanner))->error = -PARSER_ERR_BITWISEOP;
-    } else if (!mp_is_overflow(&$2, _mp_equation_get_extra(yyscanner)->wordlen)) {
-	(_mp_equation_get_extra(yyscanner))->error = -PARSER_ERR_OVERFLOW;
-    }
-    mp_not(&$2, _mp_equation_get_extra(yyscanner)->wordlen, &$$);
+%union {
+  MPNumber int_t;
+  int integer;
+  char *name;
 }
-| tSUBTRACT term {mp_invert_sign(&$2, &$$);}
-| tADD term {mp_set_from_mp(&$2, &$$);}
-| term '^' term {mp_xpowy(&$1, &$3, &$$);}
-| term func {mp_multiply(&$1, &$2, &$$);}
-| func {mp_set_from_mp(&$1, &$$);}
-| tREG {register_get($1, &$$);}
-| '(' exp ')' {mp_set_from_mp(&$2, &$$);}
+
+%left <int_t> tNUMBER
+%left UNARY_PLUS
+%left tADD tSUBTRACT
+%left tAND tOR tXOR tXNOR
+%left tMULTIPLY tDIVIDE tMOD MULTIPLICATION
+%left tNOT
+%left tROOT tROOT3 tROOT4
+%left <name> tVARIABLE tFUNCTION
+%right '^' tINVERSE '!'
+%right <integer> tSUBNUM tSUPNUM
+%left BOOLEAN_OPERATOR
+%left PERCENTAGE
+%left UNARY_MINUS
+
+%type <int_t> exp function
+%start statement
+
+%%
+
+statement:
+  exp { mp_set_from_mp(&$1, &(_mp_equation_get_extra(yyscanner))->ret);}
+| tVARIABLE '=' exp {set_variable(yyscanner, $1, &$3);}
 ;
 
-func:
-  tLOG term %prec HIGH {mp_logarithm(10, &$2, &$$);}
-| tLN term %prec HIGH {mp_ln(&$2, &$$);}
-| tLOG tSUBNUM term %prec HIGH {mp_logarithm($2, &$3, &$$);}
-| tRAND %prec HIGH {mp_set_from_random(&$$);}
-| tABS_FUNC term %prec HIGH {mp_abs(&$2, &$$);}
-| tFRAC term %prec HIGH {mp_fractional_component(&$2, &$$);}
-| tINT term %prec HIGH {mp_integer_component(&$2, &$$);}
-| tCHS term %prec HIGH {mp_invert_sign(&$2, &$$);}
-| tSIN term %prec HIGH {mp_sin(&$2, _mp_equation_get_extra(yyscanner)->angle_units, &$$);}
-| tCOS term %prec HIGH {mp_cos(&$2, _mp_equation_get_extra(yyscanner)->angle_units, &$$);}
-| tTAN term %prec HIGH {mp_tan(&$2, _mp_equation_get_extra(yyscanner)->angle_units, &$$);}
-| tSIN tSUPNUM term %prec HIGH {MPNumber t; mp_sin(&$3, _mp_equation_get_extra(yyscanner)->angle_units, &t); mp_xpowy_integer(&t, $2, &$$);}
-| tCOS tSUPNUM term %prec HIGH {MPNumber t; mp_cos(&$3, _mp_equation_get_extra(yyscanner)->angle_units, &t); mp_xpowy_integer(&t, $2, &$$);}
-| tTAN tSUPNUM term %prec HIGH {MPNumber t; mp_tan(&$3, _mp_equation_get_extra(yyscanner)->angle_units, &t); mp_xpowy_integer(&t, $2, &$$);}
-| tASIN term %prec HIGH {mp_asin(&$2, _mp_equation_get_extra(yyscanner)->angle_units, &$$);}
-| tACOS term %prec HIGH {mp_acos(&$2, _mp_equation_get_extra(yyscanner)->angle_units, &$$);}
-| tATAN term %prec HIGH {mp_atan(&$2, _mp_equation_get_extra(yyscanner)->angle_units, &$$);}
-| tSINH term %prec HIGH {mp_sinh(&$2, &$$);}
-| tCOSH term %prec HIGH {mp_cosh(&$2, &$$);}
-| tTANH term %prec HIGH {mp_tanh(&$2, &$$);}
-| tSINH tSUPNUM term %prec HIGH {MPNumber t; mp_sinh(&$3, &t); mp_xpowy_integer(&t, $2, &$$);}
-| tCOSH tSUPNUM term %prec HIGH {MPNumber t; mp_cosh(&$3, &t); mp_xpowy_integer(&t, $2, &$$);}
-| tTANH tSUPNUM term %prec HIGH {MPNumber t; mp_tanh(&$3, &t); mp_xpowy_integer(&t, $2, &$$);}
-| tASINH term %prec HIGH {mp_asinh(&$2, &$$);}
-| tACOSH term %prec HIGH {mp_acosh(&$2, &$$);}
-| tATANH term %prec HIGH {mp_atanh(&$2, &$$);}
-| tTRUNC term %prec HIGH {mp_mask(&$2, _mp_equation_get_extra(yyscanner)->wordlen, &$$);}
-| t1S term %prec HIGH  {
-    if (!mp_is_natural(&$2)) {
-	(_mp_equation_get_extra(yyscanner))->error = -PARSER_ERR_BITWISEOP;
-    } else if (!mp_is_overflow(&$2, _mp_equation_get_extra(yyscanner)->wordlen)) {
-	(_mp_equation_get_extra(yyscanner))->error = -PARSER_ERR_OVERFLOW;
-    }
-    mp_1s_complement(&$2, _mp_equation_get_extra(yyscanner)->wordlen, &$$);
-}
-| t2S term %prec HIGH {
-    if (!mp_is_natural(&$2)) {
-	(_mp_equation_get_extra(yyscanner))->error = -PARSER_ERR_BITWISEOP;
-    } else if (!mp_is_overflow(&$2, _mp_equation_get_extra(yyscanner)->wordlen)) {
-	(_mp_equation_get_extra(yyscanner))->error = -PARSER_ERR_OVERFLOW;
-    }
-    mp_2s_complement(&$2, _mp_equation_get_extra(yyscanner)->wordlen, &$$);
-}
+exp:
+  '(' exp ')' {mp_set_from_mp(&$2, &$$);}
+| '|' exp '|' {mp_abs(&$2, &$$);}
+| exp '^' exp {mp_xpowy(&$1, &$3, &$$);}
+| exp tSUPNUM {mp_xpowy_integer(&$1, $2, &$$);}
+| exp tINVERSE {mp_reciprocal(&$1, &$$);}
+| exp '!' {mp_factorial(&$1, &$$);}
+| tVARIABLE {get_variable(yyscanner, $1, &$$); free($1);}
+| tVARIABLE tVARIABLE %prec MULTIPLICATION {MPNumber t; get_variable(yyscanner, $1, &t); get_variable(yyscanner, $2, &$$); mp_multiply(&t, &$$, &$$); free($1);}
+| function {mp_set_from_mp(&$1, &$$);}
+| tNUMBER function  %prec MULTIPLICATION {mp_multiply(&$1, &$2, &$$);}
+| tNUMBER tVARIABLE %prec MULTIPLICATION {get_variable(yyscanner, $2, &$$); mp_multiply(&$1, &$$, &$$); free($2);}
+| tSUBTRACT exp %prec UNARY_MINUS {mp_invert_sign(&$2, &$$);}
+| tADD tNUMBER %prec UNARY_PLUS {mp_set_from_mp(&$2, &$$);}
+| exp tDIVIDE exp {mp_divide(&$1, &$3, &$$);}
+| exp tMOD exp {do_mod(yyscanner, &$1, &$3, &$$);}
+| exp tMULTIPLY exp {mp_multiply(&$1, &$3, &$$);}
+| exp tADD exp '%' %prec PERCENTAGE {mp_add_integer(&$3, 100, &$3); mp_divide_integer(&$3, 100, &$3); mp_multiply(&$1, &$3, &$$);}
+| exp tSUBTRACT exp '%' %prec PERCENTAGE {mp_add_integer(&$3, -100, &$3); mp_divide_integer(&$3, -100, &$3); mp_multiply(&$1, &$3, &$$);}
+| exp tADD exp {mp_add(&$1, &$3, &$$);}
+| exp tSUBTRACT exp {mp_subtract(&$1, &$3, &$$);}
+| exp '%' {mp_divide_integer(&$1, 100, &$$);}
+| tNOT exp {do_not(yyscanner, &$2, &$$);}
+| exp tAND exp %prec BOOLEAN_OPERATOR {do_bitwise(yyscanner, mp_and, &$1, &$3, &$$);}
+| exp tOR exp %prec BOOLEAN_OPERATOR {do_bitwise(yyscanner, mp_or, &$1, &$3, &$$);}
+| exp tXOR exp %prec BOOLEAN_OPERATOR {do_bitwise(yyscanner, mp_xor, &$1, &$3, &$$);}
+| exp tXNOR exp %prec BOOLEAN_OPERATOR {do_xnor(yyscanner, &$1, &$3, &$$);}
+| tNUMBER {mp_set_from_mp(&$1, &$$);}
 ;
 
-rcl:
-  tRCL '(' tNUMBER ')' {
-    int val = mp_cast_to_int(&$3);
-    register_get(val, &$$);
-  }
-  ;
 
-number:
-  tNUMBER {mp_set_from_mp(&$1, &$$);}
-| tANS {mp_set_from_mp(&_mp_equation_get_extra(yyscanner)->ans, &$$);}
+function:
+  tFUNCTION exp {get_function(yyscanner, $1, &$2, &$$); free($1);}
+| tFUNCTION tSUPNUM exp {get_function(yyscanner, $1, &$3, &$$); mp_xpowy_integer(&$$, $2, &$$); free($1);}
+| tSUBNUM tROOT exp {mp_root(&$3, $1, &$$);}
+| tROOT exp {mp_sqrt(&$2, &$$);}
+| tROOT3 exp {mp_root(&$2, 3, &$$);}
+| tROOT4 exp {mp_root(&$2, 4, &$$);}
 ;
 
 %%
diff --git a/src/mp-equation.c b/src/mp-equation.c
index b93427c..60f1e8f 100644
--- a/src/mp-equation.c
+++ b/src/mp-equation.c
@@ -2,6 +2,7 @@
 /*  $Header$
  *
  *  Copyright (C) 2004-2008 Sami Pietila
+ *  Copyright (c) 2008-2009 Robert Ancell
  *
  *  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
@@ -19,17 +20,111 @@
  *  02111-1307, USA.
  */
 
+#include <ctype.h>
+
 #include "mp-equation.h"
 #include "calctool.h"
+#include "register.h"
 #include "mp-equation-parser.h"
 #include "mp-equation-lexer.h"
 
 extern int _mp_equation_parse(yyscan_t yyscanner);
 
+static int
+get_variable(MPEquationParserState *state, const char *name, MPNumber *z)
+{
+    if (name[0] == 'R' || name[0] == 'r')
+        register_get(atoi(name+1), z);
+    else if (strcmp(name, "ans") == 0)
+        mp_set_from_mp(display_get_answer(&v->display), z);
+    else if (strcmp(name, "e") == 0)
+        mp_get_eulers(z);
+    else if (strcmp(name, "Ï?") == 0)
+        mp_get_pi(z);
+    else
+        return 0;
+    
+    return 1;
+}
+
+static void
+set_variable(MPEquationParserState *state, const char *name, MPNumber *x)
+{
+    if (name[0] == 'R' || name[0] == 'r')
+        register_set(atoi(name+1), x);
+}
+
+// FIXME: Accept "2sin" not "2 sin", i.e. let the tokenizer collect the multiple
+// Parser then distinguishes between "sin"="s*i*n" or "sin5" = "sin 5" = "sin(5)"
+// i.e. numbers+letters = variable or function depending on following arg
+// letters+numbers = numbers+letters+numbers = function
+
+
+static int
+get_function(MPEquationParserState *state, const char *name, const MPNumber *x, MPNumber *z)
+{
+    char *c, *lower_name;
+    int result = 1;
+    
+    lower_name = strdup(name);
+    for (c = lower_name; *c; c++)
+        *c = tolower(*c);
+    
+    // FIXME: Re Im ?
+
+    if (strcmp(lower_name, "log") == 0)
+        mp_logarithm(10, x, z);
+    else if (strcmp(lower_name, "ln") == 0)
+        mp_ln(x, z);
+    else if (strcmp(lower_name, "sqrt") == 0) // â??x
+        mp_sqrt(x, z);
+    else if (strcmp(lower_name, "abs") == 0) // |x|
+        mp_abs(x, z);
+    else if (strcmp(lower_name, "int") == 0)
+        mp_integer_component(x, z);
+    else if (strcmp(lower_name, "frac") == 0)
+        mp_fractional_component(x, z);
+    else if (strcmp(lower_name, "sin") == 0)
+        mp_sin(x, state->angle_units, z);
+    else if (strcmp(lower_name, "cos") == 0)
+        mp_cos(x, state->angle_units, z);
+    else if (strcmp(lower_name, "tan") == 0)
+        mp_tan(x, state->angle_units, z);    
+    else if (strcmp(lower_name, "sin�¹") == 0 || strcmp(lower_name, "asin") == 0)
+        mp_asin(x, state->angle_units, z);
+    else if (strcmp(lower_name, "cos�¹") == 0 || strcmp(lower_name, "acos") == 0)
+        mp_acos(x, state->angle_units, z);
+    else if (strcmp(lower_name, "tan�¹") == 0 || strcmp(lower_name, "atan") == 0)
+        mp_atan(x, state->angle_units, z);    
+    else if (strcmp(lower_name, "sinh") == 0)
+        mp_sinh(x, z);
+    else if (strcmp(lower_name, "cosh") == 0)
+        mp_cosh(x, z);
+    else if (strcmp(lower_name, "tanh") == 0)
+        mp_tanh(x, z);
+    else if (strcmp(lower_name, "sinh�¹") == 0 || strcmp(lower_name, "asinh") == 0)
+        mp_asinh(x, z);
+    else if (strcmp(lower_name, "cosh�¹") == 0 || strcmp(lower_name, "acosh") == 0)
+        mp_acosh(x, z);
+    else if (strcmp(lower_name, "tanh�¹") == 0 || strcmp(lower_name, "atanh") == 0)
+        mp_atanh(x, z);
+    else if (strcmp(lower_name, "ones") == 0)
+        mp_ones_complement(x, state->wordlen, z);
+    else if (strcmp(lower_name, "twos") == 0)
+        mp_twos_complement(x, state->wordlen, z);    
+    else
+        result = 0;
+    
+    free(lower_name);
+    
+    return result;
+}
+
+
 int 
-mp_equation_parse_(const char *expression, MPNumber *result, int need_result)
+mp_equation_parse(const char *expression, MPNumber *result)
 {
-    int ret = 0;
+    int ret;
     MPEquationParserState state;
     yyscan_t yyscanner;
     YY_BUFFER_STATE buffer;
@@ -41,7 +136,10 @@ mp_equation_parse_(const char *expression, MPNumber *result, int need_result)
     state.base = basevals[v->base];
     state.wordlen = v->wordlen;
     state.angle_units = v->ttype;
-    mp_set_from_mp(display_get_answer(&v->display), &state.ans);
+    state.get_variable = get_variable;
+    state.set_variable = set_variable;
+    state.get_function = get_function;    
+    state.error = 0;
     v->math_error = 0;
 
     _mp_equation_lex_init_extra(&state, &yyscanner);
@@ -52,35 +150,23 @@ mp_equation_parse_(const char *expression, MPNumber *result, int need_result)
     _mp_equation__delete_buffer(buffer, yyscanner);
     _mp_equation_lex_destroy(yyscanner);
 
-    ret = (state.error) ? state.error : ret;
+    /* Failed to parse */
     if (ret)
-        return ret;
-
-    if ((need_result != 0) != (state.have_result != 0))
-        return -EINVAL;
+        return -PARSER_ERR_INVALID;
+        
+    /* Error during parsing */
+    if (state.error)
+        return state.error;
 
     if (v->math_error)
         return v->math_error;
 
     mp_set_from_mp(&state.ret, result);
-    return 0;
-}
 
-
-int 
-mp_equation_parse(const char *expression, MPNumber *result)
-{
-    return(mp_equation_parse_(expression, result, 1));
+    return 0;
 }
 
 
-int 
-mp_equation_udf_parse(const char *expression)
-{
-    MPNumber t;
-    return mp_equation_parse_(expression, &t, 0);
-}
-
 int _mp_equation_error(void *yylloc, MPEquationParserState *state, char *text)
 {
     return 0;
diff --git a/src/mp-equation.h b/src/mp-equation.h
index 871e347..70d8400 100644
--- a/src/mp-equation.h
+++ b/src/mp-equation.h
@@ -2,6 +2,7 @@
 /*  $Header$
  *
  *  Copyright (C) 2004-2008 Sami Pietila
+ *  Copyright (c) 2008-2009 Robert Ancell
  *
  *  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
@@ -24,14 +25,19 @@
 
 #include "mp.h"
 
-#define PARSER_ERR_INVALID_BASE     10000
-#define PARSER_ERR_TOO_LONG_NUMBER  10001
-#define PARSER_ERR_BITWISEOP        10002
-#define PARSER_ERR_MODULUSOP        10003
-#define PARSER_ERR_OVERFLOW         10004
+#define PARSER_ERR_INVALID          1
+#define PARSER_ERR_TOO_LONG_NUMBER  2
+#define PARSER_ERR_BITWISEOP        3
+#define PARSER_ERR_MODULUSOP        4
+#define PARSER_ERR_OVERFLOW         5
+#define PARSER_ERR_UNKNOWN_VARIABLE 6
+#define PARSER_ERR_UNKNOWN_FUNCTION 7
+#define PARSER_ERR_INVALID_BASE     8
+
+typedef struct MPEquationParserState MPEquationParserState;
 
 /* State for parser */
-typedef struct {
+struct MPEquationParserState {
     /* The numeric base (e.g 2, 8, 10, 16) */
     int base;
 
@@ -40,23 +46,26 @@ typedef struct {
     
     /* Units for angles (e.g. radians, degrees) */
     MPAngleUnit angle_units;
+    
+    /* Function to get variable values */
+    int (*get_variable)(MPEquationParserState *state, const char *name, MPNumber *z);
+    
+    /* Function to set variable values */
+    void (*set_variable)(MPEquationParserState *state, const char *name, MPNumber *x);    
 
-    /* Error returned from parser */
-    int error;
+    /* Function to solve functions */
+    int (*get_function)(MPEquationParserState *state, const char *name, const MPNumber *x, MPNumber *z);
     
-    /* Value of Ans variable */
-    MPNumber ans;
+    // FIXME: get_operator??
 
-    /* TRUE if have a result */
-    int have_result;
+    /* Error returned from parser */
+    int error;
 
     /* Value returned from parser */
     MPNumber ret;
-} MPEquationParserState;
+};
 
 int mp_equation_parse(const char *expression, MPNumber *result);
-int mp_equation_udf_parse(const char *expression);
-
 int _mp_equation_error(void *yylloc, MPEquationParserState *state, char *text);
 
 #endif
diff --git a/src/mp.c b/src/mp.c
index 69cf983..bf4abe7 100644
--- a/src/mp.c
+++ b/src/mp.c
@@ -1799,15 +1799,12 @@ mp_factorial(const MPNumber *x, MPNumber *z)
         mp_multiply_integer(z, i, z);
 }
 
-int
+
+void
 mp_modulus_divide(const MPNumber *x, const MPNumber *y, MPNumber *z)
 {
     MPNumber t1, t2;
 
-    if (!mp_is_integer(x) || !mp_is_integer(y)) {
-        return -EINVAL;
-    }
-
     mp_divide(x, y, &t1);
     mp_integer_component(&t1, &t1);
     mp_multiply(&t1, y, &t2);
@@ -1817,8 +1814,6 @@ mp_modulus_divide(const MPNumber *x, const MPNumber *y, MPNumber *z)
     if ((mp_is_less_than(y, &t1) && mp_is_greater_than(z, &t1)) || mp_is_less_than(z, &t1)) {
         mp_add(z, y, z);
     }
-
-    return 0;
 }
 
 
diff --git a/src/mp.h b/src/mp.h
index 2e46492..7511fe5 100644
--- a/src/mp.h
+++ b/src/mp.h
@@ -168,7 +168,7 @@ void   mp_sqrt(const MPNumber *x, MPNumber *z);
 void   mp_factorial(const MPNumber *x, MPNumber *z);
 
 /* Sets z = x mod y */
-int    mp_modulus_divide(const MPNumber *x, const MPNumber *y, MPNumber *z);
+void  mp_modulus_divide(const MPNumber *x, const MPNumber *y, MPNumber *z);
 
 /* Sets z = x^y */
 void   mp_xpowy(const MPNumber *x, const MPNumber *y, MPNumber *z);
@@ -279,9 +279,9 @@ void   mp_mask(const MPNumber *x, int wordlen, MPNumber *z);
 void   mp_shift(const MPNumber *x, int count, MPNumber *z);
 
 /* Sets z to be the ones complement of x for word of length 'wordlen' */
-void   mp_1s_complement(const MPNumber *x, int wordlen, MPNumber *z);
+void   mp_ones_complement(const MPNumber *x, int wordlen, MPNumber *z);
 
 /* Sets z to be the twos complement of x for word of length 'wordlen' */
-void   mp_2s_complement(const MPNumber *x, int wordlen, MPNumber *z);
+void   mp_twos_complement(const MPNumber *x, int wordlen, MPNumber *z);
 
 #endif /* MP_H */
diff --git a/src/unittest.c b/src/unittest.c
index 5271ed2..0ced852 100644
--- a/src/unittest.c
+++ b/src/unittest.c
@@ -93,24 +93,118 @@ test(char *expression, char *expected, int expected_error)
 void
 test_parser()
 {
-    v->base = DEC;
     v->ttype = MP_DEGREES;
     v->wordlen = 32;
     v->accuracy = 9;
+
+    v->base = BIN;
+    test("0", "0", 0);
+    test("1", "1", 0);
+    test("10", "10", 0);
+    test("210", "", -1);
+
+    v->base = OCT;
+    test("0", "0", 0);
+    test("1", "1", 0);
+    test("2", "2", 0);
+    test("3", "3", 0);
+    test("4", "4", 0);
+    test("5", "5", 0);
+    test("6", "6", 0);
+    test("7", "7", 0);
+    test("76543210", "76543210", 0);
+    test("876543210", "", -1);
     
+    v->base = DEC;
+    test("0", "0", 0);
+    test("1", "1", 0);
+    test("2", "2", 0);
+    test("3", "3", 0);
+    test("4", "4", 0);
+    test("5", "5", 0);
+    test("6", "6", 0);
+    test("7", "7", 0);
+    test("8", "8", 0);
+    test("9", "9", 0);
+    test("9876543210", "9876543210", 0);
+    test("A9876543210", "", -7);
+
+    v->base = HEX;
     test("0", "0", 0);
     test("1", "1", 0);
+    test("2", "2", 0);
+    test("3", "3", 0);
+    test("4", "4", 0);
+    test("5", "5", 0);
+    test("6", "6", 0);
+    test("7", "7", 0);
+    test("8", "8", 0);
+    test("9", "9", 0);
+    test("A", "A", 0);
+    test("B", "B", 0);
+    test("C", "C", 0);
+    test("D", "D", 0);    
+    test("E", "E", 0);
+    test("F", "F", 0);    
+    test("FEDBCA9876543210", "FEDBCA9876543210", 0);
+    test("GFEDBCA9876543210", "", -7);
+
+    v->base = DEC;
     test("+1", "1", 0);
-    test("++1", "1", 0);
+    test("â??1", "â??1", 0);
+    test("+ 1", "1", 0); // FIXME: Should this be allowed?
+    test("â?? 1", "â??1", 0); // FIXME: Should this be allowed?
+    test("++1", "1", -1);
     test("â??â??1", "1", 0);
     test("255", "255", 0);
     test("256", "256", 0);
     test("½", "0.5", 0);
-    test("1½", "1.5", 0);    
+    test("1½", "1.5", 0);
     test("1.00", "1", 0);
     test("1.01", "1.01", 0);
+    //test("2A", "2000000000000000", 0);
+    test("2T", "2000000000000", 0);
+    test("2G", "2000000000", 0);
+    test("2M", "2000000", 0);
+    test("2k", "2000", 0);
+    test("2c", "0.02", 0);
+    test("2d", "0.2", 0);
+    test("2c", "0.02", 0);
+    test("2m", "0.002", 0);
+    test("2u", "0.000002", 0);
+    test("2µ", "0.000002", 0);
+    test("2n", "0.000000002", 0);
+    //test("2p", "0.000000000002", 0); // FIXME: Need to print out significant figures, not decimal places
+    //test("2f", "0.000000000000002", 0); // FIXME: Need to print out significant figures, not decimal places
+    //test("2A3", "2300000000000000", 0);
+    test("2T3", "2300000000000", 0);
+    test("2G3", "2300000000", 0);
+    test("2M3", "2300000", 0);
+    test("2k3", "2300", 0);
+    test("2c3", "0.023", 0);
+    test("2d3", "0.23", 0);
+    test("2c3", "0.023", 0);
+    test("2m3", "0.0023", 0);
+    test("2u3", "0.0000023", 0);
+    test("2µ3", "0.0000023", 0);
+    //test("2n3", "0.0000000023", 0); // FIXME: Need to print out significant figures, not decimal places
+    //test("2p3", "0.0000000000023", 0); // FIXME: Need to print out significant figures, not decimal places
+    //test("2f3", "0.0000000000000023", 0); // FIXME: Need to print out significant figures, not decimal places
     test("Ï?", "3.141592654", 0);
-    test("e^1", "2.718281828", 0);
+    test("e", "2.718281828", 0);
+
+    test("2Ï?", "6.283185307", 0);
+    test("2e", "5.436563657", 0);
+    //test("2Ï?²", "19.739208802", 0);
+    //test("2e²", "14.778112198", 0);
+    test("e2", "", -1);
+    test("Ï?2", "", -1);
+    test("Ï?e", "8.539734223", 0);
+    test("eÏ?", "8.539734223", 0);
+    //test("2Ï?e", "17.079468445", 0);
+    
+    test("١٢٣٤٥٦٧٨٩٠", "1234567890", 0);
+    test("Û±Û²Û³Û´ÛµÛ¶Û·Û¸Û¹Û°", "1234567890", 0);
 
     test("0+0", "0", 0);
     test("1+1", "2", 0);
@@ -169,8 +263,10 @@ test_parser()
     test("5!", "120", 0);
     test("69!", "171122452428141311372468338881272839092270544893520369393648040923257279754140647424000000000000000", 0);
     test("0.1!", "", -20001);
-    test("â??1!", "â??1", 0); // FIXME: Should be an error
+    test("â??1!", "", -20001);
+    test("0â??1!", "â??1", 0);    
     test("(â??1)!", "", -20001);
+    test("â??(1!)", "â??1", 0);
 
     test("2²", "4", 0);
     test("2³", "8", 0);
@@ -178,14 +274,18 @@ test_parser()
     test("2^0", "1", 0);
     test("2^1", "2", 0);
     test("2^2", "4", 0);
+    test("2�¹", "0.5", 0);
+    //test("2â?»", "", -20001); // FIXME: Maybe an error in bison?
     test("2^â??1", "0.5", 0);
     test("2^(â??1)", "0.5", 0);
-    test("â??10^2", "â??100", 0);
+    test("â??10^2", "100", 0);
     test("(â??10)^2", "100", 0);
+    test("â??(10^2)", "â??100", 0);
     test("2^100", "1267650600228229401496703205376", 0);
     test("4^3^2", "262144", 0);
     test("4^(3^2)", "262144", 0);
     test("(4^3)^2", "4096", 0);
+    //test("e^(iÏ?)", "1", 0);
     test("â??4", "2", 0);
     test("â??4â??2", "0", 0);
     test("â??8", "2", 0);
@@ -202,11 +302,11 @@ test_parser()
     test("â??4^0.5", "", -20001);
     test("â??8^(1÷3)", "â??2", 0);
     
-    test("0 Mod 7", "0", 0);
-    test("6 Mod 7", "6", 0);
-    test("7 Mod 7", "0", 0);
-    test("8 Mod 7", "1", 0);
-    test("â??1 Mod 7", "6", 0);
+    test("0 mod 7", "0", 0);
+    test("6 mod 7", "6", 0);
+    test("7 mod 7", "0", 0);
+    test("8 mod 7", "1", 0);
+    test("â??1 mod 7", "6", 0);
     
     test("Int(3.2)", "3", 0);
     test("Frac(3.2)", "0.2", 0);
@@ -216,8 +316,10 @@ test_parser()
     test("|1|", "1", 0);
     test("|â??1|", "1", 0);
     test("|3â??5|", "2", 0);
-    test("Abs(1)", "1", 0);
-    test("Abs(â??1)", "1", 0);
+    test("|e|", "2.718281828", 0);
+    test("|Ï?|", "3.141592654", 0);
+    test("abs 1", "1", 0);
+    test("abs â??1", "1", 0);
 
     test("log â??1", "", -20001);
     test("log 0", "", -20001);
@@ -230,7 +332,7 @@ test_parser()
     test("ln 0", "", -20001);
     test("ln 1", "0", 0);
     test("ln 2", "0.693147181", 0);
-    test("ln e^1", "1", 0);
+    test("ln e", "1", 0);
     test("2 ln 2", "1.386294361", 0);
 
     v->ttype = MP_DEGREES;
@@ -289,10 +391,15 @@ test_parser()
     v->ttype = MP_GRADIANS;
     test("sin 100", "1", 0);
 
-    v->base = HEX;
     test("3 and 5", "1", 0);
     test("3 or 5", "7", 0);
     test("3 xor 5", "6", 0);
+
+    v->base = HEX;
+    test("ones 1", "FFFFFFFE", 0);
+    test("ones 7FFFFFFF", "80000000", 0);
+    test("twos 1", "FFFFFFFF", 0);
+    test("twos 7FFFFFFF", "80000001", 0);
     test("3 xnor 5", "FFFFFFF9", 0);
     test("~7A", "FFFFFF85", 0);
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]