Commit c875c8db authored by Arturo Espinosa's avatar Arturo Espinosa

Lots of work as usual :-)



Lots of work as usual :-)

Cell lookup is still broken.
More functions!  COUNT, AVERAGE, AND, OR.

Changed the function framework: it is now easier to write
functions that take multiple arguments.

Added some documentation on writing functions.

Miguel.
parent b261e986
1998-08-06 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/fn-math.c: Moved the math functions to this file.
(gnumeric_sum): Make it use the new function_iterate_argument_values.
(gnumeric_and): Implement AND function.
(gnumeric_or): Implement OR function.
* src/func.c (function_iterate_argument_values): New function to
ease the creation of functions with multiple arguments. It
generates Value * for a list of expressions that might include
arrays and cell ranges.
* src/expr.c (cell_get_col_row): New routine to get the absolute
cordinates with respect to an evaluation column and row.
* src/parser.y (return_symbol): Support for constants.
* src/expr.c (value_copy_to): Support for making Value copies
(only used for our constants actually).
* src/symbol.c (init_constants): Declare TRUE and FALSE.
* src/sheet.c (sheet_selection_changed_hook): Autocomputation
routine. Whenever selection changes this routine will execute an
arbitrary expression (kept in the workbook) and display the
......@@ -64,7 +84,6 @@
* src/parser.y (alloc_glist): Keep track of argument lists.
*
1998-07-30 Federico Mena Quintero <federico@nuclecu.unam.mx>
* src/sheet.c (canvas_bar_realized):
......
1998-08-06 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/fn-math.c: Moved the math functions to this file.
(gnumeric_sum): Make it use the new function_iterate_argument_values.
(gnumeric_and): Implement AND function.
(gnumeric_or): Implement OR function.
* src/func.c (function_iterate_argument_values): New function to
ease the creation of functions with multiple arguments. It
generates Value * for a list of expressions that might include
arrays and cell ranges.
* src/expr.c (cell_get_col_row): New routine to get the absolute
cordinates with respect to an evaluation column and row.
* src/parser.y (return_symbol): Support for constants.
* src/expr.c (value_copy_to): Support for making Value copies
(only used for our constants actually).
* src/symbol.c (init_constants): Declare TRUE and FALSE.
* src/sheet.c (sheet_selection_changed_hook): Autocomputation
routine. Whenever selection changes this routine will execute an
arbitrary expression (kept in the workbook) and display the
......@@ -64,7 +84,6 @@
* src/parser.y (alloc_glist): Keep track of argument lists.
*
1998-07-30 Federico Mena Quintero <federico@nuclecu.unam.mx>
* src/sheet.c (canvas_bar_realized):
......
1998-08-06 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/fn-math.c: Moved the math functions to this file.
(gnumeric_sum): Make it use the new function_iterate_argument_values.
(gnumeric_and): Implement AND function.
(gnumeric_or): Implement OR function.
* src/func.c (function_iterate_argument_values): New function to
ease the creation of functions with multiple arguments. It
generates Value * for a list of expressions that might include
arrays and cell ranges.
* src/expr.c (cell_get_col_row): New routine to get the absolute
cordinates with respect to an evaluation column and row.
* src/parser.y (return_symbol): Support for constants.
* src/expr.c (value_copy_to): Support for making Value copies
(only used for our constants actually).
* src/symbol.c (init_constants): Declare TRUE and FALSE.
* src/sheet.c (sheet_selection_changed_hook): Autocomputation
routine. Whenever selection changes this routine will execute an
arbitrary expression (kept in the workbook) and display the
......@@ -64,7 +84,6 @@
* src/parser.y (alloc_glist): Keep track of argument lists.
*
1998-07-30 Federico Mena Quintero <federico@nuclecu.unam.mx>
* src/sheet.c (canvas_bar_realized):
......
1998-08-06 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/fn-math.c: Moved the math functions to this file.
(gnumeric_sum): Make it use the new function_iterate_argument_values.
(gnumeric_and): Implement AND function.
(gnumeric_or): Implement OR function.
* src/func.c (function_iterate_argument_values): New function to
ease the creation of functions with multiple arguments. It
generates Value * for a list of expressions that might include
arrays and cell ranges.
* src/expr.c (cell_get_col_row): New routine to get the absolute
cordinates with respect to an evaluation column and row.
* src/parser.y (return_symbol): Support for constants.
* src/expr.c (value_copy_to): Support for making Value copies
(only used for our constants actually).
* src/symbol.c (init_constants): Declare TRUE and FALSE.
* src/sheet.c (sheet_selection_changed_hook): Autocomputation
routine. Whenever selection changes this routine will execute an
arbitrary expression (kept in the workbook) and display the
......@@ -64,7 +84,6 @@
* src/parser.y (alloc_glist): Keep track of argument lists.
*
1998-07-30 Federico Mena Quintero <federico@nuclecu.unam.mx>
* src/sheet.c (canvas_bar_realized):
......
Function: AND
Syntax: AND(b1, b2, ...)
Implements the logical AND function: the result is TRUE if all of the
expression evaluate to TRUE, otherwise it returns FALSE.
b1, trough bN are expressions that should evaluate to TRUE or FALSE.
If an integer or floating point value is provided zero is considered
FALSE and anything else is TRUE.
If the values contain strings or empty cells those values are
ignored. If no logical values are provided, then the error '#VALUE!'
is returned.
See also: OR.
-----------------------
Function: AVERAGE
Syntax: AVERAGE(value1, value2,...)
Computes the average of all the values and cells referenced in the
argument list. This is equivalent to the sum of the arguments divided
by the count of the arguments.
See also: SUM, COUNT
-----------------------
Function: OR
Syntax: OR(b1, b2, ...)
Implements the logical OR function: the result is TRUE if any of the
values evaluated to TRUE.
b1, trough bN are expressions that should evaluate to TRUE or FALSE.
If an integer or floating point value is provided zero is considered
FALSE and anything else is TRUE.
If the values contain strings or empty cells those values are
ignored. If no logical values are provided, then the error '#VALUE!'
is returned.
See also: AND
-----------------------
\ No newline at end of file
Writing builtin functions for Gnumeric:
---------------------------------------
Functions in Gnumeric should be registered in the symbol table, to
register a function you just need to prepare a function definition
record.
For example, a simple routine to sum two numbers, you would do:
char *help_add2numbers = "ADD2NUMBERS: Adds two numbers";
FunctionDefinition add_two_numbers =
{ "add2numers", "ff", "number1,number2", help_add2numbers, NULL, add2numbers }
The first C declaration defines the HELP associated with this
function.
The second declaration is our function definition record: the name of
the function is the first parameter (this is how the function will be
exposed to Gnumeric), the next parameter tells gnumeric that we are
expecting two floating point arguments. The third parameter describes
the symbolic names for the arguments (in case our function supports
them, this allows users to specify named paramters); The fourth
parameter links in the help description.
Now, our routine is pretty simple: it will always require 2 arguments
to be passed, so we can let Gnumeric deal with argument count and we
can let the Gnumeric engine compute the values in the expression for
us. So, for this case we leave the fift parameter set as NULL and set
the sixth parameter to point to the function that will do the function
evaluation.
Now, to register the function we just do:
register_add2numbers ()
{
symbol_install (add_two_numbers.name, SYMBOL_FUNCTION, &add_two_numbers);
}
When the user calls the function "ADD2NUMBERS" in a Gnumeric
expression, our routine will be invoked, this is how the add2numbers
function signature looks like:
static Value *
add2numbers (Value *argv [], char **error_string)
{
}
The function should return a newly allocated Value structure.
Arguments are passed in the argv array and they contain Value
structures (look in gnumeric/src/expr.h for the definition of the
Value structure).
Here is the actual implementation:
static Value *
add2numbers (Value *argv [], char **error_string)
{
Value *result;
float number_a, number_b;
switch (argv [0].type){
case VALUE_INTEGER:
number_a = argv [0].v.v_int;
break;
case VALUE_FLOAT:
number_a = argv [0].v.v_float;
break;
default:
*error_string = "Invalid argument type";
return NULL;
}
switch (argv [1].type){
case VALUE_INTEGER:
number_a = argv [1].v.v_int;
break;
case VALUE_FLOAT:
number_a = argv [1].v.v_float;
break;
default:
*error_string = "Invalid argument type";
return NULL;
}
/*
* the line below is equivalent to:
* result = (Value *) malloc (sizeof (Value));
*
*/
result = g_new (Value, 1);
result->type = VALUE_FLOAT;
result->v.v_float = number_a + number_b;
return result;
}
Note that the typechecking is done in the routine itself, it is not
done by the upper layers. If there is an error during the function
processing, *error_string should be set to the error message
describing what went wrong and the NULL value should be returned.
Functions with a variable number of arguments
---------------------------------------------
Gnumeric supports two types of functions: those that take a fixed
number of arguments and those that do take a variable number of
arguments. In the former case, the Gnumeric engine does some work to
simplify function coding, in the later case, the function writer is
pretty much presented with the raw expression tree data as a list.
If you want to implement a function that takes a variable number of
arguments you have to change your FunctionDefinition: instead of
setting the fifth parameter as NULL and the sixth pointing to your
function, you should set the sixth parameter to NULL and you fill in
the fifth parameter, like this:
char *help_factadd = "Adds all of its arguments";
{ "addall", "", "", help_addall, addall, NULL }
We will now implement addall, a function that takes any number and
kind of arguments: strings, integers, floating point numbers, arrays
and cell ranges.
This is a simple usage of addall, lets imagine cell A1 contains the
value 5 and the cell A2 contains the value 3.
addall (1) returns 1
addall (1,2) returns 3
addall (a1:a3) returns 8
addall (a1:a3,1) returns 9
Here is the function signature for addall:
Value *
addall (void *sheet, GList *expr_node_list, int eval_col,
int eval_row, char **error_string)
As usual, this routine would return a newly allocated Value or NULL if
an error is found (and in that case, error_string would be set to
point to a message describing the problem).
The first argument points to a (Sheet *) structure, and the second
argument is a linked list (a GList) that contains (ExprTree *) nodes.
The eval_col and eval_row parameters are used to inform the function
in which context the expression should be evaluated (ie, from which
cell it is being invoked) and it is used when invoking the expr_eval
function.
......@@ -20,6 +20,7 @@ GNUMERIC_BASE_SOURCES = \
func.c \
func.h \
fn-sheet.c \
fn-math.c \
gnumeric-sheet.c \
gnumeric-sheet.h \
gnumeric.h \
......
......@@ -28,7 +28,11 @@ sheet_cell_foreach_range (Sheet *sheet,
if (ri->pos > end_row)
break;
(*callback)(sheet, (Cell *) ri->data);
v = (*callback)(sheet, (Cell *) ri->data);
/* If the callback wishes to stop, return */
if (v)
return;
}
}
}
......
#include <config.h>
#include <gnome.h>
#include "gnumeric.h"
#include "expr.h"
char *parser_expr;
ParseErr parser_error;
......@@ -100,6 +101,8 @@ expr_tree_unref (ExprTree *tree)
void
value_release (Value *value)
{
g_return_if_fail (value != NULL);
switch (value->type){
case VALUE_STRING:
string_unref (value->v.str);
......@@ -130,6 +133,36 @@ value_release (Value *value)
g_free (value);
}
/*
* Copies a Value.
*/
void
value_copy_to (Value *dest, Value *source)
{
g_return_if_fail (dest != NULL);
g_return_if_fail (source != NULL);
dest->type = source->type;
switch (source->type){
case VALUE_STRING:
dest->v.str = source->v.str;
string_ref (dest->v.str);
break;
case VALUE_INTEGER:
dest->v.v_int = source->v.v_int;
break;
case VALUE_FLOAT:
dest->v.v_float = source->v.v_float;
break;
default:
g_warning ("value_copy_to: VALUE type not yet supported\n");
}
}
/*
* Casts a value to float if it is integer, and returns
* a new Value * if required
......@@ -309,6 +342,11 @@ eval_expr (void *asheet, ExprTree *tree, int eval_col, int eval_row, char **erro
{
Value *a, *b, *res;
Sheet *sheet = asheet;
g_return_val_if_fail (tree != NULL, NULL);
g_return_val_if_fail (asheet != NULL, NULL);
g_return_val_if_fail (error_string != NULL, NULL);
g_return_val_if_fail (IS_SHEET (asheet), NULL);
switch (tree->oper){
case OP_EQUAL:
......@@ -502,15 +540,7 @@ eval_expr (void *asheet, ExprTree *tree, int eval_col, int eval_row, char **erro
}
ref = &tree->u.constant->v.cell;
if (ref->col_relative)
col = eval_col + ref->col;
else
col = ref->col;
if (ref->row_relative)
row = eval_row + ref->row;
else
row = ref->row;
cell_get_abs_col_row (&tree->u.constant->v.cell, eval_col, eval_row, &col, &row);
cell = sheet_cell_get (sheet, col, row);
if (!cell)
......@@ -551,3 +581,20 @@ eval_expr (void *asheet, ExprTree *tree, int eval_col, int eval_row, char **erro
*error_string = _("Unknown evaluation error");
return NULL;
}
void
cell_get_abs_col_row (CellRef *cell_ref, int eval_col, int eval_row, int *col, int *row)
{
g_return_if_fail (cell_ref != NULL);
if (cell_ref->col_relative)
*col = eval_col + cell_ref->col;
else
*col = cell_ref->col;
if (cell_ref->row_relative)
*row = eval_row + cell_ref->row;
else
*row = cell_ref->row;
}
......@@ -119,10 +119,11 @@ typedef struct {
* f for float
* s for string
* b for boolean
* ? for any kind
*/
char *args;
char *named_arguments;
char **help;
Value *(*expr_fn)(void *sheet, GList *expr_node_list, int eval_col, int eval_row, char **error_string);
Value *(*fn)(Value *argv [], char **error_string);
......@@ -134,26 +135,32 @@ extern ParseErr parser_error;
extern ExprTree *parser_result;
extern int parser_col, parser_row;
ExprTree *expr_parse_string (char *expr, int col, int row, char **error_msg);
void expr_tree_ref (ExprTree *tree);
void expr_tree_unref (ExprTree *tree);
/* Do not use this routine, it is intended to be used internally */
void eval_expr_release (ExprTree *tree);
Value *eval_expr (void *asheet, ExprTree *tree,
int col, int row,
char **error_string);
void value_release (Value *value);
Value *value_cast_to_float (Value *v);
int value_get_bool (Value *v, int *err);
float_t value_get_as_double (Value *v);
void cell_get_abs_col_row (CellRef *cell_ref, int eval_col, int eval_row, int *col, int *row);
void value_dump (Value *value);
char *value_string (Value *value);
ExprTree *expr_parse_string (char *expr, int col, int row, char **error_msg);
void expr_tree_ref (ExprTree *tree);
void expr_tree_unref (ExprTree *tree);
int yyparse (void);
void functions_init (void);
/* Do not use this routine, it is intended to be used internally */
void eval_expr_release (ExprTree *tree);
Value *eval_expr (void *asheet, ExprTree *tree,
int col, int row,
char **error_string);
void value_release (Value *value);
Value *value_cast_to_float (Value *v);
int value_get_bool (Value *v, int *err);
float_t value_get_as_double (Value *v);
void value_copy_to (Value *dest, Value *source);
void value_dump (Value *value);
char *value_string (Value *value);
int yyparse (void);
/* Setup of the symbol table */
void functions_init (void);
void constants_init (void);
#endif
......@@ -100,28 +100,10 @@ gnumeric_selection (void *tsheet, GList *expr_node_list, int eval_col, int eval_
return value;
}
static Value *
gnumeric_count (void *tsheet, GList *expr_node_list, int eval_col, int eval_row, char **error_string)
{
*error_string = "not yet implemented";
return NULL;
}
static Value *
gnumeric_average (void *tsheet, GList *expr_node_list, int eval_col, int eval_row, char **error_string)
{
*error_string = "not yet implemented";
return NULL;
}
FunctionDefinition sheet_functions [] = {
{ "if", 0, "logical_test,value_if_true,value_if_false",
{ "if", 0, "logical_test,value_if_true,value_if_false", NULL,
gnumeric_if, NULL },
{ "selection", 0, "", gnumeric_selection, NULL },
{ "count", 0, "", gnumeric_count, NULL },
{ "average", 0, "", gnumeric_average, NULL },
{ "selection", 0, "", NULL, gnumeric_selection, NULL },
{ NULL, NULL }
};
......
......@@ -14,439 +14,126 @@
#include "utils.h"
#include "func.h"
static Value *
gnumeric_abs (Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = fabs (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_acos (Value *argv [], char **error_string)
{
Value *v;
float_t t;
t = value_get_as_double (argv [0]);
if ((t < -1.0) || (t > 1.0)){
*error_string = _("acos - domain error");
return NULL;
}
v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = acos (t);
return v;
}
static Value *
gnumeric_acosh (Value *argv [], char **error_string)
{
Value *v;
float_t t;
t = value_get_as_double (argv [0]);
if (t < 1.0){
*error_string = _("acosh - domain error");
return NULL;
}
v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = acosh (t);
return v;
}
static Value *
gnumeric_asin (Value *argv [], char **error_string)
{
Value *v;
float_t t;
t = value_get_as_double (argv [0]);
if ((t < -1.0) || (t > 1.0)){
*error_string = _("asin - domain error");
return NULL;
}
v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = asin (t);
return v;
}
static Value *
gnumeric_asinh (Value *argv [], char **error_string)
{
Value *v;
v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = asinh (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_atan (Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = atan (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_atanh (Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
float_t t;
t = value_get_as_double (argv [0]);
if ((t <= -1.0) || (t >= 1.0)){
*error_string = _("atanh: domain error");
return NULL;
}
v->type = VALUE_FLOAT;
v->v.v_float = atanh (value_get_as_double (argv [0]));
return v;
}
typedef struct {
FunctionIterateCallback callback;
void *closure;
char **error_string;
} IterateCallbackClosure;
static Value *
gnumeric_atan2 (Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = atan2 (value_get_as_double (argv [0]),
value_get_as_double (argv [1]));
return v;
}
static Value *
gnumeric_ceil (Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = ceil (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_cos (Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = cos (value_get_as_double (argv [0]));
return v;
}