mirror of
https://github.com/Gnucash/gnucash.git
synced 2026-09-03 20:53:02 -05:00
Clean up expression parser and calculation code.
Add in extra error handling for expression parser. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@2829 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
+290
-125
@@ -254,8 +254,7 @@
|
||||
* Note: in the last five functions, in the function paramter (void
|
||||
* *vp), "vp" is the pointer returned by the "init_parser" function.
|
||||
*
|
||||
* void *init_parser(
|
||||
* var_store_ptr predefined_vars,
|
||||
* void *init_parser(var_store_ptr predefined_vars,
|
||||
* char radix_point,
|
||||
* char group_char,
|
||||
* void *trans_numeric(char *digit_str,
|
||||
@@ -371,7 +370,8 @@
|
||||
|
||||
/* structure to hold parser environment - environment particular to
|
||||
* each caller */
|
||||
typedef struct parser_env {
|
||||
typedef struct parser_env
|
||||
{
|
||||
unsigned stack_cnt;
|
||||
unsigned stack_size;
|
||||
var_store_ptr *stack;
|
||||
@@ -394,15 +394,12 @@ typedef struct parser_env {
|
||||
|
||||
void *numeric_value;
|
||||
void *(*trans_numeric) (const char *digit_str,
|
||||
char radix_point,
|
||||
char group_char,
|
||||
char **rstr);
|
||||
void *(*numeric_ops)(char op_sym,
|
||||
void *left_value,
|
||||
void *right_value);
|
||||
char radix_point, char group_char, char **rstr);
|
||||
void *(*numeric_ops) (char op_sym, void *left_value, void *right_value);
|
||||
void *(*negate_numeric) (void *value);
|
||||
void (*free_numeric) (void *numeric_value);
|
||||
} parser_env;
|
||||
}
|
||||
parser_env;
|
||||
|
||||
#include "finproto.h"
|
||||
#include "fin_static_proto.h"
|
||||
@@ -451,18 +448,21 @@ init_parser(var_store_ptr predefined_vars,
|
||||
return pe;
|
||||
} /* init_parser */
|
||||
|
||||
void exit_parser(parser_env_ptr pe)
|
||||
void
|
||||
exit_parser (parser_env_ptr pe)
|
||||
{
|
||||
var_store_ptr vars, bv;
|
||||
|
||||
if (pe == NULL)
|
||||
return;
|
||||
|
||||
for ( vars = pe->named_vars ; vars ; vars = bv ) {
|
||||
for (vars = pe->named_vars; vars; vars = bv)
|
||||
{
|
||||
g_free (vars->variable_name);
|
||||
vars->variable_name = NULL;
|
||||
|
||||
if ( vars->value ) (pe->free_numeric)(vars->value);
|
||||
if (vars->value)
|
||||
(pe->free_numeric) (vars->value);
|
||||
vars->value = NULL;
|
||||
|
||||
bv = vars->next_var;
|
||||
@@ -497,8 +497,8 @@ var_store_ptr parser_get_vars(parser_env_ptr pe)
|
||||
|
||||
/* function to delete variable with specified name from named variables
|
||||
* if it exists. If it exists return TRUE, 1, else return FALSE, 0 */
|
||||
unsigned delete_var(char *var_name,
|
||||
parser_env_ptr pe)
|
||||
unsigned
|
||||
delete_var (char *var_name, parser_env_ptr pe)
|
||||
{
|
||||
unsigned ret = FALSE;
|
||||
var_store_ptr nv, tv;
|
||||
@@ -506,16 +506,23 @@ unsigned delete_var(char *var_name,
|
||||
if (pe == NULL)
|
||||
return FALSE;
|
||||
|
||||
for ( nv = pe->named_vars , tv = NULL ; nv ; tv = nv , nv = nv->next_var ) {
|
||||
if ( strcmp(nv->variable_name,var_name) == 0 ) {
|
||||
if ( tv ) {
|
||||
for (nv = pe->named_vars, tv = NULL; nv; tv = nv, nv = nv->next_var)
|
||||
{
|
||||
if (strcmp (nv->variable_name, var_name) == 0)
|
||||
{
|
||||
if (tv)
|
||||
tv->next_var = nv->next_var;
|
||||
} else {
|
||||
else
|
||||
pe->named_vars = nv->next_var;
|
||||
} /* endif */
|
||||
|
||||
g_free (nv->variable_name);
|
||||
nv->variable_name = NULL;
|
||||
|
||||
(pe->free_numeric) (nv->value);
|
||||
nv->value = NULL;
|
||||
|
||||
g_free (nv);
|
||||
|
||||
ret = TRUE;
|
||||
break;
|
||||
} /* endif */
|
||||
@@ -529,9 +536,7 @@ unsigned delete_var(char *var_name,
|
||||
* parse error if parse error, return pointer to character at which
|
||||
* error occured. */
|
||||
char *
|
||||
parse_string(var_store_ptr value,
|
||||
const char *string,
|
||||
parser_env_ptr pe)
|
||||
parse_string (var_store_ptr value, const char *string, parser_env_ptr pe)
|
||||
{
|
||||
var_store_ptr retv;
|
||||
var_store unnamed_vars[UNNAMED_VARS];
|
||||
@@ -543,172 +548,198 @@ parse_string(var_store_ptr value,
|
||||
memset (unnamed_vars, 0, UNNAMED_VARS * sizeof (var_store));
|
||||
|
||||
pe->parse_str = string;
|
||||
pe->error_code = PARSER_NO_ERROR;
|
||||
|
||||
next_token (pe);
|
||||
|
||||
if (!pe->error_code)
|
||||
assignment_op (pe);
|
||||
|
||||
if ( pe->Token == EOS ) {
|
||||
if ( (pe->stack_cnt) && (retv = pop(pe)) ) {
|
||||
if (pe->Token == EOS)
|
||||
{
|
||||
if ((pe->stack_cnt) && (retv = pop (pe)))
|
||||
{
|
||||
if (value != NULL)
|
||||
*value = *retv;
|
||||
pe->parse_str = NULL;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
pe->error_code = STACK_UNDERFLOW;
|
||||
} /* endif */
|
||||
} /* endif */
|
||||
pe->stack_cnt = 0;
|
||||
}
|
||||
|
||||
pe->stack_cnt = 0;
|
||||
pe->unnamed_vars = NULL;
|
||||
|
||||
return (char *) pe->parse_str;
|
||||
} /* expression */
|
||||
|
||||
/* pop value off value stack */
|
||||
static var_store_ptr pop(parser_env_ptr pe)
|
||||
static var_store_ptr
|
||||
pop (parser_env_ptr pe)
|
||||
{
|
||||
var_store_ptr val;
|
||||
|
||||
if ( pe->stack_cnt ) val = pe->stack[--(pe->stack_cnt)];
|
||||
else {
|
||||
if (pe->stack_cnt)
|
||||
val = pe->stack[--(pe->stack_cnt)];
|
||||
else
|
||||
{
|
||||
val = NULL;
|
||||
pe->error_code = STACK_OVERFLOW;
|
||||
pe->error_code = STACK_UNDERFLOW;
|
||||
} /* endif */
|
||||
|
||||
return val;
|
||||
} /* pop */
|
||||
|
||||
/* push value onto value stack */
|
||||
static var_store_ptr push(var_store_ptr push_value,
|
||||
parser_env_ptr pe)
|
||||
static var_store_ptr
|
||||
push (var_store_ptr push_value, parser_env_ptr pe)
|
||||
{
|
||||
if (pe->stack_cnt > pe->stack_size)
|
||||
{
|
||||
if ( pe->stack_cnt > pe->stack_size ) {
|
||||
pe->stack_size += STACK_INIT;
|
||||
pe->stack = g_realloc (pe->stack,
|
||||
pe->stack_size * sizeof (var_store_ptr));
|
||||
} /* endif */
|
||||
|
||||
pe->stack[(pe->stack_cnt)++] = push_value;
|
||||
|
||||
return push_value;
|
||||
} /* push */
|
||||
|
||||
/* get/set variable with specified name - nothing fancy
|
||||
* just scan each variable in linked list checking for a string match
|
||||
* return variable found if match
|
||||
* create new variable if none found
|
||||
*/
|
||||
static var_store_ptr get_named_var(parser_env_ptr pe)
|
||||
/* get/set variable with specified name - nothing fancy just scan each
|
||||
* variable in linked list checking for a string match return variable
|
||||
* found if match create new variable if none found */
|
||||
static var_store_ptr
|
||||
get_named_var (parser_env_ptr pe)
|
||||
{
|
||||
var_store_ptr retp = NULL, bv;
|
||||
|
||||
for ( retp = pe->predefined_vars , bv = NULL ; retp ; retp = retp->next_var ) {
|
||||
if ( strcmp(retp->variable_name,pe->name) == 0 ) {
|
||||
for (retp = pe->predefined_vars, bv = NULL; retp; retp = retp->next_var)
|
||||
if (strcmp (retp->variable_name, pe->name) == 0)
|
||||
break;
|
||||
} /* endif */
|
||||
} /* endfor */
|
||||
|
||||
if ( !retp && pe->named_vars ) {
|
||||
for ( retp = pe->named_vars ; retp ; bv = retp , retp = retp->next_var ) {
|
||||
if ( strcmp(retp->variable_name,pe->name) == 0 ) {
|
||||
if (!retp && pe->named_vars)
|
||||
for (retp = pe->named_vars; retp; bv = retp, retp = retp->next_var)
|
||||
if (strcmp (retp->variable_name, pe->name) == 0)
|
||||
break;
|
||||
} /* endif */
|
||||
} /* endfor */
|
||||
} /* endif */
|
||||
|
||||
if ( !retp ) {
|
||||
if (!retp)
|
||||
{
|
||||
retp = g_new0 (var_store, 1);
|
||||
if ( !pe->named_vars ) {
|
||||
if (!pe->named_vars)
|
||||
pe->named_vars = retp;
|
||||
} else {
|
||||
else
|
||||
bv->next_var = retp;
|
||||
} /* endif */
|
||||
retp->variable_name = g_strdup (pe->name);
|
||||
retp->value = (pe->trans_numeric)("0",pe->radix_point,pe->group_char,NULL);
|
||||
} /* endif */
|
||||
retp->value =
|
||||
(pe->trans_numeric) ("0", pe->radix_point, pe->group_char, NULL);
|
||||
}
|
||||
|
||||
return retp;
|
||||
} /* get_var */
|
||||
|
||||
/* get un-named temporary variable
|
||||
*/
|
||||
static var_store_ptr get_unnamed_var(parser_env_ptr pe)
|
||||
/* get un-named temporary variable */
|
||||
static var_store_ptr
|
||||
get_unnamed_var (parser_env_ptr pe)
|
||||
{
|
||||
var_store_ptr retp = NULL;
|
||||
unsigned cntr;
|
||||
|
||||
for ( cntr = 0 ; cntr < UNNAMED_VARS ; cntr++ ) {
|
||||
if ( pe->unnamed_vars[cntr].use_flag == UNUSED_VAR ) {
|
||||
for (cntr = 0; cntr < UNNAMED_VARS; cntr++)
|
||||
if (pe->unnamed_vars[cntr].use_flag == UNUSED_VAR)
|
||||
{
|
||||
retp = &(pe->unnamed_vars[cntr]);
|
||||
retp->variable_name = NULL;
|
||||
retp->use_flag = USED_VAR;
|
||||
if ( retp->value ) {
|
||||
if (retp->value)
|
||||
{
|
||||
(pe->free_numeric) (retp->value);
|
||||
retp->value = NULL;
|
||||
} /* endif */
|
||||
break;
|
||||
} /* endif */
|
||||
} /* endfor */
|
||||
|
||||
if (retp == NULL)
|
||||
pe->error_code = PARSER_OUT_OF_MEMORY;
|
||||
|
||||
return retp;
|
||||
} /* get_unnamed_var */
|
||||
|
||||
/* mark un-named temporary variable unused
|
||||
*/
|
||||
static void free_var(var_store_ptr value,
|
||||
parser_env_ptr pe)
|
||||
/* mark un-named temporary variable unused */
|
||||
static void
|
||||
free_var (var_store_ptr value, parser_env_ptr pe)
|
||||
{
|
||||
/* first check that not a named variable
|
||||
*/
|
||||
if ( !value->variable_name ) {
|
||||
if (value == NULL)
|
||||
return;
|
||||
|
||||
/* first check that not a named variable */
|
||||
if (value->variable_name != NULL)
|
||||
return;
|
||||
|
||||
value->use_flag = UNUSED_VAR;
|
||||
if ( value->value ) {
|
||||
if (value->value)
|
||||
{
|
||||
(pe->free_numeric) (value->value);
|
||||
value->value = NULL;
|
||||
} /* endif */
|
||||
} /* endif */
|
||||
}
|
||||
} /* free_var */
|
||||
|
||||
/* parse next token from string
|
||||
*/
|
||||
static void next_token(parser_env_ptr pe)
|
||||
/* parse next token from string */
|
||||
static void
|
||||
next_token (parser_env_ptr pe)
|
||||
{
|
||||
char *nstr;
|
||||
const char *str_parse = pe->parse_str;
|
||||
void *number;
|
||||
|
||||
while ( isspace(*str_parse) ) str_parse++;
|
||||
while (isspace (*str_parse))
|
||||
str_parse++;
|
||||
|
||||
pe->asn_op = EOS;
|
||||
|
||||
/* test for end of string
|
||||
*/
|
||||
if ( !*str_parse ) {
|
||||
/* test for end of string */
|
||||
if (!*str_parse)
|
||||
{
|
||||
pe->Token = EOS;
|
||||
/* test for name
|
||||
*/
|
||||
} else if ( isalpha(*str_parse) || (*str_parse == '_') ) {
|
||||
/* test for name */
|
||||
}
|
||||
else if (isalpha (*str_parse) || (*str_parse == '_'))
|
||||
{
|
||||
pe->Token = VAR_TOKEN;
|
||||
nstr = pe->name;
|
||||
do {
|
||||
do
|
||||
{
|
||||
*nstr++ = *str_parse++;
|
||||
} while ( (*str_parse == '_') || isalpha(*str_parse) || isdigit(*str_parse) ); /* enddo */
|
||||
}
|
||||
while ((*str_parse == '_') ||
|
||||
isalpha (*str_parse) ||
|
||||
isdigit (*str_parse));
|
||||
|
||||
*nstr = EOS;
|
||||
/* test for possible operator
|
||||
*/
|
||||
} else if ( strchr(allowed_operators,*str_parse) ) {
|
||||
/* test for possible operator */
|
||||
}
|
||||
else if (strchr (allowed_operators, *str_parse))
|
||||
{
|
||||
pe->Token = *str_parse++;
|
||||
if ( *str_parse == '=' ) {
|
||||
if (*str_parse == '=')
|
||||
{
|
||||
str_parse++;
|
||||
pe->asn_op = pe->Token;
|
||||
pe->Token = '=';
|
||||
} /* endif */
|
||||
/* test for numeric token
|
||||
*/
|
||||
} else if ( (number = (pe->trans_numeric)(str_parse,pe->radix_point,pe->group_char,&nstr)) ) {
|
||||
/* test for numeric token */
|
||||
}
|
||||
else if ((number =
|
||||
(pe->trans_numeric) (str_parse, pe->radix_point,
|
||||
pe->group_char, &nstr)))
|
||||
{
|
||||
pe->Token = NUM_TOKEN;
|
||||
pe->numeric_value = number;
|
||||
str_parse = nstr;
|
||||
/* unrecognized character - error
|
||||
*/
|
||||
} else {
|
||||
/* unrecognized character - error */
|
||||
}
|
||||
else
|
||||
{
|
||||
pe->Token = *str_parse;
|
||||
pe->error_code = UNDEFINED_CHARACTER;
|
||||
} /* endif */
|
||||
@@ -723,40 +754,75 @@ static void next_token(parser_env_ptr pe)
|
||||
* \=
|
||||
* *=
|
||||
*/
|
||||
static void assignment_op(parser_env_ptr pe)
|
||||
static void
|
||||
assignment_op (parser_env_ptr pe)
|
||||
{
|
||||
var_store_ptr vl, /* left value */
|
||||
vr; /* right value */
|
||||
var_store_ptr vl; /* left value */
|
||||
var_store_ptr vr; /* right value */
|
||||
void *sp; /* for swapping values */
|
||||
char ao;
|
||||
|
||||
add_sub_op (pe);
|
||||
while ( pe->Token == '=' ) {
|
||||
if (pe->error_code)
|
||||
return;
|
||||
|
||||
while (pe->Token == '=')
|
||||
{
|
||||
vl = pop (pe);
|
||||
if (pe->error_code)
|
||||
return;
|
||||
|
||||
ao = pe->asn_op;
|
||||
if ( vl->variable_name ) {
|
||||
|
||||
if (vl->variable_name)
|
||||
{
|
||||
next_token (pe);
|
||||
if (pe->error_code)
|
||||
{
|
||||
free_var (vl, pe);
|
||||
return;
|
||||
}
|
||||
|
||||
assignment_op (pe);
|
||||
if (pe->error_code)
|
||||
{
|
||||
free_var (vl, pe);
|
||||
return;
|
||||
}
|
||||
|
||||
vr = pop (pe);
|
||||
if (pe->error_code)
|
||||
{
|
||||
free_var (vl, pe);
|
||||
return;
|
||||
}
|
||||
|
||||
vl->assign_flag = ASSIGNED_TO;
|
||||
if ( ao ) {
|
||||
|
||||
if (ao)
|
||||
{
|
||||
sp = vl->value;
|
||||
vl->value = (pe->numeric_ops) (ao, vl->value, vr->value);
|
||||
(pe->free_numeric) (sp);
|
||||
} else if ( vl != vr ) {
|
||||
if ( !vr->variable_name ) {
|
||||
}
|
||||
else if (vl != vr)
|
||||
{
|
||||
if (!vr->variable_name)
|
||||
{
|
||||
(pe->free_numeric) (vl->value);
|
||||
vl->value = vr->value;
|
||||
vr->value = NULL;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
vl->value = (pe->numeric_ops) (ASN_OP, vl->value, vr->value);
|
||||
} /* endif */
|
||||
|
||||
free_var (vr, pe);
|
||||
} /* endif */
|
||||
|
||||
push (vl, pe);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
pe->Token = EOS; /* error !!!!!!!!!! */
|
||||
pe->error_code = NOT_A_VARIABLE;
|
||||
} /* endif */
|
||||
@@ -764,49 +830,118 @@ static void assignment_op(parser_env_ptr pe)
|
||||
} /* assignment_op */
|
||||
|
||||
/* evaluate addition, subtraction operators */
|
||||
static void add_sub_op(parser_env_ptr pe)
|
||||
static void
|
||||
add_sub_op (parser_env_ptr pe)
|
||||
{
|
||||
var_store_ptr vl, /* left value */
|
||||
vr, /* right value */
|
||||
rslt;
|
||||
var_store_ptr vl; /* left value */
|
||||
var_store_ptr vr; /* right value */
|
||||
var_store_ptr rslt; /* result */
|
||||
char op;
|
||||
|
||||
multiply_divide_op (pe);
|
||||
while ( (pe->Token == '+') || (pe->Token == '-') ) {
|
||||
if (pe->error_code)
|
||||
return;
|
||||
|
||||
while ((pe->Token == '+') || (pe->Token == '-'))
|
||||
{
|
||||
op = pe->Token;
|
||||
|
||||
vl = pop (pe);
|
||||
if (pe->error_code)
|
||||
return;
|
||||
|
||||
next_token (pe);
|
||||
if (pe->error_code)
|
||||
{
|
||||
free_var (vl, pe);
|
||||
return;
|
||||
}
|
||||
|
||||
multiply_divide_op (pe);
|
||||
if (pe->error_code)
|
||||
{
|
||||
free_var (vl, pe);
|
||||
return;
|
||||
}
|
||||
|
||||
vr = pop (pe);
|
||||
if (pe->error_code)
|
||||
{
|
||||
free_var (vl, pe);
|
||||
return;
|
||||
}
|
||||
|
||||
rslt = get_unnamed_var (pe);
|
||||
if (pe->error_code)
|
||||
{
|
||||
free_var (vl, pe);
|
||||
return;
|
||||
}
|
||||
|
||||
rslt->value = (pe->numeric_ops) (op, vl->value, vr->value);
|
||||
|
||||
free_var (vl, pe);
|
||||
free_var (vr, pe);
|
||||
|
||||
push (rslt, pe);
|
||||
} /* endwhile */
|
||||
} /* add_sub_op */
|
||||
|
||||
/* evaluate multiplication, division operators
|
||||
*/
|
||||
static void multiply_divide_op(parser_env_ptr pe)
|
||||
static void
|
||||
multiply_divide_op (parser_env_ptr pe)
|
||||
{
|
||||
var_store_ptr vl, /* left value */
|
||||
vr, /* right value */
|
||||
rslt;
|
||||
var_store_ptr vl; /* left value */
|
||||
var_store_ptr vr; /* right value */
|
||||
var_store_ptr rslt; /* result */
|
||||
char op;
|
||||
|
||||
primary_exp (pe);
|
||||
while ( (pe->Token == '*') || (pe->Token == '/') ) {
|
||||
if (pe->error_code)
|
||||
return;
|
||||
|
||||
while ((pe->Token == '*') || (pe->Token == '/'))
|
||||
{
|
||||
op = pe->Token;
|
||||
|
||||
vl = pop (pe);
|
||||
if (pe->error_code)
|
||||
return;
|
||||
|
||||
next_token (pe);
|
||||
if (pe->error_code)
|
||||
{
|
||||
free_var (vl, pe);
|
||||
return;
|
||||
}
|
||||
|
||||
primary_exp (pe);
|
||||
if (pe->error_code)
|
||||
{
|
||||
free_var (vl, pe);
|
||||
return;
|
||||
}
|
||||
|
||||
vr = pop (pe);
|
||||
if (pe->error_code)
|
||||
{
|
||||
free_var (vl, pe);
|
||||
return;
|
||||
}
|
||||
|
||||
rslt = get_unnamed_var (pe);
|
||||
if (pe->error_code)
|
||||
{
|
||||
free_var (vl, pe);
|
||||
return;
|
||||
}
|
||||
|
||||
rslt->value = (pe->numeric_ops) (op, vl->value, vr->value);
|
||||
|
||||
free_var (vl, pe);
|
||||
free_var (vr, pe);
|
||||
|
||||
push (rslt, pe);
|
||||
} /* endwhile */
|
||||
} /* multiply_divide_op */
|
||||
@@ -817,41 +952,71 @@ static void multiply_divide_op(parser_env_ptr pe)
|
||||
* numerics
|
||||
* grouped expressions, "()"
|
||||
*/
|
||||
static void primary_exp(parser_env_ptr pe)
|
||||
static void
|
||||
primary_exp (parser_env_ptr pe)
|
||||
{
|
||||
var_store_ptr rslt = NULL;
|
||||
char LToken = pe->Token;
|
||||
|
||||
next_token (pe);
|
||||
switch ( LToken ) {
|
||||
if (pe->error_code)
|
||||
return;
|
||||
|
||||
switch (LToken)
|
||||
{
|
||||
case '(':
|
||||
/*add_sub_op(pe); */
|
||||
assignment_op (pe);
|
||||
if ( pe->Token == ')' ) {
|
||||
if (pe->error_code)
|
||||
return;
|
||||
|
||||
if (pe->Token == ')')
|
||||
{
|
||||
rslt = pop (pe);
|
||||
if (pe->error_code)
|
||||
return;
|
||||
|
||||
next_token (pe);
|
||||
} else {
|
||||
if (pe->error_code)
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
pe->Token = EOS; /* error here */
|
||||
pe->error_code = UNBALANCED_PARENS;
|
||||
} /* endif */
|
||||
|
||||
break;
|
||||
|
||||
case '-':
|
||||
case '+':
|
||||
primary_exp (pe);
|
||||
if (pe->error_code)
|
||||
return;
|
||||
|
||||
rslt = pop (pe);
|
||||
if ( LToken == '-' ) {
|
||||
(void)(pe->negate_numeric)(rslt->value);
|
||||
} /* endif */
|
||||
if (pe->error_code)
|
||||
return;
|
||||
|
||||
if (LToken == '-')
|
||||
(pe->negate_numeric) (rslt->value);
|
||||
|
||||
break;
|
||||
|
||||
case NUM_TOKEN:
|
||||
rslt = get_unnamed_var (pe);
|
||||
if (pe->error_code)
|
||||
return;
|
||||
|
||||
rslt->value = pe->numeric_value;
|
||||
pe->numeric_value = NULL;
|
||||
break;
|
||||
|
||||
case VAR_TOKEN:
|
||||
rslt = get_named_var (pe);
|
||||
break;
|
||||
} /* endswitch */
|
||||
|
||||
if (rslt != NULL)
|
||||
push (rslt, pe);
|
||||
} /* primary_exp */
|
||||
|
||||
@@ -475,7 +475,7 @@ int main(int argc, char **argv, char **env)
|
||||
stdout);
|
||||
break;
|
||||
case 'v':
|
||||
for ( value_list = get_vars(parse_env) ; value_list ; value_list = value_list->next_var ) {
|
||||
for ( value_list = parser_get_vars(parse_env) ; value_list ; value_list = value_list->next_var ) {
|
||||
printf("%s: ",value_list->variable_name);
|
||||
nval = (numeric_ptr)(value_list->value);
|
||||
switch ( nval->type ) {
|
||||
|
||||
+713
-594
File diff suppressed because it is too large
Load Diff
+57
-72
@@ -27,116 +27,101 @@
|
||||
#include "finvar.h"
|
||||
|
||||
/*==================================================*/
|
||||
/* fin.c
|
||||
*/
|
||||
/* Line Number: 1209 */
|
||||
unsigned fi_calc_num_payments(
|
||||
fi_ptr fi);
|
||||
/* Line Number: 1221 */
|
||||
double _fi_calc_num_payments(
|
||||
double nint, /* nominal interest rate */
|
||||
/* fin.c */
|
||||
|
||||
unsigned fi_calc_num_payments (fi_ptr fi);
|
||||
|
||||
double
|
||||
_fi_calc_num_payments (double nint, /* nominal interest rate */
|
||||
double pv, /* present value */
|
||||
double pmt, /* periodic payment */
|
||||
double fv, /* future value */
|
||||
unsigned CF, /* compounding frequency */
|
||||
unsigned PF, /* payment frequency */
|
||||
unsigned disc, /* discrete/continuous compounding flag */
|
||||
unsigned bep); /* beginning/end of period payment flag */
|
||||
/* Line Number: 1240 */
|
||||
double fi_calc_interest(
|
||||
fi_ptr fi);
|
||||
/* Line Number: 1257 */
|
||||
double _fi_calc_interest(
|
||||
unsigned per, /* number of periods */
|
||||
unsigned disc, /* discrete/continuous compounding */
|
||||
unsigned bep); /* beginning/end of period payment */
|
||||
|
||||
double fi_calc_interest (fi_ptr fi);
|
||||
|
||||
double
|
||||
_fi_calc_interest (unsigned per, /* number of periods */
|
||||
double pv, /* present value */
|
||||
double pmt, /* periodic payment */
|
||||
double fv, /* future value */
|
||||
unsigned CF, /* compounding frequency */
|
||||
unsigned PF, /* payment frequency */
|
||||
unsigned disc, /* discrete/continuous compounding flag */
|
||||
unsigned bep); /* beginning/end of period payment flag */
|
||||
/* Line Number: 1300 */
|
||||
double fi_calc_present_value(
|
||||
fi_ptr fi);
|
||||
/* Line Number: 1312 */
|
||||
double _fi_calc_present_value(
|
||||
unsigned per, /* number of periods */
|
||||
unsigned disc, /* discrete/continuous compounding */
|
||||
unsigned bep); /* beginning/end of period payment */
|
||||
|
||||
double fi_calc_present_value (fi_ptr fi);
|
||||
|
||||
double
|
||||
_fi_calc_present_value (unsigned per, /* number of periods */
|
||||
double nint, /* nominal interest rate */
|
||||
double pmt, /* periodic payment */
|
||||
double fv, /* future value */
|
||||
unsigned CF, /* compounding frequency */
|
||||
unsigned PF, /* payment frequency */
|
||||
unsigned disc, /* discrete/continuous compounding flag */
|
||||
unsigned bep); /* beginning/end of period payment flag */
|
||||
/* Line Number: 1332 */
|
||||
double fi_calc_payment(
|
||||
fi_ptr fi);
|
||||
/* Line Number: 1344 */
|
||||
double _fi_calc_payment(
|
||||
unsigned per, /* number of periods */
|
||||
unsigned disc, /* discrete/continuous compounding */
|
||||
unsigned bep); /* beginning/end of period payment */
|
||||
|
||||
double fi_calc_payment (fi_ptr fi);
|
||||
|
||||
double
|
||||
_fi_calc_payment (unsigned per, /* number of periods */
|
||||
double nint, /* nominal interest rate */
|
||||
double pv, /* present value */
|
||||
double fv, /* future value */
|
||||
unsigned CF, /* compounding frequency */
|
||||
unsigned PF, /* payment frequency */
|
||||
unsigned disc, /* discrete/continuous compounding flag */
|
||||
unsigned bep); /* beginning/end of period payment flag */
|
||||
/* Line Number: 1363 */
|
||||
double fi_calc_future_value(
|
||||
fi_ptr fi);
|
||||
/* Line Number: 1375 */
|
||||
double _fi_calc_future_value(
|
||||
unsigned per, /* number of periods */
|
||||
unsigned disc, /* discrete/continuous compounding */
|
||||
unsigned bep); /* beginning/end of period payment */
|
||||
|
||||
double fi_calc_future_value (fi_ptr fi);
|
||||
|
||||
double
|
||||
_fi_calc_future_value (unsigned per, /* number of periods */
|
||||
double nint, /* nominal interest rate */
|
||||
double pv, /* present value */
|
||||
double pmt, /* periodic payment */
|
||||
unsigned CF, /* compounding frequency */
|
||||
unsigned PF, /* payment frequency */
|
||||
unsigned disc, /* discrete/continuous compounding flag */
|
||||
unsigned bep); /* beginning/end of period payment flag */
|
||||
/* Line Number: 1464 */
|
||||
void set_default(
|
||||
fi_ptr fi);
|
||||
/* Line Number: 1511 */
|
||||
unsigned long julian_day_number(
|
||||
unsigned year,
|
||||
unsigned month,
|
||||
unsigned day);
|
||||
/* Line Number: 1533 */
|
||||
amort_sched_ptr Amortization_init(
|
||||
amort_sched_ptr amortsched);
|
||||
/* Line Number: 1664 */
|
||||
amort_sched_ptr Amortization_Schedule(
|
||||
amort_sched_ptr amortsched);
|
||||
/* Line Number: 2336 */
|
||||
void Amortization_free(
|
||||
amort_sched_ptr amortsched);
|
||||
unsigned disc, /* discrete/continuous compounding */
|
||||
unsigned bep); /* beginning/end of period payment */
|
||||
|
||||
void set_default (fi_ptr fi);
|
||||
|
||||
unsigned long julian_day_number (unsigned year, unsigned month, unsigned day);
|
||||
|
||||
amort_sched_ptr Amortization_init (amort_sched_ptr amortsched);
|
||||
|
||||
amort_sched_ptr Amortization_Schedule (amort_sched_ptr amortsched);
|
||||
|
||||
void Amortization_free (amort_sched_ptr amortsched);
|
||||
|
||||
|
||||
/*==================================================*/
|
||||
/* expression_parser.c */
|
||||
|
||||
/* Line Number: 377 */
|
||||
void exit_parser (parser_env_ptr pe);
|
||||
/* Line Number: 400 */
|
||||
|
||||
ParseError get_parse_error (parser_env_ptr pe);
|
||||
/* Line Number: 408 */
|
||||
|
||||
var_store_ptr parser_get_vars (parser_env_ptr pe);
|
||||
/* Line Number: 417 */
|
||||
unsigned delete_var(char *var_name,
|
||||
parser_env_ptr pe);
|
||||
/* Line Number: 451 */
|
||||
|
||||
unsigned delete_var (char *var_name, parser_env_ptr pe);
|
||||
|
||||
char *parse_string (var_store_ptr value,
|
||||
const char *string,
|
||||
parser_env_ptr pe);
|
||||
const char *string, parser_env_ptr pe);
|
||||
|
||||
|
||||
/*==================================================*/
|
||||
/* amort_opt.c */
|
||||
amort_sched_ptr amort_opt(amort_sched_ptr amortsched,
|
||||
void *parse_env);
|
||||
amort_sched_ptr amort_opt (amort_sched_ptr amortsched, void *parse_env);
|
||||
|
||||
|
||||
/*==================================================*/
|
||||
/* amort_prt.c */
|
||||
void prt_amortization_schedule (amort_sched_ptr amortsched, /* amortization schedule to print */
|
||||
FILE *ofile); /* output file */
|
||||
void prt_amortization_schedule (amort_sched_ptr amortsched, FILE * ofile);
|
||||
|
||||
#endif
|
||||
|
||||
+45
-26
@@ -45,8 +45,10 @@ typedef enum
|
||||
STACK_UNDERFLOW,
|
||||
UNDEFINED_CHARACTER,
|
||||
NOT_A_VARIABLE,
|
||||
PARSER_OUT_OF_MEMORY,
|
||||
PARSER_NUM_ERRORS
|
||||
} ParseError;
|
||||
}
|
||||
ParseError;
|
||||
|
||||
#define UNUSED_VAR '\x000'
|
||||
#define USED_VAR '\x001'
|
||||
@@ -65,13 +67,15 @@ typedef enum
|
||||
*/
|
||||
typedef struct var_store *var_store_ptr;
|
||||
|
||||
typedef struct var_store {
|
||||
typedef struct var_store
|
||||
{
|
||||
char *variable_name; /* variable name if variable, NULL otherwise */
|
||||
char use_flag; /* flag if variable has been assigned to */
|
||||
char assign_flag; /* flag if variable is used */
|
||||
void *value; /* pointer to imp[lementation defined numeric value */
|
||||
void *value; /* pointer to implementation defined numeric value */
|
||||
var_store_ptr next_var; /* pointer to next variable in linked list */
|
||||
} var_store;
|
||||
}
|
||||
var_store;
|
||||
|
||||
|
||||
/* The following structure is used for the numeric operations
|
||||
@@ -80,13 +84,17 @@ typedef struct var_store {
|
||||
/* structure used for storing numeric values - used by routines which
|
||||
* evaluate arithmetic operators '+', '-', '/', '*' */
|
||||
typedef struct numeric *numeric_ptr;
|
||||
typedef struct numeric {
|
||||
typedef struct numeric
|
||||
{
|
||||
char type; /* designates type of value */
|
||||
union {
|
||||
union
|
||||
{
|
||||
long int int_value; /* long integer value */
|
||||
double dbl_value; /* double value */
|
||||
} value;
|
||||
} numeric;
|
||||
}
|
||||
value;
|
||||
}
|
||||
numeric;
|
||||
|
||||
/* The following structures are used by the amortization functions for
|
||||
* storing amortization schedule information */
|
||||
@@ -94,28 +102,33 @@ typedef struct numeric {
|
||||
/* structure used by amortization routines for storing annual summary
|
||||
information */
|
||||
typedef struct yearly_summary *yearly_summary_ptr;
|
||||
typedef struct yearly_summary {
|
||||
typedef struct yearly_summary
|
||||
{
|
||||
unsigned year;
|
||||
double interest;
|
||||
double end_balance;
|
||||
}yearly_summary;
|
||||
}
|
||||
yearly_summary;
|
||||
|
||||
/* structure used by amortization routines for storing information on
|
||||
a single payment */
|
||||
typedef struct sched_pmt *sched_pmt_ptr;
|
||||
typedef struct sched_pmt {
|
||||
typedef struct sched_pmt
|
||||
{
|
||||
unsigned period_num;
|
||||
double interest;
|
||||
double principal;
|
||||
double advanced_pmt;
|
||||
double total_pmt;
|
||||
double balance;
|
||||
} sched_pmt;
|
||||
}
|
||||
sched_pmt;
|
||||
|
||||
/* structure used by amortization routines for storing information on
|
||||
* payments for a single year */
|
||||
typedef struct amort_sched_yr *amort_sched_yr_ptr;
|
||||
typedef struct amort_sched_yr {
|
||||
typedef struct amort_sched_yr
|
||||
{
|
||||
unsigned year;
|
||||
unsigned num_periods;
|
||||
sched_pmt_ptr payments;
|
||||
@@ -125,12 +138,14 @@ typedef struct amort_sched_yr {
|
||||
double total_interest_pd;
|
||||
double final_pmt;
|
||||
amort_sched_yr_ptr next_yr;
|
||||
} amort_sched_yr;
|
||||
}
|
||||
amort_sched_yr;
|
||||
|
||||
/* structure used by amortization routines for passing and storing
|
||||
* infomation on a particular amortization transaction */
|
||||
typedef struct amort_sched *amort_sched_ptr;
|
||||
typedef struct amort_sched {
|
||||
typedef struct amort_sched
|
||||
{
|
||||
/* following information set by function calling amortization
|
||||
functions */
|
||||
unsigned n; /* number of periods */
|
||||
@@ -150,14 +165,12 @@ functions */
|
||||
unsigned month_I; /* Initial payment date - month */
|
||||
unsigned day_I; /* Initial payment date - day of month */
|
||||
|
||||
/* following information set by calling function to indicate which schedule
|
||||
* to compute and which type of schedule
|
||||
*/
|
||||
/* following information set by calling function to indicate which
|
||||
* schedule to compute and which type of schedule */
|
||||
unsigned option; /* option flag from 1 to 6 inclusive */
|
||||
char summary; /* summary flag == 'y', 'p', 'a' or 'f' */
|
||||
|
||||
/* following information set by amortization functions
|
||||
*/
|
||||
/* following information set by amortization functions */
|
||||
double eint; /* effective interest rate */
|
||||
double bp; /* float value of bep */
|
||||
double total_interest; /* total interest paid */
|
||||
@@ -177,17 +190,21 @@ functions */
|
||||
double cpmt2; /* constant payment to principal, 2cd case */
|
||||
double delayed_int; /* interest due to delayed initial payment */
|
||||
double fixed_pmt; /* fixed prepayment amount for amortization */
|
||||
unsigned new_n; /* new number of periods to amortize due to delayed intial payment */
|
||||
unsigned new_n; /* new number of periods to amortize due to
|
||||
delayed intial payment */
|
||||
unsigned fv_case; /* fv case flag */
|
||||
unsigned long Eff_Date_jdn;
|
||||
unsigned yday_E;
|
||||
unsigned long Init_Date_jdn;
|
||||
unsigned yday_I;
|
||||
union {
|
||||
union
|
||||
{
|
||||
amort_sched_yr_ptr first_yr;
|
||||
yearly_summary_ptr summary;
|
||||
} schedule;
|
||||
} amort_sched;
|
||||
}
|
||||
schedule;
|
||||
}
|
||||
amort_sched;
|
||||
|
||||
/* The following structure is used to hold all of the financial
|
||||
* variables used by the financial calculator */
|
||||
@@ -195,7 +212,8 @@ functions */
|
||||
/* structure used by financial computation routines to store financial
|
||||
variables */
|
||||
typedef struct financial_info *fi_ptr;
|
||||
typedef struct financial_info {
|
||||
typedef struct financial_info
|
||||
{
|
||||
double ir; /* interest rate */
|
||||
double pv; /* present value */
|
||||
double pmt; /* periodic payment */
|
||||
@@ -218,7 +236,8 @@ typedef struct financial_info {
|
||||
* 2 for US Dollars
|
||||
*/
|
||||
unsigned prec;
|
||||
} financial_info;
|
||||
}
|
||||
financial_info;
|
||||
|
||||
typedef struct parser_env *parser_env_ptr;
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#ifndef __NUMERIC_OPS_H__
|
||||
#define __NUMERIC_OPS_H__
|
||||
|
||||
void *trans_numeric(char *str, /* pointer to string to translate */
|
||||
void *trans_numeric(const char *str, /* pointer to string to translate */
|
||||
char radix_point, /* radix character */
|
||||
char group_char, /* grouping character to left of radix */
|
||||
char **endstr); /* where to return pointer to first
|
||||
|
||||
@@ -366,7 +366,7 @@ gnc_exp_parser_parse (const char * expression, double *value_p,
|
||||
|
||||
exit_parser (pe);
|
||||
|
||||
return (error_loc == NULL);
|
||||
return last_error == PARSER_NO_ERROR;
|
||||
}
|
||||
|
||||
const char *
|
||||
@@ -387,5 +387,7 @@ gnc_exp_parser_error_string (void)
|
||||
return PARSER_UNDEFINED_CHARACTER;
|
||||
case NOT_A_VARIABLE:
|
||||
return PARSER_NOT_A_VARIABLE;
|
||||
case PARSER_OUT_OF_MEMORY:
|
||||
return PARSER_OUT_OF_MEMORY_STR;
|
||||
}
|
||||
}
|
||||
|
||||
+24
-30
@@ -140,37 +140,41 @@ gnc_xfer_dialog_create_tree_frame(gchar *title,
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gnc_parse_error_dialog (XferDialog *xferData)
|
||||
{
|
||||
const char *error_string;
|
||||
char * error_phrase;
|
||||
|
||||
error_string = gnc_exp_parser_error_string ();
|
||||
if (error_string == NULL)
|
||||
error_string = "";
|
||||
|
||||
error_phrase = g_strdup_printf(ERROR_IN_AMOUNT, error_string);
|
||||
|
||||
gnc_error_dialog_parented(GTK_WINDOW(xferData->dialog), error_phrase);
|
||||
|
||||
g_free(error_phrase);
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
gnc_xfer_update_cb(GtkWidget *widget, GdkEventFocus *event, gpointer data)
|
||||
{
|
||||
GtkEntry *entry = GTK_ENTRY(widget);
|
||||
XferDialog *xferData = data;
|
||||
Account *account;
|
||||
const char *new_string;
|
||||
const char *currency;
|
||||
const char *string;
|
||||
double value;
|
||||
Account *account;
|
||||
|
||||
account = gnc_account_tree_get_current_account(xferData->from);
|
||||
if (account == NULL)
|
||||
account = gnc_account_tree_get_current_account(xferData->to);
|
||||
|
||||
string = gtk_entry_get_text(entry);
|
||||
|
||||
if ((string == NULL) || (*string == 0))
|
||||
return FALSE;
|
||||
|
||||
value = 0.0;
|
||||
xaccParseAmount(string, TRUE, &value, NULL);
|
||||
|
||||
currency = xaccAccountGetCurrency(account);
|
||||
|
||||
new_string = xaccPrintAmount(value, PRTSEP, currency);
|
||||
gnc_amount_edit_set_currency (GNC_AMOUNT_EDIT (xferData->amount_edit),
|
||||
currency);
|
||||
|
||||
if (safe_strcmp(string, new_string) == 0)
|
||||
return FALSE;
|
||||
|
||||
gtk_entry_set_text(entry, new_string);
|
||||
gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT (xferData->amount_edit));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@@ -329,18 +333,8 @@ gnc_xfer_dialog_ok_cb(GtkWidget * widget, gpointer data)
|
||||
|
||||
if (!gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT (xferData->amount_edit)))
|
||||
{
|
||||
const char *error_string;
|
||||
char * error_phrase;
|
||||
|
||||
error_string = gnc_exp_parser_error_string ();
|
||||
if (error_string == NULL)
|
||||
error_string = "";
|
||||
|
||||
error_phrase = g_strdup_printf(ERROR_IN_AMOUNT, error_string);
|
||||
|
||||
gnc_error_dialog_parented(GTK_WINDOW(xferData->dialog), error_phrase);
|
||||
|
||||
g_free(error_phrase);
|
||||
gnc_parse_error_dialog (xferData);
|
||||
return;
|
||||
}
|
||||
|
||||
amount = gnc_amount_edit_get_amount(GNC_AMOUNT_EDIT(xferData->amount_edit));
|
||||
|
||||
@@ -444,6 +444,7 @@
|
||||
#define PARSER_STACK_UNDERFLOW _("Stack underflow")
|
||||
#define PARSER_UNDEFINED_CHARACTER _("Undefined character")
|
||||
#define PARSER_NOT_A_VARIABLE _("Not a variable")
|
||||
#define PARSER_OUT_OF_MEMORY_STR _("Out of memory")
|
||||
|
||||
|
||||
/** MISC INTERNATIONALIZATION STRINGS: ******************************/
|
||||
|
||||
Reference in New Issue
Block a user