Commit a7ecd1c5 authored by Arturo Espinosa's avatar Arturo Espinosa

More work.



More work.
parent cb5a5098
......@@ -3,14 +3,15 @@ CFLAGS += -g -Wall \
-Wmissing-prototypes -Wmissing-declarations
bin_PROGRAMS = gnumeric
noinst_PROGRAMS = test-format
noinst_PROGRAMS = test-format test-parser
INCLUDES = \
-DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
-I$(includedir) \
$(GNOME_INCLUDEDIR)
gnumeric_SOURCES = \
GNUMERIC_BASE_SOURCES = \
cell.h \
expr.c \
expr.h \
......@@ -27,7 +28,6 @@ gnumeric_SOURCES = \
item-edit.h \
item-grid.c \
item-grid.h \
main.c \
parser.y \
sheet.c \
sheet.h \
......@@ -39,6 +39,11 @@ gnumeric_SOURCES = \
utils.h \
workbook.c
gnumeric_SOURCES = \
main.c \
$(GNUMERIC_BASE_SOURCES)
gnumeric_LDADD = \
$(GNOME_LIBDIR) \
$(GNOMEUI_LIBS) \
......@@ -50,6 +55,14 @@ test_format_LDADD = \
$(GNOME_LIBDIR) \
$(GNOMEUI_LIBS)
test_parser_SOURCES = \
test-parser.c \
$(GNUMERIC_BASE_SOURCES)
test_parser_LDADD = \
$(GNOME_LIBDIR) \
$(GNOMEUI_LIBS) -lgmp
#test_token_SOURCES = \
# test-token.c \
# token.c \
......
......@@ -36,11 +36,12 @@ typedef struct {
char *entered_text;
/* Type of the content and the actual parsed content */
EvalNode *parsed_node;
EvalNode *parsed_node; /* Parse tree with the expression */
Value *value; /* Last value computed */
Style *style;
/* computed versions of the cell contents */
char *text; /* Text displayed */
char *text; /* Text rendered and displayed */
GdkColor color; /* color for the displayed text */
int width; /* Width of text */
int height; /* Height of text */
......@@ -48,6 +49,7 @@ typedef struct {
int flags;
} Cell;
#define CELL_IS_FORMULA(cell) (cell->entered_text [0] == '=')
#endif /* GNUMERIC_CELL_H */
......
#include <config.h>
#include <glib.h>
#include <libgnome/gnome-defs.h>
#include <libgnome/gnome-i18n.h>
#include "numbers.h"
#include "symbol.h"
#include "expr.h"
#include <gnome.h>
#include "gnumeric.h"
char *parser_expr;
ParseErr parser_error;
EvalNode *parser_result;
int parser_col, parser_row;
EvalNode *
eval_parse_string (char *expr, int col, int row, char **error_msg)
eval_parse_string (char *expr, char **error_msg)
{
parser_expr = expr;
parser_error = PARSE_OK;
parser_col = col;
parser_row = row;
yyparse ();
switch (parser_error){
case PARSE_OK:
*error_msg = NULL;
break;
return parser_result;
case PARSE_ERR_SYNTAX:
*error_msg = _("Syntax error");
break;
case PARSE_ERR_NO_QUOTE:
*error_msg = _("Missing quote");
break;
......@@ -32,7 +29,7 @@ eval_parse_string (char *expr, int col, int row, char **error_msg)
return NULL;
}
static void
void
eval_release_value (Value *value)
{
switch (value->type){
......@@ -90,14 +87,239 @@ eval_release_node (EvalNode *node)
g_free (node);
}
/*
* Casts a value to float if it is integer, and returns
* a new Value * if required
*/
Value *
eval_node (EvalNode *node)
eval_cast_to_float (Value *v)
{
Value *newv;
g_return_val_if_fail (VALUE_IS_NUMBER (v), NULL);
if (v->type == VALUE_FLOAT)
return v;
newv = g_new (Value, 1);
newv->type = VALUE_FLOAT;
mpf_set_z (newv->v.v_float, v->v.v_int);
eval_release_value (v);
return newv;
}
static Value *
eval_cell_value (Sheet *sheet, Value *value)
{
Value *res;
res = g_new (Value, 1);
res->type = value->type;
switch (res->type){
case VALUE_STRING:
res->v.str = value->v.str;
symbol_ref (res->v.str);
break;
case VALUE_INTEGER:
mpz_init (res->v.v_int);
mpz_set (res->v.v_int, value->v.v_int);
break;
case VALUE_FLOAT:
mpf_init (res->v.v_float);
mpf_set (res->v.v_float, value->v.v_float);
break;
case VALUE_CELLRANGE:
res->v.cell_range = value->v.cell_range;
break;
}
return res;
}
Value *
eval_node_value (void *asheet, EvalNode *node, char **error_string)
{
Value *a, *b, *res;
Sheet *sheet = asheet;
switch (node->oper){
case OP_ADD:
case OP_SUB:
case OP_MULT:
case OP_DIV:
case OP_EXP:
a = eval_node_value (sheet, node->u.binary.value_a,
error_string);
b = eval_node_value (sheet, node->u.binary.value_b,
error_string);
if (!(a && b)){
if (a)
eval_release_value (a);
if (b)
eval_release_value (b);
return NULL;
}
if (!VALUE_IS_NUMBER (a) || !VALUE_IS_NUMBER (b)){
eval_release_value (a);
eval_release_value (b);
*error_string = _("Type mismatch");
return NULL;
}
res = g_new (Value, 1);
if (a->type == VALUE_INTEGER && b->type == VALUE_INTEGER){
res->type = VALUE_INTEGER;
mpz_init (res->v.v_int);
switch (node->oper){
case OP_ADD:
mpz_add (res->v.v_int, a->v.v_int, b->v.v_int);
break;
case OP_SUB:
mpz_sub (res->v.v_int, a->v.v_int, b->v.v_int);
break;
case OP_MULT:
mpz_mul (res->v.v_int, a->v.v_int, b->v.v_int);
break;
case OP_DIV:
if (mpz_cmp_si (b->v.v_int, 0)){
eval_release_value (a);
eval_release_value (b);
eval_release_value (res);
*error_string = _("Division by zero");
return NULL;
}
mpz_tdivq(res->v.v_int, a->v.v_int,b->v.v_int);
break;
case OP_EXP:
mpz_set_si (res->v.v_int, 0);
g_warning ("INT EXP not implemented yet\n");
break;
default:
}
} else {
res->type = VALUE_FLOAT;
mpf_init (res->v.v_float);
a = eval_cast_to_float (a);
b = eval_cast_to_float (b);
switch (node->oper){
case OP_ADD:
mpf_add (res->v.v_float,
a->v.v_float, b->v.v_float);
break;
case OP_SUB:
mpf_sub (res->v.v_float,
a->v.v_float, b->v.v_float);
break;
case OP_MULT:
mpf_mul (res->v.v_float,
a->v.v_float, b->v.v_float);
break;
case OP_DIV:
if (mpf_cmp_si (b->v.v_int, 0)){
eval_release_value (a);
eval_release_value (b);
eval_release_value (res);
*error_string = _("Division by zero");
return NULL;
}
mpf_div (res->v.v_float,
a->v.v_float, b->v.v_float);
break;
case OP_EXP:
mpz_set_si (res->v.v_int, 0);
g_warning ("FLOAT EXP not implemented yet\n");
break;
default:
}
}
eval_release_value (a);
eval_release_value (b);
return res;
case OP_CONCAT:
g_warning ("Concat not implemented yet\n");
*error_string = _("OOPS");
return NULL;
case OP_FUNCALL:
g_warning ("Function call not implemented yet\n");
*error_string = _("OOPS");
return NULL;
case OP_CONSTANT:
return eval_cell_value (sheet, node->u.constant);
case OP_VAR:{
Cell *cell;
int col, row;
if (sheet == NULL){
/* Only the test program requests this */
res = g_new (Value, 1);
res->type = VALUE_FLOAT;
res->v.v_float = 3.14;
return res;
}
col = node->u.constant->v.cell.col;
row = node->u.constant->v.cell.row;
cell = sheet_cell_get (sheet, col, row);
if (!cell)
cell = sheet_cell_new (sheet, col, row);
if (!cell->value){
res = g_new (Value, 1);
res->type = VALUE_INTEGER;
res->v.v_int = 0;
} else {
return eval_cell_value (sheet, cell->value);
}
return res;
}
case OP_NEG:
a = eval_node_value (sheet, node->u.value,
error_string);
if (!a)
return NULL;
if (!VALUE_IS_NUMBER (a)){
*error_string = _("Type mismatch");
eval_release_value (a);
return NULL;
}
res = g_new (Value, 1);
if (a->type == VALUE_INTEGER){
mpz_init_set (res->v.v_int, a->v.v_int);
mpz_neg (res->v.v_int, a->v.v_int);
} else {
mpf_init_set (res->v.v_int, a->v.v_int);
mpf_neg (res->v.v_float, a->v.v_float);
}
eval_release_value (a);
return res;
}
*error_string = _("Unknown evaluation error");
return NULL;
}
......@@ -34,6 +34,7 @@ typedef struct {
typedef struct {
int col, row;
unsigned int col_abs:1;
unsigned int row_abs:1;
} CellRef;
......@@ -53,6 +54,9 @@ typedef struct {
} v;
} Value;
#define VALUE_IS_NUMBER(x) (((x)->type == VALUE_INTEGER) || \
((x)->type == VALUE_FLOAT))
struct EvalNode {
Operation oper;
union {
......@@ -76,16 +80,26 @@ typedef struct EvalNode EvalNode;
typedef enum {
PARSE_OK,
PARSE_ERR_NO_QUOTE
PARSE_ERR_NO_QUOTE,
PARSE_ERR_SYNTAX
} ParseErr;
/* For talking to yyparse */
extern char *parser_expr;
extern ParseErr parser_error;
extern ParseErr parser_error;
extern EvalNode *parser_result;
EvalNode *eval_parse_string (char *expr, int col, int row, char **error_msg);
void eval_release_node (EvalNode *node);
int yyparse (void);
EvalNode *eval_parse_string (char *expr, char **error_msg);
Value *eval_node_value (void *asheet, EvalNode *node,
char **error_string);
void eval_release_node (EvalNode *node);
void eval_release_value (Value *value);
Value *eval_cast_to_float (Value *v);
void eval_dump_value (Value *value);
char *eval_value_string (Value *value);
int yyparse (void);
#endif
......@@ -59,22 +59,35 @@ gnumeric_sheet_cursor_set (GnumericSheet *sheet, int col, int row)
}
void
gnumeric_sheet_accept_pending_output (GnumericSheet *sheet)
gnumeric_sheet_set_current_value (GnumericSheet *sheet)
{
Cell *cell;
int col, row;
g_return_if_fail (sheet != NULL);
g_return_if_fail (GNUMERIC_IS_SHEET (sheet));
col = sheet->cursor_col;
row = sheet->cursor_row;
cell = sheet_cell_get (sheet->sheet, col, row);
if (!cell)
cell = sheet_cell_new (sheet->sheet, sheet->cursor_col, sheet->cursor_row);
cell_set_text (sheet->sheet, cell, gtk_entry_get_text (GTK_ENTRY (sheet->entry)));
sheet_redraw_all (sheet->sheet);
}
void
gnumeric_sheet_accept_pending_output (GnumericSheet *sheet)
{
g_return_if_fail (sheet != NULL);
g_return_if_fail (GNUMERIC_IS_SHEET (sheet));
if (!sheet->item_editor)
return;
cell = sheet_cell_get (sheet->sheet, sheet->cursor_col, sheet->cursor_row);
if (!cell)
cell = sheet_cell_new (sheet->sheet, sheet->cursor_col, sheet->cursor_row);
gnumeric_sheet_set_current_value (sheet);
cell_set_text (cell, gtk_entry_get_text (GTK_ENTRY (sheet->entry)));
gtk_object_destroy (GTK_OBJECT (sheet->item_editor));
sheet->item_editor = NULL;
}
......@@ -85,14 +98,19 @@ gnumeric_sheet_load_cell_val (GnumericSheet *gsheet)
Sheet *sheet;
Workbook *wb;
GtkWidget *entry;
Cell *cell;
g_return_if_fail (GNUMERIC_IS_SHEET (gsheet));
sheet = gsheet->sheet;
wb = sheet->parent_workbook;
entry = wb->ea_input;
gtk_entry_set_text (GTK_ENTRY(entry), "");
cell = sheet_cell_get (sheet, gsheet->cursor_col, gsheet->cursor_row);
if (cell && cell->entered_text){
gtk_entry_set_text (GTK_ENTRY(entry), cell->entered_text);
} else
gtk_entry_set_text (GTK_ENTRY(entry), "");
}
/*
......@@ -126,6 +144,7 @@ start_editing_at_cursor (GnumericSheet *sheet, GtkWidget *entry)
GnomeCanvasItem *item;
GnomeCanvas *canvas = GNOME_CANVAS (sheet);
gtk_entry_set_text (GTK_ENTRY(entry), "");
item = gnome_canvas_item_new (GNOME_CANVAS_GROUP(canvas->root),
item_edit_get_type (),
"ItemEdit::Sheet", sheet->sheet,
......@@ -230,9 +249,9 @@ gnumeric_sheet_key (GtkWidget *widget, GdkEventKey *event)
{
GnumericSheet *sheet = GNUMERIC_SHEET (widget);
Workbook *wb = sheet->sheet->parent_workbook;
void (*movefn_horizontal)(GnumericSheet *, int);
void (*movefn_vertical)(GnumericSheet *, int);
void (*movefn_horizontal) (GnumericSheet *, int);
void (*movefn_vertical) (GnumericSheet *, int);
if ((event->state & GDK_SHIFT_MASK) != 0){
movefn_horizontal = gnumeric_sheet_move_horizontal_selection;
movefn_vertical = gnumeric_sheet_move_vertical_selection;
......
......@@ -36,9 +36,11 @@ void gnumeric_sheet_cursor_set (GnumericSheet *sheet,
void gnumeric_sheet_load_cell_val (GnumericSheet *gsheet);
void gnumeric_sheet_accept_pending_output (GnumericSheet *sheet);
void gnumeric_sheet_compute_visible_ranges (GnumericSheet *gsheet);
void gnumeric_sheet_set_current_value (GnumericSheet *sheet);
typedef struct {
GnomeCanvasClass parent_class;
} GnumericSheetClass;
#endif
......@@ -59,22 +59,35 @@ gnumeric_sheet_cursor_set (GnumericSheet *sheet, int col, int row)
}
void
gnumeric_sheet_accept_pending_output (GnumericSheet *sheet)
gnumeric_sheet_set_current_value (GnumericSheet *sheet)
{
Cell *cell;
int col, row;
g_return_if_fail (sheet != NULL);
g_return_if_fail (GNUMERIC_IS_SHEET (sheet));
col = sheet->cursor_col;
row = sheet->cursor_row;
cell = sheet_cell_get (sheet->sheet, col, row);
if (!cell)
cell = sheet_cell_new (sheet->sheet, sheet->cursor_col, sheet->cursor_row);
cell_set_text (sheet->sheet, cell, gtk_entry_get_text (GTK_ENTRY (sheet->entry)));
sheet_redraw_all (sheet->sheet);
}
void
gnumeric_sheet_accept_pending_output (GnumericSheet *sheet)
{
g_return_if_fail (sheet != NULL);
g_return_if_fail (GNUMERIC_IS_SHEET (sheet));
if (!sheet->item_editor)
return;
cell = sheet_cell_get (sheet->sheet, sheet->cursor_col, sheet->cursor_row);
if (!cell)
cell = sheet_cell_new (sheet->sheet, sheet->cursor_col, sheet->cursor_row);
gnumeric_sheet_set_current_value (sheet);
cell_set_text (cell, gtk_entry_get_text (GTK_ENTRY (sheet->entry)));
gtk_object_destroy (GTK_OBJECT (sheet->item_editor));
sheet->item_editor = NULL;
}
......@@ -85,14 +98,19 @@ gnumeric_sheet_load_cell_val (GnumericSheet *gsheet)
Sheet *sheet;
Workbook *wb;
GtkWidget *entry;
Cell *cell;
g_return_if_fail (GNUMERIC_IS_SHEET (gsheet));
sheet = gsheet->sheet;
wb = sheet->parent_workbook;
entry = wb->ea_input;
gtk_entry_set_text (GTK_ENTRY(entry), "");
cell = sheet_cell_get (sheet, gsheet->cursor_col, gsheet->cursor_row);
if (cell && cell->entered_text){
gtk_entry_set_text (GTK_ENTRY(entry), cell->entered_text);
} else
gtk_entry_set_text (GTK_ENTRY(entry), "");
}
/*
......@@ -126,6 +144,7 @@ start_editing_at_cursor (GnumericSheet *sheet, GtkWidget *entry)
GnomeCanvasItem *item;
GnomeCanvas *canvas = GNOME_CANVAS (sheet);
gtk_entry_set_text (GTK_ENTRY(entry), "");
item = gnome_canvas_item_new (GNOME_CANVAS_GROUP(canvas->root),
item_edit_get_type (),
"ItemEdit::Sheet", sheet->sheet,
......@@ -230,9 +249,9 @@ gnumeric_sheet_key (GtkWidget *widget, GdkEventKey *event)
{
GnumericSheet *sheet = GNUMERIC_SHEET (widget);
Workbook *wb = sheet->sheet->parent_workbook;
void (*movefn_horizontal)(GnumericSheet *, int);
void (*movefn_vertical)(GnumericSheet *, int);
void (*movefn_horizontal) (GnumericSheet *, int);
void (*movefn_vertical) (GnumericSheet *, int);
if ((event->state & GDK_SHIFT_MASK) != 0){
movefn_horizontal = gnumeric_sheet_move_horizontal_selection;
movefn_vertical = gnumeric_sheet_move_vertical_selection;
......
......@@ -36,9 +36,11 @@ void gnumeric_sheet_cursor_set (GnumericSheet *sheet,
void gnumeric_sheet_load_cell_val (GnumericSheet *gsheet);
void gnumeric_sheet_accept_pending_output (GnumericSheet *sheet);
void gnumeric_sheet_compute_visible_ranges (GnumericSheet *gsheet);
void gnumeric_sheet_set_current_value (GnumericSheet *sheet);
typedef struct {
GnomeCanvasClass parent_class;
} GnumericSheetClass;
#endif
......@@ -273,13 +273,16 @@ item_grid_draw_cell (GdkDrawable *drawable, ItemGrid *item_grid,
height - (cell->row->margin_a + cell->row->margin_b));
pixels = 0;
do {
gdk_draw_text (drawable, font, gc,
x1 + x_offset,
text_base + y_offset,
cell->text, strlen (cell->text));
pixels += cell->width;
} while (style->halign == HALIGN_FILL && pixels < cell->col->pixels);
if (cell->text){
do {
gdk_draw_text (drawable, font, gc,
x1 + x_offset,
text_base + y_offset,
cell->text, strlen (cell->text));
pixels += cell->width;
} while (style->halign == HALIGN_FILL &&
pixels < cell->col->pixels);
}
}
static void
......
......@@ -9,8 +9,28 @@ typedef double float_t;
typedef int int_t;
#define mpz_clear(x)
#define mpf_clear(x)
#define mpz_init(x) x = 0
#define mpz_set(a,b) a = b
#define mpz_init_set(a,b) a = b
#define mpz_add(x,a,b) x = a + b
#define mpz_sub(x,a,b) x = a - b
#define mpz_mul(x,a,b) x = a * b
#define mpz_tdivq(x,a,b) x = a / b
#define mpz_cmp_si(a,b) (a == b)
#define mpz_set_si(a,b) a = b
#define mpz_neg(a,b) a = -b
#define mpf_clear(x)
#define mpf_init(x) x = 0
#define mpf_init_set(a,b) a = b
#define mpf_set(a,b) a =b
#define mpf_set_z(x,v) x = v
#define mpf_add(x,a,b) x = a + b
#define mpf_sub(x,a,b) x = a - b
#define mpf_mul(x,a,b) x = a * b
#define mpf_div(x,a,b) x = a / b
#define mpf_cmp_si(a,b) a == b
#define mpf_neg(a,b) a = -b
#endif
......@@ -10,11 +10,11 @@
#include <glib.h>
#include <ctype.h>
#include <string.h>
#include "numbers.h"
#include "symbol.h"
#include "expr.h"
#include "utils.h"
#include <ctype.h>
/* Allocation with disposal-on-error */
static void *alloc_buffer (int size);
......@@ -41,7 +41,6 @@ typedef struct {
static GList *alloc_list;
/* Debugging */
static void dump_constant (EvalNode *node);
static void dump_node (EvalNode *node);
/* Bison/Yacc internals */
......@@ -67,8 +66,11 @@ static int yyerror (char *s);
%right '^'
%%
line: exp { parser_result = $1; dump_node (parser_result); }
| error { alloc_clean (); }
line: exp { parser_result = $1; /* dump_node (parser_result);*/ }
| error {
alloc_clean ();
parser_error = PARSE_ERR_SYNTAX;
}
;
exp: NUMBER { $$ = $1 }
......@@ -139,7 +141,8 @@ return_cellref (char *p)
int row = 0;
EvalNode *e;
Value *v;
CellRef *ref;
/* Try to parse a column */
if (*p == '$'){
col_absolute = TRUE;
......@@ -162,21 +165,24 @@ return_cellref (char *p)
if (!(*p >= '1' && *p <= '9'))
return 0;
while (isdigit (*p))
while (isdigit (*p)){
row = row * 10 + *p - '0';
row++;
p++;
}
row--;
e = p_new (EvalNode);
v = v_new ();
e->oper = OP_VAR;
ref = &e->u.value.v.cell;
ref = &v->v.cell;
ref->col = col;
ref->row = row;
ref->col_abs = col_absolute;
ref->row_abs = row_absolute;
e->u.constant = v;
yylval.node = e;
return CELLREF;
......@@ -188,7 +194,8 @@ return_symbol (char *string)
EvalNode *e = p_new (EvalNode);
Value *v = v_new ();
Symbol *sym;
int type;
sym = symbol_lookup (string);
type = STRING;
if (!sym)
......@@ -206,17 +213,19 @@ return_symbol (char *string)
e->u.constant = v;
yylval.node = e;
return STRING;
return type;
}
static int
try_symbol (char *string)
{
int v;
v = return_cellref (string);
if (v)
return v;
return_symbol (string);
return return_symbol (string);
}
int yylex (void)
......@@ -297,23 +306,23 @@ int yylex (void)
*string = 0;