/* util.c: Utility routines for bc. */
/* This file is part of bc written for MINIX.
Copyright (C) 1991 Free Software Foundation, Inc.
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
the Free Software Foundation; either version 2 of the License , or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
You may contact the author by:
us-mail: Philip A. Nelson
Computer Science Department, 9062
Western Washington University
Bellingham, WA 98226-9062
*************************************************************************/
/* strcopyof mallocs new memory and copies a string to to the new
temp
= (char *) bc_malloc (strlen (str
)+1);
return (strcpy (temp
,str
));
/* nextarg adds another value to the list of arguments. */
temp
= (arg_list
*) bc_malloc (sizeof (arg_list
));
/* For generate, we must produce a string in the form
"val,val,...,val". We also need a couple of static variables
for retaining old generated strings. It also uses a recursive
function that builds the string. */
static char *arglist1
= NULL
, *arglist2
= NULL
;
/* make_arg_str does the actual construction of the argument string.
ARGS is the pointer to the list and LEN is the maximum number of
characters needed. 1 char is the minimum needed. COMMAS tells
if each number should be seperated by commas.*/
_PROTOTYPE (static char *make_arg_str
, (arg_list
*args
, int len
, int commas
));
make_arg_str (args
, len
, commas
)
temp
= make_arg_str (args
->next
, len
+11, commas
);
temp
= (char *) bc_malloc (len
);
/* Add the current number to the end of the string. */
sprintf (sval
, "%d,", args
->av_name
);
sprintf (sval
, "%d", args
->av_name
);
temp
= strcat (temp
, sval
);
arglist1
= make_arg_str (args
, 1, commas
);
/* free_args frees an argument list ARGS. */
/* Check for valid parameter (PARAMS) and auto (AUTOS) lists.
There must be no duplicates any where. Also, this is where
warnings are generated for array parameters. */
check_params ( params
, autos
)
arg_list
*params
, *autos
;
/* Check for duplicate parameters. */
if (tmp2
->av_name
== tmp1
->av_name
)
yyerror ("duplicate parameter names");
warn ("Array parameter");
/* Check for duplicate autos. */
if (tmp2
->av_name
== tmp1
->av_name
)
yyerror ("duplicate auto variable names");
/* Check for duplicate between parameters and autos. */
if ((params
!= NULL
) && (autos
!= NULL
))
if (tmp2
->av_name
== tmp1
->av_name
)
yyerror ("variable in both parameter and auto lists");
/* Initialize the code generator the parser. */
/* generate code STR for the machine. */
out_count
+= strlen(str
);
/* Execute the current code as loaded. */
/* If no compile errors run the current code. */
if (!had_error
&& did_gen
)
/* Reinitialize the code generation and machine. */
/* Output routines: Write a character CH to the standard output.
It keeps track of the number of characters output and may
break the output with a "\<cr>". */
/* The following are "Symbol Table" routines for the parser. */
/* find_id returns a pointer to node in TREE that has the correct
ID. If there is no node in TREE with ID, NULL is returned. */
/* Check for an empty tree. */
/* Recursively search the tree. */
cmp_result
= strcmp (id
, tree
->id
);
return tree
; /* This is the item. */
return find_id (tree
->left
, id
);
return find_id (tree
->right
, id
);
/* insert_id_rec inserts a NEW_ID rec into the tree whose ROOT is
provided. insert_id_rec returns TRUE if the tree height from
ROOT down is increased otherwise it returns FALSE. This is a
recursive balanced binary tree insertion algorithm. */
int insert_id_rec (root
, new_id
)
/* If root is NULL, this where it is to be inserted. */
/* We need to search for a leaf. */
if (strcmp (new_id
->id
, (*root
)->id
) < 0)
/* Insert it on the left. */
if (insert_id_rec (&((*root
)->left
), new_id
))
/* The height increased. */
switch ((*root
)->balance
)
case 0: /* no height increase. */
case -1: /* height increase. */
case -2: /* we need to do a rebalancing act. */
B
->right
= (*root
)->left
;
A
->left
= (*root
)->right
;
switch ((*root
)->balance
)
/* Insert it on the right. */
if (insert_id_rec (&((*root
)->right
), new_id
))
/* The height increased. */
switch ((*root
)->balance
)
case 0: /* no height increase. */
case 1: /* height increase. */
case 2: /* we need to do a rebalancing act. */
B
->left
= (*root
)->right
;
A
->right
= (*root
)->left
;
switch ((*root
)->balance
)
/* If we fall through to here, the tree did not grow in height. */
/* Initialize variables for the symbol table tree. */
next_var
= 4; /* 0 => ibase, 1 => obase, 2 => scale, 3 => last. */
/* Lookup routines for symbol table names. */
/* Warn about non-standard name. */
warn ("multiple letter name - %s", name
);
id
= find_id (name_tree
, name
);
/* We need to make a new item. */
id
= (id_rec
*) bc_malloc (sizeof (id_rec
));
id
->id
= strcopyof (name
);
insert_id_rec (&name_tree
, id
);
/* Return the correct value. */
/* ARRAY variable numbers are returned as negative numbers. */
id
->a_name
= next_array
++;
a_names
[id
->a_name
] = name
;
if (id
->a_name
< MAX_STORE
)
if (id
->a_name
>= a_count
)
yyerror ("Too many array variables");
id
->f_name
= next_func
++;
f_names
[id
->f_name
] = name
;
if (id
->f_name
< MAX_STORE
)
if (id
->f_name
>= f_count
)
yyerror ("Too many functions");
v_names
[id
->v_name
- 1] = name
;
if (id
->v_name
<= MAX_STORE
)
if (id
->v_name
>= v_count
)
yyerror ("Too many variables");
/* Print the welcome banner. */
printf ("This is free software with ABSOLUTELY NO WARRANTY.\n");
printf ("For details type `warranty'. \n");
/* Print out the warranty information. */
printf ("\n%s%s\n\n", prefix
, BC_VERSION
);
printf ("%s%s%s%s%s%s%s%s%s%s%s",
" This program is free software; you can redistribute it and/or modify\n",
" it under the terms of the GNU General Public License as published by\n",
" the Free Software Foundation; either version 2 of the License , or\n",
" (at your option) any later version.\n\n",
" This program is distributed in the hope that it will be useful,\n",
" but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n",
" GNU General Public License for more details.\n\n",
" You should have received a copy of the GNU General Public License\n",
" along with this program. If not, write to the Free Software\n",
" Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.\n\n");
/* Print out the limits of this program. */
printf ("BC_BASE_MAX = %d\n", BC_BASE_MAX
);
printf ("BC_DIM_MAX = %ld\n", (long) BC_DIM_MAX
);
printf ("BC_SCALE_MAX = %d\n", BC_SCALE_MAX
);
printf ("BC_STRING_MAX = %d\n", BC_STRING_MAX
);
printf ("MAX Exponent = %ld\n", (long) LONG_MAX
);
printf ("MAX code = %ld\n", (long) BC_MAX_SEGS
* (long) BC_SEG_SIZE
);
printf ("multiply digits = %ld\n", (long) LONG_MAX
/ (long) 90);
printf ("Number of vars = %ld\n", (long) MAX_STORE
);
printf ("Old assignment operatiors are valid. (=-, =+, ...)\n");
/* bc_malloc will check the return value so all other places do not
have to do it! SIZE is the number of types to allocate. */
ptr
= (char *) malloc (size
);
/* The following routines are error routines for various problems. */
/* Malloc could not get enought memory. */
fprintf (stderr
, "Fatal error: Out of memory for malloc.\n");
/* The standard yyerror routine. Built with variable number of argumnets. */
fprintf (stderr
,"%s %d: ",name
,line_no
);
vfprintf (stderr
, str
, args
);
/* The routine to produce warnings about non-standard features
fprintf (stderr
,"%s %d: ",name
,line_no
);
vfprintf (stderr
, mesg
, args
);
fprintf (stderr
,"%s %d: (Warning) ",name
,line_no
);
vfprintf (stderr
, mesg
, args
);
/* Runtime error will print a message and stop the machine. */
rt_error (char *mesg
, ...)
rt_error (mesg
, va_alist
)
vsprintf (error_mesg
, mesg
, args
);
fprintf (stderr
, "Runtime error (func=%s, adr=%d): %s\n",
f_names
[pc
.pc_func
], pc
.pc_addr
, error_mesg
);
/* A runtime warning tells of some action taken by the processor that
may change the program execution but was not enough of a problem
to stop the execution. */
rt_warn (char *mesg
, ...)
vsprintf (error_mesg
, mesg
, args
);
fprintf (stderr
, "Runtime warning (func=%s, adr=%d): %s\n",
f_names
[pc
.pc_func
], pc
.pc_addr
, error_mesg
);