Commit 86c717b2 authored by Arturo Espinosa's avatar Arturo Espinosa

We got functions today.


We got functions today.

Miguel.
parent 5908feed
1998-08-04 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/func.c: More functions added.
* src/symbol.c (g_strcase_equal): Symbol hash table does is
case-insensitive.
* src/expr.c (eval_funcall): Added function evaluation.
1998-08-03 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/eval.c: New file. Move the evaluation routines here.
......
1998-08-04 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/func.c: More functions added.
* src/symbol.c (g_strcase_equal): Symbol hash table does is
case-insensitive.
* src/expr.c (eval_funcall): Added function evaluation.
1998-08-03 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/eval.c: New file. Move the evaluation routines here.
......
1998-08-04 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/func.c: More functions added.
* src/symbol.c (g_strcase_equal): Symbol hash table does is
case-insensitive.
* src/expr.c (eval_funcall): Added function evaluation.
1998-08-03 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/eval.c: New file. Move the evaluation routines here.
......
1998-08-04 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/func.c: More functions added.
* src/symbol.c (g_strcase_equal): Symbol hash table does is
case-insensitive.
* src/expr.c (eval_funcall): Added function evaluation.
1998-08-03 Miguel de Icaza <miguel@nuclecu.unam.mx>
* src/eval.c: New file. Move the evaluation routines here.
......
......@@ -140,6 +140,24 @@ value_cast_to_float (Value *v)
return newv;
}
float_t
value_get_as_double (Value *v)
{
if (v->type == VALUE_STRING){
return atof (v->v.str->str);
}
if (v->type == VALUE_CELLRANGE){
g_warning ("Getting range as a double: what to do?");
return 0.0;
}
if (v->type == VALUE_INTEGER)
return (float_t) v->v.v_int;
return v->v.v_float;
}
static Value *
eval_cell_value (Sheet *sheet, Value *value)
{
......@@ -171,6 +189,60 @@ eval_cell_value (Sheet *sheet, Value *value)
return res;
}
static Value *
eval_funcall (Sheet *sheet, ExprTree *tree, int eval_col, int eval_row, char **error_string)
{
FunctionDefinition *fd;
GList *l;
int argc, arg, i;
Value *v;
fd = (FunctionDefinition *) tree->u.function.symbol->data;
l = tree->u.function.arg_list;
argc = g_list_length (l);
if (fd->expr_fn)
{
/* Functions that deal with ExprNodes */
v = fd->expr_fn (sheet, l, eval_col, eval_row, error_string);
}
else
{
/* Functions that take pre-computed Values */
Value **values;
int fn_argc;
char *arg_type = fd->args;
fn_argc = strlen (fd->args);
if (fn_argc != argc){
*error_string = _("Invalid number of arguments");
return NULL;
}
values = g_new (Value *, argc);
for (arg = 0; l; l = l->next, arg++, arg_type++){
ExprTree *t = (ExprTree *) l->data;
v = eval_expr (sheet, t, eval_col, eval_row, error_string);
if (v == NULL)
goto free_list;
values [arg] = v;
}
v = fd->fn (arg+1, values, error_string);
free_list:
for (i = 0; i < arg; i++)
value_release (values [i]);
g_free (values);
return v;
}
return v;
}
Value *
eval_expr (void *asheet, ExprTree *tree, int eval_col, int eval_row, char **error_string)
{
......@@ -291,9 +363,7 @@ eval_expr (void *asheet, ExprTree *tree, int eval_col, int eval_row, char **erro
return NULL;
case OP_FUNCALL:
g_warning ("Function call not implemented yet\n");
*error_string = _("OOPS");
return NULL;
return eval_funcall (sheet, tree, eval_col, eval_row, error_string);
case OP_CONSTANT:
return eval_cell_value (sheet, tree->u.constant);
......
......@@ -90,6 +90,35 @@ typedef enum {
PARSE_ERR_SYNTAX
} ParseErr;
/*
* Functions come in two fashions: Those that only deal with
* very specific data types and a constant number of arguments,
* and those who dont.
*
* The former kind of functions receives a precomputed array of
* Value pointers.
*
* The latter sort of functions receives the plain ExprNodes and
* it is up to that routine to do the value computations and range
* processing.
*/
typedef struct {
/* The function name */
char *name;
/* The types accepted:
* f for float
* s for string
* b for boolean
*/
char *args;
ValueType ret_type;
Value *(*expr_fn)(void *sheet, GList *expr_node_list, int eval_col, int eval_row, char **error_string);
Value *(*fn)(int argc, Value *argv [], char **error_string);
} FunctionDefinition;
/* For communication with yyparse */
extern char *parser_expr;
extern ParseErr parser_error;
......@@ -109,7 +138,9 @@ Value *value_cast_to_float (Value *v);
void value_dump (Value *value);
char *value_string (Value *value);
float_t value_get_as_double (Value *v);
int yyparse (void);
void functions_init (void);
#endif
......@@ -8,21 +8,210 @@
*/
#include <config.h>
#include <gnome.h>
#include "math.h"
#include "gnumeric.h"
#include "gnumeric-sheet.h"
#include "utils.h"
static void
gnumeric_sin (void)
static Value *
gnumeric_abs (int argc, Value *argv [], char **error_string)
{
printf ("Sinning\n");
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 (int argc, 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_asin (int argc, 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_atan (int argc, 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_atan2 (int argc, 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 (int argc, 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 (int argc, 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;
}
static Value *
gnumeric_exp (int argc, Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = exp (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_floor (int argc, Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = floor (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_int (int argc, Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
float_t t;
t = value_get_as_double (argv [0]);
v->type = VALUE_FLOAT;
v->v.v_float = t > 0.0 ? floor (t) : ceil (t);
return v;
}
static Value *
gnumeric_log (int argc, Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = log (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_log10 (int argc, Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = log10 (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_sin (int argc, Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = sin (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_tan (int argc, Value *argv [], char **error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = tan (value_get_as_double (argv [0]));
return v;
}
static Value *
gnumeric_pi (int argc, Value *argv [], char *error_string)
{
Value *v = g_new (Value, 1);
v->type = VALUE_FLOAT;
v->v.v_float = M_PI;
return v;
}
static struct {
char *name;
void (*fn)(void);
} internal_functions [] = {
{ "sin", gnumeric_sin },
FunctionDefinition internal_functions [] = {
{ "abs", "f", VALUE_FLOAT, NULL, gnumeric_abs },
{ "acos", "f", VALUE_FLOAT, NULL, gnumeric_acos },
{ "asin", "f", VALUE_FLOAT, NULL, gnumeric_asin },
{ "atan", "f", VALUE_FLOAT, NULL, gnumeric_atan },
{ "atan2", "ff", VALUE_FLOAT, NULL, gnumeric_atan2 },
{ "cos", "f", VALUE_FLOAT, NULL, gnumeric_cos },
{ "ceil", "f", VALUE_FLOAT, NULL, gnumeric_ceil },
{ "exp", "f", VALUE_FLOAT, NULL, gnumeric_exp },
{ "floor", "f", VALUE_FLOAT, NULL, gnumeric_floor },
{ "int", "f", VALUE_FLOAT, NULL, gnumeric_int },
{ "log", "f", VALUE_FLOAT, NULL, gnumeric_log },
{ "log10", "f", VALUE_FLOAT, NULL, gnumeric_log10 },
{ "sin", "f", VALUE_FLOAT, NULL, gnumeric_sin },
{ "tan", "f", VALUE_FLOAT, NULL, gnumeric_tan },
{ "pi", "", VALUE_FLOAT, NULL, gnumeric_pi },
{ NULL, NULL },
};
......@@ -32,7 +221,8 @@ functions_init (void)
int i;
for (i = 0; internal_functions [i].name; i++){
symbol_install (internal_functions [i].name, SYMBOL_FUNCTION,
internal_functions [i].fn);
symbol_install (internal_functions [i].name,
SYMBOL_FUNCTION,
&internal_functions [i]);
}
}
......@@ -11,6 +11,7 @@
#include <gnome.h>
#include "gnumeric.h"
#include "gnumeric-sheet.h"
#include "item-bar.h"
#include "item-debug.h"
......@@ -265,27 +266,38 @@ set_cursor (ItemBar *item_bar, int pos)
}
static void
item_bar_start_resize (ItemBar *item_bar, int pos)
item_bar_start_resize (ItemBar *item_bar, int pos, int pixels)
{
GnomeCanvas *canvas = GNOME_CANVAS (item_bar->sheet->sheet_view);
GnomeCanvasGroup *group = GNOME_CANVAS_GROUP (canvas->root);
GnomeCanvasItem *item;
GnomeCanvasPoints *points;
GnumericSheet *gsheet;
double x1, x2, y1, y2;
int division_pos;
gsheet = GNUMERIC_SHEET (item_bar->sheet->sheet_view);
if (item_bar->orientation == GTK_ORIENTATION_VERTICAL){
division_pos = sheet_col_get_distance (item_bar->sheet,
gsheet->top_row,
pos);
x1 = 0.0;
x2 = INT_MAX;
y1 = GNOME_CANVAS_ITEM (item_bar)->y1 + pos;
y2 = GNOME_CANVAS_ITEM (item_bar)->y1 + pos;
x2 = canvas->width;
y1 = division_pos;
y2 = division_pos;
} else {
division_pos = sheet_row_get_distance (item_bar->sheet,
gsheet->top_col,
pos);
x1 = division_pos;
x2 = division_pos;
y1 = 0.0;
y2 = canvas->height;
}
x1 = 0.0;
x2 = 1000.0;
y1 = 0.0;
y2 = 1000.0;
item_bar->resize_guide_offset = division_pos - pixels;
/* Add a guideline to the sheet canvas */
points = gnome_canvas_points_new (2);
points->coords[0] = x1;
......@@ -296,7 +308,7 @@ item_bar_start_resize (ItemBar *item_bar, int pos)
gnome_canvas_line_get_type (),
"points", points,
"fill_color", "black",
"width_pixels", 4,
"width_pixels", 1,
NULL);
gnome_canvas_points_free (points);
......@@ -349,22 +361,22 @@ item_bar_event (GnomeCanvasItem *item, GdkEvent *e)
case GDK_MOTION_NOTIFY:
convert (canvas, e->motion.x, e->motion.y, &x, &y);
if (item_bar->orientation == GTK_ORIENTATION_VERTICAL)
if (item_bar->orientation == GTK_ORIENTATION_VERTICAL){
pos = y;
else
} else {
pos = x;
}
/* Do column resizing or incremental marking */
if (resizing){
int npos;
npos = pos - item_bar->resize_start_pos;
if (npos > 0){
item_bar->resize_width = npos;
gnome_canvas_request_redraw (
GNOME_CANVAS_ITEM(item_bar)->canvas,
0, 0, INT_MAX, INT_MAX);
}
if (npos <= 0)
break;
item_bar->resize_width = npos;
gnome_canvas_request_redraw (GNOME_CANVAS_ITEM(item_bar)->canvas, 0, 0, INT_MAX, INT_MAX);
gnome_canvas_item_move (GNOME_CANVAS_ITEM (item_bar->resize_guide), 0, pos);
} else if (ITEM_BAR_IS_SELECTING (item_bar)){
element = get_col_from_pos (item_bar, pos);
......@@ -390,9 +402,10 @@ item_bar_event (GnomeCanvasItem *item, GdkEvent *e)
item_bar->resize_start_pos = start - cri->pixels;
item_bar->resize_width = cri->pixels;
item_bar_start_resize (item_bar, pos);
item_bar_start_resize (item_bar, element, pos);
gnome_canvas_item_grab (item,
GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
GDK_POINTER_MOTION_MASK |
GDK_BUTTON_RELEASE_MASK,
item_bar->change_cursor,
e->button.time);
} else {
......
......@@ -20,7 +20,8 @@ typedef struct {
int resize_width;
int resize_start_pos;
GtkObject *resize_guide;
int resize_guide_offset;
int dragging : 1;
int start_selection;
} ItemBar;
......
......@@ -129,16 +129,7 @@ exp: NUMBER { $$ = $1 }
| CELLREF ':' CELLREF {}
| FUNCALL '(' arg_list ')' {
GList *l;
int i;
for (i = 0, l = $3; l; l = l->next){
printf ("Arg %d\n", i++);
dump_tree (l->data);
}
$$ = p_new (ExprTree);
$$->oper = OP_FUNCALL;
$$->u.function.symbol = $1->u.function.symbol;
$$ = $1;
$$->u.function.arg_list = $3;
}
;
......@@ -151,7 +142,8 @@ arg_list: exp {
forget_glist ($3);
$$ = g_list_prepend ($3, $1);
alloc_glist ($$);
}
}
| { $$ = NULL; }
;
%%
......@@ -224,27 +216,35 @@ static int
return_symbol (char *string)
{
ExprTree *e = p_new (ExprTree);
Value *v = v_new ();
Symbol *sym;
int type;
sym = symbol_lookup (string);
type = STRING;
if (!sym){
Value *v = v_new ();
v->v.str = string_get (string);
v->type = VALUE_STRING;
register_string (v->v.str);
e->oper = OP_CONSTANT;
e->u.constant = v;
} else {
symbol_ref (sym);
if (sym->type == SYMBOL_FUNCTION)
type = FUNCALL;
v->v.sym = sym;
register_symbol (v->v.sym);
else {
g_warning ("Unreachable\n");
type = -1;
}
e->oper = OP_FUNCALL;
e->u.function.symbol = sym;
e->u.function.arg_list = NULL;
register_symbol (sym);
}
v->type = VALUE_STRING;
e->oper = OP_CONSTANT;
e->u.constant = v;
yylval.tree = e;
return type;
}
......
......@@ -119,8 +119,14 @@ symbol_unref (Symbol *sym)
}
}
gint
g_strcase_equal (gconstpointer v1, gconstpointer v2)
{
return strcasecmp ((const gchar*) v1, (const gchar*) v2) == 0;
}
void
symbol_init (void)
{
symbol_hash_table = g_hash_table_new (g_str_hash, g_str_equal);
symbol_hash_table = g_hash_table_new (g_str_hash, g_strcase_equal);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment